From: Tom Tromey Date: Sun, 15 Dec 2019 14:37:06 +0000 (-0700) Subject: Move gdbserver to top level X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=919adfe84092;p=binutils-gdb.git Move gdbserver to top level This patch moves gdbserver to the top level. This patch is as close to a pure move as possible -- gdbserver still builds its own variant of gnulib and gdbsupport. Changing this will be done in a separate patch. [v2] Note that, per Simon's review comment, this patch changes the tree so that gdbserver is not built for or1k or score. This makes sense, because there is apparently not actually a gdbserver port here. [v3] This version of the patch also splits out some configury into a new file, gdbserver/configure.host, so that the top-level configure script can simply rely on it in order to decide whether gdbserver should be built. [v4] This version adds documentation and removes some unnecessary top-level dependencies. [v5] Update docs to mention "make all-gdbserver" and change how top-level configure decides whether to build gdbserver, switching to a single, shared script. Tested by the buildbot. ChangeLog 2020-02-07 Tom Tromey Pedro Alves * src-release.sh (GDB_SUPPORT_DIRS): Add gdbserver. * gdbserver: New directory, moved from gdb/gdbserver. * configure.ac (host_tools): Add gdbserver. Only build gdbserver on certain systems. * Makefile.in, configure: Rebuild. * Makefile.def (host_modules, dependencies): Add gdbserver. * MAINTAINERS: Add gdbserver. gdb/ChangeLog 2020-02-07 Tom Tromey * README: Update gdbserver documentation. * gdbserver: Move to top level. * configure.tgt (build_gdbserver): Remove. * configure.ac: Remove --enable-gdbserver. * configure: Rebuild. * Makefile.in (distclean): Don't mention gdbserver. Change-Id: I826b7565b54604711dc7a11edea0499cd51ff39e --- diff --git a/ChangeLog b/ChangeLog index 3b835d0c090..4112251fcc8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2020-02-07 Tom Tromey + Pedro Alves + + * src-release.sh (GDB_SUPPORT_DIRS): Add gdbserver. + * gdbserver: New directory, moved from gdb/gdbserver. + * configure.ac (host_tools): Add gdbserver. + Only build gdbserver on certain systems. + * Makefile.in, configure: Rebuild. + * Makefile.def (host_modules, dependencies): Add gdbserver. + * MAINTAINERS: Add gdbserver. + 2020-01-28 Sergio Durigan Junior * src-release.sh (getver): Look for gdbsupport's diff --git a/MAINTAINERS b/MAINTAINERS index 805f2e3ac43..5b8a4efbdf6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -41,7 +41,7 @@ config.guess; config.sub; readline/support/config.{sub,guess} depcomp; mkinstalldirs Send bug reports and patches to bug-automake@gnu.org. -gdb/; gdbsupport/; gnulib/; readline/; sim/; GDB's part of include/ +gdb/; gdbserver/; gdbsupport/; gnulib/; readline/; sim/; GDB's part of include/ GDB: http://www.gnu.org/software/gdb/ Patches to gdb-patches@sourceware.org. See also gdb/MAINTAINERS and sim/MAINTAINERS. diff --git a/Makefile.def b/Makefile.def index 253eb45ef14..72cb133a09a 100644 --- a/Makefile.def +++ b/Makefile.def @@ -114,6 +114,7 @@ host_modules= { module= zlib; no_install=true; no_check=true; extra_configure_flags='@extra_host_zlib_configure_flags@';}; host_modules= { module= gnulib; }; host_modules= { module= gdbsupport; }; +host_modules= { module= gdbserver; }; host_modules= { module= gdb; }; host_modules= { module= expect; }; host_modules= { module= guile; }; diff --git a/Makefile.in b/Makefile.in index af38671cbea..80fa458d8d0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -944,6 +944,7 @@ configure-host: \ maybe-configure-zlib \ maybe-configure-gnulib \ maybe-configure-gdbsupport \ + maybe-configure-gdbserver \ maybe-configure-gdb \ maybe-configure-expect \ maybe-configure-guile \ @@ -1099,6 +1100,7 @@ all-host: maybe-all-zlib @endif zlib-no-bootstrap all-host: maybe-all-gnulib all-host: maybe-all-gdbsupport +all-host: maybe-all-gdbserver all-host: maybe-all-gdb all-host: maybe-all-expect all-host: maybe-all-guile @@ -1208,6 +1210,7 @@ info-host: maybe-info-texinfo info-host: maybe-info-zlib info-host: maybe-info-gnulib info-host: maybe-info-gdbsupport +info-host: maybe-info-gdbserver info-host: maybe-info-gdb info-host: maybe-info-expect info-host: maybe-info-guile @@ -1296,6 +1299,7 @@ dvi-host: maybe-dvi-texinfo dvi-host: maybe-dvi-zlib dvi-host: maybe-dvi-gnulib dvi-host: maybe-dvi-gdbsupport +dvi-host: maybe-dvi-gdbserver dvi-host: maybe-dvi-gdb dvi-host: maybe-dvi-expect dvi-host: maybe-dvi-guile @@ -1384,6 +1388,7 @@ pdf-host: maybe-pdf-texinfo pdf-host: maybe-pdf-zlib pdf-host: maybe-pdf-gnulib pdf-host: maybe-pdf-gdbsupport +pdf-host: maybe-pdf-gdbserver pdf-host: maybe-pdf-gdb pdf-host: maybe-pdf-expect pdf-host: maybe-pdf-guile @@ -1472,6 +1477,7 @@ html-host: maybe-html-texinfo html-host: maybe-html-zlib html-host: maybe-html-gnulib html-host: maybe-html-gdbsupport +html-host: maybe-html-gdbserver html-host: maybe-html-gdb html-host: maybe-html-expect html-host: maybe-html-guile @@ -1560,6 +1566,7 @@ TAGS-host: maybe-TAGS-texinfo TAGS-host: maybe-TAGS-zlib TAGS-host: maybe-TAGS-gnulib TAGS-host: maybe-TAGS-gdbsupport +TAGS-host: maybe-TAGS-gdbserver TAGS-host: maybe-TAGS-gdb TAGS-host: maybe-TAGS-expect TAGS-host: maybe-TAGS-guile @@ -1648,6 +1655,7 @@ install-info-host: maybe-install-info-texinfo install-info-host: maybe-install-info-zlib install-info-host: maybe-install-info-gnulib install-info-host: maybe-install-info-gdbsupport +install-info-host: maybe-install-info-gdbserver install-info-host: maybe-install-info-gdb install-info-host: maybe-install-info-expect install-info-host: maybe-install-info-guile @@ -1736,6 +1744,7 @@ install-pdf-host: maybe-install-pdf-texinfo install-pdf-host: maybe-install-pdf-zlib install-pdf-host: maybe-install-pdf-gnulib install-pdf-host: maybe-install-pdf-gdbsupport +install-pdf-host: maybe-install-pdf-gdbserver install-pdf-host: maybe-install-pdf-gdb install-pdf-host: maybe-install-pdf-expect install-pdf-host: maybe-install-pdf-guile @@ -1824,6 +1833,7 @@ install-html-host: maybe-install-html-texinfo install-html-host: maybe-install-html-zlib install-html-host: maybe-install-html-gnulib install-html-host: maybe-install-html-gdbsupport +install-html-host: maybe-install-html-gdbserver install-html-host: maybe-install-html-gdb install-html-host: maybe-install-html-expect install-html-host: maybe-install-html-guile @@ -1912,6 +1922,7 @@ installcheck-host: maybe-installcheck-texinfo installcheck-host: maybe-installcheck-zlib installcheck-host: maybe-installcheck-gnulib installcheck-host: maybe-installcheck-gdbsupport +installcheck-host: maybe-installcheck-gdbserver installcheck-host: maybe-installcheck-gdb installcheck-host: maybe-installcheck-expect installcheck-host: maybe-installcheck-guile @@ -2000,6 +2011,7 @@ mostlyclean-host: maybe-mostlyclean-texinfo mostlyclean-host: maybe-mostlyclean-zlib mostlyclean-host: maybe-mostlyclean-gnulib mostlyclean-host: maybe-mostlyclean-gdbsupport +mostlyclean-host: maybe-mostlyclean-gdbserver mostlyclean-host: maybe-mostlyclean-gdb mostlyclean-host: maybe-mostlyclean-expect mostlyclean-host: maybe-mostlyclean-guile @@ -2088,6 +2100,7 @@ clean-host: maybe-clean-texinfo clean-host: maybe-clean-zlib clean-host: maybe-clean-gnulib clean-host: maybe-clean-gdbsupport +clean-host: maybe-clean-gdbserver clean-host: maybe-clean-gdb clean-host: maybe-clean-expect clean-host: maybe-clean-guile @@ -2176,6 +2189,7 @@ distclean-host: maybe-distclean-texinfo distclean-host: maybe-distclean-zlib distclean-host: maybe-distclean-gnulib distclean-host: maybe-distclean-gdbsupport +distclean-host: maybe-distclean-gdbserver distclean-host: maybe-distclean-gdb distclean-host: maybe-distclean-expect distclean-host: maybe-distclean-guile @@ -2264,6 +2278,7 @@ maintainer-clean-host: maybe-maintainer-clean-texinfo maintainer-clean-host: maybe-maintainer-clean-zlib maintainer-clean-host: maybe-maintainer-clean-gnulib maintainer-clean-host: maybe-maintainer-clean-gdbsupport +maintainer-clean-host: maybe-maintainer-clean-gdbserver maintainer-clean-host: maybe-maintainer-clean-gdb maintainer-clean-host: maybe-maintainer-clean-expect maintainer-clean-host: maybe-maintainer-clean-guile @@ -2408,6 +2423,7 @@ check-host: \ maybe-check-zlib \ maybe-check-gnulib \ maybe-check-gdbsupport \ + maybe-check-gdbserver \ maybe-check-gdb \ maybe-check-expect \ maybe-check-guile \ @@ -2543,6 +2559,7 @@ install-host-nogcc: \ maybe-install-zlib \ maybe-install-gnulib \ maybe-install-gdbsupport \ + maybe-install-gdbserver \ maybe-install-gdb \ maybe-install-expect \ maybe-install-guile \ @@ -2595,6 +2612,7 @@ install-host: \ maybe-install-zlib \ maybe-install-gnulib \ maybe-install-gdbsupport \ + maybe-install-gdbserver \ maybe-install-gdb \ maybe-install-expect \ maybe-install-guile \ @@ -2703,6 +2721,7 @@ install-strip-host: \ maybe-install-strip-zlib \ maybe-install-strip-gnulib \ maybe-install-strip-gdbsupport \ + maybe-install-strip-gdbserver \ maybe-install-strip-gdb \ maybe-install-strip-expect \ maybe-install-strip-guile \ @@ -29005,6 +29024,447 @@ maintainer-clean-gdbsupport: +.PHONY: configure-gdbserver maybe-configure-gdbserver +maybe-configure-gdbserver: +@if gcc-bootstrap +configure-gdbserver: stage_current +@endif gcc-bootstrap +@if gdbserver +maybe-configure-gdbserver: configure-gdbserver +configure-gdbserver: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + test ! -f $(HOST_SUBDIR)/gdbserver/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/gdbserver; \ + $(HOST_EXPORTS) \ + echo Configuring in $(HOST_SUBDIR)/gdbserver; \ + cd "$(HOST_SUBDIR)/gdbserver" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(HOST_SUBDIR)/gdbserver/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=gdbserver; \ + $(SHELL) \ + $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + || exit 1 +@endif gdbserver + + + + + +.PHONY: all-gdbserver maybe-all-gdbserver +maybe-all-gdbserver: +@if gcc-bootstrap +all-gdbserver: stage_current +@endif gcc-bootstrap +@if gdbserver +TARGET-gdbserver=all +maybe-all-gdbserver: all-gdbserver +all-gdbserver: configure-gdbserver + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS) \ + $(TARGET-gdbserver)) +@endif gdbserver + + + + +.PHONY: check-gdbserver maybe-check-gdbserver +maybe-check-gdbserver: +@if gdbserver +maybe-check-gdbserver: check-gdbserver + +check-gdbserver: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(FLAGS_TO_PASS) check) + +@endif gdbserver + +.PHONY: install-gdbserver maybe-install-gdbserver +maybe-install-gdbserver: +@if gdbserver +maybe-install-gdbserver: install-gdbserver + +install-gdbserver: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(FLAGS_TO_PASS) install) + +@endif gdbserver + +.PHONY: install-strip-gdbserver maybe-install-strip-gdbserver +maybe-install-strip-gdbserver: +@if gdbserver +maybe-install-strip-gdbserver: install-strip-gdbserver + +install-strip-gdbserver: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(FLAGS_TO_PASS) install-strip) + +@endif gdbserver + +# Other targets (info, dvi, pdf, etc.) + +.PHONY: maybe-info-gdbserver info-gdbserver +maybe-info-gdbserver: +@if gdbserver +maybe-info-gdbserver: info-gdbserver + +info-gdbserver: \ + configure-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + info) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-dvi-gdbserver dvi-gdbserver +maybe-dvi-gdbserver: +@if gdbserver +maybe-dvi-gdbserver: dvi-gdbserver + +dvi-gdbserver: \ + configure-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + dvi) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-pdf-gdbserver pdf-gdbserver +maybe-pdf-gdbserver: +@if gdbserver +maybe-pdf-gdbserver: pdf-gdbserver + +pdf-gdbserver: \ + configure-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 pdf in gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + pdf) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-html-gdbserver html-gdbserver +maybe-html-gdbserver: +@if gdbserver +maybe-html-gdbserver: html-gdbserver + +html-gdbserver: \ + configure-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + html) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-TAGS-gdbserver TAGS-gdbserver +maybe-TAGS-gdbserver: +@if gdbserver +maybe-TAGS-gdbserver: TAGS-gdbserver + +TAGS-gdbserver: \ + configure-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + TAGS) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-install-info-gdbserver install-info-gdbserver +maybe-install-info-gdbserver: +@if gdbserver +maybe-install-info-gdbserver: install-info-gdbserver + +install-info-gdbserver: \ + configure-gdbserver \ + info-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-info) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-install-pdf-gdbserver install-pdf-gdbserver +maybe-install-pdf-gdbserver: +@if gdbserver +maybe-install-pdf-gdbserver: install-pdf-gdbserver + +install-pdf-gdbserver: \ + configure-gdbserver \ + pdf-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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-pdf in gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-pdf) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-install-html-gdbserver install-html-gdbserver +maybe-install-html-gdbserver: +@if gdbserver +maybe-install-html-gdbserver: install-html-gdbserver + +install-html-gdbserver: \ + configure-gdbserver \ + html-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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-html in gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-html) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-installcheck-gdbserver installcheck-gdbserver +maybe-installcheck-gdbserver: +@if gdbserver +maybe-installcheck-gdbserver: installcheck-gdbserver + +installcheck-gdbserver: \ + configure-gdbserver + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + installcheck) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-mostlyclean-gdbserver mostlyclean-gdbserver +maybe-mostlyclean-gdbserver: +@if gdbserver +maybe-mostlyclean-gdbserver: mostlyclean-gdbserver + +mostlyclean-gdbserver: + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + mostlyclean) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-clean-gdbserver clean-gdbserver +maybe-clean-gdbserver: +@if gdbserver +maybe-clean-gdbserver: clean-gdbserver + +clean-gdbserver: + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + clean) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-distclean-gdbserver distclean-gdbserver +maybe-distclean-gdbserver: +@if gdbserver +maybe-distclean-gdbserver: distclean-gdbserver + +distclean-gdbserver: + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + distclean) \ + || exit 1 + +@endif gdbserver + +.PHONY: maybe-maintainer-clean-gdbserver maintainer-clean-gdbserver +maybe-maintainer-clean-gdbserver: +@if gdbserver +maybe-maintainer-clean-gdbserver: maintainer-clean-gdbserver + +maintainer-clean-gdbserver: + @: $(MAKE); $(unstage) + @[ -f ./gdbserver/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 gdbserver"; \ + (cd $(HOST_SUBDIR)/gdbserver && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + maintainer-clean) \ + || exit 1 + +@endif gdbserver + + + .PHONY: configure-gdb maybe-configure-gdb maybe-configure-gdb: @if gcc-bootstrap diff --git a/configure b/configure index 91dc42f6c79..8a3e7026f0b 100755 --- a/configure +++ b/configure @@ -2831,7 +2831,7 @@ host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktr # binutils, gas and ld appear in that order because it makes sense to run # "make check" in that particular order. # If --enable-gold is used, "gold" may replace "ld". -host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools" +host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gdbserver gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools" # these libraries are built for the target environment, and are built after # the host libraries and the host tools (which may be a cross compiler) @@ -3538,6 +3538,25 @@ case "${target}" in ;; esac +# Only allow gdbserver on some systems. +if test -d ${srcdir}/gdbserver; then + if test x$enable_gdbserver = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gdbserver support" >&5 +$as_echo_n "checking for gdbserver support... " >&6; } + if (srcdir=${srcdir}/gdbserver; \ + . ${srcdir}/configure.srv; \ + test -n "$UNSUPPORTED") + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + noconfigdirs="$noconfigdirs gdbserver" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + fi +fi + # Disable libgo for some systems where it is known to not work. # For testing, you can easily override this with --enable-libgo. if test x$enable_libgo = x; then diff --git a/configure.ac b/configure.ac index 4bd869a63a9..35a9c1867d2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, # 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, -# 2014, 2015, 2016, 2019 Free Software Foundation, Inc. +# 2014, 2015, 2016, 2019, 2020 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -140,7 +140,7 @@ host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktr # binutils, gas and ld appear in that order because it makes sense to run # "make check" in that particular order. # If --enable-gold is used, "gold" may replace "ld". -host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools" +host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gdbserver gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools" # these libraries are built for the target environment, and are built after # the host libraries and the host tools (which may be a cross compiler) @@ -782,6 +782,22 @@ case "${target}" in ;; esac +# Only allow gdbserver on some systems. +if test -d ${srcdir}/gdbserver; then + if test x$enable_gdbserver = x; then + AC_MSG_CHECKING([for gdbserver support]) + if (srcdir=${srcdir}/gdbserver; \ + . ${srcdir}/configure.srv; \ + test -n "$UNSUPPORTED") + then + AC_MSG_RESULT([no]) + noconfigdirs="$noconfigdirs gdbserver" + else + AC_MSG_RESULT([yes]) + fi + fi +fi + # Disable libgo for some systems where it is known to not work. # For testing, you can easily override this with --enable-libgo. if test x$enable_libgo = x; then diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 59648e6a252..901841e816b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2020-02-07 Tom Tromey + + * README: Update gdbserver documentation. + * gdbserver: Move to top level. + * configure.tgt (build_gdbserver): Remove. + * configure.ac: Remove --enable-gdbserver. + * configure: Rebuild. + * Makefile.in (distclean): Don't mention gdbserver. + 2020-02-06 Shahab Vahedi * source-cache.c (source_cache::ensure): Surround diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 45d1586e85e..49fff371337 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1898,13 +1898,8 @@ clean mostlyclean: $(CONFIG_CLEAN) # I believe this is wrong; the makefile standards for distclean just # describe removing files; the only sort of "re-create a distribution" # functionality described is if the distributed files are unmodified. -# NB: While GDBSERVER might be configured on native systems, it isn't -# always included in SUBDIRS. Remove the gdbserver files explicitly. distclean: clean @$(MAKE) $(FLAGS_TO_PASS) DO=distclean "DODIRS=$(CLEANDIRS)" subdir_do - rm -f gdbserver/config.status gdbserver/config.log - rm -f gdbserver/tm.h gdbserver/xm.h gdbserver/nm.h - rm -f gdbserver/Makefile gdbserver/config.cache rm -f nm.h config.status config.h stamp-h b jit-reader.h rm -f gdb-gdb.py gdb-gdb.gdb rm -f y.output yacc.acts yacc.tmp y.tab.h diff --git a/gdb/README b/gdb/README index be7fdcb65d8..3895758ece5 100644 --- a/gdb/README +++ b/gdb/README @@ -583,12 +583,11 @@ of remote stubs to be used with remote.c. They are designed to run standalone on an m68k, i386, or SPARC cpu and communicate properly with the remote.c stub over a serial line. - The directory gdb/gdbserver/ contains `gdbserver', a program that + The directory gdbserver/ contains `gdbserver', a program that allows remote debugging for Unix applications. GDBserver is only -supported for some native configurations, including Sun 3, Sun 4, and -Linux. +supported for some native configurations. - The file gdb/gdbserver/README includes further notes on GDBserver; in + The file gdbserver/README includes further notes on GDBserver; in particular, it explains how to build GDBserver for cross-debugging (where GDBserver runs on the target machine, which is of a different architecture than the host machine running GDB). diff --git a/gdb/configure b/gdb/configure index 72ffad8d37b..a1d15064972 100755 --- a/gdb/configure +++ b/gdb/configure @@ -905,7 +905,6 @@ with_tcl with_tk with_x enable_sim -enable_gdbserver with_babeltrace with_libbabeltrace_prefix with_xxhash @@ -930,8 +929,7 @@ YACC YFLAGS XMKMF' ac_subdirs_all='testsuite -gdbtk -gdbserver' +gdbtk' # Initialize some variables set by options. ac_init_help= @@ -1575,8 +1573,6 @@ Optional Features: gcc is used --enable-ubsan enable undefined behavior sanitizer (auto/yes/no) --enable-sim link gdb with simulator - --enable-gdbserver automatically build gdbserver (yes/no/auto, default - is auto) --enable-unit-tests Enable the inclusion of unit tests when compiling GDB @@ -6738,7 +6734,6 @@ fi # For other settings, only the main target counts. gdb_sim= gdb_osabi= -build_gdbserver= targ=$target; . ${srcdir}/configure.tgt # Fetch the default architecture and default target vector from BFD. @@ -17848,40 +17843,6 @@ _ACEOF fi -# Check whether --enable-gdbserver was given. -if test "${enable_gdbserver+set}" = set; then : - enableval=$enable_gdbserver; case "${enableval}" in - yes| no|auto) ;; - *) as_fn_error $? "bad value ${enableval} for --enable-gdbserver option" "$LINENO" 5 ;; -esac -else - enable_gdbserver=auto -fi - - -# We only build gdbserver automatically in a native configuration, and -# only if the user did not explicitly disable its build. -if test "$gdb_native" = "yes" -a "$enable_gdbserver" != "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gdbserver is supported on this host" >&5 -$as_echo_n "checking whether gdbserver is supported on this host... " >&6; } - if test "x$build_gdbserver" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - subdirs="$subdirs gdbserver" - - gdbserver_build_enabled=yes - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -fi - -# If the user explicitly request the gdbserver to be built, verify that -# we were in fact able to enable it. -if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then - as_fn_error $? "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5 -fi - # Check for babeltrace and babeltrace-ctf # Check whether --with-babeltrace was given. diff --git a/gdb/configure.ac b/gdb/configure.ac index 0ca169101b3..335971fdf66 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -254,7 +254,6 @@ AC_SUBST(HAVE_NATIVE_GCORE_TARGET) # For other settings, only the main target counts. gdb_sim= gdb_osabi= -build_gdbserver= targ=$target; . ${srcdir}/configure.tgt # Fetch the default architecture and default target vector from BFD. @@ -2001,33 +2000,6 @@ if test x"${gdb_osabi}" != x ; then [Define to the default OS ABI for this configuration.]) fi -AC_ARG_ENABLE(gdbserver, -AS_HELP_STRING([--enable-gdbserver], - [automatically build gdbserver (yes/no/auto, default is auto)]), -[case "${enableval}" in - yes| no|auto) ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-gdbserver option) ;; -esac],[enable_gdbserver=auto]) - -# We only build gdbserver automatically in a native configuration, and -# only if the user did not explicitly disable its build. -if test "$gdb_native" = "yes" -a "$enable_gdbserver" != "no"; then - AC_MSG_CHECKING(whether gdbserver is supported on this host) - if test "x$build_gdbserver" = xyes; then - AC_MSG_RESULT(yes) - AC_CONFIG_SUBDIRS(gdbserver) - gdbserver_build_enabled=yes - else - AC_MSG_RESULT(no) - fi -fi - -# If the user explicitly request the gdbserver to be built, verify that -# we were in fact able to enable it. -if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then - AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration) -fi - # Check for babeltrace and babeltrace-ctf AC_ARG_WITH(babeltrace, AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]), diff --git a/gdb/configure.tgt b/gdb/configure.tgt index ab4c098c0da..755187dca65 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -5,7 +5,6 @@ # gdb_target_obs target-specific object files to use # gdb_sim simulator library for target # gdb_osabi default OS ABI to use with target -# build_gdbserver set to "yes" if gdbserver supports target # gdb_have_gcore set to "true"/"false" if this target can run gcore # NOTE: Every file added to a gdb_target_obs variable for any target here @@ -129,7 +128,6 @@ aarch64*-*-linux*) arm-tdep.o arm-linux-tdep.o \ glibc-tdep.o linux-tdep.o solib-svr4.o \ symfile-mem.o linux-record.o" - build_gdbserver=yes ;; alpha*-*-linux*) @@ -162,13 +160,11 @@ arc*-*-elf32) arm*-wince-pe | arm*-*-mingw32ce*) # Target: ARM based machine running Windows CE (win32) gdb_target_obs="arm-wince-tdep.o windows-tdep.o" - build_gdbserver=yes ;; arm*-*-linux*) # Target: ARM based machine running GNU/Linux gdb_target_obs="arch/arm-linux.o arm-linux-tdep.o glibc-tdep.o \ solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o" - build_gdbserver=yes ;; arm*-*-freebsd*) # Target: FreeBSD/arm @@ -202,7 +198,6 @@ bfin-*-*linux*) # Target: Blackfin Linux gdb_target_obs="bfin-tdep.o bfin-linux-tdep.o linux-tdep.o" gdb_sim=../sim/bfin/libsim.a - build_gdbserver=yes ;; bfin-*-*) # Target: Blackfin processor @@ -285,7 +280,6 @@ i[34567]86-*-nto*) # Target: Intel 386 running qnx6. gdb_target_obs="solib-svr4.o \ i386-nto-tdep.o nto-tdep.o" - build_gdbserver=yes ;; i[34567]86-*-solaris2* | x86_64-*-solaris2*) # Target: Solaris x86_64 @@ -303,7 +297,6 @@ i[34567]86-*-linux*) # Target: GNU/Linux x86-64 gdb_target_obs="amd64-linux-tdep.o ${gdb_target_obs}" fi - build_gdbserver=yes ;; i[34567]86-*-gnu*) # Target: Intel 386 running the GNU Hurd @@ -312,12 +305,10 @@ i[34567]86-*-gnu*) i[34567]86-*-cygwin*) # Target: Intel 386 running win32 gdb_target_obs="i386-cygwin-tdep.o windows-tdep.o" - build_gdbserver=yes ;; i[34567]86-*-mingw32*) # Target: Intel 386 running win32 gdb_target_obs="i386-cygwin-tdep.o windows-tdep.o" - build_gdbserver=yes ;; i[34567]86-*-go32* | i[34567]86-*-msdosdjgpp*) # Target: i386 running DJGPP/go32. @@ -328,7 +319,6 @@ ia64-*-linux*) # Target: Intel IA-64 running GNU/Linux gdb_target_obs="ia64-linux-tdep.o linux-tdep.o \ solib-svr4.o symfile-mem.o" - build_gdbserver=yes ;; ia64-*-*vms*) # Target: Intel IA-64 running OpenVMS @@ -359,7 +349,6 @@ m32r*-*-linux*) glibc-tdep.o solib-svr4.o symfile-mem.o \ linux-tdep.o" gdb_sim=../sim/m32r/libsim.a - build_gdbserver=yes ;; m32r*-*-*) # Target: Renesas m32r processor @@ -382,7 +371,6 @@ m68*-*-linux*) # Target: Motorola m68k with a.out and ELF gdb_target_obs="m68k-tdep.o m68k-linux-tdep.o solib-svr4.o \ linux-tdep.o glibc-tdep.o symfile-mem.o" - build_gdbserver=yes ;; m68*-*-netbsd* | m68*-*-knetbsd*-gnu) # Target: NetBSD/m68k @@ -416,7 +404,6 @@ mips*-*-linux*) gdb_target_obs="mips-tdep.o mips-linux-tdep.o glibc-tdep.o \ solib-svr4.o symfile-mem.o linux-tdep.o" gdb_sim=../sim/mips/libsim.a - build_gdbserver=yes ;; mips*-*-netbsd* | mips*-*-knetbsd*-gnu) # Target: MIPS running NetBSD @@ -480,7 +467,6 @@ or1k*-*-linux*) gdb_target_obs="or1k-tdep.o or1k-linux-tdep.o solib-svr4.o \ symfile-mem.o glibc-tdep.o linux-tdep.o" gdb_sim=../sim/or1k/libsim.a - build_gdbserver=yes ;; or1k-*-* | or1knd-*-*) @@ -522,7 +508,6 @@ powerpc*-*-linux*) linux-record.o \ arch/ppc-linux-common.o" gdb_sim=../sim/ppc/libsim.a - build_gdbserver=yes ;; powerpc-*-lynx*178) # Target: PowerPC running Lynx178. @@ -541,7 +526,6 @@ s390*-*-linux*) # Target: S390 running Linux gdb_target_obs="s390-linux-tdep.o s390-tdep.o solib-svr4.o \ linux-tdep.o linux-record.o symfile-mem.o" - build_gdbserver=yes ;; riscv*-*-freebsd*) @@ -575,7 +559,6 @@ rx-*-elf) score-*-*) # Target: S+core embedded system gdb_target_obs="score-tdep.o" - build_gdbserver=yes ;; sh*-*-linux*) @@ -584,7 +567,6 @@ sh*-*-linux*) solib-svr4.o symfile-mem.o \ glibc-tdep.o linux-tdep.o" gdb_sim=../sim/sh/libsim.a - build_gdbserver=yes ;; sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu) # Target: NetBSD/sh @@ -612,7 +594,6 @@ sparc-*-linux*) gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o \ sparc64-linux-tdep.o ${gdb_target_obs}" fi - build_gdbserver=yes ;; sparc64-*-linux*) # Target: GNU/Linux UltraSPARC @@ -620,7 +601,6 @@ sparc64-*-linux*) sparc64-linux-tdep.o sparc-tdep.o sparc-sol2-tdep.o \ sparc-linux-tdep.o solib-svr4.o linux-tdep.o \ ravenscar-thread.o sparc-ravenscar-thread.o" - build_gdbserver=yes ;; sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu) # Target: FreeBSD/sparc64 @@ -689,7 +669,6 @@ tilegx-*-linux*) # Target: TILE-Gx gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \ symfile-mem.o glibc-tdep.o linux-tdep.o" - build_gdbserver=yes ;; xstormy16-*-*) @@ -742,7 +721,6 @@ x86_64-*-linux*) gdb_target_obs="amd64-linux-tdep.o ${i386_tobjs} \ i386-linux-tdep.o glibc-tdep.o \ solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o" - build_gdbserver=yes ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) # Target: FreeBSD/amd64 @@ -754,7 +732,6 @@ x86_64-*-mingw* | x86_64-*-cygwin*) gdb_target_obs="amd64-windows-tdep.o \ ${i386_tobjs} i386-cygwin-tdep.o \ windows-tdep.o" - build_gdbserver=yes ;; x86_64-*-netbsd* | x86_64-*-knetbsd*-gnu) # Target: NetBSD/amd64 @@ -772,7 +749,6 @@ x86_64-*-rtems*) xtensa*-*-*linux*) # Target: GNU/Linux Xtensa gdb_target_obs="xtensa-linux-tdep.o symfile-mem.o linux-tdep.o" - build_gdbserver=yes ;; esac diff --git a/gdb/gdbserver/.gitignore b/gdb/gdbserver/.gitignore deleted file mode 100644 index fef0d01b14e..00000000000 --- a/gdb/gdbserver/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/Makefile - -gdbreplay -gdbserver -libinproctrace.so - -build-gnulib-gdbserver -build-libiberty-gdbserver - -*-generated.c diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog deleted file mode 100644 index 9bc965a36b3..00000000000 --- a/gdb/gdbserver/ChangeLog +++ /dev/null @@ -1,17980 +0,0 @@ -2020-01-29 Maciej W. Rozycki - - * configure.srv : Fix whitespace damage. - -2020-01-29 Pedro Franco de Carvalho - - * configure.srv (powerpc*-*-linux*): Use srv_tgtobj in second - assignment instead of srv_linux_obj. - -2020-01-28 Hannes Domani - - * server.c (handle_qxfer_libraries): Write segment-address with - paddress. - -2020-01-24 Hannes Domani - - * Makefile.in (install-strip): New target. - (install_sh, INSTALL_STRIP_PROGRAM, STRIP): New variables. - * aclocal.m4: Regenerate. - * configure: Regenerate. - * configure.ac: Add AM_PROG_INSTALL_STRIP. - -2020-01-24 Maciej W. Rozycki - - * Makefile.in (SFILES): Adjust paths to point to real files. - (OBS): Move waitstatus.o to target/waitstatus.o. - (TAGS): Transform paths appropriately. - (%.o): Rename to... - (nat/%.o): ... this pattern rule. - (%.o): Rename to... - (target/%.o): ... this pattern rule. - * configure.srv: Adjust paths throughout to include nat/ prefix - with the revant files. - * configure.ac: Add `nat' and `target' to CONFIG_SRC_SUBDIR. - * configure: Regenerate. - -2020-01-24 Maciej W. Rozycki - - * Makefile.in (TAGS): Remove config files from the recipe. - -2020-01-14 Tom Tromey - - * configure: Rebuild. - * configure.ac: Remove any checks that were added to common.m4. - * acinclude.m4: Include lib-ld.m4, lib-prefix.m4, and - lib-link.m4. - -2020-01-14 Tom Tromey - - * server.h: Include config.h. - * gdbreplay.c: Include config.h. - * configure: Rebuild. - * configure.ac: Don't source common.host. - * acinclude.m4: Update path. - * Makefile.in (INCSUPPORT): New variable. - (INCLUDE_CFLAGS): Add INCSUPPORT. - (SFILES): Update paths. - (version-generated.c): Update path to create-version.sh. - (gdbsupport/%-ipa.o, gdbsupport/%.o): Update paths. - -2020-01-14 Tom Tromey - - * configure.ac (LIBS): Use WIN32APILIBS. - (USE_WIN32API): Don't define. - * configure: Rebuild. - -2020-01-14 Tom Tromey - - * configure: Rebuild. - -2020-01-13 Simon Marchi - - * Makefile.in (%-generated.c): Remove rule for files from - regformats/i386. - -2020-01-13 Simon Marchi - - * configure: Re-generate. - -2020-01-13 Simon Marchi - - * tracepoint.h (IP_AGENT_EXPORT_FUNC) [!IN_PROCESS_AGENT]: - Define to static. - * tracepoint.c (stop_tracing, flush_trace_buffer, - about_to_request_buffer_space, get_trace_state_variable_value, - set_trace_state_variable_value, gdb_collect): Add declaration. - -2020-01-13 Simon Marchi - - * linux-x86-low.c (x86_linux_regs_info, amd64_emit_eq_goto, - amd64_emit_ne_goto, amd64_emit_lt_goto, amd64_emit_le_goto, - amd64_emit_gt_goto, amd64_emit_ge_goto, amd64_emit_ge_goto, - i386_emit_eq_goto, i386_emit_ne_goto, i386_emit_lt_goto, - i386_emit_le_goto, i386_emit_gt_goto, i386_emit_ge_goto): Make - static. - -2020-01-13 Simon Marchi - - * inferiors.c: Include gdbsupport/common-inferior.h. - -2020-01-13 Simon Marchi - - * hostio-errno.c: Include hostio.h. - -2020-01-13 Simon Marchi - - * Makefile.in (%-generated.c): Make $(regdat_sh) a regular - prerequisite. - -2020-01-12 Simon Marchi - - * linux-arm-tdesc.c: Include linux-arm-tdesc.h. - * linux-arm-tdesc.h: Include arch/arm.h. - -2020-01-12 Simon Marchi - - * linux-aarch64-low.c (aarch64_write_goto_address): Make static. - -2020-01-12 Simon Marchi - - * linux-aarch32-tdesc.c: Include linux-aarch32-tdesc.h. - * linux-aarch64-tdesc.c: Include linux-aarch64-tdesc.h. - -2020-01-10 Pedro Alves - - * fork-child.c (post_fork_inferior): Pass target down to - startup_inferior. - * inferiors.c (switch_to_thread): Add process_stratum_target - parameter. - * lynx-low.c (lynx_target_ops): Now a process_stratum_target. - * nto-low.c (nto_target_ops): Now a process_stratum_target. - * linux-low.c (linux_target_ops): Now a process_stratum_target. - * remote-utils.c (prepare_resume_reply): Pass the target to - switch_to_thread. - * target.c (the_target): Now a process_stratum_target. - (done_accessing_memory): Pass the target to switch_to_thread. - (set_target_ops): Ajust to use process_stratum_target. - * target.h (struct target_ops): Rename to ... - (struct process_stratum_target): ... this. - (the_target, set_target_ops): Adjust. - (prepare_to_access_memory): Adjust comment. - * win32-low.c (child_xfer_memory): Adjust to use - process_stratum_target. - (win32_target_ops): Now a process_stratum_target. - -2020-01-06 Eli Zaretskii - Pedro Alves - - * win32-low.c (get_child_debug_event): Extract the fatal exception - from the exit status and convert to the equivalent Posix signal - number. - (win32_wait): Allow TARGET_WAITKIND_SIGNALLED status as well. - * Makefile.in (OBS, SFILES): Add gdb_wait.[co]. - -2020-01-01 Hannes Domani - - * Makefile.in: Use INSTALL_PROGRAM_ENV. - -2020-01-01 Joel Brobecker - - * server.c (gdbserver_version): Change copyright year to 2020. - * gdbreplay.c (gdbreplay_version): Likewise. - -2019-12-19 Christian Biesinger - - * configure: Regenerate. - * configure.ac: Quote variable arguments of test. - -2019-12-16 Bernd Edlinger - - * Makefile.in: Fix build with GNU Make 3.81 - -2019-12-16 Tom Tromey - - * server.c (get_exec_file): Constify result. - -2019-12-10 Christian Biesinger - - * Makefile.in: Add safe-strerror.c to gdbreplay and IPA, and change - UNDO_GNULIB_CFLAGS to undo strerror_r instead of strerror. - * config.in: Regenerate. - * configure: Regenerate. - * configure.ac: Don't check for strerror. - * linux-i386-ipa.c (initialize_fast_tracepoint_trampoline_buffer): - Call safe_strerror instead of strerror. - * server.h (strerror): Remove this now-unnecessary declaration. - * tracepoint.c (init_named_socket): Call safe_strerror instead of - strerror. - (gdb_agent_helper_thread): Likewise. - * utils.c (perror_with_name): Likewise. - -2019-11-26 Tom Tromey - - * configure, config.in: Rebuild. - -2019-11-26 Tom Tromey - - * remote-utils.c (block_unblock_async_io): Use gdb_sigmask. - * linux-low.c (linux_wait_for_event_filtered, linux_async): Use - gdb_sigmask. - * configure, config.in: Rebuild. - -2019-11-26 Tom Tromey - - * Makefile.in (PTHREAD_CFLAGS, PTHREAD_LIBS): New variables. - (INTERNAL_CFLAGS_BASE): Use PTHREAD_CFLAGS. - (GDBSERVER_LIBS): Use PTHREAD_LIBS. - * acinclude.m4: Include ax_pthread.m4. - * config.in, configure: Rebuild. - -2019-11-26 Christian Biesinger - - * debug.c (debug_set_output): Call safe_strerror instead of - strerror. - * linux-low.c (attach_proc_task_lwp_callback): Likewise. - (linux_kill_one_lwp): Likewise. - (linux_detach_one_lwp): Likewise. - (linux_wait_for_event_filtered): Likewise. - (store_register): Likewise. - * lynx-low.c (lynx_attach): Likewise. - * mem-break.c (insert_memory_breakpoint): Likewise. - (remove_memory_breakpoint): Likewise. - (delete_fast_tracepoint_jump): Likewise. - (set_fast_tracepoint_jump): Likewise. - (uninsert_fast_tracepoint_jumps_at): Likewise. - (reinsert_fast_tracepoint_jumps_at): Likewise. - * nto-low.c (nto_xfer_memory): Likewise. - (nto_resume): Likewise. - -2019-11-20 Luis Machado - - * linux-aarch64-low.c (is_sve_tdesc): Check against target feature - instead of register count. - * tdesc.c (tdesc_contains_feature): New function. - * tdesc.h (tdesc_contains_feature): New prototype. - -2019-11-15 Christian Biesinger - - * Makefile.in: Add safe-strerror.c. - * configure: Regenerate. - * configure.ac: Don't source common.host. - -2019-11-15 Christian Biesinger - - * config.in: Regenerate. - * configure: Regenerate. - -2019-11-12 Andrew Burgess - - * ax.c (ax_printf): Handle size_t_arg. - -2019-11-06 Christian Biesinger - - * linux-tdep.c (linux_info_proc): Use strtok_r instead of strtok. - * mi/mi-main.c (output_cores): Likewise. - * nat/linux-osdata.c (linux_xfer_osdata_cpus): Likewise. - (linux_xfer_osdata_modules): Likewise. - * remote.c (register_remote_support_xml): Likewise. - * sparc64-tdep.c (adi_is_addr_mapped): Likewise. - * xml-syscall.c (syscall_create_syscall_desc): Likewise. - -2019-11-01 Christian Biesinger - - * configure: Regenerate. - * configure.ac: Remove check for strerror_r. - -2019-10-31 Christian Biesinger - - * config.in: Regenerate. - * configure: Regenerate. - * configure.ac: Also check for strerror_r. - -2019-10-31 Christian Biesinger - - * ax.h (debug_agent): Remove duplicate declaration. - -2019-10-26 Tom de Vries - - * linux-aarch64-low.c: Fix typos in comments. - * linux-arm-low.c: Same. - * linux-low.c: Same. - * linux-ppc-low.c: Same. - * proc-service.c: Same. - * regcache.h: Same. - * server.c: Same. - * tracepoint.c: Same. - * win32-low.c: Same. - -2019-10-25 Tom Tromey - - * utils.c (xstrdup): Remove. - -2019-10-23 Tom Tromey - - * configure, config.in: Rebuild. - -2019-10-23 Tom Tromey - - * configure: Rebuild. - * acinclude.m4: Use m4_include, not sinclude. - -2019-10-17 Tom Tromey - - * configure: Rebuild. - * configure.ac: Use AC_CONFIG_HEADERS. Create stamp-h there, not - in AC_CONFIG_FILES invocation. - * Makefile.in (stamp-h, Makefile): Use new-style config.status - invocation. - -2019-10-16 Christian Biesinger - - * server.c: Include xml-builtin.h. - (get_xml_features): Don't declare xml_builtins here. - -2019-10-15 Andrew Burgess - - * Makefile.in: Remove references to vec-ipa.o. - -2019-10-15 Andrew Burgess - - * Makefile.in: Remove references to vec.c. - -2019-10-02 Christian Biesinger - - * server.c (server_waiting): Change to bool. - (extended_protocol): Likewise. - (response_needed): Likewise. - (exit_requested): Likewise. - (run_once): Likewise. - (report_no_resumed): Likewise. - (non_stop): Likewise. - (disable_packet_vCont): Likewise. - (disable_packet_Tthread): Likewise. - (disable_packet_qC): Likewise. - (disable_packet_qfThreadInfo): Likewise. - (handle_general_set): Update. - (handle_detach): Update. - (handle_monitor_command): Update. - (handle_query): Update. - (captured_main): Update. - (process_serial_event): Update. - * server.h (server_waiting): Change to bool. - (disable_packet_vCont): Likewise. - (disable_packet_Tthread): Likewise. - (disable_packet_qC): Likewise. - (disable_packet_qfThreadInfo): Likewise. - (run_once): Likewise. - (non_stop): Likewise. - * target.c (target_stop_and_wait): Update. - -2019-10-02 Tom Tromey - - * Makefile.in (SFILES): Add common-inferior.c. - (OBS): Add common-inferior.o. - * server.c (startup_with_shell): Don't define. - -2019-10-02 Andrew Burgess - - * linux-low.c (linux_low_read_btrace): Update for change to - std::vector. - -2019-09-20 Christian Biesinger - - * debug.c (debug_threads): Remove comment in favor of the header. - * debug.h (using_threads): Add declaration. - (debug_threads): Add comment. - * linux-aarch64-low.c: Include debug.h and remove declaration of - debug_threads. - * nto-low.c: Likewise. - * remote-utils.c: Likewise. - * thread-db.c: Likewise. - -2019-09-20 Ulrich Weigand - - * configure.srv (ipa_ppc_linux_regobj): Remove powerpc-cell32l-ipa.o - and powerpc-cell64l-ipa.o. - (powerpc*-*-linux*): Remove powerpc-cell32l.o and powerpc-cell64l.o - from srv_regobj. Remove rs6000/powerpc-cell32l.xml and - rs6000/powerpc-cell64l.xml from srv_xmlfiles. - (spu*-*-*): Remove. - - * spu-low.c: Remove file. - - * linux-ppc-low.c (INSTR_SC, NR_spu_run): Remove. - (parse_spufs_run): Remove. - (ppc_get_pc): Remove Cell/B.E. support. - (ppc_set_pc): Likewise. - (ppc_breakpoint_at): Likewise. - (ppc_arch_setup): Likewise. - (ppc_get_ipa_tdesc_idx): Do not handle tdesc_powerpc_cell64l or - tdesc_powerpc_cell32l. - (initialize_low_arch): Do not call init_registers_powerpc_cell64l - or init_registers_powerpc_cell32l. - * linux-ppc-ipa.c (get_ipa_tdesc): Do not handle PPC_TDESC_CELL. - (initialize_low_tracepoint): Do not call init_registers_powerpc_cell64l - or init_registers_powerpc_cell32l. - * linux-ppc-tdesc-init.h (PPC_TDESC_CELL): Mark as unused. - (init_registers_powerpc_cell32l): Remove prototype. - (init_registers_powerpc_cell64l): Likewise. - - * target.h (struct target_ops): Remove qxfer_spu member. - * server.c (handle_qxfer_spu): Remove. - (qxfer_packets): Remove entry for "spu". - (handle_query): No longer support qXfer:spu:read or qXfer:spu:write. - * linux-low.c (SPUFS_MAGIC): Remove. - (spu_enumerate_spu_ids): Remove. - (linux_qxfer_spu): Remove. - (linux_target_ops): Remove qxfer_spu member. - * lynx-low.c (lynx_target_ops): Remove qxfer_spu member. - * nto-low.c (nto_target_ops): Remove qxfer_spu member. - * win32-low.c (win32_target_ops): Remove qxfer_spu member. - -2019-08-23 Sergio Durigan Junior - - * Makefile.in (SFILES): Add 'gdbsupport/gdb-dlfcn.c'. - (OBS): Add 'gdbsupport/gdb-dlfcn.o'. - * config.in: Regenerate. - * configure: Regenerate. - -2019-08-15 Tom Tromey - - * target.c (target_write_memory): Use gdb::byte_vector. - -2019-08-15 Tom Tromey - - * tracepoint.c (write_inferior_data_pointer) - (write_inferior_integer, write_inferior_int8) - (write_inferior_uinteger, m_tracepoint_action_download) - (r_tracepoint_action_download, x_tracepoint_action_download) - (l_tracepoint_action_download, clear_inferior_trace_buffer) - (download_agent_expr, download_tracepoint_1) - (download_trace_state_variables, upload_fast_traceframes): Update. - * server.c (gdb_write_memory): Update. - * remote-utils.c (relocate_instruction): Update. - * proc-service.c (ps_pdwrite): Update. - * mem-break.c (remove_memory_breakpoint) - (delete_fast_tracepoint_jump, set_fast_tracepoint_jump) - (uninsert_fast_tracepoint_jumps_at) - (reinsert_fast_tracepoint_jumps_at): Update. - * linux-x86-low.c (append_insns) - (i386_install_fast_tracepoint_jump_pad) - (amd64_write_goto_address, i386_write_goto_address): Update. - * linux-s390-low.c (append_insns, s390_write_goto_address): - Update. - * linux-ppc-low.c (ppc_relocate_instruction) - (ppc_install_fast_tracepoint_jump_pad, emit_insns) - (ppc_write_goto_address): Update. - * linux-aarch64-low.c (append_insns): Update. - * target.h (struct target_ops): Update. - (write_inferior_memory): Don't declare. - * target.c (target_write_memory): Rename from - write_inferior_memory. Remove old target_write_memory. - -2019-08-15 Tom Tromey - - * target.c (write_inferior_memory): Use std::vector. - -2019-08-06 Frank Ch. Eigler - - PR build/24886 - * configure.ac: Drop enable-libmcheck support. - * configure, config.in: Rebuild. - * acinclude.m4: Don't include it. - -2019-07-19 Alan Hayward - - * configure.srv: Remove Arm xml files. - -2019-07-19 Alan Hayward - - * configure.srv: Add new files. Remove xml generated files. - * linux-aarch32-low.c (initialize_low_arch_aarch32): Don't init - registers. - * linux-aarch32-low.h (tdesc_arm_with_neon): Remove. - * linux-aarch32-tdesc.c: New file. - * linux-aarch32-tdesc.h: New file. - * linux-aarch64-low.c (aarch64_arch_setup): Call aarch32_linux_read_description. - * linux-arm-low.c (init_registers_arm, tdesc_arm) - (init_registers_arm_with_iwmmxt, tdesc_arm_with_iwmmxt) - (init_registers_arm_with_vfpv2, tdesc_arm_with_vfpv2) - (init_registers_arm_with_vfpv3, tdesc_arm_with_vfpv3): Remove. - (arm_fill_wmmxregset, arm_store_wmmxregset, arm_fill_vfpregset) - (arm_store_vfpregset): Call arm_linux_get_tdesc_fp_type. - (arm_read_description): Call arm_linux_read_description. - (initialize_low_arch): Don't init registers. - * linux-arm-tdesc.c: New file. - * linux-arm-tdesc.h: New file. - -2019-07-10 Alan Hayward - - * linux-arm-low.c (arm_fill_wmmxregset, arm_store_wmmxregset): - Move counter inside for. - (arm_read_description): Check ptrace earlier. - (arm_arch_setup): Call arm_linux_init_hwbp_cap here. - -2019-07-09 Tom Tromey - - * configure: Rebuild. - * configure.ac: Change common to gdbsupport. - * acinclude.m4: Change common to gdbsupport. - * Makefile.in (SFILES, OBS, GDBREPLAY_OBS, IPA_OBJS) - (version-generated.c, gdbsupport/%-ipa.o, gdbsupport/%.o): Change - common to gdbsupport. - * ax.c, event-loop.c, fork-child.c, gdb_proc_service.h, - gdbreplay.c, gdbthread.h, hostio-errno.c, hostio.c, i387-fp.c, - inferiors.c, inferiors.h, linux-aarch64-tdesc-selftest.c, - linux-amd64-ipa.c, linux-i386-ipa.c, linux-low.c, - linux-tic6x-low.c, linux-x86-low.c, linux-x86-tdesc-selftest.c, - linux-x86-tdesc.c, lynx-i386-low.c, lynx-low.c, mem-break.h, - nto-x86-low.c, regcache.c, regcache.h, remote-utils.c, server.c, - server.h, spu-low.c, symbol.c, target.h, tdesc.c, tdesc.h, - thread-db.c, tracepoint.c, win32-i386-low.c, win32-low.c: Change - common to gdbsupport. - -2019-07-04 Alan Hayward - - * linux-aarch32-low.c (arm_read_description, arm_regsets): Use new - defines. - * linux-arm-low.c (arm_read_description, arm_regsets): Likewise. - -2019-07-04 Alan Hayward - - * configure.srv: Remove legacy xml. - * linux-aarch64-low.c (initialize_low_arch): Remove - initialize_low_tdesc call. - * linux-aarch64-tdesc-selftest.c: Remove file. - * linux-aarch64-tdesc.h (initialize_low_tdesc): Remove. - * linux-x86-low.c (initialize_low_arch): Remove - initialize_low_tdesc call. - * linux-x86-tdesc-selftest.c: Remove file. - * linux-x86-tdesc.h (initialize_low_tdesc): Remove. - -2019-06-20 Tom de Vries - - * linux-s390-ipa.c (get_ipa_tdesc)[!__s390x__]: Use - s390_te_linux64_ft_collect_regmap for S390_TDESC_GS. - -2019-06-19 Tom de Vries - - * debug.h (debug_write): Change return type to ssize_t. - * debug.c (debug_write): Same. - -2019-06-14 Tom Tromey - - * configure.ac: Use new path to gnulib. - * configure: Rebuild. - * Makefile.in (INCGNU, $(GNULIB_BUILDDIR)/Makefile): Use new path - to gnulib. - -2019-06-11 Tom Tromey - - * Makefile.in (SFILES): Add alloc.c. - (OBS): Add alloc.o. - (IPA_OBJS): Add alloc-ipa.o. - (alloc-ipa.o): New target. - (%.o: ../%.c): New pattern rule. - -2019-06-10 Tom Tromey - - * remote-utils.c (look_up_one_symbol, relocate_instruction): Don't - end warning with a newline. - * linux-s390-low.c (s390_get_wordsize): Don't end warning with a - newline. - * thread-db.c (attach_thread): Don't end warning with a newline. - (thread_db_notice_clone): Likewise. - * tracepoint.c (gdb_agent_helper_thread): Don't end warning with a - newline. - * linux-x86-low.c (x86_get_min_fast_tracepoint_insn_len): Don't - end warning with a newline. - -2019-06-04 Pedro Alves - - * server.c (captured_main): Use make_unique_xstrdup. - -2019-06-02 Tom Tromey - - * gdbreplay.c (fromhex): Remove. - * Makefile.in (GDBREPLAY_OBS): Add rsp-low.o. - -2019-05-29 Tom Tromey - - * configure: Rebuild. - -2019-05-06 Kevin Buettner - - * linux-x86-low.c (x86_fill_gregset): Don't compile 64-bit - sign extension code on 32-bit builds. - -2019-05-03 Eli Zaretskii - - * remote-utils.c: - * gdbreplay.c [USE_WIN32API]: Remove the _WIN32_WINNT override. - -2019-04-19 Tom Tromey - - * server.c (struct vstop_notif): Derive from notif_event. - : Remove. - (queue_stop_reply): Update. - (remove_all_on_match_ptid): Change type. Rewrite. - (discard_queued_stop_replies): Rewrite. - (in_queued_stop_replies_ptid): Change type. - (in_queued_stop_replies): Rewrite. - (notif_stop): Update. - (queue_stop_reply_callback): Update. - (captured_main): Don't call initialize_notif. - (push_stop_notification): Update. - * notif.c (notif_write_event, handle_notif_ack) - (notif_event_enque, notif_push): Update. - (notif_event_xfree, initialize_notif): Remove. - * notif.h (struct notif_event): Include , not - "common/queue.h". - (struct notif_server) : Now a std::list. - (notif_event_p): Remove typedef. - (initialize_notif): Don't declare. - (struct notif_event): Add virtual destructor. - -2019-04-17 Alan Hayward - - * ax.c (ax_vdebug): Call debug_printf. - * debug.c (debug_write): New function. - * debug.h (debug_write): New declaration. - * linux-low.c (sigchld_handler): Call debug_write. - -2019-04-17 Alan Hayward - - * debug.c (debug_set_output): New function. - (debug_vprintf): Send output to debug_file. - (debug_flush): Likewise. - * debug.h (debug_set_output): New declaration. - * server.c (handle_monitor_command): Add debug-file option. - (captured_main): Likewise. - -2019-04-17 Alan Hayward - - * debug.c (remote_debug): Add definition. - * debug.h (remote_debug): Add declaration. - * hostio.c (remote_debug): Remove declaration. - * remote-utils.c (struct ui_file): Likewise. - (remote_debug): Likewise. - * remote-utils.h (remote_debug): Likewise, - * server.c (remote_debug): Remove definition. - -2019-04-10 Kevin Buettner - - * linux-x86-low.c (x86_fill_gregset): Sign extend EAX value - when using a 64-bit gdbserver. - -2019-04-09 Tom Tromey - - * linux-low.c (select_event_lwp): Use find_thread_in_random. - -2019-04-08 Tom Tromey - - * linux-low.c (linux_detach_one_lwp): Replace throw_exception with - throw. - (linux_resume_one_lwp): Likewise. - -2019-04-08 Tom Tromey - - * gdbreplay.c: Update. - * linux-low.c: Update. - * server.c: Update. - -2019-04-08 Tom Tromey - - * server.c: Use C++ exception handling. - * linux-low.c: Use C++ exception handling. - * gdbreplay.c: Use C++ exception handling. - -2019-04-08 Tom Tromey - - * server.c (handle_btrace_general_set, handle_qxfer_btrace) - (handle_qxfer_btrace_conf, detach_or_kill_for_exit_cleanup) - (captured_main, main): Update. - * gdbreplay.c (main): Update. - -2019-04-05 Pedro Franco de Carvalho - - * linux-low.c (linux_get_auxv): Remove static. Return auxv entry - value in argument pointer, return 1 if the entry is found and 0 - otherwise. Move comment. - (linux_get_hwcap, linux_get_hwcap2): Use modified linux_get_auxv. - * linux-low.h (linux_get_auxv): Declare. - * linux-ppc-low.c (is_elfv2_inferior): Use linux_get_auxv. - -2019-04-05 Tom Tromey - - * server.c (gdbserver_usage): Use upper-case for metasyntactic - variables. - -2019-03-28 Alan Hayward - - * linux-low.c (AT_HWCAP2): Add define if not already included. - -2019-03-26 Alan Hayward - - * linux-aarch64-low.c (aarch64_get_hwcap): Remove function. - (aarch64_arch_setup): Call linux_get_hwcap. - * linux-arm-low.c (arm_get_hwcap): Remove function. - (arm_read_description): Call linux_get_hwcap. - * linux-low.c (linux_get_auxv): New function. - (linux_get_hwcap): Likewise. - (linux_get_hwcap2): Likewise. - * linux-low.h (linux_get_hwcap): New declaration. - (linux_get_hwcap2): Likewise. - * linux-ppc-low.c (ppc_get_auxv): Remove function. - (ppc_arch_setup): Call linux_get_hwcap. - * linux-s390-low.c (s390_get_hwcap): Remove function. - (s390_arch_setup): Call linux_get_hwcap. - -2019-03-22 Alan Hayward - Jiong Wang - - * linux-aarch64-low.c (aarch64_store_pauthregset): New function. - * linux-low.c (regsets_store_inferior_registers): Allow optional reads - to fail. - * linux-low.h (enum regset_type): Add OPTIONAL_REGS. - -2019-03-22 Alan Hayward - Jiong Wang - - * linux-aarch64-low.c (AARCH64_HWCAP_PACA): New define. - (aarch64_get_hwcap): New function. - (aarch64_arch_setup): Read APIA hwcap. - -2019-03-22 Alan Hayward - Jiong Wang - - * linux-aarch64-ipa.c (get_ipa_tdesc): Add pauth param. - (initialize_low_tracepoint): Likewise. - * linux-aarch64-low.c (aarch64_arch_setup): Likewise. - * linux-aarch64-tdesc-selftest.c (aarch64_tdesc_test): Likewise. - * linux-aarch64-tdesc.c (struct target_desc): Likewise. - (aarch64_linux_read_description): Likewise. - * linux-aarch64-tdesc.h (aarch64_linux_read_description): Likewise. - -2019-03-12 John Baldwin - - * linux-x86-tdesc.c (i386_linux_read_description): Update call to - i386_create_target_description for 'segments' parameter. - * lynx-i386-low.c (lynx_i386_arch_setup): Likewise. - * nto-x86-low.c (nto_x86_arch_setup): Likewise. - * win32-i386-low.c (i386_arch_setup): Likewise. - -2019-03-12 Tom Tromey - - * linux-low.c (iterate_over_lwps): Update. - -2019-03-06 Tom Tromey - - * server.c (detach_or_kill_for_exit_cleanup): Remove parameter. - (captured_main): Use SCOPE_EXIT. - -2019-03-04 Sergio Durigan Junior - - * configure.srv: Use '$enable_unittest' instead of '$development' - when checking whether to fill 'srv_regobj' on 'aarch64*-*-linux*' - case. - -2019-02-27 Tom Tromey - - * gdbreplay.c (logchar): Handle \r\n. - -2019-02-07 Alan Hayward - - * linux-low.c (linux_attach): Add process before lwp. - * server.c (attach_inferior): Check if already attached. - -2019-02-07 Tom Tromey - - * x86-tdesc.h: Rename include guard. - * x86-low.h: Add include guard. - * wincecompat.h: Rename include guard. - * win32-low.h: Add include guard. - * utils.h: Rename include guard. - * tracepoint.h: Rename include guard. - * tdesc.h: Rename include guard. - * target.h: Rename include guard. - * server.h: Rename include guard. - * remote-utils.h: Rename include guard. - * regcache.h: Rename include guard. - * nto-low.h: Rename include guard. - * notif.h: Add include guard. - * mem-break.h: Rename include guard. - * lynx-low.h: Add include guard. - * linux-x86-tdesc.h: Add include guard. - * linux-s390-tdesc.h: Add include guard. - * linux-ppc-tdesc-init.h: Add include guard. - * linux-low.h: Add include guard. - * linux-aarch64-tdesc.h: Add include guard. - * linux-aarch32-low.h: Add include guard. - * inferiors.h: Rename include guard. - * i387-fp.h: Rename include guard. - * hostio.h: Rename include guard. - * gdbthread.h: Rename include guard. - * gdb_proc_service.h: Rename include guard. - * event-loop.h: Rename include guard. - * dll.h: Rename include guard. - * debug.h: Rename include guard. - * ax.h: Rename include guard. - -2018-01-30 Szabolcs Nagy - - PR gdb/23985 - * Makefile.in (IPAGENT_CFLAGS): Add UNDO_GNULIB_CFLAGS. - (UNDO_GNULIB_CFLAGS): Undo gnulib replacements. - -2019-01-25 Tom Tromey - - * Makefile.in (INCLUDE_CFLAGS): Don't add -I for common. - -2019-01-25 Tom Tromey - - * win32-low.c: Fix common/ includes. - * win32-i386-low.c: Fix common/ includes. - * tracepoint.c: Fix common/ includes. - * thread-db.c: Fix common/ includes. - * target.h: Fix common/ includes. - * symbol.c: Fix common/ includes. - * spu-low.c: Fix common/ includes. - * server.h: Fix common/ includes. - * server.c: Fix common/ includes. - * remote-utils.c: Fix common/ includes. - * regcache.h: Fix common/ includes. - * regcache.c: Fix common/ includes. - * nto-x86-low.c: Fix common/ includes. - * notif.h: Fix common/ includes. - * mem-break.h: Fix common/ includes. - * lynx-low.c: Fix common/ includes. - * lynx-i386-low.c: Fix common/ includes. - * linux-x86-tdesc-selftest.c: Fix common/ includes. - * linux-x86-low.c: Fix common/ includes. - * linux-low.c: Fix common/ includes. - * inferiors.h: Fix common/ includes. - * i387-fp.c: Fix common/ includes. - * hostio.c: Fix common/ includes. - * hostio-errno.c: Fix common/ includes. - * gdbthread.h: Fix common/ includes. - * gdbreplay.c: Fix common/ includes. - * fork-child.c: Fix common/ includes. - * event-loop.c: Fix common/ includes. - * ax.c: - (enum gdb_agent_op): Fix common/ includes. - -2019-01-21 Tom Tromey - - * tracepoint.c: Fix includes. - * remote-utils.c: Fix includes. - * linux-x86-low.c: Fix includes. - -2019-01-01 Joel Brobecker - - * gdbreplay.c (gdbreplay_version): Update copyright year in - version message. - * server.c (gdbserver_version): Likewise. - -2018-12-05 Alan Hayward - - * linux-low.c (add_lwp): Switch ordering. - -2018-11-29 Tom Tromey - - * win32-low.c (win32_join): Take pid, not process. - * target.h (struct target_ops) : Change argument type. - (join_inferior): Change argument name. - * spu-low.c (spu_join): Take pid, not process. - * server.c (handle_detach): Preserve pid before destroying - process. - * lynx-low.c (lynx_join): Take pid, not process. - * linux-low.c (linux_join): Take pid, not process. - -2018-11-23 Alan Hayward - - * linux-aarch64-low.c (aarch64_cannot_store_register): Remove. - (aarch64_cannot_fetch_register): Likewise. - (struct linux_target_ops): Update references. - -2018-10-31 Pedro Franco de Carvalho - - * linux-ppc-low.c: Include nat/linux-ptrace.h. - -2018-10-26 Pedro Franco de Carvalho - - * configure.srv (ipa_ppc_linux_regobj): Add - powerpc-isa207-htm-vsx32l-ipa.o and - powerpc-isa207-htm-vsx64l-ipa.o. - (powerpc*-*-linux*): Add powerpc-isa207-htm-vsx32l.o and - powerpc-isa207-htm-vsx64l.o to srv_regobj. Add - rs6000/power-htm-spr.xml, rs6000/power-htm-core.xml, - rs6000/power64-htm-core.xml, rs6000/power-htm-fpu.xml, - rs6000/power-htm-altivec.xml, rs6000/power-htm-vsx.xml, - rs6000/power-htm-ppr.xml, rs6000/power-htm-dscr.xml, - rs6000/power-htm-tar.xml, rs6000/powerpc-isa207-htm-vsx32l.xml, - and rs6000/powerpc-isa207-htm-vsx64l.xml to srv_xmlfiles. - * linux-ppc-tdesc-init.h (enum ppc_linux_tdesc) - : New enum value. - (init_registers_powerpc_isa207_htm_vsx32l) - (init_registers_powerpc_isa207_htm_vsx64l): Declare. - * linux-ppc-low.c (ppc_fill_tm_sprregset, ppc_store_tm_sprregset) - (ppc_store_tm_cgprregset, ppc_store_tm_cfprregset) - (ppc_store_tm_cvrregset, ppc_store_tm_cvsxregset) - (ppc_store_tm_cpprregset, ppc_store_tm_cdscrregset) - (ppc_store_tm_ctarregset): New functions. - (ppc_regsets): Add entries for HTM regsets. - (ppc_arch_setup): Set htm in features struct when needed. Set - sizes for the HTM regsets. - (ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA207_HTM_VSX. - (initialize_low_arch): Call - init_registers_powerpc_isa207_htm_vsx32l and - init_registers_powerpc_isa207_htm_vsx64l. - * linux-ppc-ipa.c (get_ipa_tdesc): Handle - PPC_TDESC_ISA207_HTM_VSX. - (initialize_low_tracepoint): Call - init_registers_powerpc_isa207_htm_vsx32l and - init_registers_powerpc_isa207_htm_vsx64l. - -2018-10-26 Pedro Franco de Carvalho - - * configure.srv (powerpc*-*-linux*): Add rs6000/power-ebb.xml and - rs6000/power-linux-pmu.xml to srv_xmlfiles. - * linux-ppc-low.c (ppc_store_ebbregset, ppc_fill_pmuregset) - (ppc_store_pmuregset): New functions. - (ppc_regsets): Add entries for ebb and pmu regsets. - (ppc_arch_setup): Set isa207 in features struct if the ebb and - pmu regsets are available. Set sizes for these regsets. - -2018-10-26 Pedro Franco de Carvalho - - * configure.srv (ipa_ppc_linux_regobj): Add - powerpc-isa207-vsx64l-ipa.o and powerpc-isa207-vsx32l-ipa.o. - (powerpc*-*-linux*): Add powerpc-isa207-vsx32l.o and - powerpc-isa207-vsx64l.o to srv_regobj, add rs6000/power-tar.xml, - rs6000/powerpc-isa207-vsx32l.xml, and - rs6000/powerpc-isa207-vsx64l.xml to srv_xmlfiles. - * linux-ppc-tdesc-init.h (enum ppc_linux_tdesc) - : New enum value. - (init_registers_powerpc_isa207_vsx32l): Declare. - (init_registers_powerpc_isa207_vsx64l): Declare. - * linux-ppc-low.c (ppc_fill_tarregset): New function. - (ppc_store_tarregset): New function. - (ppc_regsets): Add entry for the TAR regset. - (ppc_arch_setup): Set isa207 in features struct when needed. Set - size for the TAR regsets. - (ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA207_VSX. - (initialize_low_arch): Call init_registers_powerpc_isa207_vsx32l - and init_registers_powerpc_isa207_vsx64l. - * linux-ppc-ipa.c (get_ipa_tdesc): Handle PPC_TDESC_ISA207_VSX. - (initialize_low_tracepoint): Call - init_registers_powerpc_isa207_vsx32l and - init_registers_powerpc_isa207_vsx64l. - -2018-10-26 Edjunior Barbosa Machado - Pedro Franco de Carvalho - - * configure.srv (ipa_ppc_linux_regobj): Add - powerpc-isa205-ppr-dscr-vsx32l-ipa.o and - powerpc-isa205-ppr-dscr-vsx64l-ipa.o. - (powerpc*-*-linux*): Add powerpc-isa205-ppr-dscr-vsx32l.o and - powerpc-isa205-ppr-dscr-vsx64l.o to srv_regobj, add - rs6000/power-dscr.xml, rs6000/power-ppr.xml, - rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml and - rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml to srv_xmlfiles. - * linux-ppc-tdesc-init.h (enum ppc_linux_tdesc) - : New enum value. - (init_registers_powerpc_isa205_ppr_dscr_vsx32l) - (init_registers_powerpc_isa205_ppr_dscr_vsx64l): Declare. - * linux-ppc-low.c: Include "elf/common.h" and . - (ppc_hwcap): Add comment. - (ppc_hwcap2): New global. - (ppc_check_regset, ppc_fill_pprregset, ppc_store_pprregset) - (ppc_fill_dscrregset, ppc_store_dscrregset): New functions. - (ppc_regsets): Add entries for the DSCR and PPR regsets. - (ppc_arch_setup): Get AT_HWCAP2. Set ppr_dscr in features struct - when needed. Set sizes for the the DSCR and PPR regsets. - (ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA205_PPR_DSCR_VSX. - (initialize_low_arch): Call - init_registers_powerpc_isa205_ppr_dscr_vsx32l and - init_registers_powerpc_isa205_ppr_dscr_vsx64l. - * linux-ppc-ipa.c (get_ipa_tdesc): Handle - PPC_TDESC_ISA205_PPR_DSCR_VSX. - (initialize_low_tracepoint): Call - init_registers_powerpc_isa205_ppr_dscr_vsx32l and - init_registers_powerpc_isa205_ppr_dscr_vsx64l. - -2018-10-26 Pedro Franco de Carvalho - - * linux-ppc-low.c (ppc_fill_vrregset): Remove memset calls. - -2018-10-10 Sergio Durigan Junior - Simon Marchi - - * acinclude.m4: Include "../selftest.m4". - * configure: Regenerate. - * configure.ac: Use "GDB_AC_SELFTEST". - * configure.srv: Use "$enable_unittests" instead of - "$development" when checking whether unit tests have been - enabled. - * server.c (captured_main): Update message informing that - selftests have been disabled. - -2018-10-04 Tom Tromey - - * configure: Rebuild. - -2018-10-04 Tom Tromey - - * server.c (handle_status): Rename inner "thread". - (process_serial_event): Declare "res" in 'm' case. - * linux-low.c (last_thread_of_process_p, find_lwp_pid) - (iterate_over_lwps): Rename inner "thread". - (linux_qxfer_libraries_svr4): Rename inner "len". - * gdbthread.h (find_thread_in_random): Rename inner "thread". - -2018-10-01 Gary Benson - - * gdb_proc_service.h: Moved common code to - common/gdb_proc_service.h. - -2018-10-01 Gary Benson - - * gdb_proc_service.h: Synchronize comments and whitespace with - GDB's version of this file. - -2018-09-25 Tom Tromey - - * configure: Rebuild. - * configure.ac (WARN_CFLAGS): Don't remove -Wmissing-prototypes. - -2018-09-16 Simon Marchi - - * Makefile.in (gdbserver$(EXEEXT)): Sort OBS. - (gdbreplay$(EXEEXT)): Sort GDBREPLAY_OBS. - ($(IPA_LIB)): Sort IPA_OBJS. - -2018-09-16 Simon Marchi - - * Makefile.in: Remove references to $(ADD_DEPS). - -2018-09-16 Tom Tromey - - * remote-utils.c (remote_open): Use GNU style for metasyntactic - variables. - * gdbreplay.c (gdbreplay_usage): Use GNU style for metasyntactic - variables. - -2018-09-05 Tom Tromey - - * configure: Rebuild. - -2018-08-28 Simon Marchi - - PR build/23399 - * tracepoint.c (IPA_SYM_STRUCT_NAME): Define. - -2018-08-27 Tom Tromey - - PR build/23087: - * configure: Rebuild. - -2018-08-27 Tom Tromey - - * linux-s390-low.c (s390_emit_ext, s390_emit_litpool) - (s390_emit_const, s390_emit_reg, s390_emit_zero_ext) - (s390_emit_stack_adjust, s390_emit_set_r2, s390x_emit_ext) - (s390x_emit_const, s390x_emit_reg, s390x_emit_zero_ext) - (s390x_emit_stack_adjust): Add casts to unsigned char. - -2018-08-22 Simon Marchi - - PR gdb/23374 - PR gdb/23375 - * server.h (struct client_state) : - Initialize to 1. - -2018-07-22 Simon Marchi - - * linux-mips-low.c (mips_collect_ptrace_register): Remove unused - variable. - (mips_supply_ptrace_register): Likewise. - -2018-07-22 Tom Tromey - - * configure: Rebuild. - -2018-07-22 Tom Tromey - - * win32-low.c (win32_create_inferior): Remove unused variables. - * gdbreplay.c (remote_open): Remove unused variable. - * remote-utils.c (remote_prepare): Remove unused variable. - * x86-tdesc.h (X86_TDESC_H): Define. - (amd64_expedite_regs): Define conditionally. - (i386_expedite_regs): Mark ATTRIBUTE_UNUSED. - * linux-x86-tdesc.c (i386_tdescs): Move inside #if. - * remote-utils.c (readchar): Remove unused variable. - -2018-07-13 Pedro Alves - - * linux-low.c (linux_kill): Change parameter to process_info - pointer instead of pid. Adjust. - * lynx-low.c (lynx_kill): Likewise. - * nto-low.c (nto_kill): Likewise. - * spu-low.c (spu_kill): Likewise. - * win32-low.c (win32_kill): Likewise. - * server.c (handle_v_kill, kill_inferior_callback) - (detach_or_kill_for_exit): Adjust. - * target.c (kill_inferior): Change parameter to process_info - pointer instead of pid. Adjust. - * target.h (struct target_ops) : Change parameter to - process_info pointer instead of pid. Adjust all implementations - and callers. - (kill_inferior): Likewise. - -2018-07-13 Pedro Alves - - * linux-low.c (linux_detach, linux_join): Change parameter to - process_info pointer instead of pid. Adjust. - * lynx-low.c (lynx_detach, lynx_join): Likewise. - * nto-low.c (nto_detach): Likewise. - * spu-low.c (spu_detach, spu_join): Likewise. - * win32-low.c (win32_detach, win32_join): Likewise. - * server.c (handle_detach, detach_or_kill_for_exit): Adjust. - * target.h (struct target_ops) : Change parameter to - process_info pointer instead of pid. Adjust all implementations - and callers. - (detach_inferior, join_inferior): Rename 'pid' parameter to - 'proc'. - -2018-07-11 Sergio Durigan Junior - Jan Kratochvil - Paul Fertser - Tsutomu Seki - - * Makefile.in (SFILES): Add '$(srcdir)/common/netstuff.c'. - (OBS): Add 'common/netstuff.o'. - (GDBREPLAY_OBS): Likewise. - * gdbreplay.c: Include 'wspiapi.h' and 'netstuff.h'. - (remote_open): Implement support for IPv6 - connections. - * remote-utils.c: Include 'netstuff.h', 'filestuff.h' - and 'wspiapi.h'. - (handle_accept_event): Accept connections from IPv6 sources. - (remote_prepare): Handle IPv6-style hostnames; implement - support for IPv6 connections. - (remote_open): Implement support for printing connections from - IPv6 sources. - -2018-07-11 Pedro Alves - - PR gdb/23377 - * mem-break.c (any_persistent_commands): Add process_info - parameter and use it instead of relying on the current process. - Change return type to bool. - * mem-break.h (any_persistent_commands): Add process_info - parameter and change return type to bool. - * server.c (handle_detach): Remove require_running_or_return call. - Look up the process_info for the process we're about to detach. - If not found, return back error to GDB. Adjust - any_persistent_commands call to pass down a process pointer. - -2018-07-11 Pedro Alves - - * i387-fp.c (i387_cache_to_fsave, cache_to_fxsave) - (i387_cache_to_xsave): Use regcache_raw_get_unsigned_by_name - instead of collect_register_by_name. - * regcache.c (regcache_raw_get_unsigned_by_name): New. - * regcache.h (regcache_raw_get_unsigned_by_name): New. - -2018-07-04 Vyacheslav Barinov - Pedro Alves - - * linux-low.c (initialize_low): Call linux_proc_init_warnings. - -2018-07-03 Tom Tromey - - * linux-low.c: Update. - * lynx-low.c: Update. - * mem-break.c: Update. - * nto-low.c: Update. - * remote-utils.c: Update. - * server.c: Update. - * spu-low.c: Update. - * target.c: Update. - * win32-low.c: Update. - -2018-07-03 Tom Tromey - - * server.c: Update. - -2018-07-03 Tom Tromey - - * linux-low.c: Update. - -2018-07-03 Tom Tromey - - * target.c: Update. - -2018-07-03 Tom Tromey - - * linux-low.c: Update. - * linux-mips-low.c: Update. - * lynx-low.c: Update. - * nto-low.c: Update. - * remote-utils.c: Update. - * server.c: Update. - * spu-low.c: Update. - * target.c: Update. - * thread-db.c: Update. - -2018-07-03 Tom Tromey - - * linux-low.c: Update. - * linux-mips-low.c: Update. - * lynx-low.c: Update. - * mem-break.c: Update. - * nto-low.c: Update. - * remote-utils.c: Update. - * server.c: Update. - * spu-low.c: Update. - * target.c: Update. - * tracepoint.c: Update. - -2018-07-03 Tom Tromey - - * linux-low.c: Update. - * linux-ppc-low.c: Update. - * linux-x86-low.c: Update. - * proc-service.c: Update. - * server.c: Update. - * spu-low.c: Update. - * thread-db.c: Update. - * win32-low.c: Update. - -2018-07-03 Tom Tromey - - * linux-low.c: Update. - * lynx-low.c: Update. - * nto-low.c: Update. - * remote-utils.c: Update. - * spu-low.c: Update. - * thread-db.c: Update. - * win32-low.c: Update. - -2018-06-29 Joel Brobecker - - * linux-x86-tdesc.c (amd64_linux_read_description): Add missing - parameter in call to 'amd64_create_target_description'. - -2018-06-28 Jan Kratochvil - - * x86-tdesc.h: Remove executable permission flag. - -2018-06-19 Simon Marchi - - * configure.ac: Remove AC_PREREQ, add missing quoting. - * configure: Re-generate. - * config.in: Re-generate. - * aclocal.m4: Re-generate. - -2018-06-18 Simon Marchi - - * tracepoint.h (current_traceframe): Remove declaration. - -2018-06-18 Alan Hayward - - * linux-aarch64-low.c (is_sve_tdesc): New function. - (aarch64_sve_regs_copy_to_regcache): Likewise. - (aarch64_sve_regs_copy_from_regcache): Likewise. - (aarch64_regs_info): Add SVE checks. - (initialize_low_arch): Initialize SVE. - -2018-06-18 Alan Hayward - - * Makefile.in: Add aarch64-sve-linux-ptrace.c. - -2018-06-11 Alan Hayward - - * linux-aarch64-ipa.c (get_ipa_tdesc): Add null VQ param. - (initialize_low_tracepoint): Likewise - * linux-aarch64-low.c (aarch64_arch_setup): Get VQ. - * linux-aarch64-tdesc-selftest.c (aarch64_tdesc_test): Add null VQ - param. - * linux-aarch64-tdesc.c (aarch64_linux_read_description): Add VQ - checks. - * linux-aarch64-tdesc.h (aarch64_linux_read_description): Add VQ. - -2018-06-11 Alan Hayward - - * server.h (PBUFSIZ): Increase size - -2018-06-11 Alan Hayward - - * regcache.c (regcache::raw_compare): New function. - * regcache.h (regcache::raw_compare): New declaration. - -2018-06-11 Alan Hayward - - * regcache.c (new_register_cache): Use new. - (free_register_cache): Use delete. - (register_data): Use const. - (supply_register): Move body inside regcache. - (regcache::raw_supply): New override function. - (collect_register): Move body inside regcache. - (regcache::raw_collect): New override function. - (regcache::get_register_status): New override function. - * regcache.h (struct regcache): Inherit from reg_buffer_common. - -2018-06-09 Tom Tromey - - * event-loop.c (gdb_event, gdb_event_p): Remove typedefs. Don't - declare queue. - (event_queue): Use std::queue. - (gdb_event_xfree): Remove. - (initialize_event_loop, process_event, wait_for_event): Update. - -2018-06-08 Stan Cox - - * win32-low.c (win32_create_inferior): last_ptid and last_status - moved to client_state. - -2018-06-08 Pedro Alves - - * Makefile.in (GDBREPLAY_OBS): Add common/cleanups.o, - common/common-exceptions.o, common/common-utils.o, - common/errors.o, common/print-utils.o and utils.o. - * gdbreplay.c: Include "common-defs.h" instead of the two - 'config.h's here. Don't include stdio.h, errno.h, stdlib.h, - string.h or alloca.h. - (perror_with_name): Delete. - (remote_open): Use xstrdup instead of strdup. - (main): Rename to ... - (captured_main): ... this. - (main): New. - -2018-06-08 Tom Tromey - - * linux-low.c (linux_low_read_btrace): Update. - -2018-06-04 Stan Cox - - * server.h (struct client_state): New. - * server.c (cont_thread, general_thread, multi_process) - (report_fork_events, report_vfork_events, report_exec_events) - (report_thread_events, swbreak_feature, hwbreak_feature) - (vCont_supported, disable_randomization, pass_signals) - (program_signals, program_signals_p, last_status, last_ptid, own_buf): - Moved to client_state. - * remote-utils.c (remote_debug, noack_mode) - (transport_is_reliable): Moved to client_state. - * tracepoint.c (current_traceframe): Moved to client_state. - - Update all callers. - * server.c, remote-utils.c, tracepoint.c, fork-child.c, - linux-low.c, remote-utils.h, target.c: Use client_state. - -2018-05-31 Alan Hayward - - * configure.srv: Add new c/h file. - -2018-05-31 Alan Hayward - - * linux-aarch64-tdesc.c (aarch64_linux_read_description): Add - null VQ. - -2018-05-25 Maciej W. Rozycki - - * gdb.arch/mips-fpregset-core.exp: New test. - * gdb.arch/mips-fpregset-core.c: New test source. - -2018-05-23 Erik Kurzinger - - PR server/23198 - * hostio.c (require_int): Do not report overflow for integers - between 0xfffffff and 0x7fffffff. - -2018-05-22 Maciej W. Rozycki - - * linux-mips-low.c [HAVE_PTRACE_GETREGS] (mips_collect_register) - (mips_supply_register): Move outside HAVE_PTRACE_GETREGS. - (mips_collect_ptrace_register, mips_supply_ptrace_register): New - functions. - (the_low_target): Wire them. - -2018-05-22 Pedro Franco de Carvalho - - * linux-ppc-low.c (ppc_fill_vrregset): Add vscr_offset variable. - Set vscr_offset to 0 in little-endian mode and 12 in big-endian - mode. Call collect_register_by_name with vscr using - vscr_offset. Zero-pad vscr and vrsave fields in collector buffer. - (ppc_store_vrregset): Add and set vscr_offset variable as in - ppc_fill_vrregset. Call supply_register_by_name with vscr using - vscr_offset. - -2018-05-22 Pedro Franco de Carvalho - - * linux-ppc-low.c (SIZEOF_VSXREGS, SIZEOF_VRREGS): Remove. - (ppc_arch_setup): Change SIZEOF_VRREGS and SIZEOF_VSXREGS to - PPC_LINUX_SIZEOF_VRREGSET and PPC_LINUX_SIZEOF_VSXREGSET. - -2018-05-22 Pedro Franco de Carvalho - - * linux-ppc-low.c (ppc_fill_vsxregset): Remove ppc_hwcap check. - (ppc_store_vsxregset): Likewise. - (ppc_fill_vrregset): Likewise. - (ppc_store_vrregset): Likewise. - (ppc_fill_evrregset): Likewise. - (ppc_store_evrregset): Likewise. - (ppc_regsets): Set VSX/VR/EVR regset sizes to 0. - (ppc_arch_setup): Iterate through ppc_regsets and set sizes when - needed. - -2018-05-22 Pedro Franco de Carvalho - - * linux-ppc-low.c (ppc_arch_setup): Remove code for getting the - wordsize of the inferior. Call ppc_linux_target_wordsize. - -2018-05-22 Pedro Franco de Carvalho - - * configure.srv (srv_tgtobj): Add arch/ppc-linux-common.o. - * Makefile.in (SFILES): Add arch/ppc-linux-common.c. - * linux-ppc-tdesc.h: Rename to linux-ppc-tdesc-init.h. - * linux-ppc-tdesc-init.h (tdesc_powerpc_32l, tdesc_powerpc_64l) - (tdesc_powerpc_altivec32l, tdesc_powerpc_altivec64l) - (tdesc_powerpc_cell32l, tdesc_powerpc_cell64l) - (tdesc_powerpc_vsx32l, tdesc_powerpc_vsx64l) - (tdesc_powerpc_isa205_32l, tdesc_powerpc_isa205_64l) - (tdesc_powerpc_isa205_altivec32l, tdesc_powerpc_isa205_altivec64l) - (tdesc_powerpc_isa205_vsx32l, tdesc_powerpc_isa205_vsx64l) - (tdesc_powerpc_e500l): Remove. - * linux-ppc-ipa.c: Include arch/ppc-linux-tdesc.h and - linux-ppc-tdesc-init.h. Don't include linux-ppc-tdesc.h. - * linux-ppc-low.c: Include arch/ppc-linux-common.h, - arch/ppc-linux-tdesc.h, and linux-ppc-tdesc-init.h. Don't include - linux-ppc-tdesc.h. - (ppc_arch_setup): Remove target description matching code. Fill a - ppc_linux_features struct and call ppc_linux_match_description - with it. - -2018-05-22 Maciej W. Rozycki - - * linux-mips-low.c (mips_cannot_fetch_register): Return 1 if the - width of the requested register exceeds the width of the - `ptrace' data type. - (mips_cannot_store_register): Likewise. - -2018-05-21 Maciej W. Rozycki - - * linux-mips-low.c (mips_fetch_register): New function. Update - preceding comment. - (mips_store_gregset): Supply 0 rather than $restart for $zero. - (the_low_target): Wire `mips_fetch_register'. - -2018-05-10 Joel Brobecker - - * lynx-i386-low.c (LYNXOS_178): New macro. - [LYNXOS_178] (usr_fcontext_t): Provide a definition that matches - the layout on LynxOS-178. - (lynx_i386_fill_fpregset, lynx_i386_store_fpregset): Do not - handle floating point registers that are not supported by - LynxOS-178. - -2018-05-10 Tom Tromey - - * configure: Rebuild. - -2018-05-10 Joel Brobecker - - PR server/23158: - * tdesc.h (init_target_desc) : New parameter. - * tdesc.c (init_target_desc) : New parameter. - Use it to set the expedite_regs field in the given tdesc. - * x86-tdesc.h: New file. - * linux-aarch64-tdesc.c (aarch64_linux_read_description): - Adjust following the addition of the new expedite_regs parameter - to init_target_desc. - * linux-tic6x-low.c (tic6x_read_description): Likewise. - * linux-x86-tdesc.c: #include "x86-tdesc.h". - (i386_linux_read_description, amd64_linux_read_description): - Adjust following the addition of the new expedite_regs parameter - to init_target_desc. - * lynx-i386-low.c: #include "x86-tdesc.h". - (lynx_i386_arch_setup): Adjust following the addition of the new - expedite_regs parameter to init_target_desc. - * nto-x86-low.c: #include "x86-tdesc.h". - (nto_x86_arch_setup): Adjust following the addition of the new - expedite_regs parameter to init_target_desc. - * win32-i386-low.c: #include "x86-tdesc.h". - (i386_arch_setup): Adjust following the addition of the new - expedite_regs parameter to init_target_desc. - -2018-05-10 Joel Brobecker - - PR server/23158: - * win32-low.c (win32_create_inferior): Add call to my_wait - setting last_status global. - -2018-05-10 Joel Brobecker - - PR server/23158: - * win32-low.c (create_process): Only call gdb_tilde_expand if - inferior_cwd is not NULL. - -2018-05-08 Andrew Burgess - - * i387-fp.c (i387_cache_to_xsave): Only write x87 control - registers to the cache if their values have changed. - (i387_xsave_to_cache): Provide default values for x87 control - registers when these features are available, but disabled. - * regcache.c (supply_register_by_name_zeroed): New function. - * regcache.h (supply_register_by_name_zeroed): Declare new - function. - -2018-05-07 Tom Tromey - - * configure: Rebuild. - -2018-05-04 Tom Tromey - - * configure: Rebuild. - -2018-05-04 Jan Kratochvil - Pedro Alves - - * linux-aarch64-low.c (aarch64_stopped_data_address): - Likewise. - -2018-04-27 Tom Tromey - - * configure: Rebuild. - -2018-04-23 Tom Tromey - - * configure: Rebuild. - -2018-04-19 Simon Marchi - - * Makefile.in (depcomp): Add "..". - (all_deps_files): New and use it. - -2018-04-18 Alan Hayward - - * configure.srv (aarch64*-*-linux*): Don't include xml. - (i[34567]86-*-cygwin*): Likewise. - (i[34567]86-*-linux*): Likewise. - (i[34567]86-*-lynxos*): Likewise. - (i[34567]86-*-mingw32ce*): Likewise. - (i[34567]86-*-mingw*): Likewise. - (i[34567]86-*-nto*): Likewise. - (tic6x-*-uclinux): Likewise. - (x86_64-*-linux*): Likewise. - (x86_64-*-mingw*): Likewise. - (x86_64-*-cygwin*): Likewise. - -2018-04-18 Alan Hayward - - * tdesc.c: Remove xml parameter. - -2018-04-18 Alan Hayward - - * server.c (get_features_xml): Remove cast. - * tdesc.c (void target_desc::accept): Fill in function. - (tdesc_get_features_xml): Remove old xml creation. - (print_xml_feature::visit_pre): Add xml vistor. - * tdesc.h (struct target_desc): Make xmltarget mutable. - (tdesc_get_features_xml): Remove declaration. - -2018-04-18 Alan Hayward - - * tdesc.c (tdesc_architecture_name): Add new function. - (tdesc_osabi_name): Likewise. - (tdesc_get_features_xml): Use new functions. - -2018-04-18 Alan Hayward - - * tdesc.c (tdesc_create_flags): Remove. - (tdesc_add_flag): Likewise. - (tdesc_named_type): Likewise. - (tdesc_create_union): Likewise. - (tdesc_create_struct): Likewise. - (tdesc_create_vector): Likewise. - (tdesc_add_bitfield): Likewise. - (tdesc_add_field): Likewise. - (tdesc_set_struct_size): Likewise. - -2018-04-18 Alan Hayward - - * tdesc.c (~target_desc): Remove implictly deleted items. - (init_target_desc): Iterate all features. - (tdesc_get_features_xml): Use vector. - (tdesc_create_feature): Create feature. - * tdesc.h (tdesc_feature) Remove - (target_desc): Add features. - -2018-04-18 Alan Hayward - - * Makefile.in: Add common/tdesc.c - * tdesc.c (init_target_desc): init all reg_defs from register - vector. - (tdesc_create_reg): Create tdesc_reg. - * tdesc.h (tdesc_feature): Add register vector. - -2018-03-30 Simon Marchi - - * tdesc.h (struct target_desc) : Change type to - std::vector. - * tdesc.c (target_desc::~target_desc): Adjust to std::vector - changes. - (tdesc_get_features_xml): Likewise. - (tdesc_create_feature): Likewise. - -2018-03-26 Alan Hayward - - * regcache.c (find_register_by_number): Return a ref. - (find_regno): Use references. - (register_size): Likewise. - (register_data): Likewise. - * tdesc.c (target_desc::~target_desc): Remove free calls. - (target_desc::operator==): Use std::vector compare. - (init_target_desc): Use reference. - (tdesc_create_reg): Use reg constructors. - * tdesc.h (struct target_desc): Replace pointer with object. - -2018-03-23 Alan Hayward - - * regcache.c (find_register_by_number): Make static. - (find_regno): Use find_register_by_number - * regcache.h (struct reg): Remove declaration. - -2018-03-23 Alan Hayward - - * tdesc.c (target_desc::~target_desc): Move to here. - (target_desc::operator==): Likewise. - * tdesc.h (target_desc::~target_desc): Move from here. - (target_desc::operator==): Likewise. - -2018-03-22 Andreas Arnez - - * linux-s390-low.c (s390_get_wordsize): Correct brace style. - -2018-03-21 Andreas Arnez - - * linux-s390-ipa.c (get_ipa_tdesc): Add handling for - S390_TDESC_GS. - * linux-s390-low.c (s390_get_ipa_tdesc_idx): Likewise. - (initialize_low_tracepoint): Call init_registers_s390x_gs_linux64 - and init_registers_s390_gs_linux64. - -2018-03-21 Andreas Arnez - - * linux-s390-low.c (s390_fill_gs): Remove function. - (s390_fill_gsbc): Remove function. - (s390_regsets): Set fill functions for the guarded storage regsets - to NULL. - -2018-03-21 Andreas Arnez - - * linux-s390-low.c (s390_get_hwcap): Replace tdesc parameter by - the word size. Add comment. - (s390_get_wordsize): New function. - (s390_arch_setup): No longer select a temporary tdesc to fetch the - pswm with it. Instead, use s390_get_wordsize to determine the - word size first and derive the correct tdesc from that directly. - -2018-03-16 Simon Marchi - - * Makefile.in: Include silent-rules.mk. - (srcdir, abs_top_srcdir, abs_srcdir, VPATH): Move up. - (COMPILE): Add ECHO_CXX. - (gdbserver$(EXEEXT)): Add SILENCE and ECHO_CXXLD. - (gdbreplay$(EXEEXT)): Add SILENCE and ECHO_CXXLD. - ($(IPA_LIB)): Add SILENCE and ECHO_CXXLD. - (version-generated.c): Add ECHO_GEN. - (stamp-xml): Add SILENCE and ECHO_GEN_XML_BUILTIN_GENERATED. - (IPAGENT_COMPILE): Add ECHO_CXX. - (%-generated.c): Add ECHO_REGDAT. - -2018-03-14 Tom Tromey - - PR cli/14977: - * ax.c (ax_printf): Special case for NULL. - -2018-03-08 Simon Marchi - - * linux-low.c (linux_qxfer_libraries_svr4): Use - xml_escape_text_append. - -2018-03-08 Simon Marchi - - * linux-low.c (linux_qxfer_libraries_svr4): Use std::string. - -2018-03-02 Simon Marchi - - * server.c (handle_general_set): Remove unnecessary xstrdup. - -2018-03-02 Simon Marchi - - * server.c (parse_debug_format_options): Adjust to - delim_string_to_char_ptr_vec changes. - * thread-db.c (thread_db_load_search): Adjust to - dirnames_to_char_ptr_vec changes. - -2018-03-01 Markus Metzger - - * target.h (target_enable_btrace, target_disable_btrace) - (target_read_btrace, target_read_btrace_conf): Turn macro into - inline function. Throw error if target method is not defined. - * server.c (handle_qxfer_btrace handle_qxfer_btrace_conf): Remove - check for btrace target method. Be prepared to handle exceptions - from btrace target methods. - -2018-02-28 Sergio Durigan Junior - - * server.c (captured_main): Change order of error message printed - when the current working directory cannot be found. - -2018-02-28 Sergio Durigan Junior - - * server.c: Include "filenames.h" and "pathstuff.h". - (program_name): Delete variable. - (program_path): New anonymous class. - (get_exec_wrapper): Use "program_path" instead of - "program_name". - (handle_v_run): Likewise. - (captured_main): Likewise. - (process_serial_event): Likewise. - -2018-02-28 Sergio Durigan Junior - - * Makefile.in (SFILES): Add "$(srcdir)/common/pathstuff.c". - (OBJS): Add "pathstuff.o". - * server.c (current_directory): New global variable. - (captured_main): Initialize "current_directory". - -2018-02-26 Alan Hayward - - * tdesc.c: Use common/tdesc.h. - * tdesc.h: Likewise. - -2018-02-20 Alan Hayward - Simon Marchi - - * Makefile.in: Switch order of make rules. - -2018-02-19 Alan Hayward - - * Makefile.in: Add common directory in build. - * configure.ac: Add common reference. - * configure: Regenerate. - -2018-02-09 Markus Metzger - - * linux-low.c (linux_target_ops): Remove linux_supports_btrace. - * nto-low.c (nto_target_ops): Remove NULL for supports_btrace. - * spu-low.c (spu_target_ops): Likewise. - * win32-low.c (win32_target_ops): Likewise. - * server.c (supported_btrace_packets): Report packets unconditionally. - * target.h (target_ops) : Remove. - (target_supports_btrace): Remove. - -2018-02-09 Markus Metzger - - * server.c (handle_btrace_enable_bts, handle_btrace_enable_pt) - (handle_btrace_disable): Change return type to void. Use exceptions - to report errors. - (handle_btrace_general_set): Catch exception and copy message to - return message. - -2018-02-08 Tom Tromey - - * linux-low.c (install_software_single_step_breakpoints): Use - make_scoped_restore. - * inferiors.c (make_cleanup_restore_current_thread): Remove. - (do_restore_current_thread_cleanup): Remove. - * gdbthread.h (make_cleanup_restore_current_thread): Don't - declare. - -2018-02-08 Tom Tromey - - * mem-break.c (set_raw_breakpoint_at): Use - gdb::unique_xmalloc_ptr. - -2018-01-30 Pedro Alves - - PR gdb/13211 - * target.c (target_terminal::terminal_state): Rename to ... - (target_terminal::m_terminal_state): ... this. - -2018-01-19 James Clarke - - * linux-low.c (handle_extended_wait): Surround call to - thread_db_notice_clone with #ifdef USE_THREAD_DB. - -2018-01-17 Simon Marchi - - * linux-low.c (attach_proc_task_lwp_callback): Adjust to - linux_ptrace_attach_fail_reason_string now returning an - std::string. - (linux_attach): Likewise. - * thread-db.c (attach_thread): Likewise. - -2018-01-17 Eldar Abusalimov - - PR gdb/21559 - * configure.ac: Include prior to when - checking for fs_base/gs_base fields in struct user_regs_struct. - * configure: Regenerate. - -2018-01-16 Yao Qi - - PR gdb/18749 - * linux-low.c (fetch_register): Call supply_register instead of - error. - -2018-01-08 Yao Qi - Simon Marchi - - * Makefile.in (OBS): Remove selftest.o. - * configure.ac: Set srv_selftest_objs if $development is true. - (GDBSERVER_DEPFILES): Append $srv_selftest_objs. - * configure: Re-generated. - * server.c (captured_main): Wrap variable selftest_filter with - GDB_SELF_TEST. - -2018-01-07 Simon Marchi - - * server.c (parse_debug_format_options): Return std::string. - (handle_monitor_command, captured_main): Adjust. - -2018-01-05 Pedro Alves - - PR gdb/18653 - * server.c (captured_main): Pass quiet=false to - save_original_signals_state. - -2018-01-01 Joel Brobecker - - * gdbreplay.c (gdbreplay_version): Update copyright year in - version message. - * server.c (gdbserver_version): Likewise. - -2017-12-08 Tom Tromey - - * ax.c (ax_printf): Update. - -2017-12-07 Yao Qi - - * linux-aarch64-ipa.c (initialize_low_tracepoint): Call - aarch64_linux_read_description. - * linux-amd64-ipa.c (idx2mask): New array. - (get_ipa_tdesc): Move idx2mask out. - (initialize_low_tracepoint): Initialize target descriptions. - * linux-i386-ipa.c (idx2mask): New array. - (get_ipa_tdesc): Move idx2mask out. - (initialize_low_tracepoint): Initialize target descriptions. - -2017-12-05 Simon Marchi - - * tdesc.c (struct tdesc_type): Change return type. - (tdesc_add_flag): Change parameter type. - (tdesc_add_bitfield): Likewise. - (tdesc_add_field): Likewise. - (tdesc_set_struct_size): Likewise. - -2017-12-05 Simon Marchi - - * regcache.c (registers_to_string): Remove unused variable. - -2017-12-02 Simon Marchi - - * inferiors.c (for_each_inferior_with_data): Remove. - * inferiors.h (for_each_inferior_with_data): Remove. - * server.c (handle_qxfer_threads_worker): Change parameter type. - (handle_qxfer_threads_proper): Use for_each_thread. - -2017-12-02 Simon Marchi - - * inferiors.c (for_each_inferior): Remove. - (clear_inferiors): Use for_each_thread. - * inferiors.h (for_each_inferior): Remove. - * linux-low.c (linux_wait_for_event_filtered): Use - for_each_thread. - (linux_stabilize_threads): Likewise. - * regcache.c (regcache_release): Likewise. - * server.c (gdb_wants_all_threads_stopped): Likewise. - (clear_pending_status_callback): Remove. - (handle_status): Use for_each_thread. - (captured_main): Likewise. - * win32-low.c (child_init_thread_list): Likewise. - (win32_clear_inferiors): Likewise. - (fake_breakpoint_event): Likewise. - -2017-12-02 Simon Marchi - - * inferiors.h (find_inferior): Remove. - * inferiors.c (find_inferior): Remove. - -2017-12-02 Simon Marchi - - * linux-low.c (resume_status_pending_p): Update comment. - (need_step_over_p): Update comment. - -2017-12-02 Simon Marchi - - * linux-low.c (proceed_one_lwp): Return void, change parameter - type. - (unsuspend_and_proceed_one_lwp): Likewise. - (proceed_all_lwps): Use for_each_thread. - (unstop_all_lwps): Likewise. - -2017-12-02 Simon Marchi - - * linux-low.c (linux_resume_one_thread): Return void, take - parameter directly. - (linux_resume): Use for_each_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (send_sigstop_callback): Return void, change - parameter type. Rename to... - (send_sigstop): ... this. - (suspend_and_send_sigstop_callback): Return void, change parameter - type. Rename to... - (suspend_and_send_sigstop): ... this. - (stop_all_lwps): Use for_each_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (lwp_running): Return bool, remove unused - argument. - (linux_stabilize_threads): Use find_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (select_singlestep_lwp_callback): Remove. - (count_events_callback): Remove. - (select_event_lwp_callback): Remove. - (select_event_lwp): Use find_thread/for_each_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (not_stopped_callback): Return bool, take filter - argument directly. - (linux_wait_for_event_filtered): Use find_thread. - (linux_wait_1): Likewise. - -2017-12-02 Simon Marchi - - * linux-low.c (same_lwp): Remove. - (find_lwp_pid): Use find_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (delete_lwp_callback): Remove. - (linux_mourn): Use for_each_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (linux_detach_lwp_callback): Return void, remove - args parameter, don't check for pid. - (linux_detach): Use for_each_thread. - -2017-12-02 Simon Marchi - - * linux-low.c (struct counter): Remove. - (second_thread_of_pid_p): Remove. - (last_thread_of_process_p): Use find_thread. - -2017-12-02 Simon Marchi - - * inferiors.c (find_inferior_in_random): Remove. - * inferiors.h (find_inferior_in_random): Remove. - * linux-low.c (status_pending_p_callback): Return bool, accept - parameter ptid directly. - (linux_wait_for_event_filtered): Use find_thread_in_random. - (linux_wait_1): Likewise. - -2017-12-02 Simon Marchi - - * inferiors.c (find_inferior_id): Remove. - (find_thread_ptid): Move implemention from find_inferior_id to - here. - * inferiors.h (find_inferior_id): Remove. - * server.c (handle_status): Use find_thread_ptid. - (process_serial_event): Likewise. - * thread-db.c (find_one_thread): Likewise. - (thread_db_thread_handle): Likewise. - * win32-low.c (thread_rec): Likewise. - (child_delete_thread): Likewise. - (win32_thread_alive): Likewise. - (get_child_debug_event): Likewise. - -2017-12-02 Simon Marchi - - * linux-mips-low.c (update_watch_registers_callback): Return - void, remove pid_p parameter, don't check for pid. - (mips_insert_point, mips_remove_point): Use for_each_thread. - -2017-12-02 Simon Marchi - - * lynx.low (lynx_delete_thread_callback): Remove. - (lynx_mourn): Use for_each_thread. - -2017-12-02 Simon Marchi - - * regcache.c (regcache_invalidate_one): Remove. - (regcache_invalidate_pid): use for_each_thread. - -2017-11-26 Tom Tromey - - * linux-low.c (linux_create_inferior): Update. - -2017-11-24 Ulrich Weigand - - * spu-low.c (spu_create_inferior): Fix typo in argument name. - -2017-11-24 Alan Hayward - - * configure.srv: Add linux-aarch64-tdesc-selftest.o. - * linux-aarch64-low.c (initialize_low_arch): Call init func. - * linux-aarch64-tdesc-selftest.c: New file. - * linux-aarch64-tdesc.h (initialize_low_tdesc): New declaration. - -2017-11-24 Alan Hayward - - * configure.srv: Add new file. - * linux-aarch64-low.c (initialize_low_arch): Call init func. - * linux-aarch64-tdesc-selftest.c: New file. - * linux-aarch64-tdesc.h (initialize_low_tdesc): New declaration. - -2017-11-24 Alan Hayward - - * linux-aarch64-ipa.c (initialize_low_tracepoint): Remove init. - * linux-aarch64-low.c (initialize_low_arch): Remove init. - * linux-aarch64-tdesc.c (aarch64_linux_read_description): Add init. - -2017-11-24 Alan Hayward - - * configure.srv: Add new files. - * linux-aarch64-ipa.c (get_ipa_tdesc): Call - aarch64_linux_read_description. - * linux-aarch64-low.c (aarch64_linux_read_description): - Merge with aarch64_arch_setup. - (aarch64_arch_setup): Call aarch64_linux_read_description. - * linux-aarch64-tdesc.c: New file. - * linux-aarch64-tdesc.h: New file. - -2017-11-24 Yao Qi - - * configure.srv: Set $srv_regobj for tic6x-linux. - * linux-tic6x-low.c: Include "arch/tic6x.h" and "tdesc.h". - (tic6x_read_description): Move some code to tic6x_arch_setup. - (tic6x_tdesc_test): New function. - (initialize_low_arch): Call selftests::register_test. - -2017-11-22 Yao Qi - - * remote-utils.c (prepare_resume_reply): Use memcpy. - -2017-11-19 Simon Marchi - - * linux-low.c (kill_one_lwp_callback): Return void, take - argument directly, don't filter on pid. - (linux_kill): Use for_each_thread. - -2017-11-19 Simon Marchi - - * linux-low.c (need_step_over_p): Return bool, remove dummy - argument. - (linux_resume, proceed_all_lwps): Use find_thread. - -2017-11-19 Simon Marchi - - * linux-low.c (resume_status_pending_p): Return bool, remove - flag_p argument. - (linux_resume): Use find_thread. - -2017-11-19 Simon Marchi - - * linux-low.c (struct thread_resume_array): Remove. - (linux_set_resume_request): Return void, take arguments - directly. - (linux_resume): Use for_each_thread. - -2017-11-19 Simon Marchi - - * linux-low.c (stuck_in_jump_pad_callback): Change prototype, - return bool, remove data argument. - (linux_stabilize_threads): Use find_thread. - -2017-11-19 Simon Marchi - - * linux-low.c (unsuspend_one_lwp): Remove. - (unsuspend_all_lwps): Use for_each_thread, inline code from - unsuspend_one_lwp. - -2017-11-19 Simon Marchi - - * gdbthread.h (find_thread): Add overload with ptid_t filter. - * linux-low.c (struct iterate_over_lwps_args): Remove. - (iterate_over_lwps_filter): Remove. - (iterate_over_lwps): Use find_thread. - -2017-11-19 Simon Marchi - - * linux-low.c (reset_lwp_ptrace_options_callback): Remove. - (linux_handle_new_gdb_connection): Use for_each_thread, inline - code from reset_lwp_ptrace_options_callback. - -2017-11-19 Simon Marchi - - * linux-arm-low.c (struct update_registers_data): Remove. - (update_registers_callback): Return void, take arguments - directly, don't check thread's pid. - (arm_insert_point, arm_remove_point): Use for_each_thread. - -2017-11-19 Simon Marchi - - * win32-low.c (continue_one_thread): Return void, take argument - directly. - (child_continue): Use for_each_thread. - -2017-11-19 Simon Marchi - - * win32-i386-low.c (update_debug_registers_callback): Rename - to ... - (update_debug_registers): ... this, return void, remove pid_p arg. - (x86_dr_low_set_addr, x86_dr_low_set_control): Use for_each_thread. - -2017-11-17 Simon Marchi - - * inferiors.h (struct process_info): Add constructor, initialize - fields.. - : Change type to std::vector. - * inferiors.c (add_process): Allocate process_info with new. - (remove_process): Free process_info with delete. - * linux-low.c (handle_extended_wait): Adjust. - (gdb_catching_syscalls_p, gdb_catch_this_syscall_p): Adjust. - * server.c (handle_general_set): Adjust. - -2017-11-16 Pedro Alves - - * remote-utils.c (remote_close): Block SIGIO signals instead of - uninstalling the SIGIO handler. - -2017-11-16 Alan Hayward - - * tdesc.c (tdesc_get_features_xml): Allow null osabi. - -2017-11-16 Yao Qi - - * linux-tic6x-low.c (tic6x_fill_gregset): Cast buf. - (tic6x_store_gregset): Likewise. - (tic6x_usrregs_info): Move it up. - -2017-11-15 Alan Hayward - - * Makefile.in: Update arch rules. - * configure.srv: Explicitly mark arch/ files. - -2017-11-13 Andreas Schwab - - * linux-m68k-low.c (m68k_supports_hardware_single_step): New - function. - (struct linux_target_ops) : Initialize. - -2017-11-06 Pedro Alves - - * config.in, configure: Regenerate. - -2017-10-27 Simon Marchi - - * target.c (struct thread_search): Remove. - (thread_search_callback): Remove. - (prepare_to_access_memory): Use for_each_thread instead of - find_inferior. Inline code from thread_search_callback. - -2017-10-27 Simon Marchi - - * server.c (struct visit_actioned_threads_data): Remove. - (visit_actioned_threads): Change prototype to take arguments - directly. - (resume): Use find_thread instead of find_inferior. - -2017-10-27 Simon Marchi - - * server.c (queue_stop_reply_callback): Change prototype, return - void. - (find_status_pending_thread_callback): Remove. - (handle_status): Replace find_inferior with find_thread and - for_each_thread. - -2017-10-25 Alan Hayward - - * linux-aarch64-low.c (aarch64_fill_gregset): Replace defines - with REGNO. - (aarch64_store_gregset): Likewise. - (aarch64_fill_fpregset): Likewise. - (aarch64_store_fpregset): Likewise. - -2017-10-21 Simon Marchi - - * gdbthread.h (find_thread, for_each_thread): New functions. - * inferiors.c (thread_of_pid): Remove. - (find_any_thread_of_pid): Use find_thread. - * linux-low.c (num_lwps): Use for_each_thread. - -2017-10-17 Yao Qi - - * Makefile.in: Remove one rule. - * configure.srv: Rename aarch64-insn.o with arch/aarch64-insn.o. - -2017-10-17 Yao Qi - - * configure.srv: Rename arm-linux.o with arch/arm-linux.o. - Rename arm-get-next-pcs.o with arch/arm-get-next-pcs.o. - -2017-10-17 Yao Qi - - * configure.srv: Rename arm.o with arch/arm.o. - -2017-10-17 Yao Qi - - * Makefile.in (CONFIG_SRC_SUBDIR): New variable. - (clean): Remove .o files in CONFIG_SRC_SUBDIR. - (distclean): Remove DEPDIR in CONFIG_SRC_SUBDIR. - (arch-i386.o, arch-amd64.o): Remove rules. - (arch/%.o): New rule. - Update POSTCOMPILE and COMPILE.pre. - * configure.ac: Invoke AC_CONFIG_COMMANDS. - * configure: Re-generated. - * configure.srv: Replace arch-i386.o with arch/i386.o. - Replace arch-amd64.o with arch/amd64.o. - -2017-10-16 Yao Qi - - * configure: Regenerated. - -2017-10-14 Simon Marchi - - * inferiors.h: (struct inferior_list): Remove. - (struct inferior_list_entry); Remove. - (add_inferior_to_list, clear_inferior_list, one_inferior_p, - A_I_NEXT, ALL_INFERIORS_TYPE, ALL_INFERIORS, remove_inferior, - get_first_inferior): Remove. - (for_each_inferior, for_each_inferior_with_data, find_inferior, - find_inferior_id, find_inferior_in_random): Change signature. - * inferiors.c (all_threads): Change type to - std::list. - (get_thread): Remove macro. - (find_inferior, find_inferior_id): Change signature, implement - using find_thread. - (find_inferior_in_random): Change signature, implement using - find_thread_in_random. - (for_each_inferior, for_each_inferior_with_data): Change - signature, implement using for_each_thread. - (add_inferior_to_list, remove_inferior): Remove. - (add_thread, get_first_thread, thread_of_pid, - find_any_thread_of_pid, free_one_thread, remove_thread): Update. - (get_first_inferior, one_inferior_p, clear_inferior_list): - Remove. - (clear_inferiors, get_thread_process): Update. - * gdbthread.h: Include . - (struct thread_info) : Remove field. - : New field. - (all_threads): Change type to std::list. - (get_first_inferior): Add doc. - (find_thread, for_each_thread, find_thread_in_random): New - functions. - (current_ptid, pid_of, ptid_of, lwpid_of): Update. - * linux-arm-low.c (update_registers_callback): Update. - * linux-low.c (second_thread_of_pid_p): Update. - (kill_one_lwp_callback, linux_detach_lwp_callback, - delete_lwp_callback, status_pending_p_callback, same_lwp, - find_lwp_pid, num_lwps, iterate_over_lwps_filter, - iterate_over_lwps, not_stopped_callback, - resume_stopped_resumed_lwps, count_events_callback, - select_singlestep_lwp_callback, select_event_lwp_callback, - unsuspend_one_lwp, linux_wait_1, send_sigstop_callback, - suspend_and_send_sigstop_callback, wait_for_sigstop, - stuck_in_jump_pad_callback, move_out_of_jump_pad_callback, - lwp_running, linux_set_resume_request, resume_status_pending_p, - need_step_over_p, start_step_over, linux_resume_one_thread, - proceed_one_lwp, unsuspend_and_proceed_one_lwp, - reset_lwp_ptrace_options_callback): Update. - * linux-mips-low.c (update_watch_registers_callback): Update. - * regcache.c (regcache_invalidate_one, regcache_invalidate): - Update. - (free_register_cache_thread_one): Remove. - (regcache_release): Update. - * server.c (handle_btrace_enable_bts, handle_btrace_enable_pt, - handle_qxfer_threads_worker): Update. - (handle_query): Update, use list iterator. - (visit_actioned_threads, handle_pending_status, - queue_stop_reply_callback, gdb_wants_all_threads_stopped, - clear_pending_status_callback, set_pending_status_callback, - find_status_pending_thread_callback, handle_status, - process_serial_event): Update. - * target.c (thread_search_callback): Update. - * thread-db.c (thread_db_get_tls_address): Update. - * tracepoint.c (tracepoint_finished_step, tracepoint_was_hit): - Update. - * win32-i386-low.c (update_debug_registers_callback): Update. - * win32-low.c (delete_thread_info, child_delete_thread, - continue_one_thread, suspend_one_thread, - get_child_debug_event): Adjust. - -2017-10-14 Simon Marchi - - * gdbthread.h (ptid_of, pid_of, lwpid_of): New functions. - * inferiors.h: Include . - (struct process_info) : Remove field. - : New field. - (pid_of): Change macro to function. - (ptid_of, lwpid_of): Remove macro. - (all_processes): Change type to std::list. - (ALL_PROCESSES): Remove macro. - (for_each_process, find_process): New function. - * inferiors.c (all_processes): Change type to - std::list. - (find_thread_process): Adjust. - (add_process): Likewise. - (remove_process): Likewise. - (find_process_pid): Likewise. - (get_first_process): Likewise. - (started_inferior_callback): Remove. - (have_started_inferiors_p): Adjust. - (attached_inferior_callback): Remove. - (have_attached_inferiors_p): Adjust. - * linux-low.c (check_zombie_leaders): Likewise. - * linux-x86-low.c (x86_arch_setup_process_callback): Remove. - (x86_linux_update_xmltarget): Adjust. - * server.c (handle_query): Likewise. - (gdb_reattached_process): Remove. - (handle_status): Adjust. - (kill_inferior_callback): Likewise. - (detach_or_kill_inferior): Remove. - (print_started_pid): Likewise. - (print_attached_pid): Likewise. - (detach_or_kill_for_exit): Update. - (process_serial_event): Likewise. - * linux-arm-low.c (arm_new_fork): Likewise. - -2017-10-14 Simon Marchi - - * dll.h: Include . - (struct dll_info): Add constructor. - : Remove field. - (all_dlls): Change type to std::list. - * dll.c: Include . - (get_dll): Remove macro. - (all_dlls): Change type to std::list. - (free_one_dll): Remove. - (match_dll): Likewise. - (loaded_dll): Adjust. - (unloaded_dll): Adjust to all_dlls type change, use - std::find_if. Inline code from match_dll. - (clear_dlls): Adjust to all_dlls type change. - * server.c (emit_dll_description): Remove. - (handle_qxfer_libraries): Adjust to all_dlls type change, - integrate emit_dll_description's functionality. - -2017-10-12 Simon Marchi - - * linux-low.h (struct linux_target_ops) : New - field. - * linux-low.c (linux_mourn): Call the_low_target.delete_process. - * linux-aarch64-low.c (aarch64_linux_delete_process): New. - (struct linux_target_ops): Add delete_process callback. - * linux-arm-low.c (arm_delete_process): New. - (struct linux_target_ops): Add delete_process callback. - * linux-bfin-low.c (struct linux_target_ops): Likewise. - * linux-crisv32-low.c (struct linux_target_ops): Likewise. - * linux-m32r-low.c (struct linux_target_ops): Likewise. - * linux-mips-low.c (mips_linux_delete_process): New. - (struct linux_target_ops): Add delete_process callback. - * linux-ppc-low.c (struct linux_target_ops): Likewise. - * linux-s390-low.c (struct linux_target_ops): Likewise. - * linux-sh-low.c (struct linux_target_ops): Likewise. - * linux-tic6x-low.c (struct linux_target_ops): Likewise. - * linux-tile-low.c (struct linux_target_ops): Likewise. - * linux-x86-low.c (x86_linux_delete_process): New. - (struct linux_target_ops): Add delete_process callback. - * linux-xtensa-low.c (struct linux_target_ops): Likewise. - -2017-10-12 Simon Marchi - - * linux-aarch64-low.c (the_low_target): Add thread delete - callback. - * linux-arm-low.c (arm_delete_thread): New function. - (the_low_target): Add thread delete callback. - * linux-bfin-low.c (the_low_target): Likewise. - * linux-crisv32-low.c (the_low_target): Likewise. - * linux-low.c (delete_lwp): Invoke delete_thread callback if - set. - * linux-low.h (struct linux_target_ops) : New - field. - * linux-m32r-low.c (the_low_target): Add thread delete callback. - * linux-mips-low.c (mips_linux_delete_thread): New function. - (the_low_target): Add thread delete callback. - * linux-ppc-low.c (the_low_target): Likewise. - * linux-s390-low.c (the_low_target): Likewise. - * linux-sh-low.c (the_low_target): Likewise. - * linux-tic6x-low.c (the_low_target): Likewise. - * linux-tile-low.c (the_low_target): Likewise. - * linux-x86-low.c (the_low_target): Likewise. - * linux-xtensa-low.c (the_low_target): Likewise. - -2017-10-06 Yuanhui Zhang - - * win32-low.c: Include "common-inferior.h". - -2017-10-04 Sergio Durigan Junior - - * inferiors.c (set_inferior_cwd): New function. - * server.c (handle_general_set): Handle QSetWorkingDir packet. - (handle_query): Inform that QSetWorkingDir is supported. - * win32-low.c (create_process): Pass the inferior's cwd to - CreateProcess. - -2017-10-04 Sergio Durigan Junior - - * inferiors.c (current_inferior_cwd): New global variable. - (get_inferior_cwd): New function. - * inferiors.h (struct process_info) : New field. - -2017-10-04 Sergio Durigan Junior - - * Makefile.in (SFILES): Add $(srcdir)/common/gdb_tilde_expand.c. - (OBS): Add gdb_tilde_expand.o. - -2017-10-02 Simon Marchi - - * lynx-i386-low.c (lynx_i386_arch_setup): Call init_target_desc. - * nto-x86-low.c (nto_x86_arch_setup): Likewise. - -2017-09-29 Pedro Alves - - * ax.c (gdb_parse_agent_expr): Constify. - * ax.h (gdb_parse_agent_expr): Constify. - * mem-break.c (add_breakpoint_condition, add_breakpoint_commands): - Constify. - * mem-break.h (add_breakpoint_condition, add_breakpoint_commands): Constify. - * remote-utils.c (hex_or_minus_one, read_ptid): Constify. - * remote-utils.h (read_ptid): Constify. - * server.c (handle_qxfer_exec_file, handle_query, handle_v_cont) - (process_point_options, process_serial_event): Constify. - * tracepoint.c (add_tracepoint_action, cmd_qtdp, cmd_qtdpsrc) - (cmd_qtdv, cmd_qtenable_disable, cmd_qtro, cmd_qtframe, cmd_qtp) - (cmd_qtbuffer): Constify. - -2017-09-29 Pedro Alves - - * proc-service.c (ps_pdread): Return PS_ERR if reading memory - fails. - -2017-09-29 Pedro Alves - - * linux-low.c (handle_extended_wait): Pass parent thread instead - of process to thread_db_notice_clone. - * linux-low.h (thread_db_notice_clone): Replace parent process - parameter with parent thread parameter. - * thread-db.c (find_one_thread): Add comment. - (thread_db_notice_clone): Replace parent process parameter with - parent thread parameter. Temporarily switch to the parent thread. - -2017-09-26 Sergio Durigan Junior - - * gdbthread.h: Include "common-gdbthread.h". - * inferiors.c (switch_to_thread): Use "gdb_assert" instead of - "if" when validating the ptid. - * remote-utils.c: Include "gdbthread.h". - (prepare_resume_reply): Use "switch_to_thread". - * target.c (done_accessing_memory): Likewise. - -2017-09-25 Andreas Arnez - - * configure.srv (s390*-*-linux*): Add s390-gs-linux64.o and - s390x-gs-linux64.o to srv_regobj. Add s390-gs-linux64.xml, - s390x-gs-linux64.xml, s390-gs.xml, and s390-gsbc.xml to - srv_xmlfiles. Add s390-gs-linux64-ipa.o and - s390x-gs-linux64-ipa.o to ipa_obj. - * linux-s390-low.c (HWCAP_S390_GS): New define. - (s390_fill_gs, s390_store_gs, s390_fill_gsbc, s390_store_gsbc): - New functions. - (s390_regsets): Add regsets for NT_S390_GS_CB and NT_S390_GS_BC. - (s390_arch_setup): Check for guarded-storage support and choose - appropriate tdesc. - (initialize_low_arch): Invoke init_registers_s390_gs_linux64 and - init_registers_s390x_gs_linux64. - * linux-s390-tdesc.h (enum s390_linux_tdesc) : New - enum value. - (init_registers_s390x_gs_linux64, tdesc_s390x_gs_linux64) - (init_registers_s390_gs_linux64, tdesc_s390_gs_linux64): Declare. - -2017-09-22 Simon Marchi - - * win32-i386-low.c (i386_arch_setup): Call init_target_desc. - -2017-09-21 Kevin Buettner - - * linux-low.h (struct lwp_info): Add new field, thread_handle. - (thread_db_thread_handle): Declare. - * linux-low.c (linux_target_ops): Initialize thread_handle. - * server.c (handle_qxfer_threads_worker): Add support for - "handle" attribute. - * target.h (struct target_ops): Add new function pointer, - thread_handle. - (target_thread_handle): Define. - * thread-db.c (find_one_thread, attach_thread): Set thread_handle - field in lwp. - (thread_db_thread_handle): New function. - -2017-09-21 Kevin Buettner - - * linux-low.c (handle_extended_wait): Call thread_db_notice_clone(). - * linux-low.h (thread_db_notice_clone): Declare. - * thread-db.c (thread_db_notice_clone): New function. - -2017-09-21 Pedro Alves - - * server.c (gdb_read_memory, handle_status, process_serial_event) - (handle_serial_event, handle_target_event): Adjust to - set_desired_thread prototype change. - * target.c (set_desired_thread): Remove 'use_general' parameter - and adjust. - * target.h (set_desired_thread): Remove 'use_general' parameter. - -2017-09-20 Tom Tromey - - * target.c (target_terminal::terminal_state): Define. - (target_terminal::init): Rename from target_terminal_init. - (target_terminal::inferior): Rename from - target_terminal_inferior. - (target_terminal::ours): Rename from target_terminal_ours. - (target_terminal::ours_for_output, target_terminal::info): New. - -2017-09-16 Simon Marchi - - * server.c (accumulate_file_name_length): Remove. - (emit_dll_description): Adjust to std::string change. - (handle_qxfer_libraries): Use std::string to hold document. - -2017-09-16 Simon Marchi - - * linux-low.c (linux_qxfer_libraries_svr4): Adjust to change of - return type of xml_escape_text. - * server.c (emit_dll_description): Likewise. - -2017-09-16 Simon Marchi - - * server.c (captured_main): Accept argument for --selftest. - Update run_tests call. - * linux-x86-tdesc-selftest.c (initialize_low_tdesc): Add names - when registering selftests. - -2017-09-16 Sergio Durigan Junior - - * regcache.c (get_thread_regcache): Update code to use "std::vector" - instead of "VEC" for "target_desc.reg_defs". - (regcache_cpy): Likewise. - (registers_to_string): Likewise. - (registers_from_string): Likewise. - (find_regno): Likewise. - (supply_regblock): Likewise. - (regcache_raw_read_unsigned): Likewise. - * tdesc.c (init_target_desc): Likewise. - (tdesc_create_reg): Likewise. - * tdesc.h: Remove declaration of "tdesc_reg_p". Include . - (struct target_desc) : Convert to "std::vector". - (target_desc): Do not initialize "reg_defs". - (~target_desc): Update code to use "std::vector" instead of "VEC" - for "target_desc.reg_defs". - (operator==): Likewise. - -2017-09-15 Simon Marchi - - * inferiors.h (thread_to_gdb_id): Remove. - * inferiors.c (thread_to_gdb_id): Remove. - * server.c (handle_qxfer_threads_worker, handle_query): Adjust. - * lynx-low.c (lynx_resume, lynx_wait_1, lynx_fetch_registers, - lynx_store_registers, lynx_read_memory, lynx_write_memory): - Likewise. - * nto-low.c (nto_fetch_registers, nto_store_registers, - nto_stopped_by_watchpoint, nto_stopped_data_address): Likewise. - -2017-09-15 Simon Marchi - - * inferiors.h (gdb_id_to_thread_id): Remove. - * inferiors.c (gdb_id_to_thread_id): Remove. - * server.c (process_serial_event): Adjust to gdb_id_to_thread_id - removal. Move pid declaration closer to where it's used. - -2017-09-15 Simon Marchi - - * server.c (handle_detach): New function. - (process_serial_event): Move code out, call handle_detach. - -2017-09-15 Simon Marchi - - * server.c (require_running): Rename to ... - (require_running_or_return): ... this ... - (require_running_or_break): ... and this. - (handle_query, process_serial_event): Adjust. - -2017-09-15 Simon Marchi - - * linux-low.c (linux_set_resume_request): Remove unused - variables. - -2017-09-15 Simon Marchi - - * server.c (first_thread_of): Remove. - (process_serial_event): Replace usage of first_thread_of with - find_any_thread_of_pid. - * tracepoint.c (same_process_p): Remove. - (gdb_agent_about_to_close): Replace usage of same_process_p with - find_any_thread_of_pid. - * linux-x86-low.c (same_process_callback): Remove. - (x86_arch_setup_process_callback): Replace usage of - same_process_callback with find_any_thread_of_pid. - * thread-db.c (any_thread_of): Remove. - (switch_to_process): Replace usage of any_thread_of with - find_any_thread_of_pid. - * inferiors.c (thread_pid_matches_callback): Remove. - (find_thread_process): Adjust to use find_any_thread_of_pid. - -2017-09-10 Sergio Durigan Junior - - * regcache.c (get_thread_regcache): Guard calls to "memset" - with "!VEC_empty". - -2017-09-10 Sergio Durigan Junior - - * linux-low.c (handle_extended_wait): Use - "allocate_target_description" instead of "XNEW". - * linux-x86-low.c (initialize_low_arch): Likewise. - -2017-09-05 Yao Qi - - * configure.srv (srv_i386_regobj): Remove. - (srv_amd64_regobj): Remove. - (srv_regobj): Set it to "" for x86 non-linux targets. - * linux-x86-tdesc.c (i386_linux_read_description): - * lynx-i386-low.c: Include x86-xstate.h and arch/i386.h. - (init_registers_i386): Remove the declaration. - (tdesc_i386): Remove the declaration. - (lynx_i386_arch_setup): Call i386_create_target_description. - * nto-x86-low.c: Likewise. - * win32-i386-low.c [__x86_64__]: include arch/amd64.h. - [!__x86_64__]: include arch/i386.h. - (i386_arch_setup) [__x86_64__]: Call amd64_create_target_description. - -2017-09-05 Yao Qi - - * configure.srv (srv_amd64_linux_xmlfiles): Remove - i386/amd64-XXX-linux from it. - -2017-09-05 Yao Qi - - * configure.srv: Empty srv_amd64_linux_regobj if $development is - false. - (ipa_amd64_linux_regobj): Remove. - (ipa_x32_linux_regobj): Remove. - -2017-09-05 Yao Qi - - * Makefile.in (arch-amd64.o): New rule. - * configure.srv: Append arch-amd64.o. - * linux-amd64-ipa.c: Include common/x86-xstate.h. - (get_ipa_tdesc): Call amd64_linux_read_description. - (initialize_low_tracepoint): Don't call init_registers_x32_XXX - and init_registers_amd64_XXX. - * linux-x86-low.c (x86_linux_read_description): Call - amd64_linux_read_description. - (x86_get_ipa_tdesc_idx): Call amd64_get_ipa_tdesc_idx. - (initialize_low_arch): Don't call init_registers_x32_XXX and - init_registers_amd64_XXX. - * linux-x86-tdesc-selftest.c: Declare init_registers_amd64_XXX - and tdesc_amd64_XXX. - [__x86_64__] (amd64_tdesc_test): New function. - (initialize_low_tdesc) [__x86_64__]: Call init_registers_x32_XXX - and init_registers_amd64_XXX. - * linux-x86-tdesc.c: Include arch/amd64.h. - (xcr0_to_tdesc_idx): New function. - (i386_linux_read_description): New function. - (amd64_get_ipa_tdesc_idx): New function. - * linux-x86-tdesc.h (amd64_get_ipa_tdesc_idx): Declare. - (amd64_get_ipa_tdesc): Declare. - -2017-09-05 Yao Qi - - * configure.srv (srv_i386_linux_xmlfiles): Remove - i386/i386-XXX-linux.xml from it. - -2017-09-05 Yao Qi - - * configure.srv: Set srv_i386_linux_regobj empty if $development - is false. - * linux-i386-ipa.c (initialize_low_tracepoint): Don't call - initialize_low_tdesc. - * linux-x86-low.c (initialize_low_arch): Wrap initialize_low_tdesc - with #if initialize_low_tdesc. - * linux-x86-tdesc-selftest.c: New file. - * linux-x86-tdesc.c: Move code to linux-x86-tdesc-selftest.c. - -2017-09-05 Yao Qi - - * Makefile.in (arch-i386.o): New rule. - * configure.srv (i[34567]86-*-linux*): Add arch-i386.o. - (x86_64-*-linux*): Likewise. - * linux-x86-tdesc.c: Don't include ../features/i386/32bit-XXX.c, - include arch/i386.h. - (i386_linux_read_description): Remove code and call - i386_create_target_description. - * tdesc.c (allocate_target_description): New function. - * tdesc.h (set_tdesc_architecture): Remove declaration. - (set_tdesc_osabi): Likewise. - -2017-09-05 Yao Qi - - * linux-x86-tdesc.c: Don't include . - (i386_linux_read_description) [!IN_PROCESS_AGENT]: Call - set_tdesc_architecture and set_tdesc_osabi. Remove code setting - .xmltarget. - * server.c (get_features_xml): Call tdesc_get_features_xml. - * tdesc.c (set_tdesc_architecture): New function. - (set_tdesc_osabi): New function. - (tdesc_get_features_xml): New function. - (tdesc_create_feature): Add an argument. - * tdesc.h (struct target_desc) : New field. - : New field. - (~target_desc): xfree features, arch, and osabi. - (target_desc::oerator==): Don't compare .xmltarget. - [!IN_PROCESS_AGENT] (set_tdesc_architecture): Declare. - (set_tdesc_osabi): Likewise. - (tdesc_get_features_xml): Likewise. - -2017-09-05 Yao Qi - - * linux-x86-tdesc.c: Include selftest.h. - (i386_tdesc_test): New function. - (initialize_low_tdesc): Call selftests::register_test. - * tdesc.h: Include regdef.h. - (target_desc): Override operator == and !=. - -2017-09-05 Yao Qi - - * configure.srv (srv_tgtobj): Append linux-x86-tdesc.o. - (ipa_obj): Likewise. - * linux-i386-ipa.c: Include common/x86-xstate.h - (get_ipa_tdesc): Call i386_linux_read_description. - (initialize_low_tracepoint): Don't call init_registers_XXX - functions, call initialize_low_tdesc instead. - * linux-x86-low.c (x86_linux_read_description): Call - i386_linux_read_description. - (initialize_low_arch): Don't call init_registers_i386_XXX - functions, call initialize_low_tdesc. - * linux-x86-tdesc.c: New file. - * linux-x86-tdesc.h (x86_linux_tdesc): New X86_TDESC_LAST. - (i386_get_ipa_tdesc_idx): Declare. - (i386_get_ipa_tdesc): Declare. - (initialize_low_tdesc): Declare. - -2017-09-05 Yao Qi - - * linux-x86-low.c (x86_get_ipa_tdesc_idx): Use X86_TDESC_MMX - instead of 0. - -2017-09-05 Yao Qi - - * Makefile.in (IPA_OBJS): Add vec-ipa.o - * regcache.c (get_thread_regcache): Use VEC_length. - (init_register_cache): Likewise. - (regcache_cpy): Likewise. - (registers_to_string): Iterate reg_defs via VEC_iterate. - (find_regno): Likewise. - (find_register_by_number): Use VEC_index. - (register_size): Call find_register_by_number. - (register_data): Call find_register_by_number. - (supply_regblock): Use VEC_length. - (regcache_raw_read_unsigned): Likewise. - * tdesc.c (init_target_desc): Iterate reg_defs via - VEC_iterate. - (default_description): Update initializer. - (copy_target_description): Don't update field num_registers. - * tdesc.h (struct target_desc) : Change it to VEC. - : Remove. - -2017-09-04 Simon Marchi - - * Makefile.in (.SECONDARY): Define target. - -2017-09-03 Simon Marchi - - * linux-low.c (linux_wait_1): Adjust. - * server.c (queue_stop_reply_callback): Adjust. - -2017-08-31 Sergio Durigan Junior - - * server.c (handle_general_set): Handle QEnvironmentHexEncoded, - QEnvironmentUnset and QEnvironmentReset packets. - (handle_query): Inform remote that QEnvironmentHexEncoded, - QEnvironmentUnset and QEnvironmentReset are supported. - -2017-08-25 Simon Marchi - - * inferiors.h (inferior_target_data): Rename to ... - (thread_target_data): ... this. - (inferior_regcache_data): Rename to ... - (thread_regcache_data): ... this. - (set_inferior_regcache_data): Rename to ... - (set_thread_regcache_data): ... this. - * inferiors.c (inferior_target_data): Rename to ... - (thread_target_data): ... this. - (inferior_regcache_data): Rename to ... - (thread_regcache_data): ... this. - (set_inferior_regcache_data): Rename to ... - (set_thread_regcache_data): ... this. - (free_one_thread): Update. - * linux-low.h (get_thread_lwp): Update. - * regcache.c (get_thread_regcache): Update. - (regcache_invalidate_thread): Update. - (free_register_cache_thread): Update. - * win32-i386-low.c (update_debug_registers_callback): Update. - (win32_get_current_dr): Update. - * win32-low.c (thread_rec): Update. - (delete_thread_info): Update. - (continue_one_thread): Update. - (suspend_one_thread): Update. - -2017-08-24 Simon Marchi - - * inferiors.c (set_inferior_target_data): Remove. - * inferiors.h (set_inferior_target_data): Remove. - -2017-08-18 Yao Qi - - * Makefile.in (OBS): Add selftest.o. - * configure.ac: AC_DEFINE GDB_SELF_TEST if $development. - * configure, config.in: Re-generated. - * server.c: Include common/sefltest.h. - (captured_main): Handle option --selftest. - -2017-08-09 Yao Qi - - * configure.srv (srv_i386_regobj): Remove i386-avx.o, - i386-avx-avx512.o, i386-avx-mpx-avx512-pku.o, i386-mpx.o, - i386-avx-mpx.o and i386-mmx.o. - (srv_amd64_regobj): Remove amd64-avx.o, amd64-avx-avx512.o, - amd64-avx-mpx-avx512-pku.o, amd64-mpx.o and amd64-avx-mpx.o. - (srv_i386_xmlfiles): Remove i386/i386-avx.xml, - i386/i386-avx-avx512.xml, i386/i386-avx-mpx-avx512-pku.xml, - i386/i386-mpx.xml, i386/i386-avx-mpx.xml and i386/i386-mmx.xml. - (srv_amd64_xmlfile):i386/amd64-avx.xml, i386/amd64-avx-avx512.xml, - i386/amd64-avx-mpx-avx512-pku.xml, i386/amd64-mpx.xml, - i386/amd64-avx-mpx.xml. - -2017-08-09 Yao Qi - - * configure.srv (srv_amd64_regobj): Remove x32.o, x32-avx.o - and x32-avx-avx512.o. - (srv_amd64_xmlfiles): Remove i386/x32.xml, i386/x32-avx.xml - i386/x32-avx-avx512.xml. - -2017-07-26 Simon Marchi - - * tracepoint.h (enum class fast_tpoint_collect_result): New - enumeration. - (fast_tracepoint_collecting): Change return type to - fast_tpoint_collect_result. - * tracepoint.c (fast_tracepoint_collecting): Likewise. - * linux-low.h: Include tracepoint.h. - (struct lwp_info) : Change type to - fast_tpoint_collect_result. - * linux-low.c (handle_tracepoints): Adjust. - (linux_fast_tracepoint_collecting): Change return type to - fast_tpoint_collect_result. - (maybe_move_out_of_jump_pad, linux_wait_for_event_filtered, - linux_wait_1, stuck_in_jump_pad_callback, - lwp_signal_can_be_delivered, linux_resume_one_lwp_throw, - proceed_one_lwp): Adjust to type change. - -2017-07-10 Yao Qi - - * linux-x86-low.c (x86_linux_read_description): Re-indent the code. - -2017-06-29 Yao Qi - - * tdesc.h (struct target_desc) [IN_PROCESS_AGENT] : - Remove. - [IN_PROCESS_AGENT] : Likewise. - -2017-06-20 Simon Marchi - - * Makefile.in (IPA_OBJS): Sort and format one item per line. - -2017-06-20 Sergio Durigan Junior - - * linux-low.c (linux_create_inferior): Adjust code to access the - environment information via 'gdb_environ' class. - * lynx-low.c (lynx_create_inferior): Likewise. - * server.c (our_environ): Make it an instance of 'gdb_environ'. - (get_environ): Return a pointer to 'our_environ'. - (captured_main): Initialize 'our_environ'. - * server.h (get_environ): Adjust prototype. - * spu-low.c (spu_create_inferior): Adjust code to access the - environment information via 'gdb_environ' class. - -2017-06-17 Simon Marchi - - * linux-low.c (linux_read_memory, linux_write_memory): Remove - usage of "register" keyword. - -2017-06-17 Simon Marchi - - * configure: Re-generate. - -2017-06-17 Simon Marchi - - * configure: Re-generate. - -2017-06-17 Simon Marchi - - * Makefile.in (COMPILE.pre): Add "-x c++". - -2017-06-09 Sergio Durigan Junior - - * fork-child.c: Conditionally include . - -2017-06-07 Sergio Durigan Junior - - * server.c (handle_general_set): Handle new packet - "QStartupWithShell". - (handle_query): Add "QStartupWithShell" to the list of supported - packets. - (gdbserver_usage): Add help text explaining the - new "--startup-with-shell" and "--no-startup-with-shell" CLI - options. - (captured_main): Recognize and act upon the presence of the new - CLI options. - -2017-06-07 Sergio Durigan Junior - Pedro Alves - - * Makefile.in (SFILES): Add "nat/fork-inferior.o". - * configure: Regenerate. - * configure.srv (srv_linux_obj): Add "fork-child.o" and - "fork-inferior.o". - (i[34567]86-*-lynxos*): Likewise. - (spu*-*-*): Likewise. - * fork-child.c: New file. - * linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h" - and "environ.h". - (linux_ptrace_fun): New function. - (linux_create_inferior): Adjust function prototype to reflect - change on "target.h". Adjust function code to use - "fork_inferior". - (linux_request_interrupt): Delete "signal_pid". - * lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h". - (lynx_ptrace_fun): New function. - (lynx_create_inferior): Adjust function prototype to reflect - change on "target.h". Adjust function code to use - "fork_inferior". - * nto-low.c (nto_create_inferior): Adjust function prototype and - code to reflect change on "target.h". Update comments. - * server.c: Include "common-inferior.h", "nat/fork-inferior.h", - "common-terminal.h" and "environ.h". - (terminal_fd): Moved to fork-child.c. - (old_foreground_pgrp): Likewise. - (restore_old_foreground_pgrp): Likewise. - (last_status): Make it global. - (last_ptid): Likewise. - (our_environ): New variable. - (startup_with_shell): Likewise. - (program_name): Likewise. - (program_argv): Rename to... - (program_args): ...this. - (wrapper_argv): New variable. - (start_inferior): Delete function. - (get_exec_wrapper): New function. - (get_exec_file): Likewise. - (get_environ): Likewise. - (prefork_hook): Likewise. - (post_fork_inferior): Likewise. - (postfork_hook): Likewise. - (postfork_child_hook): Likewise. - (handle_v_run): Update code to deal with arguments coming from the - remote host. Update calls from "start_inferior" to - "create_inferior". - (captured_main): Likewise. Initialize environment variable. Call - "have_job_control". - * server.h (post_fork_inferior): New prototype. - (get_environ): Likewise. - (last_status): Declare. - (last_ptid): Likewise. - (signal_pid): Likewise. - * spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h". - (spu_ptrace_fun): New function. - (spu_create_inferior): Adjust function prototype to reflect change - on "target.h". Adjust function code to use "fork_inferior". - * target.c (target_terminal_init): New function. - (target_terminal_inferior): Likewise. - (target_terminal_ours): Likewise. - * target.h: Include . - (struct target_ops) : Update prototype. - (create_inferior): Update macro. - * utils.c (gdb_flush_out_err): New function. - * win32-low.c (win32_create_inferior): Adjust function prototype - and code to reflect change on "target.h". - -2017-06-07 Sergio Durigan Junior - - * inferiors.c (switch_to_thread): New function. - -2017-06-07 Sergio Durigan Junior - - * Makefile.in (SFILE): Add "common/job-control.c". - (OBS): Add "job-control.o". - -2017-05-06 Sergio Durigan Junior - - * Makefile: Remove "@host_makefile_frag@". - -2017-05-05 Pedro Alves - - * configure: Regenerate. - -2017-05-03 Sergio Durigan Junior - - * configure: Regenerate. - -2017-05-02 Simon Marchi - - * linux-arm-low.c (arm_gdbserver_get_next_pcs): Adjust to - software_single_step change of return type to - std::vector. - * linux-low.c (install_software_single_step_breakpoints): - Likewise. - * linux-low.h (install_software_single_step_breakpoints): - Likewise. - -2017-04-12 Sergio Durigan Junior - - * remote-utils.c: Include "gdb_termios.h" instead of - "terminal.h". - * terminal.h: Delete file. - -2017-04-12 Sergio Durigan Junior - - * server.c: Include . - : Convert to std::vector. - (start_inferior): Rewrite function to use C++. - (handle_v_run): Likewise. Update code that calculates the argv - based on the vRun packet; use C++. - (captured_main): Likewise. - -2017-04-06 Simon Marchi - - * server.c (handle_v_cont): Initialize thread_resume::thread - with null_ptid. - -2017-04-05 Pedro Alves - - * configure: Regenerate. - -2017-04-05 Pedro Alves - - * gdbreplay.c (sync_error): Constify. - * linux-x86-low.c (push_opcode): Constify. - -2017-04-05 Pedro Alves - - * win32-low.c (get_child_debug_event) - : Don't report TARGET_WAITKIND_EXECD. - Report TARGET_WAITKIND_SPURIOUS instead. - -2017-04-05 Pedro Alves - - * remote-utils.c (remote_prepare, remote_open): Constify. - * remote-utils.h (remote_prepare, remote_open): Constify. - * server.c (captured_main): Constify 'port' handling. - -2017-04-04 Simon Marchi - - * Makefile.in (clean): Clear .deps. - -2017-03-31 Simon Marchi - - * .gitignore: Remove generated files, replace with wildcard. - * (clean): Replace removal of generated files with wildcard. - (version.c): Replace with... - (version-generated.c): ...this. - (xml-builtin.c): Replace with... - (xml-builtin-generated.c): ...this. - (%-ipa.o: %-generated.c, %.o: %-generated.c): New rules. - (%.c: *regformats*): Replace with... - (%-generated.c: *regformats*): ...this. - -2017-03-27 Max Filippov - - * linux-xtensa-low.c (regnum::R_THREADPTR): New enum member. - (xtensa_fill_gregset): Call collect_register_by_name for - threadptr register. - (xtensa_store_gregset): Call supply_register_by_name for - threadptr register. - -2017-03-27 Max Filippov - - * linux-xtensa-low.c (xtensa_fill_gregset): Call collect_register - for all registers in a0_regnum..a0_regnum + C0_NREGS range. - (xtensa_store_gregset): Call supply_register for all registers in - a0_regnum..a0_regnum + C0_NREGS range. - -2017-03-13 Simon Marchi - - * Makefile.in (%-ipa.o: %-ipa.c): New rule. - (ax-ipa.o: ax.c): Remove. - (linux-i386-ipa.o: linux-i386-ipa.c): Remove. - (linux-amd64-ipa.o: linux-amd64-ipa.c): Remove. - (linux-aarch64-ipa.o: linux-aarch64-ipa.c): Remove. - (linux-s390-ipa.o: linux-s390-ipa.c): Remove. - (linux-ppc-ipa.o: linux-ppc-ipa.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in (%-ipa.o: ../common/%.c): New rule. - (print-utils-ipa.o: ../common/print-utils.c): Remove. - (rsp-low-ipa.o: ../common/rsp-low.c): Remove. - (errors-ipa.o: ../common/errors.c): Remove. - (format-ipa.o: ../common/format.c): Remove. - (common-utils-ipa.o: ../common/common-utils.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in (%-ipa.o: %.c): New rule. - (tracepoint-ipa.o: tracepoint.c): Remove. - (utils-ipa.o: utils.c): Remove. - (remote-utils-ipa.o: remote-utils.c): Remove. - (regcache-ipa.o: regcache.c): Remove. - (i386-linux-ipa.o: i386-linux.c): Remove. - (i386-mmx-linux-ipa.o: i386-mmx-linux.c): Remove. - (i386-avx-linux-ipa.o: i386-avx-linux.c): Remove. - (i386-mpx-linux-ipa.o: i386-mpx-linux.c): Remove. - (i386-avx-mpx-linux-ipa.o: i386-avx-mpx-linux.c): Remove. - (i386-avx-avx512-linux-ipa.o: i386-avx-avx512-linux.c): Remove. - (i386-avx-mpx-avx512-pku-linux-ipa.o: i386-avx-mpx-avx512-pku-linux.c): Remove. - (amd64-linux-ipa.o: amd64-linux.c): Remove. - (amd64-avx-linux-ipa.o: amd64-avx-linux.c): Remove. - (amd64-mpx-linux-ipa.o: amd64-mpx-linux.c): Remove. - (amd64-avx-mpx-linux-ipa.o: amd64-avx-mpx-linux.c): Remove. - (amd64-avx-avx512-linux-ipa.o: amd64-avx-avx512-linux.c): Remove. - (amd64-avx-mpx-avx512-pku-linux-ipa.o: amd64-avx-mpx-avx512-pku-linux.c): Remove. - (aarch64-ipa.o: aarch64.c): Remove. - (s390-linux32-ipa.o: s390-linux32.c): Remove. - (s390-linux32v1-ipa.o: s390-linux32v1.c): Remove. - (s390-linux32v2-ipa.o: s390-linux32v2.c): Remove. - (s390-linux64-ipa.o: s390-linux64.c): Remove. - (s390-linux64v1-ipa.o: s390-linux64v1.c): Remove. - (s390-linux64v2-ipa.o: s390-linux64v2.c): Remove. - (s390-te-linux64-ipa.o: s390-te-linux64.c): Remove. - (s390-vx-linux64-ipa.o: s390-vx-linux64.c): Remove. - (s390-tevx-linux64-ipa.o: s390-tevx-linux64.c): Remove. - (s390x-linux64-ipa.o: s390x-linux64.c): Remove. - (s390x-linux64v1-ipa.o: s390x-linux64v1.c): Remove. - (s390x-linux64v2-ipa.o: s390x-linux64v2.c): Remove. - (s390x-te-linux64-ipa.o: s390x-te-linux64.c): Remove. - (s390x-vx-linux64-ipa.o: s390x-vx-linux64.c): Remove. - (s390x-tevx-linux64-ipa.o: s390x-tevx-linux64.c): Remove. - (powerpc-32l-ipa.o: powerpc-32l.c): Remove. - (powerpc-altivec32l-ipa.o: powerpc-altivec32l.c): Remove. - (powerpc-cell32l-ipa.o: powerpc-cell32l.c): Remove. - (powerpc-vsx32l-ipa.o: powerpc-vsx32l.c): Remove. - (powerpc-isa205-32l-ipa.o: powerpc-isa205-32l.c): Remove. - (powerpc-isa205-altivec32l-ipa.o: powerpc-isa205-altivec32l.c): Remove. - (powerpc-isa205-vsx32l-ipa.o: powerpc-isa205-vsx32l.c): Remove. - (powerpc-e500l-ipa.o: powerpc-e500l.c): Remove. - (powerpc-64l-ipa.o: powerpc-64l.c): Remove. - (powerpc-altivec64l-ipa.o: powerpc-altivec64l.c): Remove. - (powerpc-cell64l-ipa.o: powerpc-cell64l.c): Remove. - (powerpc-vsx64l-ipa.o: powerpc-vsx64l.c): Remove. - (powerpc-isa205-64l-ipa.o: powerpc-isa205-64l.c): Remove. - (powerpc-isa205-altivec64l-ipa.o: powerpc-isa205-altivec64l.c): Remove. - (powerpc-isa205-vsx64l-ipa.o: powerpc-isa205-vsx64l.c): Remove. - (tdesc-ipa.o: tdesc.c): Remove. - (x32-linux-ipa.o: x32-linux.c): Remove. - (x32-avx-linux-ipa.o: x32-avx-linux.c): Remove. - (x32-avx512-linux-ipa.o: x32-avx512-linux.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in (%.o: ../arch/%.c): New rule. - (arm.o: ../arch/arm.c): Remove. - (arm-linux.o: ../arch/arm-linux.c): Remove. - (arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c): Remove. - (aarch64-insn.o: ../arch/aarch64-insn.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in (%.o: ../nat/%.c): New rule. - (x86-dregs.o: ../nat/x86-dregs.c): Remove. - (amd64-linux-siginfo.o: ../nat/amd64-linux-siginfo.c): Remove. - (linux-btrace.o: ../nat/linux-btrace.c): Remove. - (linux-osdata.o: ../nat/linux-osdata.c): Remove. - (linux-procfs.o: ../nat/linux-procfs.c): Remove. - (linux-ptrace.o: ../nat/linux-ptrace.c): Remove. - (linux-waitpid.o: ../nat/linux-waitpid.c): Remove. - (mips-linux-watch.o: ../nat/mips-linux-watch.c): Remove. - (ppc-linux.o: ../nat/ppc-linux.c): Remove. - (linux-personality.o: ../nat/linux-personality.c): Remove. - (aarch64-linux-hw-point.o: ../nat/aarch64-linux-hw-point.c): Remove. - (aarch64-linux.o: ../nat/aarch64-linux.c): Remove. - (x86-linux.o: ../nat/x86-linux.c): Remove. - (x86-linux-dregs.o: ../nat/x86-linux-dregs.c): Remove. - (linux-namespaces.o: ../nat/linux-namespaces.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in (%.o: ../common/%.c): New rule. - (signals.o: ../common/signals.c): Remove. - (print-utils.o: ../common/print-utils.c): Remove. - (rsp-low.o: ../common/rsp-low.c): Remove. - (common-utils.o: ../common/common-utils.c): Remove. - (posix-strerror.o: ../common/posix-strerror.c): Remove. - (mingw-strerror.o: ../common/mingw-strerror.c): Remove. - (vec.o: ../common/vec.c): Remove. - (gdb_vecs.o: ../common/gdb_vecs.c): Remove. - (xml-utils.o: ../common/xml-utils.c): Remove. - (ptid.o: ../common/ptid.c): Remove. - (buffer.o: ../common/buffer.c): Remove. - (format.o: ../common/format.c): Remove. - (filestuff.o: ../common/filestuff.c): Remove. - (agent.o: ../common/agent.c): Remove. - (errors.o: ../common/errors.c): Remove. - (environ.o: ../common/environ.c): Remove. - (common-debug.o: ../common/common-debug.c): Remove. - (cleanups.o: ../common/cleanups.c): Remove. - (common-exceptions.o: ../common/common-exceptions.c): Remove. - (fileio.o: ../common/fileio.c): Remove. - (common-regcache.o: ../common/common-regcache.c): Remove. - (signals-state-save-restore.o: ../common/signals-state-save-restore.c): Remove. - (new-op.o: ../common/new-op.c): Remove. - (btrace-common.o: ../common/btrace-common.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in (%.o: ../target/%.c): New rule. - (waitstatus.o: ../target/waitstatus.c): Remove. - -2017-03-13 Simon Marchi - - * Makefile.in - (%.c: ../regformats/%.dat, - (%.c: ../regformats/arm/%.dat, - (%.c: ../regformats/i386/%.dat, - (%.c: ../regformats/rs6000/%.dat): New rules. - (aarch64.c): Remove. - (reg-arm.c): Remove. - (arm-with-iwmmxt.c): Remove. - (arm-with-vfpv2.c): Remove. - (arm-with-vfpv3.c): Remove. - (arm-with-neon.c): Remove. - (reg-bfin.c): Remove. - (reg-cris.c): Remove. - (reg-crisv32.c): Remove. - (i386.c): Remove. - (i386-linux.c): Remove. - (i386-avx.c): Remove. - (i386-avx-linux.c): Remove. - (i386-avx-avx512.c): Remove. - (i386-avx-avx512-linux.c): Remove. - (i386-mpx.c): Remove. - (i386-mpx-linux.c): Remove. - (i386-avx-mpx-avx512-pku.c): Remove. - (i386-avx-mpx-avx512-pku-linux.c): Remove. - (i386-avx-mpx.c): Remove. - (i386-avx-mpx-linux.c): Remove. - (i386-mmx.c): Remove. - (i386-mmx-linux.c): Remove. - (reg-ia64.c): Remove. - (reg-m32r.c): Remove. - (reg-m68k.c): Remove. - (reg-cf.c): Remove. - (mips-linux.c): Remove. - (mips-dsp-linux.c): Remove. - (mips64-linux.c): Remove. - (mips64-dsp-linux.c): Remove. - (nios2-linux.c): Remove. - (powerpc-32.c): Remove. - (powerpc-32l.c): Remove. - (powerpc-altivec32l.c): Remove. - (powerpc-cell32l.c): Remove. - (powerpc-vsx32l.c): Remove. - (powerpc-isa205-32l.c): Remove. - (powerpc-isa205-altivec32l.c): Remove. - (powerpc-isa205-vsx32l.c): Remove. - (powerpc-e500l.c): Remove. - (powerpc-64l.c): Remove. - (powerpc-altivec64l.c): Remove. - (powerpc-cell64l.c): Remove. - (powerpc-vsx64l.c): Remove. - (powerpc-isa205-64l.c): Remove. - (powerpc-isa205-altivec64l.c): Remove. - (powerpc-isa205-vsx64l.c): Remove. - (s390-linux32.c): Remove. - (s390-linux32v1.c): Remove. - (s390-linux32v2.c): Remove. - (s390-linux64.c): Remove. - (s390-linux64v1.c): Remove. - (s390-linux64v2.c): Remove. - (s390-te-linux64.c): Remove. - (s390-vx-linux64.c): Remove. - (s390-tevx-linux64.c): Remove. - (s390x-linux64.c): Remove. - (s390x-linux64v1.c): Remove. - (s390x-linux64v2.c): Remove. - (s390x-te-linux64.c): Remove. - (s390x-vx-linux64.c): Remove. - (s390x-tevx-linux64.c): Remove. - (tic6x-c64xp-linux.c): Remove. - (tic6x-c64x-linux.c): Remove. - (tic6x-c62x-linux.c): Remove. - (reg-sh.c): Remove. - (reg-sparc64.c): Remove. - (reg-spu.c): Remove. - (amd64.c): Remove. - (amd64-linux.c): Remove. - (amd64-avx.c): Remove. - (amd64-avx-linux.c): Remove. - (amd64-avx-avx512.c): Remove. - (amd64-avx-avx512-linux.c): Remove. - (amd64-mpx.c): Remove. - (amd64-mpx-linux.c): Remove. - (amd64-avx-mpx-avx512-pku.c): Remove. - (amd64-avx-mpx-avx512-pku-linux.c): Remove. - (amd64-avx-mpx.c): Remove. - (amd64-avx-mpx-linux.c): Remove. - (x32.c): Remove. - (x32-linux.c): Remove. - (x32-avx.c): Remove. - (x32-avx-linux.c): Remove. - (x32-avx-avx512.c): Remove. - (x32-avx-avx512-linux.c): Remove. - (reg-xtensa.c): Remove. - (reg-tilegx.c): Remove. - (reg-tilegx32.c): Remove. - -2017-03-07 Sergio Durigan Junior - - * Makefile.in (SFILES): Add "common/environ.c". - (OBJS): Add "common/environ.h". - -2017-01-27 Walfred Tedeschi - - * configure.ac: Check if the fs_base and gs_base members of - `struct user_regs_struct' exist. - * config.in: Regenerated. - * configure: Likewise. - -2017-01-09 Antoine Tremblay - - * linux-aarch32-low.c (arm_breakpoint_kind_from_pc): Use - target_read_memory. - * linux-arm-low.c (get_next_pcs_read_memory_unsigned_integer): Likewise. - (get_next_pcs_syscall_next_pc): Likewise. - -2016-12-23 Luis Machado - - * win32-i386-low.c: Fix incorrect reference to a couple source files. - * nto-x86-low.c: Likewise. - -2016-11-30 Simon Marchi - - * Makefile.in: Include disable-implicit-rules.mk. - -2016-11-23 Pedro Alves - - * debug.c: Include instead of "gdb_sys_time.h". - (debug_vprintf): Use std::chrono::steady_clock instead of - gettimeofday. Use '.' instead of ':'. - * tracepoint.c: Include instead of "gdb_sys_time.h". - (get_timestamp): Use std::chrono::steady_clock instead of - gettimeofday. - -2016-11-22 Simon Marchi - - * Makefile.in: Fix whitespace formatting. - -2016-11-22 Simon Marchi - - * Makefile.in (SFILES, OBS): Flatten list and order - alphabetically. - -2016-11-23 Pedro Alves - - * event-loop.c (handle_file_event): Use warning. - * linux-low.c (linux_resume_one_lwp_throw): Use warning. - * mem-break.c (add_breakpoint_condition, add_breakpoint_commands): - Use warning. - -2016-11-23 Pedro Alves - - * linux-low.c (check_zombie_leaders): Use debug_printf for debug - output. - * notif.c (handle_notif_ack, notif_event_enque): Likewise. - * remote-utils.c (putpkt_binary_1, readchar, getpkt): Use - debug_printf and debug_flush for debug output. - * server.c (handle_general_set): Likewise. - * thread-db.c (try_thread_db_load): Use debug_printf for debug - output. - -2016-11-17 Simon Marchi - - * Makefile.in (.c.o): Replace rule with ... - (%.o: %.c): ... this one. - -2016-11-17 Simon Marchi - - * Makefile.in: Remove @GMAKE_TRUE@ prefixes and removes lines - prefixed with @GMAKE_FALSE@. Update comment related to non-GNU - make. - * configure.ac: Remove checks for the make program. - * configure: Re-generate. - -2016-10-28 Pedro Alves - - * Makefile.in (CXX_DIALECT): Get from configure. - (COMPILE.pre, CC_LD): Append $(CXX_DIALECT). - * acinclude.m4: Include ../ax_cxx_compile_stdcxx.m4. - * configure.ac: Call AX_CXX_COMPILE_STDCXX. - * config.in: Regenerate. - * configure: Regenerate. - -2016-10-27 Yao Qi - - * linux-low.c (linux_supports_range_stepping): Return true if - can_software_single_step return true. - -2016-10-27 Yao Qi - - * inferiors.c (find_inferior_in_random): New function. - * inferiors.h (find_inferior_in_random): Declare. - * linux-low.c (linux_wait_for_event_filtered): Call - find_inferior_in_random instead of find_inferior. - -2016-10-27 Yao Qi - - * linux-low.c (linux_wait_1): If single-step breakpoints are - inserted, remove them. - -2016-10-26 Pedro Alves - - * linux-low.c (handle_extended_wait): Link parent/child fork - threads. - (linux_wait_1): Unlink them. - (linux_set_resume_request): Ignore resume requests for - already-resumed and unhandled fork child threads. - * linux-low.h (struct lwp_info) : New field. - * server.c (in_queued_stop_replies_ptid, in_queued_stop_replies): - New functions. - (handle_v_requests) : Don't call require_running. - * server.h (in_queued_stop_replies): New declaration. - -2016-10-24 Yao Qi - - PR server/20733 - * linux-aarch64-low.c (append_insns): Cast the return value to - 'uint32_t *'. - -2016-10-10 Yao Qi - - * linux-aarch32-low.c (enum arm_breakpoint_kinds): Remove. - -2016-10-06 Sergio Durigan Junior - - * target.c (target_supports_multi_process): New function, moved - from... - * target.h (target_supports_multi_process): ... here. Remove - macro. - -2016-10-05 Tom Tromey - - PR remote/20655: - * tracepoint.c (handle_tracepoint_bkpts): Check - ipa_error_tracepoint, not ipa_stopping_tracepoint. - -2016-10-05 Yao Qi - - * configure.srv: Update the path of arm-*.xml files. - -2016-10-05 Terry Guo - Yao Qi - - * Makefile.in: Adjust the path of rules. - * configure.srv: Update the path of xml files. - * regformats/arm-with-iwmmxt.dat: Regenerated. - * regformats/arm-with-neon.dat: Likewise. - * regformats/arm-with-vfpv2.dat: Likewise. - * regformats/arm-with-vfpv3.dat Likewise. - -2016-09-30 Yao Qi - - PR gdbserver/20627 - * target.c (target_stop_and_wait): Don't call - target_continue_no_signal, use resume_stop instead. - -2016-09-26 Yao Qi - - * linux-low.c (linux_wait_1): Call debug_exit. - -2016-09-23 Pedro Alves - - * Makefile.in (SFILES): Add common/new-op.c. - (OBS): Add common/new-op.o. - (new-op.o): New rule. - -2016-09-21 Simon Marchi - - * .gitinore: Ignore more files. - -2016-09-21 Yao Qi - - * linux-aarch32-low.c (arm_fill_gregset): Keep bits 20 to - 23. - -2016-09-19 Sergio Durigan Junior - - * server.c (start_inferior): Call target_mourn_inferior instead of - mourn_inferior; pass ptid_t argument to it. - (resume): Likewise. - (handle_target_event): Likewise. - * target.c (target_mourn_inferior): New function. - * target.h (mourn_inferior): Delete macro. - -2016-09-16 Andreas Arnez - - * linux-low.c (lwp_is_stepping): New function. - -2016-09-06 Carl Love - - * server.c (start_inferior): Fixed comment, requested comment change - didn't get updated correctly. Removed reference to ptrace () call as - it is only true on Linux systems. - -2016-09-06 Carl Love - - * server.c (start_inferior): Do not call - function target_post_create_inferior () if the - inferior process has already exited. - -2016-09-05 Pedro Alves - - * Makefile.in (COMPILER, COMPILER_CFLAGS): Remove. - (COMPILE.pre, CC_LD): Use CXX directly. - (INTERNAL_CFLAGS_BASE): Use CXXFLAGS directly. - * acinclude.m4: Don't include build-with-cxx.m4. - * configure.ac: Remove GDB_AC_BUILD_WITH_CXX call. - * configure: Regenerate. - -2016-09-02 Akash Trehan - - PR gdb/19495 - * remote-utils.c (relocate_instruction): Remove redundant strcpy() - call writing data to own_buf. - -2016-09-01 Sergio Durigan Junior - - * target.c (mywait): Call target_wait instead of - the_target->wait. - (target_wait): New function. - -2016-09-01 Sergio Durigan Junior - - * server.c (start_inferior): New variable 'ptid'. Replace calls - to the_target->resume by target_continue{,_no_signal}, depending - on the case. - * target.c (target_stop_and_wait): Call target_continue_no_signal - instead of the_target->resume. - (target_continue): New function. - -2016-08-31 Antoine Tremblay - - * linux-low.c (linux_wait_1): Move event switch after unsuspend_lwps. - -2016-08-25 Adhemerval Zanella - - PR server/20491 - * gdb_proc_service.h (ps_get_thread_area): Remove const from struct - ps_prochandle. - * linux-aarch64-low.c (ps_get_thread_area): Likewise. - * linux-arm-low.c (ps_get_thread_area): Likewise. - * linux-crisv32-low.c (ps_get_thread_area): Likewise. - * linux-m68k-low.c (ps_get_thread_area): Likewise. - * linux-mips-low.c (ps_get_thread_area): Likewise. - * linux-nios2-low.c (ps_get_thread_area): Likewise. - * linux-tic6x-low.c (ps_get_thread_area): Likewise. - * linux-x86-low.c (ps_get_thread_area): Likewise. - * linux-xtensa-low.c (ps_get_thread_area): Likewise. - -2016-08-19 Pedro Alves - - * linux-x86-low.c (amd64_emit_call): Emit missing call opcode. - -2016-08-19 Pedro Alves - - * linux-x86-low.c (amd64_install_fast_tracepoint_jump_pad): Fix - comment. Use memcpy instead of casting through unsigned long. - -2016-08-19 Pedro Alves - - * linux-amd64-ipa.c (alloc_jump_pad_buffer) [__ILP32__]: Try - allocating around 0x80000000. - -2016-08-19 Pedro Alves - - PR gdb/20415 - * Makefile.in (x32-linux-ipa.o, x32-avx-linux-ipa.o) - (x32-avx512-linux-ipa.o): New rules. - * configure.ac (x86_64-*-linux*): New x32 check. - * configure.srv (ipa_x32_linux_regobj): New. - (x86_64-*-linux*): Use $ipa_x32_linux_regobj if building for x32. - * linux-amd64-ipa.c (get_ipa_tdesc) [__ILP32__]: Return x32 - descriptions. - (initialize_low_tracepoint) [__ILP32__]: Initialize x32 - descriptions. - * configure: Regenerate. - -2016-08-09 Pedro Alves - - PR gdb/18653 - * Makefile.in (OBS): Add signals-state-save-restore.o. - (signals-state-save-restore.o): New rule. - * config.in: Regenerate. - * configure: Regenerate. - * linux-low.c: Include "signals-state-save-restore.h". - (linux_create_inferior): Call - restore_original_signals_state. - * server.c: Include "dispositions-save-restore.h". - (captured_main): Call save_original_signals_state. - -2016-08-05 Pedro Alves - - * configure: Regenerate. - -2016-08-04 Yao Qi - - * linux-low.c (regsets_fetch_inferior_registers): Check - errno is ESRCH or not. - -2016-08-02 Yao Qi - - * thread-db.c (struct thread_db) : Remove. - : Remove. - (thread_db_load_search): Update. - (try_thread_db_load_1): Don't look for td_ta_event_addr, - td_ta_set_event and td_ta_event_getmsg. - -2016-07-26 Pedro Alves - - PR server/20414 - * linux-x86-low.c (x86_get_pc, x86_set_pc): Use uint64_t instead - of unsigned long for 64-bit registers and use uint32_t instead of - unsigned int for 32-bit registers. - -2016-07-26 Pedro Alves - - * linux-x86-low.c (x86_siginfo_fixup): Rename 'native' parameter - to 'ptrace'. - -2016-07-21 Tom Tromey - - * configure: Rebuild. - -2016-07-21 Yao Qi - - * mem-break.c (find_gdb_breakpoint): Cast bp to - 'struct gdb_breakpoint *' rather than 'gdb_breakpoint *'. - -2016-07-21 Yao Qi - - * server.c (handle_v_requests): Support s and S actions - if target_supports_software_single_step return true. - -2016-07-21 Yao Qi - - * linux-low.c (resume_stopped_resumed_lwps): If resume request - is resume_step, call maybe_hw_step. - (linux_wait_1): Stop all threads, remove reinsert breakpoints, - and unstop them. - (linux_resume_one_lwp_throw): Don't assert the thread has reinsert - breakpoints or not. - (proceed_one_lwp): If resume request is resume_step, install - reinsert breakpoints and call maybe_hw_step. - -2016-07-21 Yao Qi - - * linux-low.c (proceed_one_lwp): Declare. - (linux_resume_one_thread): Remove local variable 'step'. - Lift code enqueue signal. Call proceed_one_lwp instead of - linux_resume_one_lwp. - -2016-07-21 Yao Qi - - * linux-low.c (linux_resume_one_thread): Call - enqueue_pending_signal. - -2016-07-21 Yao Qi - - * gdbthread.h (make_cleanup_restore_current_thread): Declare. - * inferiors.c (do_restore_current_thread_cleanup): New function. - (make_cleanup_restore_current_thread): Likewise. - * linux-low.c (install_software_single_step_breakpoints): Call - make_cleanup_restore_current_thread. Switch current_thread to - thread. - -2016-07-21 Yao Qi - - * mem-break.c (struct reinsert_breakpoint) : New field. - (set_reinsert_breakpoint): New parameter ptid. Callers updated. - (clone_one_breakpoint): Likewise. - (delete_reinsert_breakpoints): Change parameter to thread. - Callers updated. - (has_reinsert_breakpoints): Likewise. - (uninsert_reinsert_breakpoints): Likewise. - (reinsert_reinsert_breakpoints): Likewise. - * mem-break.h (set_reinsert_breakpoint): Update declaration. - (delete_reinsert_breakpoints): Likewise. - (reinsert_reinsert_breakpoints): Likewise. - (uninsert_reinsert_breakpoints): Likewise. - (has_reinsert_breakpoints): Likewise. - -2016-07-21 Yao Qi - - * inferiors.c (get_thread_process): Make parameter const. - * inferiors.h (get_thread_process): Update declaration. - * mem-break.c (clone_all_breakpoints): Remove all parameters. - Add new parameters child_thread and parent_thread. Callers - updated. - * mem-break.h (clone_all_breakpoints): Update declaration. - -2016-07-21 Yao Qi - - * mem-break.c (struct breakpoint) : Remove. - : Remove. - (struct gdb_breakpoint): New. - (struct other_breakpoint): New. - (struct reinsert_breakpoint): New. - (is_gdb_breakpoint): New function. - (any_persistent_commands): Update command_list if - is_gdb_breakpoint returns true. - (set_breakpoint): Create breakpoints according to their types. - (find_gdb_breakpoint): Return 'struct gdb_breakpoint *'. - (set_gdb_breakpoint_1): Likewise. - (set_gdb_breakpoint): Likewise. - (clear_breakpoint_conditions): Change parameter type to - 'struct gdb_breakpoint *'. - (clear_breakpoint_commands): Likewise. - (clear_breakpoint_conditions_and_commands): Likewise. - (add_condition_to_breakpoint): Likewise. - (add_breakpoint_condition): Likewise. - (add_commands_to_breakpoint): Likewise. - (check_breakpoints): Check other_breakpoint. - (clone_one_breakpoint): Clone breakpopint according to its type. - * mem-break.h (struct gdb_breakpoint): Declare. - (set_gdb_breakpoint): Update declaration. - (clear_breakpoint_conditions_and_commands): Likewise. - (add_breakpoint_condition): Likewise. - (add_breakpoint_commands): Likewise. - * server.c (process_point_options): Change parameter type to - 'struct gdb_breakpoint *'. - -2016-07-21 Yao Qi - - * mem-break.c (set_breakpoint_at): Rename it to ... - (set_breakpoint_type_at): ... it. - (set_breakpoint_at): Call set_breakpoint_type_at. - (set_reinsert_breakpoint): Call set_breakpoint_type_at. - * mem-break.h (set_breakpoint_at): Update comments. - -2016-07-12 Chung-Lin Tang - - * linux-nios2-low.c (nios2_fill_gregset): Add type cast - to buf parameter. - (nios2_store_gregset): Likewise. - -2016-07-01 Pedro Alves - Antoine Tremblay - - * linux-low.c: Change interface to take the target lwp_info - pointer directly and return void. Handle detaching from a zombie - thread. - (linux_detach_lwp_callback): New function. - (linux_detach): Detach from the leader thread after detaching from - the clone threads. - -2016-06-28 Yao Qi - - * linux-aarch64-low.c (aarch64_ftrace_insn_reloc_b): Use int64_t - for variable new_offset. - (aarch64_ftrace_insn_reloc_b_cond): Likewise. - (aarch64_ftrace_insn_reloc_cb): Likewise. - (aarch64_ftrace_insn_reloc_tb): Likewise. - (aarch64_install_fast_tracepoint_jump_pad): Likewise. Use - PRIx64 instead of PRIx32. - -2016-06-28 Yao Qi - - * linux-arm-low.c (arm_get_syscall_trapinfo): New function. - (the_low_target): Install arm_get_syscall_trapinfo. - -2016-06-28 Yao Qi - - * linux-aarch64-low.c (aarch64_get_syscall_trapinfo): New - function. - (the_low_target): Install aarch64_get_syscall_trapinfo. - -2016-06-28 Yao Qi - - * linux-low.c (get_syscall_trapinfo): Remove parameter sysret. - Callers updated. - * linux-low.h (struct linux_target_ops) : - Remove parameter sysno. - * linux-x86-low.c (x86_get_syscall_trapinfo): Remove parameter - sysret. - -2016-06-21 Andreas Arnez - - * linux-s390-low.c (s390_emit_eq_goto): Mark function static. - (s390_emit_ne_goto): Likewise. - (s390_emit_lt_goto): Likewise. - (s390_emit_le_goto): Likewise. - (s390_emit_gt_goto): Likewise. - (s390_emit_ge_goto): Likewise. - (s390x_emit_eq_goto): Likewise. - (s390x_emit_ne_goto): Likewise. - (s390x_emit_lt_goto): Likewise. - (s390x_emit_le_goto): Likewise. - (s390x_emit_gt_goto): Likewise. - (s390x_emit_ge_goto): Likewise. - (s390_emit_ops_impl): Mark variable static. - (s390x_emit_ops): Likewise. - -2016-06-17 Yao Qi - - * linux-low.c (handle_extended_wait): Call - uninsert_reinsert_breakpoints for the parent process. Remove - reinsert breakpoints from the child process. Reinsert them to - the parent process when vfork is done. - * mem-break.c (uninsert_reinsert_breakpoints): New function. - (reinsert_reinsert_breakpoints): New function. - * mem-break.h (uninsert_reinsert_breakpoints): Declare - (reinsert_reinsert_breakpoints): Declare. - -2016-06-17 Yao Qi - - * linux-low.c (handle_extended_wait): If the parent is doing - step-over, remove the reinsert breakpoints from the forked child. - -2016-06-17 Yao Qi - - * linux-low.c (unsuspend_all_lwps): Declare. - (linux_low_filter_event): If thread exited, call finish_step_over. - If step-over is finished, unsuspend other threads. - -2016-06-17 Yao Qi - - * linux-low.c (linux_resume_one_lwp_throw): Assert - has_reinsert_breakpoints returns false. - * mem-break.c (delete_disabled_breakpoints): Assert - bp type isn't reinsert_breakpoint. - -2016-06-17 Yao Qi - - * linux-low.c (maybe_hw_step): New function. - (linux_resume_one_lwp_throw): Call maybe_hw_step. - (finish_step_over): Switch current_thread to lwp temporarily, - and assert has_reinsert_breakpoints returns true. - (proceed_one_lwp): Call maybe_hw_step. - * mem-break.c (has_reinsert_breakpoints): New function. - * mem-break.h (has_reinsert_breakpoints): Declare. - -2016-06-02 Jon Turney - - * win32-low.c (win32_create_inferior): Add pointer casts for C++. - -2016-05-17 Yao Qi - - * linux-low.c (linux_stabilize_threads): Call unsuspend_all_lwps - instead of find_inferior. - -2016-05-05 Yao Qi - - * linux-arm-low.c (get_next_pcs_read_memory_unsigned_integer): - Initialize res to zero. - -2016-05-05 Yao Qi - - * linux-arm-low.c (arm_sigreturn_next_pc): Change type of cpsr - to uint32_t. - -2016-05-04 Ulrich Weigand - - * spu-low.c (fetch_ppc_register): Cast PowerPC-Linux-specific value - used as first ptrace argument to PTRACE_TYPE_ARG1 for C++. - (fetch_ppc_memory_1, store_ppc_memory_1): Likewise. - -2016-04-28 Par Olsson - Simon Marchi - - * tracepoint.c (write_inferior_int8): New function. - (cmd_qtenable_disable): Write enable flag using - write_inferior_int8. - -2016-04-25 Yao Qi - - * linux-low.c (lwp_signal_can_be_delivered): Adjust. - (need_step_over_p): Return zero if the LWP has pending signals - can be delivered on software single step target. - -2016-04-25 Yao Qi - - * linux-low.c (reinsert_raw_breakpoint): If bp->inserted is true - return instead of error. - -2016-04-22 Yao Qi - - * linux-aarch32-low.c (arm_store_gregset): Clear CPSR bits 20 - to 23. - -2016-04-22 Yao Qi - - * linux-low.c (lwp_signal_can_be_delivered): Don't deliver - signal when stepping over breakpoint with software single - step. - -2016-04-21 Pedro Alves - - * linux-s390-low.c (s390_collect_ptrace_register) - (s390_supply_ptrace_register, s390_get_hwcap): Use gdb_byte * and - add casts. - (s390_check_regset): Use void * instead of gdb_byte *. - -2016-04-20 Pedro Alves - - * configure: Renegerate. - -2016-04-20 Yao Qi - - * linux-aarch32-low.c: Include "arch/arm-linux.h". - (arm_fill_gregset): Use ARM_CPSR_GREGNUM rather than magic - number 16. - (arm_store_gregset): Likewise. - -2016-04-16 Walfred Tedeschi - - * Makefile.in (clean): Add removal for i386-avx-mpx.c, - i386-avx-mpx-linux.c, amd64-avx-mpx.c and amd64-avx-mpx-linux.c. - (i386-avx-mpx.c, i386-avx-mpx-linux.c, amd64-avx-mpx.c) - (amd64-avx-mpx-linux.c): New rules. - (amd64-avx-mpx-linux-ipa.o, i386-avx-mpx-linux-ipa.o): New rule. - * configure.srv (srv_i386_regobj): Add i386-avx-mpx.o. - (srv_i386_linux_regobj): Add i386-avx-mpx-linux.o. - (srv_amd64_regobj): Add amd64-avx-mpx.o. - (srv_amd64_linux_regobj): Add amd64-avx-mpx-linux.o. - (srv_i386_xmlfiles): Add i386/i386-avx-mpx.xml. - (srv_amd64_xmlfiles): Add i386/amd64-avx-mpx.xml. - (srv_i386_linux_xmlfiles): Add i386/i386-avx-mpx-linux.xml. - (srv_amd64_linux_xmlfiles): Add i386/amd64-avx-mpx-linux.xml. - (ipa_i386_linux_regobj): Add i386-avx-mpx-linux-ipa.o. - (ipa_amd64_linux_regobj): Add amd64-avx-mpx-linux-ipa.o. - * linux-x86-low.c (x86_linux_read_description): Add case for - X86_XSTATE_AVX_MPX_MASK. - (x86_get_ipa_tdesc_idx): Add cases for avx_mpx. - (initialize_low_arch): Call init_registers_amd64_avx_mpx_linux and - init_registers_i386_avx_mpx_linux. - * linux-i386-ipa.c (get_ipa_tdesc): Add case for avx_mpx. - (initialize_low_tracepoint): Call - init_registers_i386_avx_mpx_linux. - * linux-amd64-ipa.c (get_ipa_tdesc): Add case for avx_mpx. - (initialize_low_tracepoint): Call - init_registers_amd64_avx_mpx_linux. - * linux-x86-tdesc.h (X86_TDESC_AVX_MPX): New enum value. - (init_registers_amd64_avx_mpx_linux, tdesc_amd64_avx_mpx_linux) - (init_registers_i386_avx_mpx_linux, tdesc_i386_avx_mpx_linux): New - declarations. - -2016-04-18 Pedro Alves - - * configure: Regenerate. - -2016-04-13 Antoine Tremblay - - * linux-aarch64-low.c (aarch64_emit_add): Switch x1 and x0. - (aarch64_emit_sub): Likewise. - -2016-04-12 Pedro Alves - - * utils.c (prepare_to_throw_exception): Delete. - -2016-04-05 Simon Marchi - - * Makefile.in ($(IPA_LIB)): Set SONAME of the IPA lib. - -2016-04-05 Marcin Kościelnicki - - * tracepoint.c (getauxval): Move to #ifdef IN_PROCESS_AGENT. - -2016-04-03 Marcin Kościelnicki - - * linux-aarch64-ipa.c: Add include. - * linux-ppc-ipa.c: Add include. - * linux-s390-ipa.c: Add include. - -2016-03-31 Marcin Kościelnicki - - * tracepoint.c (gdb_collect_ptr): Remove const qualifier. - (get_raw_reg_ptr): Likewise. - (get_trace_state_variable_value_ptr): Likewise. - (set_trace_state_variable_value_ptr): Likewise. - (initialize_tracepoint): Cast alloc_jump_pad_buffer result to - char *. - -2016-03-31 Wei-cheng Wang - Marcin Kościelnicki - - PR/17221 - * linux-ppc-low.c (emit_insns): New function. - (__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros. - (ppc_emit_prologue): New function. - (ppc_emit_epilogue): New function. - (ppc_emit_add): New function. - (ppc_emit_sub): New function. - (ppc_emit_mul): New function. - (ppc_emit_lsh): New function. - (ppc_emit_rsh_signed): New function. - (ppc_emit_rsh_unsigned): New function. - (ppc_emit_ext): New function. - (ppc_emit_zero_ext): New function. - (ppc_emit_log_not): New function. - (ppc_emit_bit_and): New function. - (ppc_emit_bit_or): New function. - (ppc_emit_bit_xor): New function. - (ppc_emit_bit_not): New function. - (ppc_emit_equal): New function. - (ppc_emit_less_signed): New function. - (ppc_emit_less_unsigned): New function. - (ppc_emit_ref): New function. - (ppc_emit_const): New function. - (ppc_emit_reg): New function. - (ppc_emit_pop): New function. - (ppc_emit_stack_flush): New function. - (ppc_emit_swap): New function. - (ppc_emit_stack_adjust): New function. - (ppc_emit_call): New function. - (ppc_emit_int_call_1): New function. - (ppc_emit_void_call_2): New function. - (ppc_emit_if_goto): New function. - (ppc_emit_goto): New function. - (ppc_emit_eq_goto): New function. - (ppc_emit_ne_goto): New function. - (ppc_emit_lt_goto): New function. - (ppc_emit_le_goto): New function. - (ppc_emit_gt_goto): New function. - (ppc_emit_ge_goto): New function. - (ppc_write_goto_address): New function. - (ppc_emit_ops_impl): New static variable. - (ppc64v1_emit_prologue): New function. - (ppc64v2_emit_prologue): New function. - (ppc64_emit_epilogue): New function. - (ppc64_emit_add): New function. - (ppc64_emit_sub): New function. - (ppc64_emit_mul): New function. - (ppc64_emit_lsh): New function. - (ppc64_emit_rsh_signed): New function. - (ppc64_emit_rsh_unsigned): New function. - (ppc64_emit_ext): New function. - (ppc64_emit_zero_ext): New function. - (ppc64_emit_log_not): New function. - (ppc64_emit_bit_and): New function. - (ppc64_emit_bit_or): New function. - (ppc64_emit_bit_xor): New function. - (ppc64_emit_bit_not): New function. - (ppc64_emit_equal): New function. - (ppc64_emit_less_signed): New function. - (ppc64_emit_less_unsigned): New function. - (ppc64_emit_ref): New function. - (ppc64_emit_const): New function. - (ppc64v1_emit_reg): New function. - (ppc64v2_emit_reg): New function. - (ppc64_emit_pop): New function. - (ppc64_emit_stack_flush): New function. - (ppc64_emit_swap): New function. - (ppc64v1_emit_call): New function. - (ppc64v2_emit_call): New function. - (ppc64v1_emit_int_call_1): New function. - (ppc64v2_emit_int_call_1): New function. - (ppc64v1_emit_void_call_2): New function. - (ppc64v2_emit_void_call_2): New function. - (ppc64_emit_if_goto): New function. - (ppc64_emit_eq_goto): New function. - (ppc64_emit_ne_goto): New function. - (ppc64_emit_lt_goto): New function. - (ppc64_emit_le_goto): New function. - (ppc64_emit_gt_goto): New function. - (ppc64_emit_ge_goto): New function. - (ppc64v1_emit_ops_impl): New static variable. - (ppc64v2_emit_ops_impl): New static variable. - (ppc_emit_ops): New function. - (linux_low_target): Wire in ppc_emit_ops. - -2016-03-31 Wei-cheng Wang - Marcin Kościelnicki - - PR/17221 - * Makefile.in: Add powerpc-*-ipa.o - * configure.srv: Add ipa_obj for powerpc*-linux. - * linux-ppc-ipa.c: New file. - * linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h, tracepoint.h - includes. - (PPC_FIELD): New macro. - (PPC_SEXT): New macro. - (PPC_OP6): New macro. - (PPC_BO): New macro. - (PPC_LI): New macro. - (PPC_BD): New macro. - (init_registers_*): Move prototype to linux-ppc-tdesc.h. - (tdesc_*): Move declaration to linux-ppc-tdesc.h. - (ppc_get_hwcap): Rename to ppc_get_auxv and add type parameter. - (ppc_get_thread_area): New function. - (is_elfv2_inferior): New function. - (gen_ds_form): New function. - (GEN_STD): New macro. - (GEN_STDU): New macro. - (GEN_LD): New macro. - (GEN_LDU): New macro. - (gen_d_form): New function. - (GEN_ADDI): New macro. - (GEN_ADDIS): New macro. - (GEN_LI): New macro. - (GEN_LIS): New macro. - (GEN_ORI): New macro. - (GEN_ORIS): New macro. - (GEN_LWZ): New macro. - (GEN_STW): New macro. - (GEN_STWU): New macro. - (gen_xfx_form): New function. - (GEN_MFSPR): New macro. - (GEN_MTSPR): New macro. - (GEN_MFCR): New macro. - (GEN_MTCR): New macro. - (GEN_SYNC): New macro. - (GEN_LWSYNC): New macro. - (gen_x_form): New function. - (GEN_OR): New macro. - (GEN_MR): New macro. - (GEN_LWARX): New macro. - (GEN_STWCX): New macro. - (GEN_CMPW): New macro. - (gen_md_form): New function. - (GEN_RLDICL): New macro. - (GEN_RLDICR): New macro. - (gen_i_form): New function. - (GEN_B): New macro. - (GEN_BL): New macro. - (gen_b_form): New function. - (GEN_BNE): New macro. - (GEN_LOAD): New macro. - (GEN_STORE): New macro. - (gen_limm): New function. - (gen_atomic_xchg): New function. - (gen_call): New function. - (ppc_relocate_instruction): New function. - (ppc_install_fast_tracepoint_jump_pad): New function. - (ppc_get_min_fast_tracepoint_insn_len): New function. - (ppc_get_ipa_tdesc_idx): New function. - (the_low_target): Wire in the new functions. - (initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit - tdescs. - * linux-ppc-tdesc.h: New file. - -2016-03-31 Marcin Kościelnicki - - * linux-aarch64-ipa.c: Add and includes. - (alloc_jump_pad_buffer): New function. - * linux-amd64-ipa.c: Add include. - (alloc_jump_pad_buffer): New function. - * linux-i386-ipa.c (alloc_jump_pad_buffer): New function. - * linux-s390-ipa.c: Add and includes. - (alloc_jump_pad_buffer): New function. - * tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function. - (initialize_tracepoint): Delegate to alloc_jump_pad_buffer. - * tracepoint.h (alloc_jump_pad_buffer): New prototype. - (getauxval) [!HAVE_GETAUXVAL]: New prototype. - -2016-03-30 Marcin Kościelnicki - - * linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg. - * linux-amd64-ipa.c: Likewise. - * linux-i386-ipa.c: Likewise. - * linux-s390-ipa.c: Likewise. - * tracepoint.c: IPA-export gdb_collect_ptr instead of gdb_collect, - ditto for get_raw_reg_ptr, get_trace_state_variable_value_ptr, - set_trace_state_variable_value_ptr. - (struct ipa_sym_addresses): Likewise. - (symbol_list): Likewise. - (install_fast_tracepoint): Dereference gdb_collect_ptr instead of - accessing gdb_collect directly. - (gdb_collect_ptr_type): New typedef. - (get_raw_reg_ptr_type): New typedef. - (get_trace_state_variable_value_ptr_type): New typedef. - (set_trace_state_variable_value_ptr_type): New typedef. - (gdb_collect_ptr): New global. - (get_raw_reg_ptr): New global. - (get_trace_state_variable_value_ptr): New global. - (set_trace_state_variable_value_ptr): New global. - (get_raw_reg_func_addr): Dereference get_raw_reg_ptr instead of - accessing get_raw_reg directly. - (get_get_tsv_func_addr): Likewise for - get_trace_state_variable_value_ptr. - (get_set_tsv_func_addr): Likewise for - set_trace_state_variable_value_ptr. - * tracepoint.h: Rename gdb_agent_get_raw_reg to get_raw_reg. - -2016-03-30 Simon Marchi - - * tracepoint.c (cmd_qtenable_disable): Remove whitespace. - -2016-03-30 Marcin Kościelnicki - - * remote-utils.c (look_up_one_symbol): Remove own_buf, handle 'v' - packets. - (relocate_instruction): Remove own_buf. - * server.c (own_buf): Make global. - (handle_v_requests): Make global. - * server.h (own_buf): New declaration. - (handle_v_requests): New prototype. - -2016-03-29 Marcin Kościelnicki - - PR 18377 - * linux-s390-low.c (add_insns): New function. - (s390_emit_prologue): New function. - (s390_emit_epilogue): New function. - (s390_emit_add): New function. - (s390_emit_sub): New function. - (s390_emit_mul): New function. - (s390_emit_lsh): New function. - (s390_emit_rsh_signed): New function. - (s390_emit_rsh_unsigned): New function. - (s390_emit_ext): New function. - (s390_emit_log_not): New function. - (s390_emit_bit_and): New function. - (s390_emit_bit_or): New function. - (s390_emit_bit_xor): New function. - (s390_emit_bit_not): New function. - (s390_emit_equal): New function. - (s390_emit_less_signed): New function. - (s390_emit_less_unsigned): New function. - (s390_emit_ref): New function. - (s390_emit_if_goto): New function. - (s390_emit_goto): New function. - (s390_write_goto_address): New function. - (s390_emit_litpool): New function. - (s390_emit_const): New function. - (s390_emit_call): New function. - (s390_emit_reg): New function. - (s390_emit_pop): New function. - (s390_emit_stack_flush): New function. - (s390_emit_zero_ext): New function. - (s390_emit_swap): New function. - (s390_emit_stack_adjust): New function. - (s390_emit_set_r2): New function. - (s390_emit_int_call_1): New function. - (s390_emit_void_call_2): New function. - (s390_emit_eq_goto): New function. - (s390_emit_ne_goto): New function. - (s390_emit_lt_goto): New function. - (s390_emit_le_goto): New function. - (s390_emit_gt_goto): New function. - (s390_emit_ge_goto): New function. - (s390x_emit_prologue): New function. - (s390x_emit_epilogue): New function. - (s390x_emit_add): New function. - (s390x_emit_sub): New function. - (s390x_emit_mul): New function. - (s390x_emit_lsh): New function. - (s390x_emit_rsh_signed): New function. - (s390x_emit_rsh_unsigned): New function. - (s390x_emit_ext): New function. - (s390x_emit_log_not): New function. - (s390x_emit_bit_and): New function. - (s390x_emit_bit_or): New function. - (s390x_emit_bit_xor): New function. - (s390x_emit_bit_not): New function. - (s390x_emit_equal): New function. - (s390x_emit_less_signed): New function. - (s390x_emit_less_unsigned): New function. - (s390x_emit_ref): New function. - (s390x_emit_if_goto): New function. - (s390x_emit_const): New function. - (s390x_emit_call): New function. - (s390x_emit_reg): New function. - (s390x_emit_pop): New function. - (s390x_emit_stack_flush): New function. - (s390x_emit_zero_ext): New function. - (s390x_emit_swap): New function. - (s390x_emit_stack_adjust): New function. - (s390x_emit_int_call_1): New function. - (s390x_emit_void_call_2): New function. - (s390x_emit_eq_goto): New function. - (s390x_emit_ne_goto): New function. - (s390x_emit_lt_goto): New function. - (s390x_emit_le_goto): New function. - (s390x_emit_gt_goto): New function. - (s390x_emit_ge_goto): New function. - (s390_emit_ops): New function. - (struct linux_target_ops): Fill in emit_ops hook. - -2016-03-29 Marcin Kościelnicki - - PR 18377 - * Makefile.in: Add s390 IPA files. - * configure.srv: Build IPA for s390. - * linux-s390-ipa.c: New file. - * linux-s390-low.c: New includes - inttypes.h and linux-s390-tdesc.h. - (init_registers_s390_linux32): Move declaration to linux-s390-tdesc.h. - (tdesc_s390_linux32): Likewise. - (init_registers_s390_linux32v1): Likewise. - (tdesc_s390_linux32v1): Likewise. - (init_registers_s390_linux32v2): Likewise. - (tdesc_s390_linux32v2): Likewise. - (init_registers_s390_linux64): Likewise. - (tdesc_s390_linux64): Likewise. - (init_registers_s390_linux64v1): Likewise. - (tdesc_s390_linux64v1): Likewise. - (init_registers_s390_linux64v2): Likewise. - (tdesc_s390_linux64v2): Likewise. - (init_registers_s390_te_linux64): Likewise. - (tdesc_s390_te_linux64): Likewise. - (init_registers_s390_vx_linux64): Likewise. - (tdesc_s390_vx_linux64): Likewise. - (init_registers_s390_tevx_linux64): Likewise. - (tdesc_s390_tevx_linux64): Likewise. - (init_registers_s390x_linux64): Likewise. - (tdesc_s390x_linux64): Likewise. - (init_registers_s390x_linux64v1): Likewise. - (tdesc_s390x_linux64v1): Likewise. - (init_registers_s390x_linux64v2): Likewise. - (tdesc_s390x_linux64v2): Likewise. - (init_registers_s390x_te_linux64): Likewise. - (tdesc_s390x_te_linux64): Likewise. - (init_registers_s390x_vx_linux64): Likewise. - (tdesc_s390x_vx_linux64): Likewise. - (init_registers_s390x_tevx_linux64): Likewise. - (tdesc_s390x_tevx_linux64): Likewise. - (have_hwcap_s390_vx): New static variable. - (s390_arch_setup): Fill have_hwcap_s390_vx. - (s390_get_thread_area): New function. - (s390_ft_entry_gpr_esa): New const. - (s390_ft_entry_gpr_zarch): New const. - (s390_ft_entry_misc): New const. - (s390_ft_entry_fr): New const. - (s390_ft_entry_vr): New const. - (s390_ft_main_31): New const. - (s390_ft_main_64): New const. - (s390_ft_exit_fr): New const. - (s390_ft_exit_vr): New const. - (s390_ft_exit_misc): New const. - (s390_ft_exit_gpr_esa): New const. - (s390_ft_exit_gpr_zarch): New const. - (append_insns): New function. - (s390_relocate_instruction): New function. - (s390_install_fast_tracepoint_jump_pad): New function. - (s390_get_min_fast_tracepoint_insn_len): New function. - (s390_get_ipa_tdesc_idx): New function. - (struct linux_target_ops): Wire in the above functions. - (initialize_low_arch) [!__s390x__]: Don't initialize s390x tdescs. - * linux-s390-tdesc.h: New file. - -2016-03-29 Marcin Kościelnicki - - * linux-s390-low.c (s390_supports_tracepoints): New function. - (struct linux_target_ops): Fill supports_tracepoints hook. - -2016-03-18 Yao Qi - - * linux-low.c (lwp_signal_can_be_delivered): New function. - (linux_resume_one_lwp_throw): Use lwp_signal_can_be_delivered. - -2016-03-18 Yao Qi - - * linux-low.c (linux_resume_one_lwp_throw): Set 'signal' to - 0 if signal is enqueued. Remove 'signal' from one debugging - message. Move one debugging message to some lines below. - Remove code setting 'signal' to 0. - -2016-03-18 Yao Qi - - * linux-low.c (linux_low_filter_event): Remove redundant - WIFSTOPPED check together with linux_wstatus_maybe_breakpoint. - -2016-03-09 Marcin Kościelnicki - - * linux-ppc-low.c (ppc_supports_tracepoints): New function. - (struct linux_target_ops): Wire in the above. - -2016-03-03 Yao Qi - - * linux-low.c: Update comments to start_step_over. - -2016-03-03 Yao Qi - - PR server/19736 - * linux-low.c (handle_extended_wait): Set child suspended - if event_lwp->bp_reinsert isn't zero. - -2016-03-02 Yao Qi - - * linux-low.c (linux_resume_one_lwp_throw): Replace code with - enqueue_pending_signal. - -2016-03-02 Marcin Kościelnicki - - * tracepoint.c (cmd_qtstart): Only set ipa_tdesc_idx if agent - is actually loaded. - -2016-02-25 Marcin Kościelnicki - - * linux-s390-low.c (s390_num_regs_3264): Define on 31-bit too. - (s390_regmap_3264) [!__s390x__]: New global. - (s390_collect_ptrace_register): Skip map entries containing -1. - (s390_supply_ptrace_register): Ditto. - (s390_fill_gprs_high): New function. - (s390_store_gprs_high): New function. - (s390_regsets): Add NT_S390_HIGH_GPRS. - (s390_get_hwcap): Enable on 31-bit. - (have_hwcap_s390_high_gprs): Enable on 31-bit. - (s390_arch_setup): Enable detection of high GPRs, TDB, VX on 31-bit. - Detect NT_S390_HIGH_GPRS. - (s390_usrregs_info_3264): Enable on 31-bit. - (s390_regs_info): Enable regs_info_3264 on 31-bit. - (initialize_low_arch): Initialize s390_regsets_info_3264 on 31-bit. - -2016-02-25 Marcin Kościelnicki - - PR gdb/13808 - * Makefile.in: Add i386-*-linux-ipa.o and amd64-*-linux-ipa.o. - * configure.srv: Ditto. - * linux-aarch64-ipa.c (get_ipa_tdesc): New function. - (initialize_low_tracepoint): Remove ipa_tdesc assignment. - * linux-amd64-ipa.c: Add "linux-x86-tdesc.h" include. - (init_registers_amd64_linux): Remove prototype. - (tdesc_amd64_linux): Remove declaration. - (get_ipa_tdesc): New function. - (initialize_low_tracepoint): Remove ipa_tdesc assignment, - initialize remaining tdescs. - * linux-i386-ipa.c: Add "linux-x86-tdesc.h" include. - (init_registers_i386_linux): Remove prototype. - (tdesc_i386_linux): Remove declaration. - (get_ipa_tdesc): New function. - (initialize_low_tracepoint): Remove ipa_tdesc assignment, - initialize remaining tdescs. - * linux-low.c (linux_get_ipa_tdesc_idx): New function. - (linux_target_ops): wire in linux_get_ipa_tdesc_idx. - * linux-low.h (struct linux_target_ops): Add get_ipa_tdesc_idx. - * linux-x86-low.c: Move tdesc declarations to linux-x86-tdesc.h. - (x86_get_ipa_tdesc_idx): New function. - (the_low_target): Wire in x86_get_ipa_tdesc_idx. - * linux-x86-tdesc.h: New file. - * target.h (struct target_ops): Add get_ipa_tdesc_idx. - (target_get_ipa_tdesc_idx): New macro. - * tracepoint.c (ipa_tdesc_idx): New macro. - (struct ipa_sym_addresses): Add addr_ipa_tdesc_idx. - (symbol_list): Add ipa_tdesc_idx. - (cmd_qtstart): Write ipa_tdesc_idx in the target. - (ipa_tdesc): Remove. - (ipa_tdesc_idx): New variable. - (get_context_regcache): Use get_ipa_tdesc. - (gdb_collect): Ditto. - (gdb_probe): Ditto. - * tracepoint.h (get_ipa_tdesc): New prototype. - (ipa_tdesc): Remove. - -2016-02-24 Pedro Alves - - * linux-low.c (check_stopped_by_breakpoint): Rename to ... - (save_stop_reason): ... this. Use GDB_ARCH_IS_TRAP_HWBKPT and - handle ambiguous GDB_ARCH_IS_TRAP_BRKPT / GDB_ARCH_IS_TRAP_HWBKPT. - Factor out common code between the USE_SIGTRAP_SIGINFO and - !USE_SIGTRAP_SIGINFO blocks. - (linux_low_filter_event): Call save_stop_reason instead of - check_stopped_by_breakpoint and check_stopped_by_watchpoint. - Update comments. - (linux_wait_1): Update comments. - -2016-02-24 Wei-cheng Wang - - * linux-ppc-low.c (ppc_supports_z_point_type): New function: - (ppc_insert_point, ppc_remove_point): Insert/remove z-packet breakpoints. - (ppc64_emit_ops_vector): Add target ops - ppc_supports_z_point_type, - ppc_insert_point, ppc_remove_point. - -2016-02-17 Marcin Kościelnicki - - * linux-s390-low.c (s390_supports_z_point_type): New function. - (struct linux_target_ops): Wire s390_supports_z_point_type in. - -2016-02-16 Yao Qi - - * linux-arm-low.c (get_next_pcs_syscall_next_pc): Remove argument - PC. Get pc from regcache_read_pc. - -2016-02-12 Yao Qi - - * linux-aarch64-low.c (aarch64_get_pc): Call linux_get_pc_64bit - or linux_get_pc_32bit. - (aarch64_set_pc): Call linux_set_pc_64bit or linux_set_pc_32bit. - -2016-02-12 Yao Qi - - * linux-arm-low.c (get_next_pcs_ops): Initialize it with - arm_linux_get_next_pcs_fixup. - -2016-02-12 Marcin Kościelnicki - - * tracepoint.c (x_tracepoint_action_download): Change - write_inferior_data_ptr to write_inferior_data_pointer. - (cmd_qtstart): Likewise. - (write_inferior_data_ptr): Remove. - (download_agent_expr): Change write_inferior_data_ptr to - write_inferior_data_pointer. - (download_tracepoint_1): Likewise. - (download_tracepoint): Likewise. - (download_trace_state_variables): Likewise. - -2016-02-11 Wei-cheng Wang - Marcin Kościelnicki - - * tracepoint.c (struct tracepoint_action_ops): Remove. - (struct tracepoint_action): Remove ops. - (m_tracepoint_action_download, r_tracepoint_action_download) - (x_tracepoint_action_download, l_tracepoint_action_download): Adjust - size and offset accordingly. - (m_tracepoint_action_ops, r_tracepoint_action_ops) - (x_tracepoint_action_ops, l_tracepoint_action_ops): Remove. - (tracepoint_action_send, tracepoint_action_download): New functions. - Helpers for trace action handlers. - (add_tracepoint_action): Remove setup actions ops. - (download_tracepoint_1, tracepoint_send_agent): Call helper functions. - -2016-02-10 Yao Qi - - * regcache.c (regcache_raw_read_unsigned): Clear *VAL. - -2016-02-09 Simon Marchi - - * configure.ac: Use AC_CONFIG_FILES instead of passing arguments - to AC_OUTPUT. - * configure: Regenerate. - -2016-02-09 Simon Marchi - - * linux-aarch64-low.c (aarch64_linux_siginfo_fixup): Change - void * to gdb_byte *. - * linux-low.c (siginfo_fixup): Likewise. - (linux_xfer_siginfo): Likewise. - * linux-low.h (struct linux_target_ops) : - Likewise. - * linux-x86-low.c (x86_siginfo_fixup): Likewise. - -2016-02-02 Walfred Tedeschi - - * configure.srv (x86_64-*-linux*): Add amd64-linux-siginfo.o - to srv_tgtobj. - (i[34567]86-*-linux*): Add amd64-linux-siginfo.o - to srv_tgtobj. - * linux-x86-low.c [__x86_64__]: Include - "nat/amd64-linux-siginfo.h". - (compat_siginfo_from_siginfo, siginfo_from_compat_siginfo) - (compat_x32_siginfo_from_siginfo, siginfo_from_compat_x32_siginfo) - (compat_timeval, compat_sigval, compat_x32_clock, cpt_si_pid) - (cpt_si_uid, cpt_si_timerid, cpt_si_overrun, cpt_si_status) - (cpt_si_utime, cpt_si_stime, cpt_si_ptr, cpt_si_addr, cpt_si_band) - (cpt_si_fd, si_timerid, si_overrun): Move from - nat/amd64-linux-siginfo.c. - * Makefile.in (amd64-linux-siginfo.o:): New rule. - -2016-01-28 Simon Marchi - - * server.c (skip_to_semicolon): Remove. - (process_point_options): Use strchrnul instead of - skip_to_semicolon. - -2016-01-26 Yao Qi - - * linux-arm-low.c (arm_gdbserver_get_next_pcs): Remove argument pc. - * linux-low.c (install_software_single_step_breakpoints): Don't - call regcache_read_pc. - * linux-low.h (struct linux_target_ops) : Remove - argument pc. - -2016-01-26 Yao Qi - - * linux-low.c (install_software_single_step_breakpoints): Call - regcache_read_pc instead of get_pc. - -2016-01-26 Yao Qi - - * remote-utils.c (remote_close) [!USE_WIN32API]: Ignore SIGIO. - (unblock_async_io): Rename to ... - (block_unblock_async_io): ... it. New function. - (enable_async_io): Don't install SIGIO handler. Unblock it - instead. - (disable_async_io): Don't ignore SIGIO. Block it instead. - (initialize_async_io): Install SIGIO handler. Don't call - unblock_async_io. - -2016-01-26 Yao Qi - - * remote-utils.c (getpkt): If the buffer isn't empty, and the - first character is '\003', call *the_target->request_interrupt. - -2016-01-25 Yao Qi - - * remote-utils.c (new_thread_notify): Remove. - (dead_thread_notify): Likewise. - * remote-utils.h (new_thread_notify): Remove declaration. - (dead_thread_notify): Likewise. - -2016-01-23 Marcin Kościelnicki - - * gdb.trace/pending.exp: Fix expected message on continue. - -2016-01-22 Marcin Kościelnicki - - * tracepoint.c (write_inferior_data_ptr): Cast to uintptr_t, so that - it works properly on big-endian machines where sizeof (CORE_ADDR) - != sizeof (void *). - -2016-01-21 Pedro Alves - - * Makefile.in (COMPILER_CFLAGS, CXXFLAGS): New. - (INTERNAL_CFLAGS_BASE): Use COMPILER_CFLAGS instead of CFLAGS. - * configure: Regenerate. - -2016-01-21 Yao Qi - - * linux-arm-low.c (arm_sigreturn_next_pc): Add parameter - is_thumb and set it according to CPSR saved on the stack. - (get_next_pcs_syscall_next_pc): Pass is_thumb to - arm_sigreturn_next_pc. - -2016-01-18 Yao Qi - - * linux-low.c (linux_set_pc_64bit): New function. - (linux_get_pc_64bit): New function. - * linux-low.h (linux_set_pc_64bit, linux_get_pc_64bit): - Declare. - * linux-sparc-low.c (debug_threads): Remove declaration. - (sparc_get_pc): Remove. - (the_low_target): Use linux_get_pc_64bit instead of - sparc_get_pc. - * linux-tile-low.c (tile_get_pc, tile_set_pc): Remove. - (the_low_target): Use linux_get_pc_64bit and - linux_set_pc_64bit. - -2016-01-18 Yao Qi - - * linux-arm-low.c (debug_threads): Remove declaration. - (arm_get_pc, arm_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-bfin-low.c (bfin_get_pc, bfin_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-cris-low.c (debug_threads): Remove declaration. - (cris_get_pc, cris_set_pc,): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-crisv32-low.c (debug_threads): Remove declaration. - (cris_get_pc, cris_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-low.c: Include inttypes.h. - (linux_get_pc_32bit, linux_set_pc_32bit): New functions. - * linux-low.h (linux_get_pc_32bit, linux_set_pc_32bit): Declare. - * linux-m32r-low.c (m32r_get_pc, m32r_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-m68k-low.c (m68k_get_pc, m68k_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-nios2-low.c (nios2_get_pc, nios2_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-sh-low.c (sh_get_pc, sh_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - * linux-xtensa-low.c (xtensa_get_pc, xtensa_set_pc): Remove. - (the_low_target): Use linux_get_pc_32bit and - linux_set_pc_32bit. - -2016-01-18 Gary Benson - - * configure.ac (AC_FUNC_FORK): New check. - * config.in: Regenerate. - * configure: Likewise. - -2016-01-14 Yao Qi - - * linux-aarch32-low.c (thumb2_breakpoint): Make it static. - * linux-aarch32-low.h (thumb2_breakpoint): Remove declaration. - * linux-arm-low.c (arm_gdbserver_get_next_pcs): Pass 1 to - arm_get_next_pcs_ctor. - -2016-01-12 Josh Stone - Philippe Waroquiers - - * inferiors.h: Include "gdb_vecs.h". - (struct process_info): Add syscalls_to_catch. - * inferiors.c (remove_process): Free syscalls_to_catch. - * remote-utils.c (prepare_resume_reply): Report syscall_entry and - syscall_return stops. - * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. - * server.c (handle_general_set): Handle QCatchSyscalls. - (handle_query): Report support for QCatchSyscalls. - * target.h (struct target_ops): Add supports_catch_syscall. - (target_supports_catch_syscall): New macro. - * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. - (struct lwp_info): Add syscall_state. - * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. - Maintain syscall_state and syscalls_to_catch across exec. - (get_syscall_trapinfo): New function, proxy to the_low_target. - (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. - (linux_low_filter_event): Toggle syscall_state entry/return for - syscall traps, and set it ignored for all others. - (gdb_catching_syscalls_p): New function. - (gdb_catch_this_syscall_p): New function. - (linux_wait_1): Handle SYSCALL_SIGTRAP. - (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. - (linux_supports_catch_syscall): New function. - (linux_target_ops): Install it. - * linux-x86-low.c (x86_get_syscall_trapinfo): New function. - (the_low_target): Install it. - -2016-01-12 Mike Frysinger - - * acinclude.m4: Include new ../warning.m4 file. - * configure: Regenerated. - * configure.ac: Replace all warning logic with AM_GDB_WARNINGS. - -2016-01-12 Mike Frysinger - - * ax.c (is_goto_target): Mark static. - * linux-low.c (register_addr): Likewise. - (linux_fetch_registers, linux_store_registers): Likewise. - * mem-break.c (any_persistent_commands): Fix old prototype. - (add_commands_to_breakpoint): Mark static. - * regcache.c (find_register_by_name): Delete unused func. - * remote-utils.c (hex_or_minus_one): Mark static. - * server.c (monitor_show_help): Mark static. - (handle_query, handle_v_cont, handle_v_attach, handle_v_kill, - handle_v_requests): Likewise. - -2016-01-12 Pedro Alves - - Remove use of the registered trademark symbol throughout. - -2016-01-08 Yao Qi - - * remote-utils.c (getpkt): If c is '\003', call target hook - request_interrupt. - -2016-01-06 Yao Qi - - * linux-aarch32-low.h (arm_abi_breakpoint): Move to - linux-aarch32-low.c. - (arm_eabi_breakpoint, arm_breakpoint): Likewise. - (arm_breakpoint_len, thumb_breakpoint_len): Likewise. - (thumb2_breakpoint, thumb2_breakpoint_len): Likewise. - (thumb2_breakpoint): Declare. - * linux-aarch32-low.c (arm_abi_breakpoint): Moved from - linux-aarch32-low.h. - (arm_eabi_breakpoint, arm_breakpoint): Likewise. - (arm_breakpoint_len, thumb_breakpoint_len): Likewise. - (thumb2_breakpoint, thumb2_breakpoint_len): Likewise. - -2016-01-01 Joel Brobecker - - * gdbreplay.c (gdbreplay_version): Change copyright year in - version message. - * server.c (gdbserver_version): Likewise. - -2015-12-28 Patrick Palka - - * server.c (crc32_table): Delete. - (crc32): Use libiberty's xcrc32 function. - -2015-12-22 Joel Brobecker - - * lynx-low.c (lynx_delete_thread_callback): New function. - (lynx_mourn): Properly delete our process and all of its - threads. Remove call to clear_inferiors. - -2015-12-22 Joel Brobecker - - * target.c (thread_search_callback): Add check that - the thread_stopped target callback is not NULL before - calling it. - -2015-12-21 Yao Qi - - * linux-aarch32-low.h [__aarch64__]: Use arm_abi_breakpoint - arm breakpoint. - -2015-12-18 Antoine Tremblay - - * server.c (handle_query): Call target_supports_software_single_step. - -2015-12-18 Antoine Tremblay - - * linux-low.c (single_step): New function. - (linux_resume_one_lwp_throw): Call single_step. - (start_step_over): Likewise. - -2015-12-18 Antoine Tremblay - - * Makefile.in (SFILES): Append arch/arm-linux.c, - arch/arm-get-next-pcs.c. - (arm-linux.o): New rule. - (arm-get-next-pcs.o): New rule. - * configure.srv (arm*-*-linux*): Add arm-get-next-pcs.o, - arm-linux.o. - * linux-aarch32-low.c (arm_abi_breakpoint): Remove macro. Moved - to linux-aarch32-low.c. - (arm_eabi_breakpoint, arm_breakpoint): Likewise. - (arm_breakpoint_len, thumb_breakpoint): Likewise. - (thumb_breakpoint_len, thumb2_breakpoint): Likewise. - (thumb2_breakpoint_len): Likewise. - (arm_is_thumb_mode): Make non-static. - * linux-aarch32-low.h (arm_abi_breakpoint): New macro. Moved - from linux-aarch32-low.c. - (arm_eabi_breakpoint, arm_breakpoint): Likewise. - (arm_breakpoint_len, thumb_breakpoint): Likewise. - (thumb_breakpoint_len, thumb2_breakpoint): Likewise. - (thumb2_breakpoint_len): Likewise. - (arm_is_thumb_mode): New declaration. - * linux-arm-low.c: Include arch/arm-linux.h - aarch/arm-get-next-pcs.h, sys/syscall.h. - (get_next_pcs_ops): New struct. - (get_next_pcs_addr_bits_remove): New function. - (get_next_pcs_is_thumb): New function. - (get_next_pcs_read_memory_unsigned_integer): Likewise. - (arm_sigreturn_next_pc): Likewise. - (get_next_pcs_syscall_next_pc): Likewise. - (arm_gdbserver_get_next_pcs): Likewise. - (struct linux_target_ops) : - Initialize. - * linux-low.h: Move CORE_ADDR vector definition to gdb_vecs.h. - * server.h: Include gdb_vecs.h. - -2015-12-18 Antoine Tremblay - - * Makefile.in (SFILES): Append common/common-regcache.c. - (OBS): Append common-regcache.o. - (common-regcache.o): New rule. - * regcache.c (init_register_cache): Initialize cache to - REG_UNAVAILABLE. - (regcache_raw_read_unsigned): New function. - * regcache.h (REG_UNAVAILABLE, REG_VALID): Replaced by shared - register_status enum. - -2015-12-18 Antoine Tremblay - - * linux-aarch64-low.c (the_low_targets): Rename - breakpoint_reinsert_addr to get_next_pcs. - * linux-arm-low.c (the_low_targets): Likewise. - * linux-bfin-low.c (the_low_targets): Likewise. - * linux-cris-low.c (the_low_targets): Likewise. - * linux-crisv32-low.c (the_low_targets): Likewise. - * linux-low.c (can_software_single_step): Likewise. - (install_software_single_step_breakpoints): New function. - (start_step_over): Use install_software_single_step_breakpoints. - * linux-low.h: New CORE_ADDR vector. - (struct linux_target_ops) Rename breakpoint_reinsert_addr to - get_next_pcs. - * linux-mips-low.c (the_low_targets): Likewise. - * linux-nios2-low.c (the_low_targets): Likewise. - * linux-sparc-low.c (the_low_targets): Likewise. - -2015-12-17 Pedro Alves - - * linux-low.c (linux_kill_one_lwp): Remove references to - LinuxThreads. - (kill_lwp): Remove HAVE_TKILL_SYSCALL check. No longer fall back - to 'kill'. - (linux_init_signals): Delete. - (initialize_low): Adjust. - * thread-db.c (thread_db_init): Remove LinuxThreads reference. - -2015-12-16 Pedro Alves - - * configure.ac (compiler warning flags): When testing a - -Wno-foo option, check whether -Wfoo works instead. - * configure: Regenerate. - -2015-12-11 Don Breazeal - - * server.c (process_serial_event): Don't exit from gdbserver - in remote mode if there are still active inferiors. - -2015-12-11 Yao Qi - - * linux-aarch64-low.c (aarch64_breakpoint_at): Call - arm_breakpoint_at if the process is 32-bit. - -2015-12-11 Yao Qi - - * linux-aarch32-low.c [__aarch64__]: Use arm_abi_breakpoint - arm breakpoint. - -2015-12-07 Yao Qi - - * configure.srv: Append arm.o to srv_tgtobj for - aarch64*-*-linux* target. - * linux-aarch32-low.c (arm_abi_breakpoint): New macro. Moved - from linux-arm-low.c. - (arm_eabi_breakpoint, arm_breakpoint): Likewise. - (arm_breakpoint_len, thumb_breakpoint): Likewise. - (thumb_breakpoint_len, thumb2_breakpoint): Likewise. - (thumb2_breakpoint_len): Likewise. - (arm_is_thumb_mode, arm_breakpoint_at): Likewise. - (arm_breakpoint_kinds): Likewise. - (arm_breakpoint_kind_from_pc): Likewise. - (arm_sw_breakpoint_from_kind): Likewise. - (arm_breakpoint_kind_from_current_state): Likewise. - * linux-aarch32-low.h (arm_breakpoint_kind_from_pc): Declare. - (arm_sw_breakpoint_from_kind): Declare. - (arm_breakpoint_kind_from_current_state): Declare. - (arm_breakpoint_at): Declare. - * linux-aarch64-low.c (aarch64_sw_breakpoint_from_kind): Call - arm_sw_breakpoint_from_kind if process is 32-bit. - (aarch64_breakpoint_kind_from_pc): New function. - (aarch64_breakpoint_kind_from_current_state): New function. - (the_low_target): Initialize fields breakpoint_kind_from_pc - and breakpoint_kind_from_current_state. - * linux-arm-low.c (arm_breakpoint_kinds): Move to - linux-aarch32-low.c. - (arm_abi_breakpoint, arm_eabi_breakpoint): Likewise. - (arm_breakpoint, arm_breakpoint_len): Likewise. - (thumb_breakpoint, thumb_breakpoint_len): Likewise. - (thumb2_breakpoint, thumb2_breakpoint_len): Likewise. - (arm_is_thumb_mode): Likewise. - (arm_breakpoint_at): Likewise. - (arm_breakpoint_kind_from_pc): Likewise. - (arm_sw_breakpoint_from_kind): Likewise. - (arm_breakpoint_kind_from_current_state): Likewise. - - Revert: - 2015-08-04 Yao Qi - - * linux-aarch64-low.c (aarch64_supports_z_point_type): Return - 0 for Z_PACKET_SW_BP if it may be used in multi-arch debugging. - * server.c (extended_protocol): Remove "static". - * server.h (extended_protocol): Declare it. - -2015-12-04 Josh Stone - - * target.h (struct target_ops) : Rename to ... - (struct target_ops) : ... this. - (target_arch_setup): Rename to ... - (target_post_create_inferior): ... this, calling post_create_inferior. - * server.c (start_inferior): Update target_arch_setup calls to - target_post_create_inferior. - * linux-low.c (linux_low_ptrace_options): Forward declare. - (linux_arch_setup): Update its comment for general use. - (linux_post_create_inferior): New, run arch_setup and setup ptrace. - (struct linux_target_ops): Use linux_post_create_inferior. - * lynx-low.c (struct lynx_target_ops): Update arch_setup stub comment - to post_create_inferior. - * nto-low.c (struct nto_target_ops): Likewise. - * spu-low.c (struct spu_target_ops): Likewise. - * win32-low.c (struct win32_target_ops): Likewise. - -2015-12-03 Antoine Tremblay - - * linux-arm-low.c: Remove duplicate arch/arm.h include. - -2015-11-30 Antoine Tremblay - - * linux-arm-low.c (arm_reinsert_addr): Remove function. - (struct linux_target_ops : Set to NULL. - * linux-cris-low.c (cris_reinsert_addr> Remove function. - (struct linux_target_ops) : Set to NULL. - * linux-crisv32-low.c (cris_reinsert_addr): Remove function. - (struct linux_target_ops) : Set to NULL. - * linux-mips-low.c (mips_reinsert_addr): Remove function. - (struct linux_target_ops) : Set to NULL. - * linux-nios2-low.c (nios2_reinsert_addr): Remove function. - (struct linux_target_ops) : Set to NULL. - * linux-sparc-low.c (sparc_reinsert_addr): Remove function. - (struct linux_target_ops) : Set to NULL. - -2015-11-30 Antoine Tremblay - - * linux-low.c (linux_look_up_symbols): Don't call - linux_supports_traceclone. - * linux-low.h (thread_db_init): Remove use_events argument. - * thread-db.c (thread_db_use_event): Remove global variable. - (struct thread_db) : Remove field. - (struct thread_db) : Remove field. - (thread_db_create_event): Remove function. - (thread_db_enable_reporting): Likewise. - (find_one_thread): Don't check for thread_db_use_events. - (attach_thread): Likewise. - (thread_db_load_search): Remove td_thr_event_enable_p initialization. - (try_thread_db_load_1): Don't check for thread_db_use_events. - (thread_db_init): Remove use_events argument and thread events - handling. - (remove_thread_event_breakpoints): Remove function. - (thread_db_detach): Remove call to remove_thred_event_breakpoints. - -2015-11-30 Antoine Tremblay - - * linux-aarch64-low.c (aarch64_supports_hardware_single_step): - New function. - (struct linux_target_ops) : Initialize. - * linux-arm-low.c (arm_supports_hardware_single_step): New function. - (struct linux_target_ops) : Initialize. - * linux-bfin-low.c (bfin_supports_hardware_single_step): New function. - (struct linux_target_ops) : - Initialize. - * linux-crisv32-low.c (cris_supports_hardware_single_step): - New function. - (struct linux_target_ops) : Initialize. - * linux-low.c (can_hardware_single_step): Use - supports_hardware_single_step. - (can_software_single_step): New function. - (start_step_over): Call can_software_single_step. - (linux_supports_hardware_single_step): New function. - (struct target_ops) : Initialize. - * linux-low.h (struct linux_target_ops) - : Initialize. - * linux-m32r-low.c (m32r_supports_hardware_single_step): New function. - (struct linux_target_ops) : Initialize. - * linux-ppc-low.c (ppc_supports_hardware_single_step): New function. - (struct linux_target_ops) Initialize. - * linux-s390-low.c (s390_supports_hardware_single_step): New function. - (struct linux_target_ops) : Initialize. - * linux-sh-low.c (sh_supports_hardware_single_step): New function. - (struct linux_target_ops) : Initialize. - * linux-tic6x-low.c (tic6x_supports_hardware_single_step): New function. - (struct linux_target_ops) : - Initialize. - * linux-tile-low.c (tile_supports_hardware_single_step): New function. - (struct linux_target_ops) : - Initialize. - * linux-x86-low.c (x86_supports_hardware_single_step) New function. - (struct linux_target_ops) : Initialize. - * linux-xtensa-low.c (xtensa_supports_hardware_single_step): - New function. - (struct linux_target_ops) : Initialize. - * target.h (struct target_ops): : - New field. - (target_supports_software_single_step): New macro. - -2015-11-30 Antoine Tremblay - - * linux-low.c (linux_wait_1): Fix pc advance condition. - * mem-break.c (reinsert_breakpoint_inserted_here): New function. - * mem-break.h (reinsert_breakpoint_inserted_here): New declaration. - -2015-11-30 Antoine Tremblay - - * linux-arm-low.c (arm_is_thumb_mode): New function. - (arm_breakpoint_at): Use arm_is_thumb_mode. - (arm_breakpoint_kind_from_current_state): New function. - (struct linux_target_ops) : - Initialize. - * linux-low.c (linux_wait_1): Call breakpoint_kind_from_current_state. - (linux_breakpoint_kind_from_current_state): New function. - (struct target_ops : Initialize. - * linux-low.h (struct linux_target_ops) - : New field. - * target.h (struct target_ops): Likewise. - (target_breakpoint_kind_from_current_state): New macro. - -2015-11-30 Pedro Alves - - * linux-low.c (linux_resume): Wake up the event loop before - returning. - -2015-11-30 Pedro Alves - - * mem-break.c (check_gdb_bp_preconditions): Remove current_thread - check. - (set_gdb_breakpoint): If prepare_to_access_memory fails, set *ERR - to -1. - * target.c (struct thread_search): New structure. - (thread_search_callback): New function. - (prev_general_thread): New global. - (prepare_to_access_memory, done_accessing_memory): New functions. - * target.h (prepare_to_access_memory, done_accessing_memory): - Replace macros with function declarations. - -2015-11-30 Pedro Alves - - PR 14618 - * linux-low.c (linux_wait_1): If the last resumed thread is gone, - report TARGET_WAITKIND_NO_RESUMED. - * remote-utils.c (prepare_resume_reply): Handle - TARGET_WAITKIND_NO_RESUMED. - * server.c (report_no_resumed): New global. - (handle_query) : Handle "no-resumed+". Report - "no-resumed+" support. - (resume): When the target reports TARGET_WAITKIND_NO_RESUMED, only - return error if the client doesn't support no-resumed events. - (push_stop_notification): New function. - (handle_target_event): Use it. Report TARGET_WAITKIND_NO_RESUMED - events if the client supports them. - -2015-11-30 Pedro Alves - - * linux-low.c (thread_still_has_status_pending_p): Don't check - vCont;t here. - (lwp_resumed): New function. - (status_pending_p_callback): Return early if the LWP is not - supposed to be resumed. - -2015-11-30 Pedro Alves - - * linux-low.c (handle_extended_wait): Assert that the LWP's - waitstatus is TARGET_WAITKIND_IGNORE. If GDB wants to hear about - thread create events, leave the new child's status pending. - (linux_low_filter_event): If GDB wants to hear about thread exit - events, leave the LWP marked dead and don't delete it. - (linux_wait_for_event_filtered): Don't check for thread exit. - (filter_exit_event): New function. - (linux_wait_1): Use it, when returning an exit event. - (linux_resume_one_lwp_throw): Assert that the LWP's - waitstatus is TARGET_WAITKIND_IGNORE. - * remote-utils.c (prepare_resume_reply): Handle - TARGET_WAITKIND_THREAD_CREATED and TARGET_WAITKIND_THREAD_EXITED. - * server.c (report_thread_events): New global. - (handle_general_set): Handle QThreadEvents. - (handle_query) : Handle and report QThreadEvents+; - (handle_target_event): Handle TARGET_WAITKIND_THREAD_CREATED and - TARGET_WAITKIND_THREAD_EXITED. - * server.h (report_thread_events): Declare. - -2015-11-30 Pedro Alves - - * linux-low.c (resume_stopped_resumed_lwps): Don't check whether - the thread's last_resume_kind was resume_stop. - -2015-11-30 Pedro Alves - - * linux-low.c (linux_attach): In non-stop mode, wait for one stop - before returning. - -2015-11-30 Pedro Alves - - * server.c (handle_v_requests): Handle vCtrlC. - -2015-11-30 Pedro Alves - - * gdbthread.h (find_any_thread_of_pid): Declare. - * inferiors.c (thread_of_pid, find_any_thread_of_pid): New - functions. - * server.c (handle_query): If current_thread is NULL, look for - another thread of the selected process. - -2015-11-26 Daniel Colascione - Simon Marchi - - * linux-low.c (linux_target_ops): Use linux_proc_tid_get_name. - * server.c (handle_qxfer_threads_worker): Refactor to include thread - name in reply. - * target.h (struct target_ops) : New field. - (target_thread_name): New macro. - -2015-11-23 Joel Brobecker - - * regcache.h (regcache_invalidate_pid): Add declaration. - * regcache.c (regcache_invalidate_pid): New function, extracted - from regcache_invalidate. - (regcache_invalidate): Reimplement using regcache_invalidate_pid. - Add trivial documentation comment. - * lynx-low.c: Use regcache_invalidate_pid instead of - regcache_invalidate. - -2015-11-23 Joel Brobecker - - * configure.ac: Do not call AC_CHECK_TYPES for Elf32_auxv_t - and Elf64_auxv_t if the target is Android. - -2015-11-22 Doug Evans - - * target.h: #include . - -2015-11-19 Pedro Alves - - * linux-low.c (linux_process_qsupported): Change prototype. - Adjust. - * linux-low.h (struct linux_target_ops) : - Change prototype. - * linux-x86-low.c (x86_linux_process_qsupported): Change prototype - and adjust to loop over all features. - * server.c (handle_query) : Adjust to call - target_process_qsupported once, passing it a vector of unprocessed - features. - * target.h (struct target_ops) : Change - prototype. - (target_process_qsupported): Adjust. - -2015-11-19 Pedro Alves - - * configure.ac (ERROR_ON_WARNING): Don't check whether in C++ - mode. - * configure: Regenerate. - -2015-11-19 Pedro Alves - - * configure: Regenerate. - -2015-11-19 Yao Qi - - * linux-aarch64-low.c (emit_data_processing_reg): Change opcode - type to uint32_t. - -2015-11-19 Yao Qi - - * linux-aarch64-low.c (enum aarch64_operand_type): New. - (struct aarch64_operand): Move enum out. - -2015-11-19 Yao Qi - - * linux-aarch64-low.c (aarch64_fill_fpregset): Cast buf to - struct user_fpsimd_state *. - (aarch64_store_fpregset): Likewise. - -2015-11-19 Yao Qi - - * linux-aarch64-low.c (aarch64_fill_gregset): Cast buf to - struct user_pt_regs *. - (aarch64_store_gregset): Likewise. - -2015-11-18 Pedro Alves - - * Makefile.in (all_object_files): Add $IPA_OBJS. - -2015-11-17 Pedro Alves - - * win32-low.c (win32_resume): Use gdb_signal_from_host, - GDB_SIGNAL_0 and gdb_signal_to_string. - -2015-11-17 Pedro Alves - - * win32-low.c (handle_output_debug_string): Remove parameter. - (win32_kill): Remove our_status local and adjust call to - handle_output_debug_string. - (get_child_debug_event): Adjust call to - handle_output_debug_string. - -2015-11-03 Simon Marchi - - * linux-mips-low.c (mips_fill_gregset): Add cast. - (mips_store_gregset): Likewise. - (mips_fill_fpregset): Likewise. - (mips_store_fpregset): Likewise. - -2015-11-03 Simon Marchi - - * linux-mips-low.c (mips_add_watchpoint): Rename private to - priv. - -2015-11-03 Simon Marchi - - * linux-mips-low.c (mips_linux_new_thread): Change type of - watch_type to enum target_hw_bp_type. - -2015-11-03 Simon Marchi - - * linux-arm-low.c (raw_bkpt_type_to_arm_hwbp_type): - Change return type to arm_hwbp_type. - -2015-11-03 Simon Marchi - - * linux-aarch32-low.c (arm_fill_gregset): Add cast. - (arm_store_gregset): Likewise. - * linux-arm-low.c (arm_get_hwcap): Likewise. - (arm_read_description): Likewise. - -2015-11-03 Simon Marchi - - * linux-aarch32-low.c (aarch32_regsets): Use NULL_REGSET. - -2015-11-03 Simon Marchi - - * linux-ppc-low.c (ppc_get_hwcap): Add cast. - (ppc_fill_vsxregset): Likewise. - (ppc_store_vsxregset): Likewise. - (ppc_fill_vrregset): Likewise. - (ppc_store_vrregset): Likewise. - (ppc_fill_evrregset): Likewise. - (ppc_store_evrregset): Likewise. - -2015-11-03 Simon Marchi - - * linux-ppc-low.c (ppc_usrregs_info): Remove - forward-declaration. - (ppc_arch_setup): Move lower in file. - -2015-10-30 Simon Marchi - - * proc-service.c (ps_pdread): Change CORE_ADDR cast to uintptr_t. - (ps_pdwrite): Likewise. - -2015-10-29 Henrik Wallin - - * linux-arm-low.c (arm_new_thread): Move pointer dereference - to after assert checks. - -2015-10-29 Simon Marchi - - * proc-service.c (ps_pdread): Add/adjust casts. - (ps_pdwrite): Add/adjust casts. - -2015-10-29 Simon Marchi - - * server.c (handle_search_memory_1): Cast return value of - memmem. - -2015-10-29 Simon Marchi - - * server.c (write_qxfer_response): Change type of data to - gdb_byte *. - -2015-10-29 Pedro Alves - - * mem-break.c (Z_packet_to_bkpt_type): Add cast. - -2015-10-29 Pedro Alves - - * tracepoint.c (clear_installed_tracepoints): Add casts. - -2015-10-29 Pedro Alves - - * server.c (handle_v_cont, process_serial_event): Add enum - gdb_signal casts to signal parsing code. - -2015-10-29 Pedro Alves - - * linux-low.h (NULL_REGSET): Define. - * linux-aarch64-low.c (aarch64_regsets): Use NULL_REGSET. - * linux-arm-low.c (arm_regsets): Likewise. - * linux-crisv32-low.c (cris_regsets): Likewise. - * linux-m68k-low.c (m68k_regsets): Likewise. - * linux-mips-low.c (mips_regsets): Likewise. - * linux-nios2-low.c (nios2_regsets): Likewise. - * linux-ppc-low.c (ppc_regsets): Likewise. - * linux-s390-low.c (s390_regsets): Likewise. - * linux-sh-low.c (sh_regsets): Likewise. - * linux-sparc-low.c (sparc_regsets): Likewise. - * linux-tic6x-low.c (tic6x_regsets): Likewise. - * linux-tile-low.c (tile_regsets): Likewise. - * linux-x86-low.c (x86_regsets): Likewise. - * linux-xtensa-low.c (xtensa_regsets): Likewise. - -2015-10-29 Pedro Alves - - * linux-low.h (NULL_REGSET): Define. - * linux-aarch64-low.c (aarch64_regsets): Use NULL_REGSET. - * linux-arm-low.c (arm_regsets): Likewise. - * linux-crisv32-low.c (cris_regsets): Likewise. - * linux-m68k-low.c (m68k_regsets): Likewise. - * linux-mips-low.c (mips_regsets): Likewise. - * linux-nios2-low.c (nios2_regsets): Likewise. - * linux-ppc-low.c (ppc_regsets): Likewise. - * linux-s390-low.c (s390_regsets): Likewise. - * linux-sh-low.c (sh_regsets): Likewise. - * linux-sparc-low.c (sparc_regsets): Likewise. - * linux-tic6x-low.c (tic6x_regsets): Likewise. - * linux-tile-low.c (tile_regsets): Likewise. - * linux-x86-low.c (x86_regsets): Likewise. - * linux-xtensa-low.c (xtensa_regsets): Likewise. - -2015-10-26 Doug Evans - - * linux-low.c (__SIGRTMIN): Move to nat/linux-nat.h. - -2015-10-26 Doug Evans - - * linux-low.c (W_STOPCODE): Moved to common/gdb_wait.h. - -2015-10-26 Doug Evans - - * thread-db.c (find_one_thread): Cast ti.ti_tid to unsigned long - for debug_printf. - (attach_thread, find_new_threads_callback): Ditto. - -2015-10-23 Antoine Tremblay - - * mem-break.h (set_breakpoint_data): Remove. - -2015-10-23 Antoine Tremblay - - * nto-low.c (nto_sw_breakpoint_from_kind): New function. - (struct target_ops) : Initialize. - (initialize_low): Remove set_breakpoint_data call. - * spu-low.c (spu_sw_breakpoint_from_kind): New function. - (struct target_ops) : Iniitalize. - (initialize_low): Remove set_breakpoint_data call. - * win32-low.c (win32_sw_breakpoint_from_kind): New function. - (struct target_ops) : Initialize. - (initialize_low): Remove set_breakpoint_data call. - -2015-10-23 Antoine Tremblay - - * linux-low.c (default_breakpoint_kind_from_pc): Move to target.c. - * mem-break.c (set_breakpoint_at): Use target_breakpoint_kind_from_pc. - * target.c (default_breakpoint_kind_from_pc): Moved from linux-low.c - * target.h (target_breakpoint_kind_from_pc): New macro. - -2015-10-22 Antoine Tremblay - - * linux-low.c (default_breakpoint_kind_from_pc): New function. - (linux_breakpoint_kind_from_pc): Use default_breakpoint_kind_from_pc for - the default breakpoint kind. - -2015-10-21 Antoine Tremblay - - * linux-arm-low.c (arm_supports_z_point_type): Add software - breakpoint support. - -2015-10-21 Antoine Tremblay - - * linux-arm-low.c: Refactor breakpoint definitions. - (arm_breakpoint_at): Adjust for arm_abi_breakpoint. - (arm_sw_breakpoint_from_kind): Adjust for arm_breakpoint. - -2015-10-21 Antoine Tremblay - - * Makefile.in: Add arm.c/o. - * configure.srv: Likewise. - * linux-arm-low.c (arm_breakpoint_kinds): New enum. - (arm_breakpoint_kind_from_pc): New function. - (arm_sw_breakpoint_from_kind): Return proper kind. - (struct linux_target_ops) : Initialize. - -2015-10-21 Antoine Tremblay - - * linux-low.c (initialize_low): Ajdust for breakpoint global variables - removal. - * mem-break.c : Remove breakpoint_data/breakpoint_len global variables. - (struct raw_breakpoint) : Remove. - (struct raw_breakpoint) : Add. - (bp_size): New function. - (bp_opcode): Likewise. - (find_raw_breakpoint_at): Adjust for kind. - (insert_memory_breakpoint): Adjust for kind call bp_size,bp_opcode. - (remove_memory_breakpoint): Adjust for kind call bp_size. - (set_raw_breakpoint_at): Adjust for kind. - (set_breakpoint): Likewise. - (set_breakpoint_at): Call breakpoint_kind_from_pc. - (delete_raw_breakpoint): Adjust for kind. - (delete_breakpoint): Likewise. - (find_gdb_breakpoint): Likewise. - (set_gdb_breakpoint_1): Likewise. - (set_gdb_breakpoint): Likewise. - (delete_gdb_breakpoint_1): Likewise. - (delete_gdb_breakpoint): Likewise. - (uninsert_raw_breakpoint): Likewise. - (reinsert_raw_breakpoint): Likewise. - (set_breakpoint_data): Remove. - (validate_inserted_breakpoint): Adjust for kind call bp_size,bp_opcode. - (check_mem_read): Adjust for kind call bp_size. - (check_mem_write): Adjust for kind call bp_size,bp_opcode. - (clone_one_breakpoint): Adjust for kind. - * mem-break.h (set_gdb_breakpoint): Likewise. - (delete_gdb_breakpoint): Likewise. - * server.c (process_serial_event): Likewise. - -2015-10-21 Antoine Tremblay - - * linux-aarch64-low.c (aarch64_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-arm-low.c (arm_breakpoint_kind_from_pc): New function. - (arm_sw_breakpoint_from_kind): New function. - * linux-bfin-low.c (bfin_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-cris-low.c (cris_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-crisv32-low.c (cris_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-low.c (linux_wait_1): Call breakpoint_kind_from_pc - and sw_breakpoint_from_kind to increment the pc. - (linux_breakpoint_kind_from_pc): New function. - (linux_sw_breakpoint_from_kind): New function. - (struct target_ops) : Initialize field. - (initialize_low): Call breakpoint_kind_from_pc and - sw_breakpoint_from_kind to replace breakpoint_data/len. - * linux-low.h (struct linux_target_ops) : - New field. - (struct linux_target_ops) : Likewise. - * linux-m32r-low.c (m32r_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-m68k-low.c (m68k_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-mips-low.c (mips_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-nios2-low.c (nios2_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-ppc-low.c (ppc_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-s390-low.c (s390_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-sh-low.c (sh_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-sparc-low.c (sparc_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-tic6x-low.c (tic6x_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-tile-low.c (tile_sw_breakpoint_from_kind): New function. - * linux-x86-low.c (x86_sw_breakpoint_from_kind): New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - * linux-xtensa-low.c (xtensa_sw_breakpoint_from_kind) New function. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Remove. - (struct linux_target_ops) : Initialize field. - (struct linux_target_ops) : Initialize field. - -2015-10-21 Antoine Tremblay - - * linux-cris-low.c (cris_get_pc): Remove void arg. - -2015-10-16 Aleksandar Ristovski - - * gdbserver/nto-low.c (nto_insert_point, nto_remove_point): Fix - variable name. - -2015-10-16 Aleksandar Ristovski - - * inferiors.c (thread_pid_matches_callback): New function. - (find_thread_process): New function. - (remove_thread): Reset current_thread. - (remove_process): Assert threads have been removed first. - -2015-10-15 Yao Qi - - * linux-aarch64-low.c (aarch64_insert_point): Set len to 2 - if it is 3. - (aarch64_remove_point): Likewise. - * regcache.c (regcache_register_size): New function. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c: Update all callers as emit_load_store - is renamed to aarch64_emit_load_store. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c: Update all callers of function renaming - from emit_insn to aarch64_emit_insn. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c (enum aarch64_opcodes): Move to - arch/aarch64-insn.h. - (struct aarch64_memory_operand): Likewise. - (ENCODE): Likewise. - (emit_insn): Move to arch/aarch64-insn.c. - (emit_b, emit_bcond, emit_cb, emit_tb): Remove. - (emit_load_store): Move to arch/aarch64-insn.c. - (emit_ldr, emit_ldrb, emit_ldrsw, emit_nop): Remove. - (can_encode_int32): Remove. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c (extract_signed_bitfield): Remove. - (aarch64_decode_ldr_literal): Move to gdb/arch/aarch64-insn.c. - (aarch64_relocate_instruction): Likewise. - (struct aarch64_insn_data): Move to gdb/arch/aarch64-insn.h. - (struct aarch64_insn_visitor): Likewise. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c (struct aarch64_insn_data): New. - (struct aarch64_insn_visitor): New. - (struct aarch64_insn_relocation_data): New. - (aarch64_ftrace_insn_reloc_b): New function. - (aarch64_ftrace_insn_reloc_b_cond): Likewise. - (aarch64_ftrace_insn_reloc_cb): Likewise. - (aarch64_ftrace_insn_reloc_tb): Likewise. - (aarch64_ftrace_insn_reloc_adr): Likewise. - (aarch64_ftrace_insn_reloc_ldr_literal): Likewise. - (aarch64_ftrace_insn_reloc_others): Likewise. - (visitor): New. - (aarch64_relocate_instruction): Use visitor. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c (aarch64_relocate_instruction): Return - int. Add argument buf. - (aarch64_install_fast_tracepoint_jump_pad): Pass buf to - aarch64_relocate_instruction. - -2015-10-12 Yao Qi - - * linux-aarch64-low.c (aarch64_relocate_instruction): Add - argument insn. Remove local variable insn. Don't call - target_read_uint32. - (aarch64_install_fast_tracepoint_jump_pad): Call - target_read_uint32. - -2015-09-30 Yao Qi - - * linux-aarch64-low.c (emit_movk): Shorten a long line. - (emit_load_store_pair): Likewise. - -2015-09-25 Simon Marchi - - * dll.c (match_dll): Add cast(s). - (unloaded_dll): Likewise. - * linux-low.c (second_thread_of_pid_p): Likewise. - (delete_lwp_callback): Likewise. - (count_events_callback): Likewise. - (select_event_lwp_callback): Likewise. - (linux_set_resume_request): Likewise. - * server.c (accumulate_file_name_length): Likewise. - (emit_dll_description): Likewise. - (handle_qxfer_threads_worker): Likewise. - (visit_actioned_threads): Likewise. - * thread-db.c (any_thread_of): Likewise. - * tracepoint.c (same_process_p): Likewise. - (match_blocktype): Likewise. - (build_traceframe_info_xml): Likewise. - -2015-09-25 Simon Marchi - - * ax.c (gdb_parse_agent_expr): Add cast to allocation result - assignment. - (gdb_unparse_agent_expr): Likewise. - * hostio.c (require_data): Likewise. - (handle_pread): Likewise. - * linux-low.c (disable_regset): Likewise. - (fetch_register): Likewise. - (store_register): Likewise. - (get_dynamic): Likewise. - (linux_qxfer_libraries_svr4): Likewise. - * mem-break.c (delete_fast_tracepoint_jump): Likewise. - (set_fast_tracepoint_jump): Likewise. - (uninsert_fast_tracepoint_jumps_at): Likewise. - (reinsert_fast_tracepoint_jumps_at): Likewise. - (validate_inserted_breakpoint): Likewise. - (clone_agent_expr): Likewise. - * regcache.c (init_register_cache): Likewise. - * remote-utils.c (putpkt_binary_1): Likewise. - (decode_M_packet): Likewise. - (decode_X_packet): Likewise. - (look_up_one_symbol): Likewise. - (relocate_instruction): Likewise. - (monitor_output): Likewise. - * server.c (handle_search_memory): Likewise. - (handle_qxfer_exec_file): Likewise. - (handle_qxfer_libraries): Likewise. - (handle_qxfer): Likewise. - (handle_query): Likewise. - (handle_v_cont): Likewise. - (handle_v_run): Likewise. - (captured_main): Likewise. - * target.c (write_inferior_memory): Likewise. - * thread-db.c (try_thread_db_load_from_dir): Likewise. - * tracepoint.c (init_trace_buffer): Likewise. - (add_tracepoint_action): Likewise. - (add_traceframe): Likewise. - (add_traceframe_block): Likewise. - (cmd_qtdpsrc): Likewise. - (cmd_qtdv): Likewise. - (cmd_qtstatus): Likewise. - (response_source): Likewise. - (response_tsv): Likewise. - (cmd_qtnotes): Likewise. - (gdb_collect): Likewise. - (initialize_tracepoint): Likewise. - -2015-09-21 Pierre Langlois - - * linux-aarch64-low-.c: Include ax.h and tracepoint.h. - (enum aarch64_opcodes) , , , , , - , , , , , , , , - : New. - (enum aarch64_condition_codes): New enum. - (w0): New static global. - (fp): Likewise. - (lr): Likewise. - (struct aarch64_memory_operand) : New - MEMORY_OPERAND_POSTINDEX type. - (postindex_memory_operand): New helper function. - (emit_ret): New function. - (emit_load_store_pair): New function, factored out of emit_stp - with support for MEMORY_OPERAND_POSTINDEX. - (emit_stp): Rewrite using emit_load_store_pair. - (emit_ldp): New function. - (emit_load_store): Likewise. - (emit_ldr): Mention post-index instruction in comment. - (emit_ldrh): New function. - (emit_ldrb): New function. - (emit_ldrsw): Mention post-index instruction in comment. - (emit_str): Likewise. - (emit_subs): New function. - (emit_cmp): Likewise. - (emit_and): Likewise. - (emit_orr): Likewise. - (emit_orn): Likewise. - (emit_eor): Likewise. - (emit_mvn): Likewise. - (emit_lslv): Likewise. - (emit_lsrv): Likewise. - (emit_asrv): Likewise. - (emit_mul): Likewise. - (emit_sbfm): Likewise. - (emit_sbfx): Likewise. - (emit_ubfm): Likewise. - (emit_ubfx): Likewise. - (emit_csinc): Likewise. - (emit_cset): Likewise. - (emit_nop): Likewise. - (emit_ops_insns): New helper function. - (emit_pop): Likewise. - (emit_push): Likewise. - (aarch64_emit_prologue): New function. - (aarch64_emit_epilogue): Likewise. - (aarch64_emit_add): Likewise. - (aarch64_emit_sub): Likewise. - (aarch64_emit_mul): Likewise. - (aarch64_emit_lsh): Likewise. - (aarch64_emit_rsh_signed): Likewise. - (aarch64_emit_rsh_unsigned): Likewise. - (aarch64_emit_ext): Likewise. - (aarch64_emit_log_not): Likewise. - (aarch64_emit_bit_and): Likewise. - (aarch64_emit_bit_or): Likewise. - (aarch64_emit_bit_xor): Likewise. - (aarch64_emit_bit_not): Likewise. - (aarch64_emit_equal): Likewise. - (aarch64_emit_less_signed): Likewise. - (aarch64_emit_less_unsigned): Likewise. - (aarch64_emit_ref): Likewise. - (aarch64_emit_if_goto): Likewise. - (aarch64_emit_goto): Likewise. - (aarch64_write_goto_address): Likewise. - (aarch64_emit_const): Likewise. - (aarch64_emit_call): Likewise. - (aarch64_emit_reg): Likewise. - (aarch64_emit_pop): Likewise. - (aarch64_emit_stack_flush): Likewise. - (aarch64_emit_zero_ext): Likewise. - (aarch64_emit_swap): Likewise. - (aarch64_emit_stack_adjust): Likewise. - (aarch64_emit_int_call_1): Likewise. - (aarch64_emit_void_call_2): Likewise. - (aarch64_emit_eq_goto): Likewise. - (aarch64_emit_ne_goto): Likewise. - (aarch64_emit_lt_goto): Likewise. - (aarch64_emit_le_goto): Likewise. - (aarch64_emit_gt_goto): Likewise. - (aarch64_emit_ge_got): Likewise. - (aarch64_emit_ops_impl): New static global variable. - (aarch64_emit_ops): New target function, return - &aarch64_emit_ops_impl. - (struct linux_target_ops): Install it. - -2015-09-21 Pierre Langlois - - * Makefile.in (linux-aarch64-ipa.o, aarch64-ipa.o): New rules. - * configure.srv (aarch64*-*-linux*): Add linux-aarch64-ipa.o and - aarch64-ipa.o. - * linux-aarch64-ipa.c: New file. - * linux-aarch64-low.c: Include arch/aarch64-insn.h, inttypes.h - and endian.h. - (aarch64_get_thread_area): New target method. - (extract_signed_bitfield): New helper function. - (aarch64_decode_ldr_literal): New function. - (enum aarch64_opcodes): New enum. - (struct aarch64_register): New struct. - (struct aarch64_operand): New struct. - (x0): New static global. - (x1): Likewise. - (x2): Likewise. - (x3): Likewise. - (x4): Likewise. - (w2): Likewise. - (ip0): Likewise. - (sp): Likewise. - (xzr): Likewise. - (aarch64_register): New helper function. - (register_operand): Likewise. - (immediate_operand): Likewise. - (struct aarch64_memory_operand): New struct. - (offset_memory_operand): New helper function. - (preindex_memory_operand): Likewise. - (enum aarch64_system_control_registers): New enum. - (ENCODE): New macro. - (emit_insn): New helper function. - (emit_b): New function. - (emit_bcond): Likewise. - (emit_cb): Likewise. - (emit_tb): Likewise. - (emit_blr): Likewise. - (emit_stp): Likewise. - (emit_ldp_q_offset): Likewise. - (emit_stp_q_offset): Likewise. - (emit_load_store): Likewise. - (emit_ldr): Likewise. - (emit_ldrsw): Likewise. - (emit_str): Likewise. - (emit_ldaxr): Likewise. - (emit_stxr): Likewise. - (emit_stlr): Likewise. - (emit_data_processing_reg): Likewise. - (emit_data_processing): Likewise. - (emit_add): Likewise. - (emit_sub): Likewise. - (emit_mov): Likewise. - (emit_movk): Likewise. - (emit_mov_addr): Likewise. - (emit_mrs): Likewise. - (emit_msr): Likewise. - (emit_sevl): Likewise. - (emit_wfe): Likewise. - (append_insns): Likewise. - (can_encode_int32_in): New helper function. - (aarch64_relocate_instruction): New function. - (aarch64_install_fast_tracepoint_jump_pad): Likewise. - (aarch64_get_min_fast_tracepoint_insn_len): Likewise. - (struct linux_target_ops): Install aarch64_get_thread_area, - aarch64_install_fast_tracepoint_jump_pad and - aarch64_get_min_fast_tracepoint_insn_len. - -2015-09-21 Pierre Langlois - - * Makefile.in (aarch64-insn.o): New rule. - * configure.srv (aarch64*-*-linux*): Add aarch64-insn.o. - -2015-09-21 Yao Qi - - * ax.c [!IN_PROCESS_AGENT] (gdb_agent_op_sizes): Define it. - -2015-09-21 Yao Qi - - * tracepoint.c (max_jump_pad_size): Remove. - -2015-09-18 Yao Qi - - * linux-aarch64-low.c: Don't include sys/uio.h. - (ps_get_thread_area): Call aarch64_ps_get_thread_area. - -2015-09-16 Wei-cheng Wang - - * tracepoint.c (eval_result_type): Change prototype. - (condition_true_at_tracepoint): Fix argument to compiled_cond. - -2015-09-15 Pedro Alves - - * remote-utils.c (prepare_resume_reply) : - Check whether to report exec events instead of checking whether - multiprocess is enabled. - -2015-09-15 Pedro Alves - - PR remote/18965 - * remote-utils.c (prepare_resume_reply): Merge - TARGET_WAITKIND_VFORK_DONE switch case with the - TARGET_WAITKIND_FORKED case. - -2015-09-15 Yao Qi - - * server.c (handle_query): Check string comparison using - "else if" instead of "if". - -2015-09-15 Yao Qi - - * server.c (vCont_supported): New global variable. - (handle_query): Set vCont_supported to 1 if "vContSupported+" - matches. Append ";vContSupported+" to own_buf. - (handle_v_requests): Append ";s;S" to own_buf if target supports - hardware single step or vCont_supported is false. - (capture_main): Set vCont_supported to zero. - -2015-09-15 Yao Qi - - * linux-low.c (linux_supports_conditional_breakpoints): Rename - it to ... - (linux_supports_hardware_single_step): ... New function. - (linux_target_ops): Update. - * lynx-low.c (lynx_target_ops): Set field - supports_hardware_single_step to target_can_do_hardware_single_step. - * nto-low.c (nto_target_ops): Likewise. - * spu-low.c (spu_target_ops): Likewise. - * win32-low.c (win32_target_ops): Likewise. - * target.c (target_can_do_hardware_single_step): New function. - * target.h (struct target_ops) : - Remove. : New field. - (target_supports_conditional_breakpoints): Remove. - (target_supports_hardware_single_step): New macro. - (target_can_do_hardware_single_step): Declare. - * server.c (handle_query): Use target_supports_hardware_single_step - instead of target_supports_conditional_breakpoints. - -2015-09-15 Yao Qi - - * linux-aarch64-low.c (aarch64_linux_siginfo_fixup): New - function. - (struct linux_target_ops the_low_target): Install - aarch64_linux_siginfo_fixup. - -2015-09-11 Don Breazeal - Luis Machado - - * linux-low.c (linux_mourn): Static declaration. - (linux_arch_setup): Move in front of - handle_extended_wait. - (linux_arch_setup_thread): New function. - (handle_extended_wait): Handle exec events. Call - linux_arch_setup_thread. Make event_lwp argument a - pointer-to-a-pointer. - (check_zombie_leaders): Do not check stopped threads. - (linux_low_ptrace_options): Add PTRACE_O_TRACEEXEC. - (linux_low_filter_event): Add lwp and thread for exec'ing - non-leader thread if leader thread has been deleted. - Refactor code into linux_arch_setup_thread and call it. - Pass child lwp pointer by reference to handle_extended_wait. - (linux_wait_for_event_filtered): Update comment. - (linux_wait_1): Prevent clobbering exec event status. - (linux_supports_exec_events): New function. - (linux_target_ops) : Initialize new member. - * lynx-low.c (lynx_target_ops) : Initialize - new member. - * remote-utils.c (prepare_resume_reply): New stop reason 'exec'. - * server.c (report_exec_events): New global variable. - (handle_query): Handle qSupported query for exec-events feature. - (captured_main): Initialize report_exec_events. - * server.h (report_exec_events): Declare new global variable. - * target.h (struct target_ops) : New - member. - (target_supports_exec_events): New macro. - * win32-low.c (win32_target_ops) : - Initialize new member. - -2015-09-09 Markus Metzger - - * linux-low.c (linux_low_enable_btrace): Remove. - (linux_target_ops): Replace linux_low_enable_btrace with - linux_enable_btrace. - -2015-09-03 Yao Qi - - * linux-aarch64-low.c (aarch64_insert_point): Call - aarch64_handle_watchpoint if aarch64_linux_region_ok_for_watchpoint - returns true. - -2015-08-27 Ulrich Weigand - - * linux-low.c (check_stopped_by_breakpoint): Use - GDB_ARCH_IS_TRAP_BRKPT instead of GDB_ARCH_TRAP_BRKPT. - -2015-08-27 Pedro Alves - - * proc-service.c (ps_pdwrite): Return PS_ERR/PS_OK explicily. - -2015-08-26 Simon Marchi - - * ax.c (gdb_parse_agent_expr): Replace xmalloc-family function with - the XNEW-family equivalent. - (compile_bytecodes): Likewise. - * dll.c (loaded_dll): Likewise. - * event-loop.c (append_callback_event): Likewise. - (create_file_handler): Likewise. - (create_file_event): Likewise. - * hostio.c (handle_open): Likewise. - * inferiors.c (add_thread): Likewise. - (add_process): Likewise. - * linux-aarch64-low.c (aarch64_linux_new_process): Likewise. - * linux-arm-low.c (arm_new_process): Likewise. - (arm_new_thread): Likewise. - * linux-low.c (add_to_pid_list): Likewise. - (linux_add_process): Likewise. - (handle_extended_wait): Likewise. - (add_lwp): Likewise. - (enqueue_one_deferred_signal): Likewise. - (enqueue_pending_signal): Likewise. - (linux_resume_one_lwp_throw): Likewise. - (linux_resume_one_thread): Likewise. - (linux_read_memory): Likewise. - (linux_write_memory): Likewise. - * linux-mips-low.c (mips_linux_new_process): Likewise. - (mips_linux_new_thread): Likewise. - (mips_add_watchpoint): Likewise. - * linux-x86-low.c (initialize_low_arch): Likewise. - * lynx-low.c (lynx_add_process): Likewise. - * mem-break.c (set_raw_breakpoint_at): Likewise. - (set_breakpoint): Likewise. - (add_condition_to_breakpoint): Likewise. - (add_commands_to_breakpoint): Likewise. - (clone_agent_expr): Likewise. - (clone_one_breakpoint): Likewise. - * regcache.c (new_register_cache): Likewise. - * remote-utils.c (look_up_one_symbol): Likewise. - * server.c (queue_stop_reply): Likewise. - (start_inferior): Likewise. - (queue_stop_reply_callback): Likewise. - (handle_target_event): Likewise. - * spu-low.c (fetch_ppc_memory): Likewise. - (store_ppc_memory): Likewise. - * target.c (set_target_ops): Likewise. - * thread-db.c (thread_db_load_search): Likewise. - (try_thread_db_load_1): Likewise. - * tracepoint.c (add_tracepoint): Likewise. - (add_tracepoint_action): Likewise. - (create_trace_state_variable): Likewise. - (cmd_qtdpsrc): Likewise. - (cmd_qtro): Likewise. - (add_while_stepping_state): Likewise. - * win32-low.c (child_add_thread): Likewise. - (get_image_name): Likewise. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (aarch64_linux_new_thread): Remove. - -2015-08-25 Yao Qi - - * Makefile.in (aarch64-linux.o): New rule. - * configure.srv (aarch64*-*-linux*): Append aarch64-linux.o to - srv_tgtobj. - * linux-aarch64-low.c: Include nat/aarch64-linux.h. - (aarch64_init_debug_reg_state): Make it extern. - (aarch64_linux_prepare_to_resume): Remove. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (aarch64_linux_prepare_to_resume): Use - lwp_arch_private_info and ptid_of_lwp. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (aarch64_get_debug_reg_state): Add argument pid. - Find proc_info by find_process_pid. All callers updated. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (struct arch64_dr_update_callback_param): - Remove. - (debug_reg_change_callback): Remove. - (aarch64_notify_debug_reg_change): Remove. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (aarch64_notify_debug_reg_change): - Call current_lwp_ptid. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (debug_reg_change_callback): Use - debug_printf. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (debug_reg_change_callback): Use phex. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (debug_reg_change_callback): Remove comments. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (debug_reg_change_callback): Re-indent - the code. - -2015-08-25 Yao Qi - - * linux-aarch64-low.c (aarch64_dr_update_callback_param) : - Remove. - (debug_reg_change_callback): Remove argument entry and add argument - lwp. Remove local variable thread. Don't print thread id in the - debugging output. Don't check whether pid of thread equals to pid. - (aarch64_notify_debug_reg_change): Don't set param.pid. Call - iterate_over_lwps instead find_inferior. - -2015-08-24 Pedro Alves - - * inferiors.c (get_first_process): New function. - * inferiors.h (get_first_process): New declaration. - * remote-utils.c (read_ptid): Default to the first process in the - list, instead of to the current thread's process. - -2015-08-24 Pedro Alves - - * debug.c: Include gdb_sys_time.h instead of sys/time.h. - * event-loop.c: Likewise. - * remote-utils.c: Likewise. - * tracepoint.c: Likewise. - -2015-08-24 Pedro Alves - - * spu-low.c (spu_request_interrupt): Use lwpid_of instead of - ptid_get_lwp. - -2015-08-21 Pedro Alves - - * ax.c (gdb_eval_agent_expr): Return expr_eval_unhandled_opcode - instead of literal 1. - -2015-08-21 Pedro Alves - - * tdesc.c (default_description): Explicitly zero-initialize. - -2015-08-21 Pedro Alves - - PR gdb/18749 - * inferiors.c (remove_thread): Discard any pending stop reply for - this thread. - * server.c (remove_all_on_match_pid): Rename to ... - (remove_all_on_match_ptid): ... this. Work with a filter ptid - instead of a pid. - (discard_queued_stop_replies): Change parameter to a ptid. Now - extern. - (handle_v_kill, kill_inferior_callback, captured_main) - (process_serial_event): Adjust. - * server.h (discard_queued_stop_replies): Declare. - -2015-08-21 Pedro Alves - - * linux-low.c (wait_for_sigstop): Always switch to no thread - selected if the previously current thread dies. - * lynx-low.c (lynx_request_interrupt): Use the first thread's - process instead of the current thread's. - * remote-utils.c (input_interrupt): Don't check if there's no - current thread. - * server.c (gdb_read_memory, gdb_write_memory): If setting the - current thread to the general thread fails, error out. - (handle_qxfer_auxv, handle_qxfer_libraries) - (handle_qxfer_libraries_svr4, handle_qxfer_siginfo) - (handle_qxfer_spu, handle_qxfer_statictrace, handle_qxfer_fdpic) - (handle_query): Check if there's a thread selected instead of - checking whether there's any thread in the thread list. - (handle_qxfer_threads, handle_qxfer_btrace) - (handle_qxfer_btrace_conf): Don't error out early if there's no - thread in the thread list. - (handle_v_cont, myresume): Don't set the current thread to the - continue thread. - (process_serial_event) : Also set thread_id if the - previous general thread is still alive. - (process_serial_event) : If setting the current - thread to the general thread fails, error out. - * spu-low.c (spu_resume, spu_request_interrupt): Use the first - thread's lwp instead of the current thread's. - * target.c (set_desired_thread): If the desired thread was not - found, leave the current thread pointing to NULL. Return an int - (boolean) indicating success. - * target.h (set_desired_thread): Change return type to int. - -2015-08-20 Max Filippov - - * configure.srv (xtensa*-*-linux*): Add srv_linux_thread_db=yes. - * linux-xtensa-low.c (arch/xtensa.h gdb_proc_service.h): New - #includes. - (ps_get_thread_area): New function. - -2015-08-19 Gary Benson - - * hostio.c (handle_pread): Do not attempt to read more data - than hostio_reply_with_data can fit in a packet. - -2015-08-18 Joel Brobecker - - * linux-aarch32-low.c (NT_ARM_VFP): Define if not already defined. - -2015-08-14 Matthew Fortune - - * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP_REL. - -2015-08-06 Pedro Alves - - * tracepoint.c (expr_eval_result): Now an int. - -2015-08-06 Pedro Alves - - * gdbthread.h (struct regcache): Forward declare. - (struct thread_info) : Now a struct regcache - pointer. - * inferiors.c (inferior_regcache_data) - (set_inferior_regcache_data): Now work with struct regcache - pointers. - * inferiors.h (struct regcache): Forward declare. - (inferior_regcache_data, set_inferior_regcache_data): Now work - with struct regcache pointers. - * regcache.c (get_thread_regcache, regcache_invalidate_thread) - (free_register_cache_thread): Remove struct regcache pointer - casts. - -2015-08-06 Pedro Alves - - * server.c (captured_main): On error, print the exception message - to stderr, and if run_once is set, throw a quit. - -2015-08-06 Pedro Alves - - * linux-low.c (move_out_of_jump_pad_callback): Temporarily switch - the current thread. - -2015-08-06 Pedro Alves - - * linux-low.c (linux_write_memory): Rewrite debug output to avoid - reading beyond the passed in buffer length. - -2015-08-06 Pierre Langlois - - * tracepoint.c (symbol_list) : Remove. - -2015-08-06 Pedro Alves - - * linux-low.c (handle_extended_wait): Set the fork child's suspend - count if stopping and suspending threads. - (check_stopped_by_breakpoint): If stopped by trace, set the LWP's - stop reason to TARGET_STOPPED_BY_SINGLE_STEP. - (linux_detach): Complete an ongoing step-over. - (lwp_suspended_inc, lwp_suspended_decr): New functions. Use - throughout. - (resume_stopped_resumed_lwps): Don't resume a suspended thread. - (linux_wait_1): If passing a signal to the inferior after - finishing a step-over, unsuspend and re-resume all lwps. If we - see a single-step event but the thread should be continuing, don't - pass the trap to gdb. - (stuck_in_jump_pad_callback, move_out_of_jump_pad_callback): Use - internal_error instead of gdb_assert. - (enqueue_pending_signal): New function. - (check_ptrace_stopped_lwp_gone): Add debug output. - (start_step_over): Use internal_error instead of gdb_assert. - (complete_ongoing_step_over): New function. - (linux_resume_one_thread): Don't resume a suspended thread. - (proceed_one_lwp): If the LWP is stepping over a breakpoint, reset - it stepping. - -2015-08-06 Pedro Alves - - * linux-low.c (add_lwp): Set waitstatus to TARGET_WAITKIND_IGNORE. - (linux_thread_alive): Use lwp_is_marked_dead. - (extended_event_reported): Delete. - (linux_wait_1): Check if waitstatus is TARGET_WAITKIND_IGNORE - instead of extended_event_reported. - (mark_lwp_dead): Don't set the 'dead' flag. Store the waitstatus - as well. - (lwp_is_marked_dead): New function. - (lwp_running): Use lwp_is_marked_dead. - * linux-low.h: Delete 'dead' field, and update 'waitstatus's - comment. - -2015-08-06 Pedro Alves - - * linux-low.c (linux_wait_1): Move fork event output out of the - !report_to_gdb check. Pass event_child->waitstatus to - target_waitstatus_to_string instead of ourstatus. - -2015-08-04 Yao Qi - - * linux-aarch64-low.c (aarch64_supports_tracepoints): Return 0 - if current_thread is 32 bit. - -2015-08-04 Yao Qi - - * linux-aarch64-low.c (aarch64_supports_z_point_type): Return - 0 for Z_PACKET_SW_BP if it may be used in multi-arch debugging. - * server.c (extended_protocol): Remove "static". - * server.h (extended_protocol): Declare it. - -2015-08-04 Yao Qi - - * linux-aarch64-low.c (aarch64_get_pc): Get PC register on - both aarch64 and aarch32. - (aarch64_set_pc): Likewise. - -2015-08-04 Yao Qi - - * configure.srv (case aarch64*-*-linux*): Append arm-with-neon.o - to srv_regobj and append arm-core.xml arm-vfpv3.xml and - arm-with-neon.xml to srv_xmlfiles. - * linux-aarch64-low.c: Include linux-aarch32-low.h. - (is_64bit_tdesc): New function. - (aarch64_linux_read_description): New function. - (aarch64_arch_setup): Call aarch64_linux_read_description. - (regs_info): Rename to regs_info_aarch64. - (aarch64_regs_info): Return right regs_info. - (initialize_low_arch): Call initialize_low_arch_aarch32. - -2015-08-04 Yao Qi - - * configure.srv (srv_tgtobj): Add linux-aarch32-low.o. - * linux-aarch32-low.c: New file. - * linux-aarch32-low.h: New file. - * linux-arm-low.c (arm_fill_gregset): Move it to - linux-aarch32-low.c. - (arm_store_gregset): Likewise. - (arm_fill_vfpregset): Call arm_fill_vfpregset_num - (arm_store_vfpregset): Call arm_store_vfpregset_num. - (arm_arch_setup): Check if PTRACE_GETREGSET works. - (regs_info): Rename to regs_info_arm. - (arm_regs_info): Return regs_info_aarch32 if - have_ptrace_getregset is 1 and target description is - arm_with_neon or arm_with_vfpv3. - (initialize_low_arch): Don't call init_registers_arm_with_neon. - Call initialize_low_arch_aarch32 instead. - -2015-08-04 Yao Qi - - * linux-x86-low.c (have_ptrace_getregset): Move it to ... - * linux-low.c: ... here. - * linux-low.h (have_ptrace_getregset): Declare it. - -2015-08-04 Pedro Alves - - * thread-db.c (struct thread_db): Use new typedefs. - (try_thread_db_load_1): Define local TDB_DLSYM macro and use it in - CHK calls. - (disable_thread_event_reporting): Cast result of dlsym to - destination function pointer type. - (thread_db_mourn): Use td_ta_delete_ftype. - -2015-08-03 Sandra Loosemore - - * linux-nios2-low.c (NIOS2_BREAKPOINT): Conditionalize for - arch variant. - (CDX_BREAKPOINT): Define for R2. - (nios2_breakpoint_at): Check for CDX_BREAKPOINT when R2. - (the_low_target): Add comments. - -2015-07-30 Yao Qi - - * linux-arm-low.c (arm_hwcap): Remove it. - (arm_read_description): New local variable arm_hwcap. Don't - set arm_hwcap to zero. - -2015-07-30 Yao Qi - - * linux-arm-low.c (arm_fill_wmmxregset): Don't use arm_hwcap. - Use regcache->tdesc instead. - (arm_store_wmmxregset): Likewise. - (arm_fill_vfpregset): Likewise. - (arm_store_vfpregset): Likewise. - -2015-07-30 Yao Qi - - * linux-arm-low.c: Include arch/arm.h. - (arm_fill_gregset): Don't use arm_num_regs and arm_regmap. - (arm_store_gregset): Likewise. - -2015-07-29 Simon Marchi - - * linux-mips-low.c (mips_linux_prepare_to_resume): Add NULL as - ptrace's 4th parameter. - -2015-07-27 Yao Qi - - * configure.srv (case aarch64*-*-linux*): Don't set - srv_linux_usrregs. - -2015-07-24 Pedro Alves - - * linux-aarch64-low.c: Include nat/gdb_ptrace.h instead of - sys/ptrace.h. - * linux-arm-low.c: Likewise. - * linux-cris-low.c: Likewise. - * linux-crisv32-low.c: Likewise. - * linux-low.c: Likewise. - * linux-m68k-low.c: Likewise. - * linux-mips-low.c: Likewise. - * linux-nios2-low.c: Likewise. - * linux-s390-low.c: Likewise. - * linux-sparc-low.c: Likewise. - * linux-tic6x-low.c: Likewise. - * linux-tile-low.c: Likewise. - * linux-x86-low.c: Likewise. - -2015-07-24 Pedro Alves - - * config.in: Regenerate. - * configure: Regenerate. - -2015-07-24 Pedro Alves - - * acinclude.m4: Include ../ptrace.m4. - * configure.ac: Call GDB_AC_PTRACE. - * config.in, configure: Regenerate. - -2015-07-24 Yao Qi - - * linux-low.c (linux_create_inferior): Remove setting to - proc->priv->new_inferior. - (linux_attach): Likewise. - (linux_low_filter_event): Likewise. - * linux-low.h (struct process_info_private) : Remove. - -2015-07-24 Yao Qi - - * linux-low.c (linux_arch_setup): New function. - (linux_low_filter_event): If proc->tdesc is NULL and - proc->attached is true, call the_low_target.arch_setup. - Otherwise, keep status pending, and return. - (linux_resume_one_lwp_throw): Don't call get_pc if - thread->while_stepping isn't NULL. Don't call - get_thread_regcache if proc->tdesc is NULL. - (need_step_over_p): Return 0 if proc->tdesc is NULL. - (linux_target_ops): Install arch_setup. - * server.c (start_inferior): Call the_target->arch_setup. - * target.h (struct target_ops) : New field. - (target_arch_setup): New marco. - * lynx-low.c (lynx_target_ops): Update. - * nto-low.c (nto_target_ops): Update. - * spu-low.c (spu_target_ops): Update. - * win32-low.c (win32_target_ops): Update. - -2015-07-24 Yao Qi - - * linux-low.c (linux_add_process): Don't set - proc->priv->new_inferior. - (linux_create_inferior): Set proc->priv->new_inferior to 1. - (linux_attach): Likewise. - -2015-07-24 Yao Qi - - * server.c (start_inferior): Code refactor. - -2015-07-24 Yao Qi - - * server.c (process_serial_event): Set general_thread. - -2015-07-21 Yao Qi - - * linux-aarch64-low.c (aarch64_arch_setup): Remove code and call - aarch64_linux_get_debug_reg_capacity. - -2015-07-17 Yao Qi - - * Makefile.in (aarch64-linux-hw-point.o): New rule. - * configure.srv (srv_tgtobj): Append aarch64-linux-hw-point.o. - * linux-aarch64-low.c: Include nat/aarch64-linux-hw-point.h. - (AARCH64_HBP_MAX_NUM): Move to nat/aarch64-linux-hw-point.h. - (AARCH64_HWP_MAX_NUM, AARCH64_HBP_ALIGNMENT): Likewise. - (AARCH64_HWP_ALIGNMENT): Likewise. - (AARCH64_HWP_MAX_LEN_PER_REG): Likewise. - (AARCH64_DEBUG_NUM_SLOTS, AARCH64_DEBUG_ARCH): Likewise. - (aarch64_num_bp_regs, aarch64_num_wp_regs): Likewise. - (AARCH64_DEBUG_ARCH_V8, DR_MARK_ALL_CHANGED): Likewise. - (DR_MARK_N_CHANGED, DR_CLEAR_CHANGED): Likewise. - (DR_HAS_CHANGED, DR_N_HAS_CHANGE): Likewise. - (struct aarch64_debug_reg_state): Likewise. - (struct arch_lwp_info): Likewise. - (aarch64_align_watchpoint): Likewise. - (DR_CONTROL_ENABLED, DR_CONTROL_LENGTH): Likewise. - (aarch64_watchpoint_length): Likewise. - (aarch64_point_encode_ctrl_reg): Likewise - (aarch64_point_is_aligned): Likewise. - (aarch64_align_watchpoint): Likewise. - (aarch64_linux_set_debug_regs): - (aarch64_dr_state_insert_one_point): Likewise. - (aarch64_dr_state_remove_one_point): Likewise. - (aarch64_handle_breakpoint): Likewise. - (aarch64_handle_aligned_watchpoint): Likewise. - (aarch64_handle_unaligned_watchpoint): Likewise. - (aarch64_handle_watchpoint): Likewise. - -2015-07-17 Yao Qi - - * linux-aarch64-low.c (aarch64_handle_breakpoint): Add argument state - and don't aarch64_get_debug_reg_state. All callers update. - (aarch64_handle_aligned_watchpoint): Likewise. - (aarch64_handle_unaligned_watchpoint): Likewise. - (aarch64_handle_watchpoint): Likewise. - (aarch64_insert_point): Call aarch64_get_debug_reg_state earlier. - (aarch64_remove_point): Likewise. - -2015-07-17 Yao Qi - - * linux-aarch64-low.c (aarch64_show_debug_reg_state): Use - debug_printf. - (aarch64_handle_unaligned_watchpoint): Likewise. - -2015-07-15 Jan Kratochvil - - Revert the previous 3 commits: - Move gdb_regex* to common/ - Move linux_find_memory_regions_full & co. - gdbserver build-id attribute generator - -2015-07-15 Aleksandar Ristovski - - gdbserver build-id attribute generator. - * linux-low.c (nat/linux-maps.h, search.h, rsp-low.h): Include. - (ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New. - (ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New. - (find_phdr): New. - (get_dynamic): Use find_pdhr to traverse program headers. - (struct mapping_entry, mapping_entry_s, free_mapping_entry_vec) - (compare_mapping_entry_range, struct find_memory_region_callback_data) - (read_build_id, find_memory_region_callback, lrfind_mapping_entry) - (get_hex_build_id): New. - (linux_qxfer_libraries_svr4): Add optional build-id attribute - to reply XML document. - -2015-07-15 Aleksandar Ristovski - - * target.c: Include target/target-utils.h and fcntl.h. - (target_fileio_read_stralloc_1_pread, target_fileio_read_stralloc_1) - (target_fileio_read_stralloc): New functions. - -2015-07-15 Jan Kratochvil - - * Makefile.in (OBS): Add gdb_regex.o. - (gdb_regex.o): New. - * config.in: Rebuilt. - * configure: Rebuilt. - -2015-07-15 Aleksandar Ristovski - - Create empty nat/linux-maps.[ch] and common/target-utils.[ch]. - * Makefile.in (OBS): Add target-utils.o. - (linux-maps.o, target-utils.o): New. - * configure.srv (srv_linux_obj): Add linux-maps.o. - -2015-07-15 Pierre Langlois - - * linux-aarch64-low.c (aarch64_supports_range_stepping): New - function, return 1. - (the_low_target): Install it. - -2015-07-14 Pedro Alves - - * linux-low.c (kill_wait_lwp): Don't assert if waitpid fails. - Instead, ignore ECHILD, and throw an error for other errnos. - -2015-07-10 Pedro Alves - - * event-loop.c (struct callback_event) : Change type to - gdb_client_data instance instead of gdb_client_data pointer. - (append_callback_event): Adjust. - -2015-07-10 Pierre Langlois - - * linux-aarch64-low.c: Add comments for each linux_target_ops - method. Remove comments already covered in target_ops and - linux_target_ops definitions. - (the_low_target): Add comments for each unimplemented method. - -2015-07-09 Yao Qi - - * linux-aarch64-low.c (aarch64_regmap): Remove. - (aarch64_usrregs_info): Remove. - (regs_info): Set field usrregs to NULL. - -2015-07-02 Markus Metzger - - * linux-low.c: Include "rsp-low.h" - (linux_low_encode_pt_config, linux_low_encode_raw): New. - (linux_low_read_btrace): Support BTRACE_FORMAT_PT. - (linux_low_btrace_conf): Support BTRACE_FORMAT_PT. - (handle_btrace_enable_pt): New. - (handle_btrace_general_set): Support "pt". - (handle_btrace_conf_general_set): Support "pt:size". - -2015-06-29 Pierre Langlois - - * linux-aarch64-low.c (aarch64_supports_z_point_type): Enable for - Z_PACKET_SW_BP. - -2015-06-29 Pierre Langlois - - * linux-aarch64-low.c: Remove comment about endianness. - (aarch64_breakpoint): Change type to gdb_byte[]. Set to "brk #0". - (aarch64_breakpoint_at): Change type of insn to gdb_byte[]. Use - memcmp. - -2015-06-24 Gary Benson - - * linux-i386-ipa.c (stdint.h): Do not include. - * lynx-i386-low.c (stdint.h): Likewise. - * lynx-ppc-low.c (stdint.h): Likewise. - * mem-break.c (stdint.h): Likewise. - * thread-db.c (stdint.h): Likewise. - * tracepoint.c (stdint.h): Likewise. - * win32-low.c (stdint.h): Likewise. - -2015-06-18 Simon Marchi - - * server.c (write_qxfer_response): Update call to - remote_escape_output. - -2015-06-15 Aleksandar Ristovski - - Merge multiple hex conversions. - * gdbreplay.c (tohex): Rename to 'fromhex'. - (logchar): Use fromhex. - -2015-06-10 Jan Kratochvil - - * server.c (handle_qxfer_libraries): Set `version' attribute for - . - -2015-06-10 Gary Benson - - * target.h (struct target_ops) : New field. - : Likewise. - : Likewise. - * linux-low.c (nat/linux-namespaces.h): New include. - (linux_target_ops): Initialize the_target->multifs_open, - the_target->multifs_unlink and the_target->multifs_readlink. - * hostio.h (hostio_handle_new_gdb_connection): New declaration. - * hostio.c (hostio_fs_pid): New static variable. - (hostio_handle_new_gdb_connection): New function. - (handle_setfs): Likewise. - (handle_open): Use the_target->multifs_open as appropriate. - (handle_unlink): Use the_target->multifs_unlink as appropriate. - (handle_readlink): Use the_target->multifs_readlink as - appropriate. - (handle_vFile): Handle vFile:setfs packets. - * server.c (handle_query): Call hostio_handle_new_gdb_connection - after target_handle_new_gdb_connection. - -2015-06-10 Gary Benson - - * configure.ac (AC_CHECK_FUNCS): Add setns. - * config.in: Regenerate. - * configure: Likewise. - * Makefile.in (SFILES): Add nat/linux-namespaces.c. - (linux-namespaces.o): New rule. - * configure.srv (srv_linux_obj): Add linux-namespaces.o. - -2015-06-09 Gary Benson - - * hostio.c (handle_open): Process mode argument with - fileio_to_host_mode. - -2015-06-01 Yao Qi - - * linux-s390-low.c (PTRACE_GETREGSET, PTRACE_SETREGSET): Remove. - * linux-x86-low.c: Likewise. - -2015-05-28 Don Breazeal - - * linux-low.c (handle_extended_wait): Initialize - thread_info.last_resume_kind for new fork children. - -2015-05-15 Pedro Alves - - * target.h (target_handle_new_gdb_connection): Rewrite using if - wrapped in do/while. - -2015-05-14 Joel Brobecker - - * configure.ac: Add prfpregset_t BFD_HAVE_SYS_PROCFS_TYPE check. - * configure, config.in: Regenerate. - * gdb_proc_service.h [HAVE_PRFPREGSET_T] (prfpregset_t): - Declare typedef. - -2015-05-12 Don Breazeal - - * linux-low.c (handle_extended_wait): Handle PTRACE_EVENT_FORK and - PTRACE_EVENT_VFORK_DONE. - (linux_low_ptrace_options, extended_event_reported): Add vfork - events. - * remote-utils.c (prepare_resume_reply): New stop reasons "vfork" - and "vforkdone" for RSP 'T' Stop Reply Packet. - * server.h (report_vfork_events): Declare - global variable. - -2015-05-12 Don Breazeal - - * linux-aarch64-low.c (aarch64_linux_new_fork): New function. - (the_low_target) : Initialize new member. - * linux-arm-low.c (arm_new_fork): New function. - (the_low_target) : Initialize new member. - * linux-low.c (handle_extended_wait): Call new target function - new_fork. - * linux-low.h (struct linux_target_ops) : New member. - * linux-mips-low.c (mips_add_watchpoint): New function - extracted from mips_insert_point. - (the_low_target) : Initialize new member. - (mips_linux_new_fork): New function. - (mips_insert_point): Call mips_add_watchpoint. - * linux-x86-low.c (x86_linux_new_fork): New function. - (the_low_target) : Initialize new member. - -2015-05-12 Don Breazeal - - * linux-low.c (handle_extended_wait): Implement return value, - rename argument 'event_child' to 'event_lwp', handle - PTRACE_EVENT_FORK, call internal_error for unrecognized event. - (linux_low_ptrace_options): New function. - (linux_low_filter_event): Call linux_low_ptrace_options, - use different argument fo linux_enable_event_reporting, - use return value from handle_extended_wait. - (extended_event_reported): New function. - (linux_wait_1): Call extended_event_reported and set - status to report fork events. - (linux_write_memory): Add pid to debug message. - (reset_lwp_ptrace_options_callback): New function. - (linux_handle_new_gdb_connection): New function. - (linux_target_ops): Initialize new structure member. - * linux-low.h (struct lwp_info) : New member. - * lynx-low.c: Initialize new structure member. - * remote-utils.c (prepare_resume_reply): Implement stop reason - "fork" for "T" stop message. - * server.c (handle_query): Call handle_new_gdb_connection. - * server.h (report_fork_events): Declare global flag. - * target.h (struct target_ops) : - New member. - (target_handle_new_gdb_connection): New macro. - * win32-low.c: Initialize new structure member. - -2015-05-12 Don Breazeal - - * mem-break.c (APPEND_TO_LIST): Define macro. - (clone_agent_expr): New function. - (clone_one_breakpoint): New function. - (clone_all_breakpoints): New function. - * mem-break.h: Declare new functions. - -2015-05-12 Don Breazeal - - * linux-low.c (linux_supports_fork_events): New function. - (linux_supports_vfork_events): New function. - (linux_target_ops): Initialize new structure members. - (initialize_low): Call linux_check_ptrace_features. - * lynx-low.c (lynx_target_ops): Initialize new structure - members. - * server.c (report_fork_events, report_vfork_events): - New global flags. - (handle_query): Add new features to qSupported packet and - response. - (captured_main): Initialize new global variables. - * target.h (struct target_ops) : - New member. - : New member. - (target_supports_fork_events): New macro. - (target_supports_vfork_events): New macro. - * win32-low.c (win32_target_ops): Initialize new structure - members. - -2015-05-12 Gary Benson - - * server.c (handle_qxfer_exec_file): Use current process - if annex is empty. - -2015-05-08 Sandra Loosemore - - * linux-nios2-low.c: Include elf/common.h. Adjust comments. - Remove HAVE_PTRACE_GETREGS conditionals. - (nios2_regsets): Use PTRACE_GETREGSET and PTRACE_SETREGSET - instead of PTRACE_GETREGS and PTRACE_SETREGS. - -2015-05-08 Yao Qi - - * linux-low.c (linux_supports_conditional_breakpoints): New - function. - (linux_target_ops): Install new target method. - * lynx-low.c (lynx_target_ops): Install NULL hook for - supports_conditional_breakpoints. - * nto-low.c (nto_target_ops): Likewise. - * spu-low.c (spu_target_ops): Likewise. - * win32-low.c (win32_target_ops): Likewise. - * server.c (handle_query): Check - target_supports_conditional_breakpoints. - * target.h (struct target_ops) : - New field. - (target_supports_conditional_breakpoints): New macro. - -2015-05-06 Pedro Alves - - PR server/18081 - * server.c (start_inferior): If the process exits, mourn it. - -2015-04-21 Gary Benson - - * hostio.c (fileio_open_flags_to_host): Factored out to - fileio_to_host_openflags in common/fileio.c. Single use - updated. - -2015-04-17 Max Filippov - - * linux-xtensa-low.c (xtensa_fill_gregset) - (xtensa_store_gregset): Check XCHAL_HAVE_LOOPS instead of - XCHAL_HAVE_LOOP. - -2015-04-17 Max Filippov - - * linux-xtensa-low.c (xtensa_usrregs_info): Remove. - (regs_info): Replace usrregs pointer with NULL. - -2015-04-17 Gary Benson - - * target.h (struct target_ops) : New field. - * linux-low.c (linux_target_ops): Initialize pid_to_exec_file. - * server.c (handle_qxfer_exec_file): New function. - (qxfer_packets): Add exec-file entry. - (handle_query): Report qXfer:exec-file:read as supported packet. - -2015-04-14 Romain Naour (tiny change) - - * linux-low.c (linux_read_offsets): Remove get_thread_lwp. - -2015-04-09 Gary Benson - - * hostio-errno.c (errno_to_fileio_error): Remove function. - Update caller to use remote_fileio_to_fio_error. - -2015-04-09 Yao Qi - - * linux-low.c (linux_insert_point): Call - insert_memory_breakpoint if TYPE is raw_bkpt_type_sw. - (linux_remove_point): Call remove_memory_breakpoint if type is - raw_bkpt_type_sw. - * linux-x86-low.c (x86_insert_point): Don't call - insert_memory_breakpoint. - (x86_remove_point): Don't call remove_memory_breakpoint. - -2015-04-01 Pedro Alves - Cleber Rosa - - * server.c (gdbserver_usage): Reorganize and extend the usage - message. - -2015-03-24 Pedro Alves - - * linux-low.c (check_stopped_by_breakpoint): Tweak debug log - output. Also dump TRAP_TRACE. - (linux_low_filter_event): In debug output, distinguish a - resume_stop SIGSTOP from a delayed SIGSTOP. - -2015-03-24 Gary Benson - - * linux-x86-low.c (x86_linux_new_thread): Moved to - nat/x86-linux.c. - (x86_linux_prepare_to_resume): Likewise. - -2015-03-24 Gary Benson - - * Makefile.in (x86-linux-dregs.o): New rule. - * configure.srv: Add x86-linux-dregs.o to relevant targets. - * linux-x86-low.c: Include nat/x86-linux-dregs.h. - (u_debugreg_offset): Moved to nat/x86-linux-dregs.c. - (x86_linux_dr_get): Likewise. - (x86_linux_dr_set): Likewise. - (update_debug_registers_callback): Likewise. - (x86_linux_dr_set_addr): Likewise. - (x86_linux_dr_get_addr): Likewise. - (x86_linux_dr_set_control): Likewise. - (x86_linux_dr_get_control): Likewise. - (x86_linux_dr_get_status): Likewise. - (x86_linux_update_debug_registers): Likewise. - -2015-03-24 Gary Benson - - * linux-x86-low.c (x86_linux_update_debug_registers): - New function, factored out from... - (x86_linux_prepare_to_resume): ...this. - -2015-03-24 Gary Benson - - * linux-x86-low.c (x86_linux_dr_get): Update comments. - (x86_linux_dr_set): Likewise. - (update_debug_registers_callback): Likewise. - (x86_linux_dr_set_addr): Likewise. - (x86_linux_dr_get_addr): Likewise. - (x86_linux_dr_set_control): Likewise. - (x86_linux_dr_get_control): Likewise. - (x86_linux_dr_get_status): Likewise. - (x86_linux_prepare_to_resume): Likewise. - -2015-03-24 Gary Benson - - * linux-x86-low.c (x86_linux_dr_get): Add assertion. - Use perror_with_name. Pass string through gettext. - (x86_linux_dr_set): Likewise. - -2015-03-24 Gary Benson - - * linux-x86-low.c (x86_dr_low_set_addr): Rename to... - (x86_linux_dr_set_addr): ...this. - (x86_dr_low_get_addr): Rename to... - (x86_linux_dr_get_addr): ...this. - (x86_dr_low_set_control): Rename to... - (x86_linux_dr_set_control): ...this. - (x86_dr_low_get_control): Rename to... - (x86_linux_dr_get_control): ...this. - (x86_dr_low_get_status): Rename to... - (x86_linux_dr_get_status): ...this. - (x86_dr_low): Update with new function names. - -2015-03-24 Gary Benson - - * Makefile.in (x86-linux.o): New rule. - * configure.srv: Add x86-linux.o to relevant targets. - * linux-low.c (lwp_set_arch_private_info): New function. - (lwp_arch_private_info): Likewise. - * linux-x86-low.c: Include nat/x86-linux.h. - (arch_lwp_info): Removed structure. - (update_debug_registers_callback): - Use lwp_set_debug_registers_changed. - (x86_linux_prepare_to_resume): Use lwp_debug_registers_changed - and lwp_set_debug_registers_changed. - (x86_linux_new_thread): Use lwp_set_debug_registers_changed. - -2015-03-24 Gary Benson - - * linux-low.h (linux_target_ops) : Changed signature. - * linux-arm-low.c (arm_new_thread): Likewise. - * linux-aarch64-low.c (aarch64_linux_new_thread): Likewise. - * linux-mips-low.c (mips_linux_new_thread): Likewise. - * linux-x86-low.c (x86_linux_new_thread): Likewise. - * linux-low.c (add_lwp): Update the_low_target.new_thread call. - -2015-03-24 Gary Benson - - * linux-low.c (ptid_of_lwp): New function. - (lwp_is_stopped): Likewise. - (lwp_stop_reason): Likewise. - * linux-x86-low.c (update_debug_registers_callback): - Use lwp_is_stopped. - (x86_linux_prepare_to_resume): Use ptid_of_lwp and - lwp_stop_reason. - -2015-03-24 Gary Benson - - * linux-low.h (linux_stop_lwp): Remove declaration. - -2015-03-24 Gary Benson - - * linux-low.h: Include nat/linux-nat.h. - * linux-low.c (iterate_over_lwps_args): New structure. - (iterate_over_lwps_filter): New function. - (iterate_over_lwps): Likewise. - * linux-x86-low.c (update_debug_registers_callback): - Update signature to what iterate_over_lwps expects. - Remove PID check that iterate_over_lwps now performs. - (x86_dr_low_set_addr): Use iterate_over_lwps. - (x86_dr_low_set_control): Likewise. - -2015-03-24 Gary Benson - - * linux-x86-low.c (x86_debug_reg_state): New function. - (x86_linux_prepare_to_resume): Use the above. - -2015-03-24 Gary Benson - - * linux-low.c (current_lwp_ptid): New function. - * linux-x86-low.c: Include nat/linux-nat.h. - (x86_dr_low_get_addr): Use current_lwp_ptid. - (x86_dr_low_get_control): Likewise. - (x86_dr_low_get_status): Likewise. - -2015-03-20 Pedro Alves - - * tracepoint.c (cmd_qtstatus): Make "str" const. - -2015-03-20 Pedro Alves - - * server.c (handle_general_set): Make "req_str" const. - -2015-03-19 Pedro Alves - - * linux-low.c (linux_resume_one_lwp): Rename to ... - (linux_resume_one_lwp_throw): ... this. Don't handle ESRCH here, - instead call perror_with_name. - (check_ptrace_stopped_lwp_gone): New function. - (linux_resume_one_lwp): Reimplement as wrapper around - linux_resume_one_lwp_throw that swallows errors if the LWP is - gone. - -2015-03-19 Pedro Alves - - * linux-low.c (count_events_callback, select_event_lwp_callback): - No longer check whether the thread has resume_stop as last resume - kind. - -2015-03-19 Pedro Alves - - * linux-low.c (count_events_callback, select_event_lwp_callback): - Use the lwp's status_pending_p field, not the thread's. - -2015-03-19 Pedro Alves - - * linux-low.c (select_event_lwp_callback): Update comments to - no longer mention SIGTRAP. - -2015-03-18 Gary Benson - - * server.c (handle_query): Do not report vFile:fstat as supported. - -2015-03-11 Gary Benson - - * hostio.c (sys/types.h): New include. - (sys/stat.h): Likewise. - (common-remote-fileio.h): Likewise. - (handle_fstat): New function. - (handle_vFile): Handle vFile:fstat packets. - -2015-03-11 Gary Benson - - * configure.ac (AC_CHECK_MEMBERS): Add checks for - struct stat.st_blocks and struct stat.st_blksize. - * configure: Regenerate. - * config.in: Likewise. - * Makefile.in (SFILES): Add common/common-remote-fileio.c. - (OBS): Add common-remote-fileio.o. - (common-remote-fileio.o): New rule. - -2015-03-09 Pedro Alves - - * tracepoint.c (gdb_agent_helper_thread): Cast '&sockaddr' to - 'struct sockaddr' pointer in 'accept' call. - -2015-03-09 Pedro Alves - - Revert: - 2015-03-07 Pedro Alves - * gdbreplay.c: No longer include , , - or here. Instead include "gdb_socket.h". - (remote_open): Use union gdb_sockaddr_u. - * remote-utils.c: No longer include , - or here. Instead include "gdb_socket.h". - (handle_accept_event, remote_prepare): Use union gdb_sockaddr_u. - * tracepoint.c: Include "gdb_socket.h" instead of - or . - (init_named_socket, gdb_agent_helper_thread): Use union - gdb_sockaddr_u. - -2015-03-07 Pedro Alves - - * configure.ac (build_warnings): Move - -Wdeclaration-after-statement to the C-specific set. - * configure: Regenerate. - -2015-03-07 Pedro Alves - - * gdbreplay.c: No longer include , , - or here. Instead include "gdb_socket.h". - (remote_open): Use union gdb_sockaddr_u. - * remote-utils.c: No longer include , - or here. Instead include "gdb_socket.h". - (handle_accept_event, remote_prepare): Use union gdb_sockaddr_u. - * tracepoint.c: Include "gdb_socket.h" instead of - or . - (init_named_socket, gdb_agent_helper_thread): Use union - gdb_sockaddr_u. - -2015-03-07 Pedro Alves - - Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH - instead. - -2015-03-06 Yao Qi - - * linux-aarch64-low.c (aarch64_insert_point): Use - show_debug_regs as a boolean. - (aarch64_remove_point): Likewise. - -2015-03-05 Pedro Alves - - * lynx-low.c (lynx_target_ops): Install NULL hooks for - stopped_by_sw_breakpoint, supports_stopped_by_sw_breakpoint, - stopped_by_hw_breakpoint, supports_stopped_by_hw_breakpoint. - * nto-low.c (nto_target_ops): Likewise. - * spu-low.c (spu_target_ops): Likewise. - * win32-low.c (win32_target_ops): Likewise. - -2015-03-04 Pedro Alves - - * linux-low.c (check_stopped_by_breakpoint) [USE_SIGTRAP_SIGINFO]: - Decide whether a breakpoint triggered based on the SIGTRAP's - siginfo.si_code. - (thread_still_has_status_pending_p) [USE_SIGTRAP_SIGINFO]: Don't check whether a - breakpoint is inserted if relying on SIGTRAP's siginfo.si_code. - (linux_low_filter_event): Check for breakpoints before checking - watchpoints. - (linux_wait_1): Don't re-increment the PC if relying on SIGTRAP's - siginfo.si_code. - (linux_stopped_by_sw_breakpoint) - (linux_supports_stopped_by_sw_breakpoint) - (linux_stopped_by_hw_breakpoint) - (linux_supports_stopped_by_hw_breakpoint): New functions. - (linux_target_ops): Install new target methods. - -2015-03-04 Pedro Alves - - * remote-utils.c (prepare_resume_reply): Report swbreak/hbreak. - * server.c (swbreak_feature, hwbreak_feature): New globals. - (handle_query) : Handle "swbreak+" and "hwbreak+". - (captured_main): Clear swbreak_feature and hwbreak_feature. - * server.h (swbreak_feature, hwbreak_feature): Declare. - * target.h (struct target_ops) : New fields. - (target_supports_stopped_by_sw_breakpoint) - (target_stopped_by_sw_breakpoint) - (target_supports_stopped_by_hw_breakpoint) - (target_stopped_by_hw_breakpoint): Declare. - -2015-03-04 Pedro Alves - - enum lwp_stop_reason -> enum target_stop_reason - * linux-low.c (check_stopped_by_breakpoint): Adjust. - (thread_still_has_status_pending_p, check_stopped_by_watchpoint) - (linux_wait_1, stuck_in_jump_pad_callback) - (move_out_of_jump_pad_callback, linux_resume_one_lwp) - (linux_stopped_by_watchpoint): - * linux-low.h (enum lwp_stop_reason): Delete. - (struct lwp_info) : Now an enum target_stop_reason. - * linux-x86-low.c (x86_linux_prepare_to_resume): Adjust. - -2015-03-04 Yao Qi - - * Makefile.in (SFILES): Add linux-aarch64-low.c. - -2015-03-03 Gary Benson - - * hostio.c (handle_vFile): Fix prefix lengths. - -2015-03-03 Markus Metzger - - * linux-low.c (linux_low_enable_btrace): Do not overwrite non-zero - ptr_bits. - -2015-03-02 Andreas Arnez - - * Makefile.in (s390-vx-linux64.c, s390-tevx-linux64.c) - (s390x-vx-linux64.c, s390x-tevx-linux64.c): New rules. - (clean): Add "rm -f" for above C files. - * configure.srv (srv_regobj): Add s390-vx-linux64.o, - s390-tevx-linux64.o, s390x-vx-linux64.o, and s390x-tevx-linux64.o. - (srv_xmlfiles): Add s390-vx-linux64.xml, s390-tevx-linux64.xml, - s390x-vx-linux64.xml, s390x-tevx-linux64.xml, and s390-vx.xml. - * linux-s390-low.c (HWCAP_S390_VX): New macro. - (init_registers_s390_vx_linux64, init_registers_s390_tevx_linux64) - (init_registers_s390x_vx_linux64) - (init_registers_s390x_tevx_linux64) - (tdesc_s390_vx_linux64, tdesc_s390_tevx_linux64) - (tdesc_s390x_vx_linux64, tdesc_s390x_tevx_linux64): New extern - declarations. - (s390_fill_vxrs_low, s390_store_vxrs_low, s390_fill_vxrs_high) - (s390_store_vxrs_high): New functions. - (s390_regsets): Add entries for NT_S390_VXRS_LOW and - NT_S390_VXRS_HIGH. - (s390_arch_setup): Add logic for selecting one of the new target - descriptions. Activate the new vector regsets if applicable. - (initialize_low_arch): Also invoke init_registers_s390_vx_linux64, - init_registers_s390_tevx_linux64, init_registers_s390x_vx_linux64, - and init_registers_s390x_tevx_linux64. - -2015-03-01 Pedro Alves - - * linux-i386-ipa.c (gdb_agent_get_raw_reg): Constify 'raw_regs' - parameter. - -2015-02-27 Pedro Alves - - * linux-x86-low.c (u_debugreg_offset): New function. - (x86_linux_dr_get, x86_linux_dr_set): Use it. - -2015-02-27 Pedro Alves - - * gdb_proc_service.h: Wrap with EXTERN_C_PUSH/EXTERN_C_POP. - [!HAVE_PROC_SERVICE_H] (struct ps_prochandle): Forward declare. - [!HAVE_PROC_SERVICE_H] (ps_pdread, ps_pdwrite, ps_ptread) - ps_ptwrite, ps_lgetregs, ps_lsetregs, ps_lgetfpregs) - (ps_lsetfpregs, ps_getpid) - (ps_get_thread_area, ps_pglobal_lookup, ps_pstop, ps_pcontinue) - (ps_lstop, ps_lcontinue, ps_lgetxregsize, ps_lgetxregs) - (ps_lsetxregs, ps_plog): Declare. - -2015-02-27 Pedro Alves - - * linux-amd64-ipa.c (gdb_agent_get_raw_reg): Use - IP_AGENT_EXPORT_FUNC. - * linux-i386-ipa.c (gdb_agent_get_raw_reg): Use - IP_AGENT_EXPORT_FUNC. - * tracepoint.c (ATTR_USED, ATTR_NOINLINE, ATTR_CONSTRUCTOR) - (IP_AGENT_EXPORT): Delete. - (gdb_tp_heap_buffer, gdb_jump_pad_buffer, gdb_jump_pad_buffer_end) - (gdb_trampoline_buffer, gdb_trampoline_buffer_end) - (gdb_trampoline_buffer_error, collecting, gdb_collect) - (stop_tracing, flush_trace_buffer, about_to_request_buffer_space) - (trace_buffer_is_full, stopping_tracepoint, expr_eval_result) - (error_tracepoint, tracepoints, tracing, trace_buffer_ctrl) - (trace_buffer_ctrl_curr, trace_buffer_lo, trace_buffer_hi) - (traceframe_read_count, traceframe_write_count) - (traceframes_created, trace_state_variables, get_raw_reg) - (get_trace_state_variable_value, set_trace_state_variable_value) - (ust_loaded, helper_thread_id, cmd_buf): Use - IPA_SYM_EXPORTED_NAME. - (stop_tracing, flush_trace_buffer): Use IP_AGENT_EXPORT_FUNC. - (tracepoints) Use IP_AGENT_EXPORT_VAR. - (stopping_tracepoint, trace_buffer_is_full, expr_eval_result): Use - IP_AGENT_EXPORT_VAR and wrap in EXTERN_C_PUSH/EXTERN_C_POP. - (last_tracepoint): Move into !IN_PROCESS_AGENT block. - (error_tracepoint): Use IP_AGENT_EXPORT_VAR and wrap in - EXTERN_C_PUSH/EXTERN_C_POP. - (trace_state_variables): Use IP_AGENT_EXPORT_VAR. - (trace_buffer_lo, trace_buffer_hi): Use IP_AGENT_EXPORT_VAR and - wrap in EXTERN_C_PUSH/EXTERN_C_POP. - (trace_buffer_ctrl, trace_buffer_ctrl_curr) - (traceframe_write_count, traceframe_read_count) - (traceframes_created, tracing): Use IP_AGENT_EXPORT_VAR. - (about_to_request_buffer_space, get_trace_state_variable_value) - (set_trace_state_variable_value): Use IP_AGENT_EXPORT_FUNC. - (collecting): Use IP_AGENT_EXPORT_VAR and wrap in - EXTERN_C_PUSH/EXTERN_C_POP. - (gdb_collect): Use IP_AGENT_EXPORT_FUNC. - (ust_loaded, cmd_buf): Use IP_AGENT_EXPORT_VAR. - (helper_thread_id, gdb_agent_capability): Use IP_AGENT_EXPORT_VAR - and wrap in EXTERN_C_PUSH/EXTERN_C_POP. - (gdb_tp_heap_buffer, gdb_jump_pad_buffer, gdb_jump_pad_buffer_end) - (gdb_trampoline_buffer, gdb_trampoline_buffer_end) - (gdb_trampoline_buffer_error): Use IP_AGENT_EXPORT_VAR. - * tracepoint.h (ATTR_USED, ATTR_NOINLINE, EXPORTED_SYMBOL): - Define. - (IP_AGENT_EXPORT_FUNC, IP_AGENT_EXPORT_VAR) - (IP_AGENT_EXPORT_VAR_DECL): Define. - (tracing): Declare. - (gdb_agent_get_raw_reg): Declare. - -2015-02-27 Tom Tromey - Pedro Alves - - Rename symbols whose names are reserved C++ keywords throughout. - -2015-02-27 Pedro Alves - - * Makefile.in (COMPILER): New, get it from autoconf. - (CXX): Get from autoconf instead. - (COMPILE.pre): Use COMPILER. - (CC-LD): Rename to ... - (CC_LD): ... this. Use COMPILER. - (gdbserver$(EXEEXT), gdbreplay$(EXEEXT), $(IPA_LIB)): Adjust. - (CXX_FOR_TARGET): Default to g++ instead of gcc. - * acinclude.m4: Include build-with-cxx.m4. - * configure.ac: Call AC_PROG_CXX and GDB_AC_BUILD_WITH_CXX. - Disable -Werror by default if building in C++ mode. - (build_warnings): Add -Wno-sign-compare, -Wno-write-strings and - -Wno-narrowing in C++ mode. Run supported-warning-flags tests with - the C++ compiler. Save/restore CXXFLAGS too. - * configure: Regenerate. - -2015-02-27 Pedro Alves - - * acinclude.m4: Include libiberty.m4. - * configure.ac: Call libiberty_INIT. - * config.in, configure: Regenerate. - -2015-02-26 Pedro Alves - - * linux-low.c (linux_wait_1): When incrementing the PC past a - program breakpoint always use the_low_target.breakpoint_len as - increment, rather than the maximum between that and - the_low_target.decr_pc_after_break. - -2015-02-23 Pedro Alves - - * linux-low.c (check_stopped_by_breakpoint): Don't check if the - thread was doing a step-over; always adjust the PC if - we stepped over a permanent breakpoint. - (linux_wait_1): If we stepped over breakpoint that was on top of a - permanent breakpoint, manually advance the PC past it. - -2015-02-23 Pedro Alves - - * linux-x86-low.c (REGSIZE): Define in both 32-bit and 64-bit - modes. - (x86_fill_gregset, x86_store_gregset): Use it when handling - $orig_eax. - -2015-02-20 Pedro Alves - - * thread-db.c: Include "nat/linux-procfs.h". - (thread_db_init): Skip listing new threads if the kernel supports - PTRACE_EVENT_CLONE and /proc/PID/task/ is accessible. - -2015-02-20 Pedro Alves - - * linux-low.c (status_pending_p_callback): Use ptid_match. - -2015-02-19 Antoine Tremblay - - PR breakpoints/16812 - * linux-low.c (wstatus_maybe_breakpoint): Remove. - (linux_low_filter_event): Update wstatus_maybe_breakpoint name. - (linux_wait_1): Report SIGTRAP,SIGILL,SIGSEGV. - -2015-02-10 Antoine Tremblay - - PR breakpoints/15956 - * tracepoint.c (cmd_qtinit): Add check for current_thread. - -2015-02-09 Markus Metzger - - * linux-low.c (linux_low_btrace_conf): Print size. - * server.c (handle_btrace_conf_general_set): New. - (hanle_general_set): Call handle_btrace_conf_general_set. - (handle_query): Report Qbtrace-conf:bts:size as supported. - -2015-02-09 Markus Metzger - - * linux-low.c (linux_low_enable_btrace): Update parameters. - (linux_low_btrace_conf): New. - (linux_target_ops): Initialize. - * server.c (current_btrace_conf): New. - (handle_btrace_enable): Rename to ... - (handle_btrace_enable_bts): ... this. Pass ¤t_btrace_conf - to target_enable_btrace. Update comment. Update users. - (handle_qxfer_btrace_conf): New. - (qxfer_packets): Add btrace-conf entry. - (handle_query): Report qXfer:btrace-conf:read as supported packet. - * target.h (target_ops): Update parameters and comment. - (target_ops): New. - (target_enable_btrace): Update parameters. - (target_read_btrace_conf): New. - -2015-02-09 Markus Metzger - - * server.c (handle_btrace_general_set): Remove call to - target_supports_btrace. - (supported_btrace_packets): New. - (handle_query): Call supported_btrace_packets. - * target.h: include btrace-common.h. - (btrace_target_info): Removed. - (supports_btrace, target_supports_btrace): Update parameters. - -2015-02-09 Markus Metzger - - * Makefile.in (SFILES): Add common/btrace-common.c. - (OBS): Add common/btrace-common.o. - (btrace-common.o): Add build rules. - * linux-low: Include btrace-common.h. - (linux_low_read_btrace): Use struct btrace_data. Call - btrace_data_init and btrace_data_fini. - -2015-02-06 Pedro Alves - - * thread-db.c (find_new_threads_callback): Add debug output. - -2015-02-04 Pedro Alves - - * linux-low.c (handle_extended_wait): Don't resume LWPs here. - (resume_stopped_resumed_lwps): New function. - (linux_wait_for_event_filtered): Use it. - -2015-01-15 Sergio Durigan Junior - - * Makefile.in (SFILES): Add linux-personality.c. - (linux-personality.o): New rule. - * configure.srv (srv_linux_obj): Add linux-personality.o to the - list of objects to be built. - * linux-low.c: Include nat/linux-personality.h. - (linux_create_inferior): Remove code to disable address space - randomization (moved to ../nat/linux-personality.c). Create - cleanup to disable address space randomization. - -2015-01-15 Sergio Durigan Junior - - * Makefile.in (posix-strerror.o): New rule. - (mingw-strerror.o): Likewise. - * configure: Regenerated. - * configure.ac: Source file ../common/common.host. Initialize new - variable srv_host_obs. Add srv_host_obs to GDBSERVER_DEPFILES. - -2015-01-14 Yao Qi - - * Makefile.in (SFILES): Add nat/ppc-linux.c. - (ppc-linux.o): New rule. - * configure.srv (powerpc*-*-linux*): Add ppc-linux.o. - * configure.ac: AC_CHECK_FUNCS(getauxval). - * config.in: Re-generated. - * configure: Re-generated. - * linux-ppc-low.c (ppc_arch_setup) [__powerpc64__]: Call - ppc64_64bit_inferior_p - -2015-01-14 Yao Qi - - * linux-ppc-low.c: Include "nat/ppc-linux.h". - (PPC_FEATURE_HAS_VSX): Move to nat/ppc-linux.h. - (PPC_FEATURE_HAS_ALTIVEC, PPC_FEATURE_HAS_SPE): Likewise. - (PT_ORIG_R3, PT_TRAP): Likewise. - (PTRACE_GETVSXREGS, PTRACE_SETVSXREGS): Likewise. - (PTRACE_GETVRREGS, PTRACE_SETVRREGS): Likewise. - (PTRACE_GETEVRREGS, PTRACE_SETEVRREGS): Likewise. - -2015-01-10 Joel Brobecker - - * i387-fp.c (i387_cache_to_xsave): In look over - num_avx512_zmmh_high_registers, replace use of struct i387_xsave - zmmh_low_space field by use of zmmh_high_space. - -2015-01-09 Pedro Alves - - * linux-low.c (step_over_bkpt): Move higher up in the file. - (handle_extended_wait): Don't store the stop_pc here. - (get_stop_pc): Adjust comments and rename to ... - (check_stopped_by_breakpoint): ... this. Record whether the LWP - stopped for a software breakpoint or hardware breakpoint. - (thread_still_has_status_pending_p): New function. - (status_pending_p_callback): Use - thread_still_has_status_pending_p. If the event is no longer - interesting, resume the LWP. - (handle_tracepoints): Add assert. - (maybe_move_out_of_jump_pad): Remove cancel_breakpoints call. - (wstatus_maybe_breakpoint): New function. - (cancel_breakpoint): Delete function. - (check_stopped_by_watchpoint): New function, factored out from - linux_low_filter_event. - (lp_status_maybe_breakpoint): Delete function. - (linux_low_filter_event): Remove filter_ptid argument. - Leave thread group exits pending here. Store the LWP's stop PC. - Always leave events pending. - (linux_wait_for_event_filtered): Pull all events out of the - kernel, and leave them all pending. - (count_events_callback, select_event_lwp_callback): Consider all - events. - (cancel_breakpoints_callback, linux_cancel_breakpoints): Delete. - (select_event_lwp): Only give preference to the stepping LWP in - all-stop mode. Adjust comments. - (ignore_event): New function. - (linux_wait_1): Delete 'retry' label. Use ignore_event. Remove - references to cancel_breakpoints. Adjust to renames. Also give - equal priority to all LWPs that have had events in non-stop mode. - If reporting a software breakpoint event, unadjust the LWP's PC. - (linux_wait): If linux_wait_1 returned an ignored event, retry. - (stuck_in_jump_pad_callback, move_out_of_jump_pad_callback): - Adjust. - (linux_resume_one_lwp): Store the LWP's PC. Adjust. - (resume_status_pending_p): Use thread_still_has_status_pending_p. - (linux_stopped_by_watchpoint): Adjust. - (linux_target_ops): Remove reference to linux_cancel_breakpoints. - * linux-low.h (enum lwp_stop_reason): New. - (struct lwp_info) : Adjust comment. - : Delete field. - : New field. - * linux-x86-low.c (x86_linux_prepare_to_resume): Adjust. - * mem-break.c (software_breakpoint_inserted_here) - (hardware_breakpoint_inserted_here): New function. - * mem-break.h (software_breakpoint_inserted_here) - (hardware_breakpoint_inserted_here): Declare. - * target.h (struct target_ops) : Remove field. - (cancel_breakpoints): Delete. - * tracepoint.c (clear_installed_tracepoints, stop_tracing) - (upload_fast_traceframes): Remove references to - cancel_breakpoints. - -2015-01-09 Pedro Alves - - * thread-db.c (find_new_threads_callback): Ignore thread if the - kernel thread ID is -1. - -2015-01-09 Pedro Alves - - * linux-low.c (linux_attach_fail_reason_string): Move to - nat/linux-ptrace.c, and rename. - (linux_attach_lwp): Update comment. - (attach_proc_task_lwp_callback): New function. - (linux_attach): Adjust to rename and use - linux_proc_attach_tgid_threads. - (linux_attach_fail_reason_string): Delete declaration. - -2015-01-01 Joel Brobecker - - * gdbreplay.c (gdbreplay_version): Update copyright year to 2015. - * server.c (gdbserver_version): Likewise. - -2014-12-29 Sergio Durigan Junior - - * remote-utils.c: Include ctype.h. - (input_interrupt): Explicitly handle the case when the char - received is the NUL byte. Improve the printing of non-ASCII - characters. - -2014-12-16 Joel Brobecker - - * linux-low.c (linux_low_filter_event): Update call to - linux_enable_event_reporting following the addition of - a new parameter to that function. - -2014-12-16 Catalin Udma - - PR server/17457 - * linux-aarch64-low.c (AARCH64_FPSR_REGNO): New define. - (AARCH64_FPCR_REGNO): Likewise. - (AARCH64_NUM_REGS): Update to include fpsr/fpcr registers. - (aarch64_fill_fpregset): Add missing fpsr/fpcr registers. - (aarch64_store_fpregset): Likewise. - -2014-12-15 Joel Brobecker - - * lynx-low.c (lynx_resume): Use PTRACE_SINGLESTEP_ONE if N == 1. - Remove FIXME comment about assumption about N. - -2014-12-13 Joel Brobecker - - * configure.ac: If large-file support is disabled in GDBserver, - pass --disable-largefile to ACX_CONFIGURE_DIR call for "gnulib". - * configure: Regenerate. - -2014-12-12 Andreas Arnez - - * linux-low.c (regsets_fetch_inferior_registers): Suppress the - warning upon ENODATA from ptrace. - * linux-s390-low.c (s390_store_tdb): New. - (s390_regsets): Add regset for NT_S390_TDB. - -2014-12-12 Andreas Arnez - - * linux-low.c (regsets_store_inferior_registers): Skip regsets - without a fill_function. - * linux-s390-low.c (s390_fill_last_break): Remove. - (s390_regsets): Set fill_function to NULL for NT_S390_LAST_BREAK. - (s390_arch_setup): Use regset's size instead of fill_function for - loop end condition. - -2014-12-12 Andreas Arnez - - * linux-low.c (regsets_fetch_inferior_registers): Do not invoke - the regset's store function when ptrace returned an error. - * regcache.c (get_thread_regcache): Invalidate register cache - before fetching inferior's registers. - -2014-12-12 Andreas Arnez - - * linux-low.c (regsets_fetch_inferior_registers): Rephrase - while-loop as for-loop. - (regsets_store_inferior_registers): Likewise. - -2014-11-28 Yao Qi - - * configure.ac(AC_CHECK_FUNCS): Remove readlink. - * config.in, configure: Re-generate. - * hostio.c (handle_unlink): Remove code checking HAVE_READLINK - is defined. - -2014-11-21 Yao Qi - - * configure.ac: Don't invoke AC_FUNC_ALLOCA. - (AC_CHECK_HEADERS): Remove malloc.h. - * configure: Re-generated. - * config.in: Re-generated. - * server.h: Don't include alloca.h and malloc.h. - * gdbreplay.c: Don't check HAVE_ALLOCA_H is defined. - Don't include malloc.h. - -2014-11-17 Joel Brobecker - - * lynx-low.c (lynx_write_memory): Put lynx_read_memory and - corresponding ERRNO check in same block. - -2014-11-12 Pedro Alves - - * server.c (cont_thread): Update comment. - (start_inferior, attach_inferior): No longer clear cont_thread. - (handle_v_cont): No longer set cont_thread. - (captured_main): Clear cont_thread each time a GDB connects. - -2014-11-12 Pedro Alves - - * linux-low.c (linux_wait_1): Don't force a wait for the Hc - thread, and don't resume all threads if the Hc thread has exited. - -2014-11-12 Pedro Alves - - * linux-low.c (linux_request_interrupt): Always send a SIGINT to - the process group instead of to a specific LWP. - -2014-10-15 Pedro Alves - - PR server/17487 - * win32-arm-low.c (arm_set_thread_context): Remove current_event - parameter. - (arm_set_thread_context): Delete. - (the_low_target): Adjust. - * win32-i386-low.c (debug_registers_changed) - (debug_registers_used): Delete. - (update_debug_registers_callback): New function. - (x86_dr_low_set_addr, x86_dr_low_set_control): Mark all threads as - needing to update their debug registers. - (win32_get_current_dr): New function. - (x86_dr_low_get_addr, x86_dr_low_get_control) - (x86_dr_low_get_status): Fetch the debug register from the thread - record's context. - (i386_initial_stuff): Adjust. - (i386_get_thread_context): Remove current_event parameter. Don't - clear debug_registers_changed nor copy DR values to - debug_reg_state. - (i386_set_thread_context): Delete. - (i386_prepare_to_resume): New function. - (i386_thread_added): Mark the thread as needing to update irs - debug registers. - (the_low_target): Remove i386_set_thread_context and install - i386_prepare_to_resume. - * win32-low.c (win32_get_thread_context): Adjust. - (win32_set_thread_context): Use SetThreadContext - directly. - (win32_prepare_to_resume): New function. - (win32_require_context): New function, factored out from ... - (thread_rec): ... this. - (continue_one_thread): Call win32_prepare_to_resume on each thread - we're about to continue. - (win32_resume): Call win32_prepare_to_resume on the event thread. - * win32-low.h (struct win32_thread_info) - : New field. - (struct win32_target_ops): Change prototype of set_thread_context, - delete set_thread_context and add prepare_to_resume. - (win32_require_context): New declaration. - -2014-10-08 Gary Benson - - * server.h: Do not include common-exceptions.h. - -2014-10-08 Gary Benson - - * server.h: Do not include cleanups.h. - -2014-09-30 James Hogan - - * Makefile.in (clean): Add rm -f commands for mips-dsp-linux.c and - mips64-dsp-linux.c. - -2014-09-23 Yao Qi - - * linux-low.c (lp_status_maybe_breakpoint): New function. - (linux_low_filter_event): Call lp_status_maybe_breakpoint. - (count_events_callback): Likewise. - (select_event_lwp_callback): Likewise. - (cancel_breakpoints_callback): Likewise. - -2014-09-19 Don Breazeal - - * linux-low.c (handle_extended_wait): Call - linux_ptrace_get_extended_event. - (get_stop_pc, get_detach_signal, linux_low_filter_event): Call - linux_is_extended_waitstatus. - -2014-09-16 Joel Brobecker - - * Makefile.in (CPPFLAGS): Define. - (INTERNAL_CFLAGS_BASE): Add ${CPPFLAGS}. - (IPAGENT_CFLAGS): Remove ${CPPFLAGS}. - -2014-09-16 Gary Benson - - * inferiors.h (current_inferior): Renamed as... - (current_thread): New variable. All uses updated. - * linux-low.c (get_pc): Renamed saved_inferior as saved_thread. - (maybe_move_out_of_jump_pad): Likewise. - (cancel_breakpoint): Likewise. - (linux_low_filter_event): Likewise. - (wait_for_sigstop): Likewise. - (linux_resume_one_lwp): Likewise. - (need_step_over_p): Likewise. - (start_step_over): Likewise. - (linux_stabilize_threads): Renamed save_inferior as saved_thread. - * linux-x86-low.c (x86_linux_update_xmltarget): Likewise. - * proc-service.c (ps_lgetregs): Renamed reg_inferior as reg_thread - and save_inferior as saved_thread. - * regcache.c (get_thread_regcache): Renamed saved_inferior as - saved_thread. - (regcache_invalidate_thread): Likewise. - * remote-utils.c (prepare_resume_reply): Likewise. - * thread-db.c (thread_db_get_tls_address): Likewise. - (disable_thread_event_reporting): Likewise. - (remove_thread_event_breakpoints): Likewise. - * tracepoint.c (gdb_agent_about_to_close): Renamed save_inferior - as saved_thread. - * target.h (set_desired_inferior): Renamed as... - (set_desired_thread): New declaration. All uses updated. - * server.c (myresume): Updated comment to reference thread instead - of inferior. - (handle_serial_event): Likewise. - (handle_target_event): Likewise. - -2014-09-12 Tom Tromey - Gary Benson - - * regcache.h: Include common-regcache.h. - (regcache_read_pc): Don't declare. - * regcache.c (get_thread_regcache_for_ptid): New function. - -2014-09-11 Tom Tromey - Gary Benson - - * symbol.c: New file. - * Makefile.in (SFILES): Add symbol.c. - (OBS): Add symbol.o. - -2014-09-11 Gary Benson - - * target.c (target_stop_ptid, target_continue_ptid): New - functions. - -2014-09-11 Tom Tromey - Gary Benson - - * target.h: Include target/target.h. - * target.c (target_read_memory, target_read_uint32) - (target_write_memory): New functions. - -2014-09-11 Gary Benson - - * server.h (debug_hw_points): Don't declare. - * server.c (debug_hw_points): Don't define. Replace all uses - with show_debug_regs. - * linux-aarch64-low.c (debug_hw_points): Don't define. Replace - all uses with show_debug_regs. - -2014-09-08 Edjunior Barbosa Machado - - * linux-ppc-low.c (ppc_collect_ptrace_register): Adjust routine to take - endianness into account. - (ppc_supply_ptrace_register): Likewise. - -2014-09-03 James Hogan - - * linux-mips-low.c (mips_read_description): Reset errno to 0 prior - to reading DSP_CONTROL with PTRACE_PEEKUSER ptrace call. - -2014-09-03 Gary Benson - - * linux-x86-low.c (x86_linux_prepare_to_resume): Use - ALL_DEBUG_ADDRESS_REGISTERS. - -2014-09-02 Gary Benson - - * i386-low.h: Renamed as... - * x86-low.h: New file. All type, function and variable name - prefixes changed from "i386_" to "x86_". All references updated. - * i386-low.c: Renamed as... - * x86-low.c: New file. All type, function and variable name - prefixes changed from "i386_" to "x86_". All references updated. - -2014-09-02 Gary Benson - - * linux-x86-low.c (x86_linux_new_process): Use XCNEW. - (x86_linux_new_thread): Likewise. - -2014-08-29 Gary Benson - - * server.h (setjmp.h): Do not include. - (toplevel): Do not declare. - (common-exceptions.h): Include. - (cleanups.h): Likewise. - * server.c (toplevel): Do not define. - (exit_code): New static global. - (detach_or_kill_for_exit_cleanup): New function. - (main): New function. Original main renamed to... - (captured_main): New function. - * utils.c (verror) [!IN_PROCESS_AGENT]: Use throw_verror. - -2014-08-29 Gary Benson - - * Makefile.in (SFILES): Add common/common-exceptions.c. - (OBS): Add common-exceptions.o. - (common-exceptions.o): New rule. - * utils.c (prepare_to_throw_exception): New function. - -2014-08-29 Gary Benson - - * config.in: Regenerate. - * configure: Likewise. - -2014-08-29 Gary Benson - - * Makefile.in (SFILES): Add common/cleanups.c. - (OBS): cleanups.o. - (cleanups.o): New rule. - -2014-08-29 Gary Benson - - * utils.c (internal_vwarning): New function. - -2014-08-28 Gary Benson - - * utils.h (fatal): Remove declaration. - * utils.c (fatal): Remove function. - -2014-08-28 Gary Benson - - * tracepoint.c (gdb_agent_init): Replace fatal with - perror_with_name. - (initialize_tracepoint): Likewise. - -2014-08-28 Gary Benson - - * remote-utils.c (remote_prepare): Replace fatal with error. - -2014-08-28 Gary Benson - - * linux-low.c (linux_async): Replace fatal with warning. - Tidy up and return. - (linux_start_non_stop): Return -1 if linux_async failed. - -2014-08-28 Gary Benson - - * linux-x86-low.c (i386_dr_low_set_addr): Replace check with - gdb_assert. - (i386_dr_low_get_addr): Remove vague comment. - * win32-i386-low.c (i386_dr_low_set_addr): Replace check with - gdb_assert. - -2014-08-28 Gary Benson - - * inferiors.c (get_thread_process): Replace check with gdb_assert. - * linux-low.c (linux_wait_for_event_filtered): Replace fatal with - internal_error. - (linux_resume_one_lwp): Likewise. - * linux-x86-low.c (x86_siginfo_fixup): Replace checks with - gdb_assert. - * mem-break.c (raw_bkpt_type_to_target_hw_bp_type): Replace fatal - with internal_error. - * regcache.c (get_thread_regcache): Replace check with gdb_assert. - (init_register_cache): Replace fatal with gdb_assert_not_reached. - (find_register_by_name): Replace fatal with internal_error. - (find_regno): Likewise. - * tdesc.c (init_target_desc): Replace check with gdb_assert. - * thread-db.c (thread_db_create_event): Likewise. - (thread_db_load_search): Likewise. - (try_thread_db_load_1): Likewise. - * tracepoint.c (get_jump_space_head): Replace fatal with - internal_error. - (claim_trampoline_space): Likewise. - (have_fast_tracepoint_trampoline_buffer): Likewise. - (cmd_qtstart): Likewise. - (stop_tracing): Likewise. - (fast_tracepoint_collecting): Likewise. - (target_malloc): Likewise. - (download_tracepoint): Likewise. - (download_trace_state_variables): Replace check with gdb_assert. - (upload_fast_traceframes): Replace fatal with internal_error. - -2014-08-19 Tom Tromey - Gary Benson - - * Makefile.in (SFILES): Add common/common-debug.c. - (OBS): Add common-debug.o. - (common-debug.o): New rule. - * debug.h (debug_printf): Don't declare. - * debug.c (debug_printf): Renamed and rewritten as... - (debug_vprintf): New function. - -2014-08-19 Gary Benson - - * utils.h: Do not include print-utils.h. - -2014-08-19 Tom Tromey - Gary Benson - - * server.h: Add static assertion. - (gdb_byte, CORE_ADDR, LONGEST, ULONGEST): Remove. - -2014-08-19 Tom Tromey - Gary Benson - - * Makefile.in (SFILES): Add common/errors.c. - (OBS): Add errors.o. - (IPA_OBS): Add errors-ipa.o. - (errors.o): New rule. - (errors-ipa.o): Likewise. - * utils.h (perror_with_name, error, warning): Don't declare. - * utils.c (warning): Renamed and rewritten as... - (vwarning): New function. - (error): Renamed and rewritten as... - (verror): New function. - (internal_error): Renamed and rewritten as... - (internal_verror): New function. - -2014-08-07 Gary Benson - - * configure.ac (AC_CHECK_HEADERS): Remove errno.h. - * configure: Regenerate. - * config.in: Likewise. - * server.h: Do not include errno.h. - * event-loop.c: Likewise. - * hostio-errno.c: Likewise. - * linux-low.c: Likewise. - * remote-utils.c: Likewise. - * spu-low.c: Likewise. - * utils.c: Likewise. - * gdbreplay.c: Unconditionally include errno.h. - -2014-08-07 Gary Benson - - * server.h: Do not include string.h. - * event-loop.c: Likewise. - * linux-low.c: Likewise. - * regcache.c: Likewise. - * remote-utils.c: Likewise. - * spu-low.c: Likewise. - * utils.c: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include gdb_assert.h. - -2014-08-07 Gary Benson - - * server.h: Do not include common-utils.h. - -2014-08-07 Gary Benson - - * server.h: Do not include ptid.h. - * notif.h: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include gdb_locale.h. - -2014-08-07 Gary Benson - - * server.h: Do not include gdb/signals.h. - * win32-low.c: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include pathmax.h. - -2014-08-07 Gary Benson - - * server.h: Do not include libiberty.h. - * linux-bfin-low.c: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include ansidecl.h. - -2014-08-07 Gary Benson - - * linux-x86-low.c: Do not include stddef.h. - * lynx-ppc-low.c: Likewise. - * tracepoint.c: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include stdarg.h. - * nto-low.c: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include stdlib.h. - * inferiors.c: Likewise. - * linux-low.c: Likewise. - * regcache.c: Likewise. - * spu-low.c: Likewise. - * tracepoint.c: Likewise. - * utils.c: Likewise. - -2014-08-07 Gary Benson - - * server.h: Do not include stdio.h. - * linux-low.c: Likewise. - * remote-utils.c: Likewise. - * spu-low.c: Likewise. - * utils.c: Likewise. - * wincecompat.c: Likewise. - -2014-08-06 Gary Benson - - * regcache.c (init_register_cache): Move conditionals inside if. - -2014-08-06 Gary Benson - - * linux-low.c (linux_supports_non_stop): Use target_is_async_p. - -2014-07-31 Gary Benson - - * ax.h: Do not include server.h. - * gdbthread.h: Likewise. - * lynx-low.h: Likewise. - * notif.h: Likewise. - -2014-07-30 Gary Benson - - * server.h: Include common-defs.h. - Do not include config.h or build-gnulib-gdbserver/config.h. - -2014-07-30 Gary Benson - - * hostio-errno.c: Move server.h to top of includes list. - * inferiors.c: Likewise. - * linux-x86-low.c: Likewise. - * notif.c: Include server.h. - -2014-07-24 Tom Tromey - Gary Benson - - * server.h (CORE_ADDR): Now unsigned. - -2014-07-16 Pedro Alves - - * linux-low.c (linux_kill_one_lwp): Use kill_lwp, not kill. - -2014-07-15 Pedro Alves - - * linux-low.c (linux_kill_one_lwp): Save errno and work with saved - copy. - -2014-07-11 Pedro Alves - - * linux-low.c (kill_wait_lwp): New function, based on - kill_one_lwp_callback, but use my_waitpid directly. - (kill_one_lwp_callback, linux_kill): Use it. - -2014-06-23 Pedro Alves - - * linux-x86-low.c (x86_linux_prepare_to_resume): Clear DR_CONTROL - before setting DR0..DR3. - -2014-06-20 Gary Benson - - * configure.ac (AC_REPLACE_FUNCS) : Removed. - * configure: Regenerated. - * config.in: Likewise. - -2014-06-20 Gary Benson - - * Makefile.in (SFILES): Update locations for files moved - from common to nat. - (object file files): Reordered. - -2014-06-20 Gary Benson - - * i386-low.h (i386_dr_low_can_set_addr): Removed. - (i386_dr_low_set_addr): Likewise. - (i386_dr_low_get_addr): Likewise. - (i386_dr_low_can_set_control): Likewise. - (i386_dr_low_set_control): Likewise. - (i386_dr_low_get_control): Likewise. - (i386_dr_low_get_status): Likewise. - (i386_get_debug_register_length): Likewise. - * linux-x86-low.c (i386_dr_low_set_addr): - Changed signature. Made static. - (i386_dr_low_get_addr): Likewise. - (i386_dr_low_set_control): Likewise. - (i386_dr_low_get_control): Likewise. - (i386_dr_low_get_status): Likewise. - (i386_dr_low): New global variable. - * win32-i386-low.c (i386_dr_low_set_addr): - Changed signature. Made static. - (i386_dr_low_get_addr): Likewise. - (i386_dr_low_set_control): Likewise. - (i386_dr_low_get_control): Likewise. - (i386_dr_low_get_status): Likewise. - (i386_dr_low): New global variable. - -2014-06-20 Marcus Shawcroft - - * configure.ac: Invoke. AC_CHECK_TOOL(AR, ar). - * Makefile.in (AR, AR_FLAGS): Define. - * configure: Regenerate. - -2014-06-19 Gary Benson - - * Makefile.in (i386-dregs.o): New rule. - * configure.srv: Add i386-dregs.o to all targets using i386-low.o. - * i386-low.c (target.h): Remove include. - (TARGET_HAS_DR_LEN_8): Now in i386-dregs.c. - (DR_CONTROL_SHIFT): Likewise. - (DR_CONTROL_SIZE): Likewise. - (DR_RW_EXECUTE): Likewise. - (DR_RW_WRITE): Likewise. - (DR_RW_READ): Likewise. - (DR_RW_IORW): Likewise. - (DR_LEN_1): Likewise. - (DR_LEN_2): Likewise. - (DR_LEN_4): Likewise. - (DR_LEN_8): Likewise. - (DR_LOCAL_ENABLE_SHIFT): Likewise. - (DR_GLOBAL_ENABLE_SHIFT): Likewise. - (DR_ENABLE_SIZE): Likewise. - (DR_LOCAL_SLOWDOWN): Likewise. - (DR_GLOBAL_SLOWDOWN): Likewise. - (DR_CONTROL_RESERVED): Likewise. - (I386_DR_CONTROL_MASK): Likewise. - (I386_DR_VACANT): Likewise. - (I386_DR_LOCAL_ENABLE): Likewise. - (I386_DR_GLOBAL_ENABLE): Likewise. - (I386_DR_DISABLE): Likewise. - (I386_DR_SET_RW_LEN): Likewise. - (I386_DR_GET_RW_LEN): Likewise. - (I386_DR_WATCH_HIT): Likewise. - (i386_wp_op_t): Likewise. - (i386_show_dr): Likewise. - (i386_length_and_rw_bits): Likewise. - (i386_insert_aligned_watchpoint): Likewise. - (i386_remove_aligned_watchpoint): Likewise. - (i386_handle_nonaligned_watchpoint): Likewise. - i386_update_inferior_debug_regs(): Likewise. - (i386_dr_insert_watchpoint): Likewise. - (i386_dr_remove_watchpoint): Likewise. - (i386_dr_region_ok_for_watchpoint): Likewise. - (i386_dr_stopped_data_address): Likewise. - (i386_dr_stopped_by_watchpoint): Likewise. - -2014-06-19 Gary Benson - - * i386-low.c (i386_dr_show): Renamed to - i386_show_dr and made static. All uses updated. - (i386_dr_length_and_rw_bits): Renamed to - i386_length_and_rw_bits and made static. - All uses updated. - (i386_dr_insert_aligned_watchpoint): Renamed to - i386_insert_aligned_watchpoint and made static. - All uses updated. - (i386_dr_remove_aligned_watchpoint): Renamed to - i386_remove_aligned_watchpoint and made static. - All uses updated. - (i386_dr_update_inferior_debug_regs): Renamed to - i386_update_inferior_debug_regs and made static. - All uses updated. - -2014-06-18 Gary Benson - - * i386-low.h (i386_dr_low_can_set_addr): New macro. - (i386_dr_low_can_set_control): Likewise. - (i386_get_debug_register_length): Likewise. - * i386-low.c (i386_dr_low_can_set_addr): Now in i386-low.h. - (i386_dr_low_can_set_control): Likewise. - (i386_get_debug_register_length): Likewise. - -2014-06-17 Gary Benson - - * i386-low.h (i386-dregs.h): New include. - (DR_FIRSTADDR): Now in i386-dregs.h. - (DR_LASTADDR): Likewise. - (DR_NADDR): Likewise. - (DR_STATUS): Likewise. - (DR_CONTROL): Likewise. - (i386_debug_reg_state): Likewise. - (i386_dr_insert_watchpoint): Likewise. - (i386_dr_remove_watchpoint): Likewise. - (i386_dr_region_ok_for_watchpoint): Likewise. - (i386_dr_stopped_data_address): Likewise. - (i386_dr_stopped_by_watchpoint): Likewise. - * i386-low.c (ALL_DEBUG_REGISTERS): Likewise. - -2014-06-18 Gary Benson - - * i386-low.h (i386_low_insert_watchpoint): Renamed to - i386_dr_insert_watchpoint. - (i386_low_remove_watchpoint): Renamed to - i386_dr_remove_watchpoint. - (i386_low_region_ok_for_watchpoint): Renamed to - i386_dr_region_ok_for_watchpoint. - (i386_low_stopped_data_address): Renamed to - i386_dr_stopped_data_address. - (i386_low_stopped_by_watchpoint): Renamed to - i386_dr_stopped_by_watchpoint. - * i386-low.c (i386_show_dr): Renamed to - i386_dr_show and made nonstatic. All uses updated. - (i386_length_and_rw_bits): Renamed to - i386_dr_length_and_rw_bits and made nonstatic. - All uses updated. - (i386_insert_aligned_watchpoint): Renamed to - i386_dr_insert_aligned_watchpoint and made nonstatic. - All uses updated. - (i386_remove_aligned_watchpoint): Renamed to - i386_dr_remove_aligned_watchpoint and made nonstatic. - All uses updated. - (i386_update_inferior_debug_regs): Renamed to - i386_dr_update_inferior_debug_regs and made nonstatic. - All uses updated. - (i386_low_insert_watchpoint): Renamed to - i386_dr_insert_watchpoint. All uses updated. - (i386_low_remove_watchpoint): Renamed to - i386_dr_remove_watchpoint. All uses updated. - (i386_low_region_ok_for_watchpoint): Renamed to - i386_dr_region_ok_for_watchpoint. All uses updated. - (i386_low_stopped_data_address): Renamed to - i386_dr_stopped_data_address. All uses updated. - (i386_low_stopped_by_watchpoint): Renamed to - i386_dr_stopped_by_watchpoint. All uses updated. - -2014-06-18 Gary Benson - - * i386-low.c (i386_dr_low_can_set_addr): New macro. - (i386_dr_low_can_set_control): Likewise. - (i386_insert_aligned_watchpoint): New check. - -2014-06-18 Gary Benson - - * i386-low.c (i386_update_inferior_debug_regs) : - Renamed to state. - -2014-06-18 Gary Benson - - * i386-low.c (i386_length_and_rw_bits): Use internal_error - instead of fatal and error. - (i386_handle_nonaligned_watchpoint): Likewise. - -2014-06-18 Gary Benson - - * i386-low.c (i386_get_debug_register_length): New macro. - (TARGET_HAS_DR_LEN_8): Remove conditional. Use above macro. - (i386_show_dr): Use debug_printf instead of fprintf. Use - phex to format values. - -2014-06-18 Gary Benson - - * i386-low.h: Comment changes. - * i386-low.c: Likewise. - -2014-06-18 Gary Benson - - * i386-low.c: Whitespace changes. - -2014-06-12 Tom Tromey - - * utils.c (freeargv): Remove. - -2014-06-12 Tom Tromey - - * debug.c (debug_printf): Remove HAVE_GETTIMEOFDAY checks. - * server.c (monitor_show_help): Remove HAVE_GETTIMEOFDAY check. - (parse_debug_format_options): Likewise. - (gdbserver_usage): Likewise. - * Makefile.in (LIBIBERTY_BUILDDIR, LIBIBERTY): New variables. - (SUBDIRS, REQUIRED_SUBDIRS): Add libiberty. - (gdbserver$(EXEEXT), gdbreplay$(EXEEXT)): Depend on and link - against libiberty. - ($(LIBGNU)): Depend on libiberty. - (all-lib): Recurse into all subdirs. - (install-only): Invoke "install" target in subdirs. - (vasprintf.o, vsnprintf.o, safe-ctype.o, lbasename.o): Remove - targets. - * configure: Rebuild. - * configure.ac: Add ACX_CONFIGURE_DIR for libiberty. Don't check - for vasprintf, vsnprintf, or gettimeofday. - * configure.srv: Don't add safe-ctype.o or lbasename.o to - srv_tgtobj. - -2014-06-05 Joel Brobecker - - * development.sh: Delete. - * Makefile.in (config.status): Adjust dependency on development.sh. - * configure.ac: Adjust development.sh source call. - * configure: Regenerate. - -2014-06-02 Pedro Alves - - * ax.c (gdb_free_agent_expr): New function. - * ax.h (gdb_free_agent_expr): New declaration. - * mem-break.c (delete_gdb_breakpoint_1): Also clear the commands - list. - (clear_breakpoint_conditions, clear_breakpoint_commands): Make - static. - (clear_breakpoint_conditions_and_commands): New function. - * mem-break.h (clear_breakpoint_conditions): Delete declaration. - (clear_breakpoint_conditions_and_commands): New declaration. - -2014-05-23 Ramana Radhakrishnan - - * linux-aarch64-low.c (asm/ptrace.h): Include. - -2014-05-21 Jan Kratochvil - - Fix TLS access for -static -pthread. - * gdbserver/thread-db.c (struct thread_db): Add td_thr_tlsbase_p. - (thread_db_get_tls_address): Call it if LOAD_MODULE is zero. - (thread_db_load_search, try_thread_db_load_1): Initialize it. - -2014-05-20 Pedro Alves - - * linux-aarch64-low.c (aarch64_insert_point) - (aarch64_remove_point): No longer check whether the type is - supported here. Adjust to new interface. - (the_low_target): Install aarch64_supports_z_point_type as - supports_z_point_type method. - * linux-arm-low.c (raw_bkpt_type_to_arm_hwbp_type): New function. - (arm_linux_hw_point_initialize): Take an enum raw_bkpt_type - instead of a Z packet char. Adjust. - (arm_supports_z_point_type): New function. - (arm_insert_point, arm_remove_point): Adjust to new interface. - (the_low_target): Install arm_supports_z_point_type. - * linux-crisv32-low.c (cris_supports_z_point_type): New function. - (cris_insert_point, cris_remove_point): Adjust to new interface. - Don't check whether the type is supported here. - (the_low_target): Install cris_supports_z_point_type. - * linux-low.c (linux_supports_z_point_type): New function. - (linux_insert_point, linux_remove_point): Adjust to new interface. - * linux-low.h (struct linux_target_ops) : Take an enum raw_bkpt_type instead of a char. Add - raw_breakpoint pointer parameter. - : New method. - * linux-mips-low.c (mips_supports_z_point_type): New function. - (mips_insert_point, mips_remove_point): Adjust to new interface. - Use mips_supports_z_point_type. - (the_low_target): Install mips_supports_z_point_type. - * linux-ppc-low.c (the_low_target): Install NULL as - supports_z_point_type method. - * linux-s390-low.c (the_low_target): Install NULL as - supports_z_point_type method. - * linux-sparc-low.c (the_low_target): Install NULL as - supports_z_point_type method. - * linux-x86-low.c (x86_supports_z_point_type): New function. - (x86_insert_point): Adjust to new insert_point interface. Use - insert_memory_breakpoint. Adjust to new - i386_low_insert_watchpoint interface. - (x86_remove_point): Adjust to remove_point interface. Use - remove_memory_breakpoint. Adjust to new - i386_low_remove_watchpoint interface. - (the_low_target): Install x86_supports_z_point_type. - * lynx-low.c (lynx_target_ops): Install NULL as - supports_z_point_type callback. - * nto-low.c (nto_supports_z_point_type): New. - (nto_insert_point, nto_remove_point): Adjust to new interface. - (nto_target_ops): Install nto_supports_z_point_type. - * mem-break.c: Adjust intro comment. - (struct raw_breakpoint) : New fields. - : Update comment. - : Delete field. - (enum bkpt_type) : Delete value. - : New values. - (raw_bkpt_type_to_target_hw_bp_type): New function. - (find_enabled_raw_code_breakpoint_at): New function. - (find_raw_breakpoint_at): New type and size parameters. Use them. - (insert_memory_breakpoint): New function, based off - set_raw_breakpoint_at. - (remove_memory_breakpoint): New function. - (set_raw_breakpoint_at): Reimplement. - (set_breakpoint): New, based on set_breakpoint_at. - (set_breakpoint_at): Reimplement. - (delete_raw_breakpoint): Go through the_target->remove_point - instead of assuming memory breakpoints. - (find_gdb_breakpoint_at): Delete. - (Z_packet_to_bkpt_type, Z_packet_to_raw_bkpt_type): New functions. - (find_gdb_breakpoint): New function. - (set_gdb_breakpoint_at): Delete. - (z_type_supported): New function. - (set_gdb_breakpoint_1): New function, loosely based off - set_gdb_breakpoint_at. - (check_gdb_bp_preconditions, set_gdb_breakpoint): New functions. - (delete_gdb_breakpoint_at): Delete. - (delete_gdb_breakpoint_1): New function, loosely based off - delete_gdb_breakpoint_at. - (delete_gdb_breakpoint): New function. - (clear_gdb_breakpoint_conditions): Rename to ... - (clear_breakpoint_conditions): ... this. Don't handle a NULL - breakpoint. - (add_condition_to_breakpoint): Make static. - (add_breakpoint_condition): Take a struct breakpoint pointer - instead of an address. Adjust. - (gdb_condition_true_at_breakpoint): Rename to ... - (gdb_condition_true_at_breakpoint_z_type): ... this, and add - z_type parameter. - (gdb_condition_true_at_breakpoint): Reimplement. - (add_breakpoint_commands): Take a struct breakpoint pointer - instead of an address. Adjust. - (gdb_no_commands_at_breakpoint): Rename to ... - (gdb_no_commands_at_breakpoint_z_type): ... this. Add z_type - parameter. Return true if no breakpoint was found. Change debug - output. - (gdb_no_commands_at_breakpoint): Reimplement. - (run_breakpoint_commands): Rename to ... - (run_breakpoint_commands_z_type): ... this. Add z_type parameter, - and change return type to boolean. - (run_breakpoint_commands): New function. - (gdb_breakpoint_here): Also check for Z1 breakpoints. - (uninsert_raw_breakpoint): Don't try to reinsert a disabled - breakpoint. Go through the_target->remove_point instead of - assuming memory breakpoint. - (uninsert_breakpoints_at, uninsert_all_breakpoints): Uninsert - software and hardware breakpoints. - (reinsert_raw_breakpoint): Go through the_target->insert_point - instead of assuming memory breakpoint. - (reinsert_breakpoints_at, reinsert_all_breakpoints): Reinsert - software and hardware breakpoints. - (check_breakpoints, breakpoint_here, breakpoint_inserted_here): - Check both software and hardware breakpoints. - (validate_inserted_breakpoint): Assert the breakpoint is a - software breakpoint. Set the inserted flag to -1 instead of - setting shlib_disabled. - (delete_disabled_breakpoints): Adjust. - (validate_breakpoints): Only validate software breakpoints. - Adjust to inserted flag change. - (check_mem_read, check_mem_write): Skip breakpoint types other - than software breakpoints. Adjust to inserted flag change. - * mem-break.h (enum raw_bkpt_type): New enum. - (raw_breakpoint, struct process_info): Forward declare. - (Z_packet_to_target_hw_bp_type): Delete declaration. - (raw_bkpt_type_to_target_hw_bp_type, Z_packet_to_raw_bkpt_type) - (set_gdb_breakpoint, delete_gdb_breakpoint) - (clear_breakpoint_conditions): New declarations. - (set_gdb_breakpoint_at, clear_gdb_breakpoint_conditions): Delete. - (breakpoint_inserted_here): Update comment. - (add_breakpoint_condition, add_breakpoint_commands): Replace - address parameter with a breakpoint pointer parameter. - (gdb_breakpoint_here): Update comment. - (delete_gdb_breakpoint_at): Delete. - (insert_memory_breakpoint, remove_memory_breakpoint): Declare. - * server.c (process_point_options): Take a struct breakpoint - pointer instead of an address. Adjust. - (process_serial_event) : Use set_gdb_breakpoint and - delete_gdb_breakpoint. - * spu-low.c (spu_target_ops): Install NULL as - supports_z_point_type method. - * target.h: Include mem-break.h. - (struct target_ops) : Update comment. - : New field. - : Take an enum raw_bkpt_type argument - instead of a char. Also take a raw breakpoint pointer. - * win32-arm-low.c (the_low_target): Install NULL as - supports_z_point_type. - * win32-i386-low.c (i386_supports_z_point_type): New function. - (i386_insert_point, i386_remove_point): Adjust to new interface. - (the_low_target): Install i386_supports_z_point_type. - * win32-low.c (win32_supports_z_point_type): New function. - (win32_insert_point, win32_remove_point): Adjust to new interface. - (win32_target_ops): Install win32_supports_z_point_type. - * win32-low.h (struct win32_target_ops): - : New method. - : Take an enum raw_bkpt_type argument - instead of a char. Also take a raw breakpoint pointer. - -2014-05-20 Pedro Alves - - * mem-break.h: Include break-common.h. - (Z_PACKET_SW_BP, Z_PACKET_HW_BP, Z_PACKET_WRITE_WP) - (Z_PACKET_READ_WP, Z_PACKET_ACCESS_WP): New defines. - (Z_packet_to_target_hw_bp_type): New declaration. - * mem-break.c (Z_packet_to_target_hw_bp_type): New function. - * i386-low.c (Z_PACKET_HW_BP, Z_PACKET_WRITE_WP, Z_PACKET_READ_WP) - (Z_PACKET_ACCESS_WP): Delete macros. - (Z_packet_to_hw_type): Delete function. - * i386-low.h: Don't include break-common.h here. - (Z_packet_to_hw_type): Delete declaration. - * linux-x86-low.c (x86_insert_point, x86_insert_point): Call - Z_packet_to_target_hw_bp_type instead of Z_packet_to_hw_type. - * win32-i386-low.c (i386_insert_point, i386_remove_point): Call - Z_packet_to_target_hw_bp_type instead of Z_packet_to_hw_type. - * linux-aarch64-low.c: Don't include break-common.h here. - (Z_PACKET_SW_BP, Z_PACKET_HW_BP, Z_PACKET_WRITE_WP) - (Z_PACKET_READ_WP, Z_PACKET_ACCESS_WP): Delete macros. - (Z_packet_to_target_hw_bp_type): Delete function. - * linux-mips-low.c (rsp_bp_type_to_target_hw_bp_type): Delete - function. - (mips_insert_point, mips_remove_point): Use - Z_packet_to_target_hw_bp_type. - -2014-05-20 Pedro Alves - - * linux-aarch64-low.c: Include break-common.h. - (enum target_point_type): Delete. - (Z_packet_to_point_type): Rename to ... - (Z_packet_to_target_hw_bp_type): ... this, and return a - target_hw_bp_type instead. - (aarch64_show_debug_reg_state): Take an enum target_hw_bp_type - instead of an enum target_point_type. - (aarch64_point_encode_ctrl_reg): Likewise. Compute type mask from - breakpoint type. - (aarch64_dr_state_insert_one_point) - (aarch64_dr_state_remove_one_point, aarch64_handle_breakpoint) - (aarch64_handle_aligned_watchpoint) - (aarch64_handle_unaligned_watchpoint, aarch64_handle_watchpoint): - Take an enum target_hw_bp_type instead of an enum - target_point_type. - (aarch64_supports_z_point_type): New function. - (aarch64_insert_point, aarch64_remove_point): Use it. Adjust to - use Z_packet_to_target_hw_bp_type. - -2014-05-20 Joel Brobecker - - * configure.ac: Only use -Werror by default when DEVELOPMENT - is true. - * configure: Regenerate. - -2014-05-19 Jan Kratochvil - - Fix gdbserver qGetTLSAddr for x86_64 -m32. - * linux-x86-low.c (X86_64_USER_REGS): New. - (x86_fill_gregset): Call memset for BUF first in x86_64 -m32 case. - -2014-04-28 Yao Qi - - * Makefile.in (i386-avx512.c): Fix the typo of generated file - name. - -2014-04-25 Pedro Alves - - PR server/16255 - * linux-low.c (linux_attach_fail_reason_string): New function. - (linux_attach_lwp): Delete. - (linux_attach_lwp_1): Rename to ... - (linux_attach_lwp): ... this. Take a ptid instead of a pid as - argument. Remove "initial" parameter. Return int instead of - void. Don't error or warn here. - (linux_attach): Adjust to call linux_attach_lwp. Call error on - failure to attach to the tgid. Call warning when failing to - attach to an lwp. - * linux-low.h (linux_attach_lwp): Take a ptid instead of a pid as - argument. Remove "initial" parameter. Return int instead of - void. Don't error or warn here. - (linux_attach_fail_reason_string): New declaration. - * thread-db.c (attach_thread): Adjust to linux_attach_lwp's - interface change. Use linux_attach_fail_reason_string. - -2014-04-24 Michael Sturm - Walfred Tedeschi - - * Makefile.in: Added rules to handle new files - i386-avx512.c i386-avx512-linux.c amd64-avx512.c - amd64-avx512-linux.c x32-avx512.c x32-avx512-linux.c. - * configure.srv (srv_i386_regobj): Add i386-avx512.o. - (srv_i386_linux_regobj): Add i386-avx512-linux.o. - (srv_amd64_regobj): Add amd64-avx512.o and x32-avx512.o. - (srv_amd64_linux_regobj): Add amd64-avx512-linux.o and - x32-avx512-linux.o. - (srv_i386_32bit_xmlfiles): Add i386/32bit-avx512.xml. - (srv_i386_64bit_xmlfiles): Add i386/64bit-avx512.xml. - (srv_amd64_xmlfiles): Add i386/amd64-avx512.xml and - i386/x32-avx512.xml. - (srv_i386_linux_xmlfiles): Add i386/i386-avx512-linux.xml. - (srv_amd64_linux_xmlfiles): Add i386/amd64-avx512-linux.xml and - i386/x32-avx512-linux.xml. - * i387-fp.c (num_avx512_k_registers): New constant for number - of K registers. - (num_avx512_zmmh_low_registers): New constant for number of - lower ZMM registers (0-15). - (num_avx512_zmmh_high_registers): New constant for number of - higher ZMM registers (16-31). - (num_avx512_ymmh_registers): New contant for number of higher - YMM registers (ymm16-31 added by avx521 on x86_64). - (num_avx512_xmm_registers): New constant for number of higher - XMM registers (xmm16-31 added by AVX512 on x86_64). - (struct i387_xsave): Add space for AVX512 registers. - (i387_cache_to_xsave): Change raw buffer size to 64 characters. - Add code to handle AVX512 registers. - (i387_xsave_to_cache): Add code to handle AVX512 registers. - * linux-x86-low.c (init_registers_amd64_avx512_linux): New - prototypei from generated file. - (tdesc_amd64_avx512_linux): Likewise. - (init_registers_x32_avx512_linux): Likewise. - (tdesc_x32_avx512_linux): Likewise. - (init_registers_i386_avx512_linux): Likewise. - (tdesc_i386_avx512_linux): Likewise. - (x86_64_regmap): Add AVX512 registers. - (x86_linux_read_description): Add code to handle AVX512 XSTATE - mask. - (initialize_low_arch): Add code to initialize AVX512 registers. - -2014-04-23 Pedro Alves - - * mem-break.c (find_gdb_breakpoint_at): Make static. - * mem-break.h (find_gdb_breakpoint_at): Delete declaration. - -2014-04-23 Pedro Alves - - * i386-low.c: Don't include break-common.h here. - (i386_low_insert_watchpoint, i386_low_remove_watchpoint): Change - prototype to take target_hw_bp_type as argument instead of a Z - packet char. - * i386-low.h: Include break-common.h here. - (Z_packet_to_hw_type): Declare. - (i386_low_insert_watchpoint, i386_low_remove_watchpoint): Change - prototypes. - * linux-x86-low.c (x86_insert_point): Convert the packet number to - a target_hw_bp_type before calling i386_low_insert_watchpoint. - (x86_remove_point): Convert the packet number to a - target_hw_bp_type before calling i386_low_remove_watchpoint. - * win32-i386-low.c (i386_insert_point): Convert the packet number - to a target_hw_bp_type before calling i386_low_insert_watchpoint. - (i386_remove_point): Convert the packet number to a - target_hw_bp_type before calling i386_low_remove_watchpoint. - -2014-04-23 Pedro Alves - - * utils.h (perror_with_name): Add ATTRIBUTE_NORETURN. - -2014-04-10 Pedro Alves - - * mem-break.c (add_breakpoint_condition, add_breakpoint_commands): - Check if the condition or command is NULL before checking if the - breakpoint is known. On success, return true. - * mem-break.h (add_breakpoint_condition): Document return. - (add_breakpoint_commands): Add describing comment. - * server.c (skip_to_semicolon): New function. - (process_point_options): Use it. - -2014-04-09 Pedro Alves - - * linux-low.c (linux_read_loadmap): Pass current_inferior directly - to lwpid_of. - -2014-02-27 Pedro Alves - - PR 12702 - * inferiors.h (A_I_NEXT, ALL_INFERIORS_TYPE, ALL_PROCESSES): New - macros. - * linux-low.c (delete_lwp, handle_extended_wait): Add debug - output. - (last_thread_of_process_p): Take a PID argument instead of a - thread pointer. - (linux_wait_for_lwp): Delete. - (num_lwps, check_zombie_leaders, not_stopped_callback): New - functions. - (linux_low_filter_event): New function, party factored out from - linux_wait_for_event. - (linux_wait_for_event): Rename to ... - (linux_wait_for_event_filtered): ... this. Add new filter ptid - argument. Partly rewrite. Always use waitpid(-1, WNOHANG) and - sigsuspend. Check for zombie leaders. - (linux_wait_for_event): Reimplement as wrapper around - linux_wait_for_event_filtered. - (linux_wait_1): Handle TARGET_WAITKIND_NO_RESUMED. Assume that if - a normal or signal exit is seen, it's the whole process exiting. - (wait_for_sigstop): No longer a for_each_inferior callback. - Rewrite on top of linux_wait_for_event_filtered. - (stop_all_lwps): Call wait_for_sigstop directly. - * server.c (resume, handle_target_event): Handle - TARGET_WAITKIND_NO_RESUMED. - -2014-02-26 Joel Brobecker - - * win32-low.c (psapi_get_dll_name, - * win32_CreateToolhelp32Snapshot): Delete. - (win32_CreateToolhelp32Snapshot, win32_Module32First) - (win32_Module32Next, load_toolhelp, toolhelp_get_dll_name): - Delete. - (handle_load_dll): Add function description. - Remove code using psapi_get_dll_name and toolhelp_get_dll_name. - -2014-02-26 Joel Brobecker - - * win32-low.c (win32_add_one_solib): Add 0x1000 to load_addr. - Add comment. - (win32_add_all_dlls): Remove 0x1000 offset applied to DLL - base address when calling win32_add_one_solib. - (handle_load_dll): Delete local variable load_addr. - Remove 0x1000 offset applied to DLL base address when calling - win32_add_one_solib. - (handle_unload_dll): Add comment. - -2014-02-26 Joel Brobecker - - * win32-low.c (win32_add_all_dlls): Renames - win32_ensure_ntdll_loaded. Rewrite function documentation. - Adjust implementation to always load all DLLs. - Add 0x1000 offset to DLL base address when calling - win32_add_one_solib. - (child_initialization_done): New static global. - (do_initial_child_stuff): Set child_initialization_done to - zero during child initialization, and 1 after. Replace call - to win32_ensure_ntdll_loaded by call to win32_add_all_dlls. - Add comment. - (match_dll_by_basename, dll_is_loaded_by_basename): Delete. - (handle_unload_dll): Add function documentation. - (get_child_debug_event): Ignore load and unload DLL events - during child initialization. - -2014-02-20 Doug Evans - - Remove global all_lwps. - * inferiors.h (ptid_of): Move here from linux-low.h. - (pid_of, lwpid_of): Ditto. - * linux-aarch64-low.c (debug_reg_change_callback): Update, "entry" - parameter is a struct thread_info * now. - (aarch64_notify_debug_reg_change): Fetch pid from current_inferior - directly. Pass &all_threads to find_inferior instead of &all_lwps. - (aarch64_stopped_data_address): Fetch lwpid from current_inferior - directly. - (aarch64_linux_prepare_to_resume): Fetch ptid from thread. - (aarch64_arch_setup): Fetch lwpid from current_inferior directly. - * linux-arm-low.c (update_registers_callback): Update, "entry" - parameter is a struct thread_info * now. - Fetch lwpid from current_inferior directly. - (arm_insert_point): Pass &all_threads to find_inferior instead of - &all_lwps. - (arm_remove_point): Ditto. - (arm_stopped_by_watchpoint): Fetch lwp from current_inferior. - (arm_prepare_to_resume): Fetch pid from thread. - (arm_read_description): Fetch lwpid from current_inferior directly. - * linux-low.c (all_lwps): Delete. - (delete_lwp): Delete call to remove_inferior. - (handle_extended_wait): Fetch lwpid from thread. - (add_lwp): Don't set lwp->entry.id. Remove call to - add_inferior_to_list. - (linux_attach_lwp_1): Fetch pid from current_inferior directly. - (linux_kill_one_lwp): Fetch ptid,lwpid from thread. - (kill_one_lwp_callback): Ditto. - (linux_kill): Don't dereference NULL pointer. - Fetch ptid,lwpid from thread. - (get_detach_signal): Fetch ptid from thread. - (linux_detach_one_lwp): Fetch ptid,lwpid from thread. - Simplify call to regcache_invalidate_thread. - (delete_lwp_callback): Update, "entry" parameter is a - struct thread_info * now. Fetch pid from thread. - (linux_mourn): Pass &all_threads to find_inferior instead of &all_lwps. - (status_pending_p_callback): Update, "entry" parameter is a - struct thread_info * now. Fetch ptid from thread. - (find_lwp_pid): Update, "entry" parameter is a - struct thread_info * now. - (linux_wait_for_lwp): Fetch pid from thread. - (linux_fast_tracepoint_collecting): Fetch lwpid from thread. - (maybe_move_out_of_jump_pad): Fetch lwpid from current_inferior. - (enqueue_one_deferred_signal): Fetch lwpid from thread. - (dequeue_one_deferred_signal): Ditto. - (cancel_breakpoint): Fetch ptid from current_inferior. - (linux_wait_for_event): Pass &all_threads to find_inferior, - not &all_lwps. Fetch ptid, lwpid from thread. - (count_events_callback): Update, "entry" parameter is a - struct thread_info * now. - (select_singlestep_lwp_callback): Ditto. - (select_event_lwp_callback): Ditto. - (cancel_breakpoints_callback): Ditto. - (linux_cancel_breakpoints): Pass &all_threads to find_inferior, - not &all_lwps. - (select_event_lwp): Ditto. Fetch ptid from event_thread. - (unsuspend_one_lwp): Update, "entry" parameter is a - struct thread_info * now. - (unsuspend_all_lwps): Pass &all_threads to find_inferior, - not &all_lwps. - (linux_stabilize_threads): Ditto. And for for_each_inferior. - Fetch lwpid from thread, not lwp. - (linux_wait_1): Fetch ptid, lwpid from current_inferior. - Pass &all_threads to find_inferior, not &all_lwps. - (send_sigstop): Fetch lwpid from thread, not lwp. - (send_sigstop_callback): Update, "entry" parameter is a - struct thread_info * now. - (suspend_and_send_sigstop_callback): Ditto. - (wait_for_sigstop): Ditto. Fetch ptid, lwpid from thread, lwp. - (stuck_in_jump_pad_callback): Update, "entry" parameter is a - struct thread_info * now. - (move_out_of_jump_pad_callback): Ditto. Fetch ptid, lwpid - from thread, lwp. - (lwp_running): Update, "entry" parameter is a - struct thread_info * now. - (stop_all_lwps): Fetch ptid from thread. - Pass &all_threads to find_inferior, for_each_inferior, not &all_lwps. - (linux_resume_one_lwp): Fetch lwpid from thread. - (linux_set_resume_request): Update, "entry" parameter is a - struct thread_info * now. Fetch pid, lwpid from thread. - (resume_status_pending_p): Update, "entry" parameter is a - struct thread_info * now. - (need_step_over_p): Ditto. Fetch lwpid from thread. - (start_step_over): Fetch lwpid from thread. - (linux_resume_one_thread): Update, "entry" parameter is a - struct thread_info * now. Fetch lwpid from thread. - (linux_resume): Pass &all_threads to find_inferior, not &all_lwps. - (proceed_one_lwp): Update, "entry" parameter is a - struct thread_info * now. Fetch lwpid from thread. - (unsuspend_and_proceed_one_lwp): Update, "entry" parameter is a - struct thread_info * now. - (proceed_all_lwps): Pass &all_threads to find_inferior, not &all_lwps. - (unstop_all_lwps): Ditto. Fetch lwpid from thread. - (regsets_fetch_inferior_registers): Fetch lwpid from current_inferior - directly. - (regsets_store_inferior_registers): Ditto. - (fetch_register, store_register): Ditto. - (linux_read_memory, linux_write_memory): Ditto. - (linux_request_interrupt): Ditto. - (linux_read_auxv): Ditto. - (linux_xfer_siginfo): Ditto. - (linux_qxfer_spu): Ditto. - (linux_qxfer_libraries_svr4): Ditto. - * linux-low.h (ptid_of, pid_of, lwpid_of): Delete, - moved to inferiors.h. - (get_lwp): Delete. - (get_thread_lwp): Update. - (struct lwp_info): Delete member "entry". Simplify comment for - member "thread". - (all_lwps): Delete. - * linux-mips-low.c (mips_read_description): Fetch lwpid from - current_inferior directly. - (update_watch_registers_callback): Update, "entry" parameter is a - struct thread_info * now. Fetch pid from thread. - (mips_linux_prepare_to_resume): Fetch ptid from thread. - (mips_insert_point): Fetch lwpid from current_inferior. - Pass &all_threads to find_inferior, not &all_lwps. - (mips_remove_point): Pass &all_threads to find_inferior, not &all_lwps. - (mips_stopped_by_watchpoint): Fetch lwpid from current_inferior - directly. - (mips_stopped_data_address): Ditto. - * linux-s390-low.c (s390_arch_setup): Fetch pid from current_inferior - directly. - * linux-tile-low.c (tile_arch_setup): Ditto. - * linux-x86-low.c (x86_get_thread_area): Fetch lwpid from thread. - (update_debug_registers_callback): Update, "entry" parameter is a - struct thread_info * now. Fetch pid from thread. - (i386_dr_low_set_addr): Fetch pid from current_inferior directly. - Pass &all_threads to find_inferior, not &all_lwps. - (i386_dr_low_get_addr): Fetch ptid from current_inferior directly. - (i386_dr_low_set_control): Fetch pid from current_inferior directly. - Pass &all_threads to find_inferior, not &all_lwps. - (i386_dr_low_get_control): Fetch ptid from current_inferior directly. - (i386_dr_low_get_status): Ditto. - (x86_linux_prepare_to_resume): Fetch ptid from thread. - (x86_siginfo_fixup): Fetch lwpid from current_inferior directly. - (x86_linux_read_description): Ditto. - * proc-service.c (ps_getpid): Fetch pid from current_inferior directly. - -2014-02-20 Doug Evans - - * inferiors.c (get_first_inferior): Fix buglet. - -2014-02-19 Doug Evans - - * gdbthread.h (add_thread): Change result type to struct thread_info *. - * inferiors.c (add_thread): Change result type to struct thread_info *. - All callers updated. - (add_lwp): Call add_thread here instead of in callers. - All callers updated. - * linux-low.h (get_lwp_thread): Rewrite. - (struct lwp_info): New member "thread". - -2014-02-19 Doug Evans - - * linux-low.c (add_lwp): Change result to struct lwp_info *. - All callers updated. - -2014-02-19 Doug Evans - - * inferiors.c (add_thread): Fix whitespace. - -2014-02-19 Doug Evans - - * dll.c (clear_dlls): Replace accessing list implemention details - with API function. - * gdbthread.h (get_first_thread): Declare. - * inferiors.c (for_each_inferior_with_data): New function. - (get_first_thread): New function. - (find_thread_ptid): Simplify. - (get_first_inferior): New function. - (clear_list): Delete. - (one_inferior_p): New function. - (clear_inferior_list): New function. - (clear_inferiors): Update. - * inferiors.h (for_each_inferior_with_data): Declare. - (clear_inferior_list): Declare. - (one_inferior_p): Declare. - (get_first_inferior): Declare. - * linux-low.c (linux_wait_for_event): Replace accessing list - implemention details with API function. - * server.c (target_running): Ditto. - (accumulate_file_name_length): New function. - (emit_dll_description): New function. - (handle_qxfer_libraries): Replace accessing list implemention - details with API function. - (handle_qxfer_threads_worker): New function. - (handle_qxfer_threads_proper): Replace accessing list implemention - details with API function. - (handle_query): Ditto. - (visit_actioned_threads_callback_ftype): New typedef. - (visit_actioned_threads_data): New struct. - (visit_actioned_threads): Rewrite to be find_inferior callback. - (resume): Call find_inferior. - (handle_status): Replace accessing list implemention - details with API function. - (process_serial_event): Replace accessing list implemention details - with API function. - * target.c (set_desired_inferior): Replace accessing list implemention - details with API function. - * tracepoint.c (same_process_p): New function. - (gdb_agent_about_to_close): Replace accessing list implemention - details with API function. - * win32-low.c (child_delete_thread): Replace accessing list - implemention details with API function. - (match_dll_by_basename): New function. - (dll_is_loaded_by_basename): New function. - (win32_ensure_ntdll_loaded): Replace accessing list implemention - details call to dll_is_loaded_by_basename. - -2014-02-19 Doug Evans - - * dll.h (struct dll_info): Add comment. - * gdbthread.h (struct thread_info): Add comment. - (current_ptid): Simplify. - * inferiors.c (add_process): Update. - (remove_process): Update. - * inferiors.h (struct process_info): Rename member "head" to "entry". - * linux-low.c (delete_lwp): Update. - (add_lwp): Update. - (last_thread_of_process_p): Update. - (kill_one_lwp_callback, linux_kill): Update. - (status_pending_p_callback): Update. - (wait_for_sigstop): Update. Simplify read of ptid. - (start_step_over): Update. - * linux-low.h (ptid_of, pid_of, lwpid_of): Update. - (get_lwp_thread): Update. - (struct lwp_info): Rename member "head" to "entry". - * regcache.h (inferior_list_entry): Delete. - * server.c (kill_inferior_callback): Update. - (detach_or_kill_inferior_callback): Update. - (print_started_pid): Update. - (print_attached_pid): Update. - (process_serial_event): Simplify read of ptid. - * thread-db.c (thread_db_create_event): Update. - (thread_db_get_tls_address): Update. - * win32-low.c (current_inferior_ptid): Simplify. - -2014-02-19 Tom Tromey - - * target.h (struct target_ops) : Add target_ops - argument. - (target_supports_btrace): Update. - -2014-02-14 Yao Qi - - * Makefile.in (IPA_OBJS): Append rsp-low-ipa.o. - (rsp-low-ipa.o): New target. - -2014-02-12 Tom Tromey - - * ax.c (gdb_parse_agent_expr): Use hex2bin, not - convert_ascii_to_int. - * regcache.c (registers_to_string): Likewise. - * remote-utils.c (decode_M_packet): Likewise. - * server.c (process_serial_event): Likewise. - -2014-02-12 Tom Tromey - - * server.c (handle_query, handle_v_run): Use hex2bin, not - unhexify. - * tracepoint.c (cmd_qtdpsrc, cmd_qtdv, cmd_qtnotes): Likewise. - -2014-02-12 Tom Tromey - - * ax.c (gdb_unparse_agent_expr): Use bin2hex, not - convert_int_to_ascii. - * regcache.c (registers_to_string, collect_register_as_string): - Likewise. - * remote-utils.c (look_up_one_symbol, relocate_instruction): - Likewise. - * server.c (process_serial_event): Likewise. - * tracepoint.c (cmd_qtstatus, response_source, response_tsv) - (cmd_qtbuffer, cstr_to_hexstr): Likewise. - -2014-02-12 Tom Tromey - - * remote-utils.c (look_up_one_symbol, monitor_output): Use - bin2hex, not hexify. - * tracepoint.c (cmd_qtstatus): Likewise. - -2014-02-12 Tom Tromey - - * remote-utils.c (monitor_output): Pass explicit length to - hexify. - -2014-02-12 Tom Tromey - - * tracepoint.c: Include rsp-low.h. - * server.c: Include rsp-low.h. - * remote-utils.h (convert_ascii_to_int, convert_int_to_ascii) - (unhexify, hexify, remote_escape_output, unpack_varlen_hex): Don't - declare. - * remote-utils.c: Include rsp-low.h. - (fromhex, hexchars, ishex, unhexify, tohex, hexify) - (remote_escape_output, remote_unescape_input, unpack_varlen_hex) - (convert_int_to_ascii, convert_ascii_to_int): Move to - common/rsp-low.c. - * regcache.c: Include rsp-low.h. - * ax.c: Include rsp-low.h. - * Makefile.in (SFILES): Add common/rsp-low.c. - (OBS): Add rsp-low.o. - (rsp-low.o): New target. - -2014-02-12 Tom Tromey - - * utils.h (pulongest, plongest, phex_nz): Don't declare. - Include print-utils.h. - * utils.c (NUMCELLS, CELLSIZE, get_cell, decimal2str, pulongest) - (plongest, thirty_two, phex_nz): Remove. - * Makefile.in (SFILES): Add common/print-utils.c. - (OBS): Add print-utils.o. - (print-utils-ipa.o): New target. - (print-utils.o): New target. - (IPA_OBJS): Add print-utils-ipa.o. - -2014-02-06 Tom Tromey - - * Makefile.in (SFILES): Fix indentation. - -2014-02-05 Doug Evans - - * linux-low.c (linux_wait_for_event): Improve comment. - (linux_wait_1): Keep current_inferior in sync with event_child. - -2014-01-22 Doug Evans - - * gdbthread.h (gdb_id_to_thread): Delete, unused. - -2014-01-22 Doug Evans - - * configure.ac (AC_CHECK_FUNCS): Add test for gettimeofday. - * configure: Regenerate. - * config.in: Regenerate. - * Makefile.in (SFILES): Add debug.c. - (OBS): Add debug.o. - * debug.c: New file. - * debug.h: New file. - * linux-aarch64-low.c (*): Update all debugging printfs to use - debug_printf instead of fprintf. - * linux-arm-low.c (*): Ditto. - * linux-cris-low.c (*): Ditto. - * linux-crisv32-low.c (*): Ditto. - * linux-m32r-low.c (*): Ditto. - * linux-sparc-low.c (*): Ditto. - * linux-x86.c (*): Ditto. - * linux-low.c (*): Ditto. - (linux_wait_1): Add calls to debug_enter, debug_exit. - (linux_wait): Remove redundant debugging printf. - (stop_all_lwps): Add calls to debug_enter, debug_exit. - (linux_resume, unstop_all_lwps): Ditto. - * mem-break.c (*): Update all debugging printfs to use - debug_printf instead of fprintf. - * remote-utils.c (*): Ditto. - * thread-db.c (*): Ditto. - * server.c #include , "gdb_vecs.h". - (debug_threads): Moved to debug.c. - (*): Update all debugging printfs to use debug_printf instead of - fprintf. - (start_inferior): Replace call to fflush with call to debug_flush. - (monitor_show_help): Mention set debug-format. - (parse_debug_format_options): New function. - (handle_monitor_command): Handle "monitor set debug-format". - (gdbserver_usage): Mention --debug-format. - (main): Parse --debug-format. - * server.h (debug_threads): Declaration moved to debug.h. - #include "debug.h". - * tracepoint.c (trace_debug_1) [!IN_PROCESS_AGENT]: Add version of - trace_debug_1 that uses debug_printf. - (tracepoint_look_up_symbols): Update all debugging printfs to use - debug_printf instead of fprintf. - -2014-01-20 Baruch Siach - - * linux-xtensa-low.c: Include asm/ptrace.h instead of - sys/ptrace.h. - -2014-01-17 Pedro Alves - - PR build/16445 - * linux-x86-low.c: Don't include elf/common.h if ELFMAG0 is - defined after including gdb_proc_service.h. - -2014-01-16 Doug Evans - - * dll.c (UNSPECIFIED_CORE_ADDR): New macro. - (match_dll): Use it. - -2014-01-16 Markus Metzger - - * target.h (target_ops) : Change parameters and - return type to allow error reporting. - * server.c (handle_qxfer_btrace): Support delta reads. Pass - trace reading errors on. - * linux-low.c (linux_low_read_btrace): Pass trace reading - errors on. - (linux_low_disable_btrace): New. - -2014-01-15 Doug Evans - - * inferiors.c (thread_id_to_gdb_id): Delete. - * inferiors.h (thread_id_to_gdb_id): Delete. - -2014-01-13 Eli Zaretskii - - * Makefile.in (INCLUDE_CFLAGS): Remove trailing slash from - "-I$(srcdir)/../". Fixes MinGW compilation errors with old GCC - versions. - -2014-01-08 Pedro Alves - - * server.c (handle_status): Don't discard previous queued stop - replies or thread's pending status here. - (main) : Do it here instead. - -2014-01-08 Pedro Alves - - * gdbthread.h (struct thread_info) : New field. - * server.c (visit_actioned_threads, handle_pending_status): New - function. - (handle_v_cont): Factor out parts to ... - (resume): ... this new function. If in all-stop, and a thread - being resumed has a pending status, report it without actually - resuming. - (myresume): Adjust to use the new 'resume' function. - (clear_pending_status_callback, set_pending_status_callback) - (find_status_pending_thread_callback): New functions. - (handle_status): Handle the case of multiple threads having - interesting statuses to report. Report threads' real last signal - instead of always reporting GDB_SIGNAL_TRAP. Look for a thread - with an interesting thread to report the status for, instead of - always reporting the status of the first thread. - -2014-01-01 Joel Brobecker - - * gdbserver.c (gdbserver_version): Set copyright year to 2014. - * gdbreplay.c (gdbreplay_version): Likewise. - -2013-12-18 Yufeng Zhang - - * linux-aarch64-low.c (aarch64_linux_set_debug_regs): Set - iov.iov_len with the real length in use. - -2013-12-13 Joel Brobecker - - * Makefile.in (safe-ctype.o, lbasename.o): New rules. - * configure.srv: Add safe-ctype.o and lbasename.o to srv_tgtobj - for all targets that use win32-low.c. - * win32-low.c (win32_ensure_ntdll_loaded): New function. - (do_initial_child_stuff): Add call to win32_ensure_ntdll_loaded. - -2013-12-13 Pedro Alves - - * target.c (mywait): Set OURSTATUS->KIND to TARGET_WAITKIND_STOPPED - if equal to TARGET_WAITKIND_LOADED. - * win32-low.c (cached_status): New static global. - (win32_wait): Add declaration. - (do_initial_child_stuff): Flush all initial pending debug events - up to the initial breakpoint. - (win32_wait): If CACHED_STATUS was set, return that instead - of doing a real wait. Remove the code resuming the execution - of the inferior after receiving a TARGET_WAITKIND_LOADED event - during the initial phase. Also remove the code changing - OURSTATUS->KIND from TARGET_WAITKIND_LOADED to - TARGET_WAITKIND_STOPPED. - -2013-12-11 Yao Qi - - * notif.c (handle_notif_ack): Return 0 if no notification - matches. - -2013-11-20 Doug Evans - - * linux-low.c (linux_set_resume_request): Fix comment. - -2013-11-20 Doug Evans - - * linux-low.c (resume_status_pending_p): Tweak comment. - -2013-11-20 Walfred Tedeschi - - * Makefile.in: Add i386-mpx.c, i386-mpx-linux.c, amd64-mpx.c, - amd64-mpx-linux.c, x32-mpx.c and x32-mpx-linux.c generation. - * configure.srv (srv_i386_regobj): Add i386-mpx.o. - (srv_i386_linux_regobj): Add i386-mpx-linux.o. - (srv_amd64_regobj): Add amd64-mpx.o. - (srv_amd64_linux_regobj): Add amd64-mpx-linux.o. - (srv_i386_32bit_xmlfiles): Add i386/32bit-mpx.xml. - (srv_i386_64bit_xmlfiles): Add i386/64bit-mpx.xml. - * i387-fp.c (num_pl_bnd_register) Added constant. - (num_pl_bnd_cfg_registers) Added constant. - (struct i387_xsave) Added reserved area and MPX fields. - (i387_cache_to_xsave, i387_xsave_to_cache) Add MPX. - * linux-x86-low.c (init_registers_i386_mpx_linux): Declare new - function. - (tdesc_i386_mpx_linux): Add MPX amd64 target. - (init_registers_amd64_mpx_linux): Declare new function. - (tdesc_amd64_mpx_linux): Add MPX amd64 target. - (x86_64_regmap): Add MPX registers. - (x86_linux_read_description): Add MPX case. - (initialize_low_arch): Initialize MPX targets. - -2013-11-18 Tom Tromey - - * configure: Rebuild. - * configure.ac: Don't check for stdlib.h. - * gdbreplay.c: Unconditionally include stdlib.h. - -2013-11-18 Tom Tromey - - * config.in: Rebuild. - * configure: Rebuild. - * configure.ac: Don't use AC_HEADER_DIRENT. - -2013-11-18 Tom Tromey - - * server.h: Don't check HAVE_STRING_H. - * gdbreplay.c: Don't check HAVE_STRING_H. - * configure: Rebuild. - -2013-11-18 Tom Tromey - - * Makefile.in (gdbreplay$(EXEEXT)): Depend on and link against - LIBGNU. - -2013-11-08 Tom Tromey - - * configure, config.in: Rebuild. - * configure.ac: Remove unused configury. - -2013-11-08 Tom Tromey - - * acinclude.m4: Include common.m4, codeset.m4. - * configure, config.in: Rebuild. - * configure.ac: Use GDB_AC_COMMON. - -2013-11-06 Andreas Arnez - - * linux-s390-low.c (HWCAP_S390_TE): New define. - (s390_arch_setup): Consider the TE field in the HWCAP for - determining 'have_regset_tdb'. - -2013-10-16 Sergio Durigan Junior - - PR gdb/16014 - * tracepoint.c (download_tracepoint_1): Remove unnecessary double - call to sizeof. - -2013-10-02 Pedro Alves - - * server.c (process_serial_event): Don't output "GDBserver - exiting" if GDB is connected through stdio. - * target.c (mywait): Likewise, be silent if GDB is connected - through stdio. - -2013-10-01 Joel Brobecker - - * lynx-low.c (lynx_add_threads_after_attach): New function. - (lynx_attach): Remove call to add_thread. Add call to - lynx_add_threads_after_attach instead. - -2013-09-28 Mike Frysinger - - * configure.ac (AC_CHECK_HEADERS): Add sys/syscall.h - * config.in, configure: Regenerated. - -2013-09-18 Yao Qi - - PR server/15959 - * server.c (start_inferior): Clear 'resume_info'. - -2013-09-16 Jiong Wang - - * linux-tile-low.c (tile_regsets): Modify the size field to 64-bit - for each register. - -2013-09-16 Jiong Wang - - * configure.srv : Remove linux-osdata.o from and add - linux-tile-low.o to srv_tgtobj. - -2013-09-16 Will Newton - - * linux-aarch64-low.c (aarch64_linux_set_debug_regs): Zero - out regs. - -2013-09-06 Pedro Alves - - * Makefile.in (gdb_proc_service_h, regdef_h, regcache_h) - (signals_def, signals_h, ptid_h, ax_h, agent_h, linux_btrace_h) - (linux_osdata_h, vec_h, gdb_vecs_h, host_defs_h, libiberty_h) - (server_h, gdbthread_h, linux_low_h, linux_ptrace_h) - (gdb_thread_db_h, linux_procfs_h, lynx_low_h, nto_low_h) - (mips_linux_watch_h, i386_low_h, win32_low_h): Delete. - -2013-09-06 Pedro Alves - - * Makefile.in (linux-btrace.o, mips-linux-watch.o): Remove - explicit header dependencies and use $COMPILE/$POSTCOMPILE. - -2013-09-06 Pedro Alves - - * linux-amd64-ipa.c: Include tracepoint.h. - * linux-i386-ipa.c: Include tracepoint.h. - -2013-09-06 Ricard Wanderlof - - * linux-crisv32-low.c (PTRACE_GET_THREAD_AREA): New macro. - (ps_get_thread_area): New function. - -2013-09-06 Ricard Wanderlof - - * linux-crisv32-low.c (elf_gregset_t): Delete typedef. - (initialize_low_arch): Call init_registers_crisv32 rather than - init_register_crisv32. - -2013-09-05 Pedro Alves - - * server.h (handle_vFile, hostio_last_error_from_errno): Move - to ... - * hostio.h: ... this new file. - * hostio.c, server.c, linux-low.c, nto-low.c, spu-low, - win32-low.c: Include hostio.h. - -2013-09-05 Pedro Alves - - * server.h (gdb_client_data, handler_func, callback_handler_func) - (delete_file_handler, add_file_handler, append_callback_event) - (delete_callback_event, start_event_loop, initialize_event_loop): - Move to event-loop.h and include it. - * event-loop.h: New file. - -2013-09-05 Pedro Alves - - * dll.c, inferiors.c, remote-utils.c, server.c: Include "dll.h". - * server.h (struct dll_info, all_dlls, dlls_changed, clear_dlls) - (loaded_dll, unloaded_dll): Move to ... - * dll.h: ... this new file. - * inferiors.c, remote-utils.c, win32-low.c: Include "dll.h". - -2013-09-05 Pedro Alves - - * server.h (current_process, get_thread_process, all_processes) - (add_inferior_to_list, for_each_inferior, current_inferior) - (remove_inferior, add_process, remove_process, find_process_pid) - (have_started_inferiors_p, have_attached_inferiors_p) - (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id) - (clear_inferiors, find_inferior, find_inferior_id) - (inferior_target_data, set_inferior_target_data) - (inferior_regcache_data, set_inferior_regcache_data): Move to - inferiors.h, and include it. - * inferiors.h: New file. - -2013-09-05 Pedro Alves - - * server.h (struct emit_ops, current_insn_ptr, emit_error): - Move ... - * ax.h: ... here. - -2013-09-05 Pedro Alves - - * ax.c, linux-low.c, linux-x86-low.c, server.c: Include - tracepoint.h. - * server.h (IPA_BUFSIZ, initialize_tracepoint, tracing) - (disconnected_tracing, tracepoint_look_up_symbols, stop_tracing - (handle_tracepoint_general_set, handle_tracepoint_query) - (tracepoint_finished_step, tracepoint_was_hit) - (release_while_stepping_state_list, current_traceframe) - (in_readonly_region, traceframe_read_mem) - (fetch_traceframe_registers, traceframe_read_sdata) - (traceframe_read_info, struct fast_tpoint_collect_status) - (fast_tracepoint_collecting, force_unlock_trace_buffer) - (handle_tracepoit_bkpts, initialize_low_tracepoint) - (supply_fast_tracepoint_registers) - (supply_static_tracepoint_registers, set_trampoline_buffer_space) - (ipa_tdesc, claim_trampoline_space) - (have_fast_tracepoint_trampoline_buffer, gdb_agent_about_to_close) - (agent_mem_read, agent_get_trace_state_variable_value) - (agent_set_trace_state_variable_value, agent_tsv_read) - (agent_mem_read_string, get_raw_reg_func_addr) - (get_get_tsv_func_addr, get_set_tsv_func_addr): Move to ... - * tracepoint.h: ... this new file. - -2013-09-05 Pedro Alves - - * server.h (perror_with_name, error, fatal, warning, paddress) - (pulongest, plongest, phex_nz, pfildes): Move to utils.h, and - include it. - * utils.h: New file. - -2013-09-05 Pedro Alves - - * server.h (remote_debug, noack_mode, transport_is_reliable) - (gdb_connected, STDIO_CONNECTION_NAME, remote_connection_is_stdio) - (read_ptid, write_ptid, putpkt, putpkt_binary, putpkt_notif) - (getpkt, remote_prepare, remote_open, remote_close, write_ok) - (write_enn, initialize_async_io, enable_async_io) - (disable_async_io, check_remote_input_interrupt_request) - (convert_ascii_to_int, convert_int_to_ascii, new_thread_notify) - (dead_thread_notify, prepare_resume_reply) - (decode_address_to_semicolon, decode_address, decode_m_packet) - (decode_M_packet, decode_X_packet, decode_xfer_write) - (decode_search_memory_packet, unhexify, hexify) - (remote_escape_output, unpack_varlen_hex, clear_symbol_cache) - (look_up_one_symbol, relocate_instruction) - (monitor_output): Move to remote-utils.h, and include it. - * remote-utils.h: New file. - -2013-09-05 Pedro Alves - - * server.h (_): Delete. - -2013-09-02 Pedro Alves - - * tracepoint.c (TRACEFRAME_EOB_MARKER_SIZE): New macro. - (init_trace_buffer): Ensure at least TRACEFRAME_EOB_MARKER_SIZE is - allocated. - (trace_buffer_alloc): Use TRACEFRAME_EOB_MARKER_SIZE. - -2013-09-02 Pierre Muller - - * win32-low.c (child_xfer_memory): Check if ReadProcessMemory - or WriteProcessMemory complete successfully and handle - ERROR_PARTIAL_COPY error. - -2013-09-02 Pedro Alves - - * server.c (gdb_read_memory): Return -1 on traceframe memory read - error instead of EIO. - -2013-08-28 Jan Kratochvil - - PR server/15604 - * linux-low.c: Include filestuff.h. - (linux_create_inferior) : Call close_most_fds. - * lynx-low.c: Include filestuff.h. - (lynx_create_inferior) : Call close_most_fds. - * server.c: Include filestuff.h. - (main): Call notice_open_fds. - * spu-low.c: Include filestuff.h. - (spu_create_inferior) : Call close_most_fds. - -2013-08-22 Luis Machado - - * Makefile.in: Explain why ../target and ../nat are not - listed as include file search paths. - (linux-waitpid.o): New object file rule. - * configure.srv (srv_native_linux_obj): New variable. - Replace all occurrences of linux native object files with - $srv_native_linux_obj. - * linux-low.c: Include nat/linux-nat.h and nat/linux-waitpid.h. - (HAS_NOMMU): Move defining logic to common/linux-ptrace.c. - (linux_enable_event_reporting): Remove declaration. - (my_waitpid): Moved to common/linux-waitpid.c. - (linux_wait_for_event): Pass ptid when calling - linux_enable_event_reporting. - (linux_supports_tracefork_flag): Remove. - (linux_enable_event_reporting): Likewise. - (linux_tracefork_grandchild): Remove. - (STACK_SIZE): Moved to common/linux-ptrace.c. - (linux_tracefork_child): Remove. - (linux_test_for_tracefork): Remove. - (linux_look_up_symbols): Call linux_supports_traceclone. - (initialize_low): Remove call to linux_test_for_tracefork. - * linux-low.h (PTRACE_TYPE_ARG3): Move to - common/linux-ptrace.h. - (PTRACE_TYPE_ARG4): Likewise. - Include linux-ptrace.h. - -2013-08-21 Pedro Alves - - * config.in: Renegerate. - -2013-08-19 Luis Machado - - * Makefile.in (INCLUDE_CFLAGS): Include -I$(srcdir)/../. - (SFILES): Remove $(srcdir)/common/target-common.c and - add $(srcdir)/target/waitstatus.c. - (OBS): Remove target-common.o and add waitstatus.o. - (server_h): Remove $(srcdir)/../common/target-common.h and - add $(srcdir)/../target/resume.h, $(srcdir)/../target/wait.h - and $(srcdir)/../target/waitstatus.h. - (target-common.o): Remove. - (waitstatus.o): New target object file. - * target.h: Do not include target-common.h and - include target/resume.h, target/wait.h and - target/waitstatus.h. - -2013-08-13 Luis Machado - - * linux-arm-low.c: Rename all occurrences of PTRACE_ARG3_TYPE - to PTRACE_TYPE_ARG3. - * linux-low.c: Rename all occurrences of PTRACE_ARG3_TYPE - to PTRACE_TYPE_ARG3 and PTRACE_ARG4_TYPE to - PTRACE_TYPE_ARG4. - * linux-low.h (PTRACE_ARG3_TYPE): Rename to PTRACE_TYPE_ARG3. - (PTRACE_ARG4_TYPE): Rename to PTRACE_TYPE_ARG4. - -2013-07-27 Jie Zhang - Daniel Jacobowitz - Yao Qi - - * Makefile.in (SFILES): Add common/mips-linux-watch.c. - (mips-linux-watch.o): New rule. - (mips_linux_watch_h): New variable. - * configure.srv : Add mips-linux-watch.o to - srv_tgtobj. - * linux-mips-low.c: Include mips-linux-watch.h. - (struct arch_process_info, struct arch_lwp_info): New. - (update_watch_registers_callback): New function. - (mips_linux_new_process, mips_linux_new_thread) New functions. - (mips_linux_prepare_to_resume, mips_insert_point): New - functions. - (mips_remove_point, mips_stopped_by_watchpoint): New - functions. - (rsp_bp_type_to_target_hw_bp_type): New function. - (mips_stopped_data_address): New function. - (the_low_target): Add watchpoint support functions. - -2013-07-27 Yao Qi - - * i386-low.c: Include break-common.h. - (enum target_hw_bp_type): Remove. - -2013-07-24 Luis Machado - - * Makefile.in (SFILES): /common/target-common.c. - (OBS): Add target-common.o. - (server_h): Add $(srcdir)/../common/target-common.h. - (target-common.o): New target. - * server.c (queue_stop_reply_callback): Free - status string after use. - * target.c (target_waitstatus_to_string): Remove. - * target.h: Include target-common.h. - (resume_kind): Likewise. - (target_waitkind): Likewise. - (target_waitstatus): Likewise. - (TARGET_WNOHANG): Likewise. - -2013-07-04 Yao Qi - - * Makefile.in (host_alias): Use @host_noncanonical@. - (target_alias): Use @target_noncanonical@. - * configure.ac: Use ACX_NONCANONICAL_TARGET and - ACX_NONCANONICAL_HOST. - * configure: Regenerated. - - Revert: - 2013-06-28 Mircea Gherzan - - * configure.ac (version_host, version_target): Set and AC_SUBST them. - * configure: Rebuild. - * Makefile.in (version_host, version_target): Get from configure. - (version.c): Use $(version_host) and $(version_target). - -2013-07-03 Pedro Alves - - * Makefile.in (config.status): Depend on development.sh. - * acinclude.m4: Include libmcheck.m4. - * configure: Regenerate. - -2013-07-02 Mircea Gherzan - - * win32-low.c (winapi_DebugActiveProcessStop): Move the WINAPI - attribute inside the parentheses. - (winapi_DebugSetProcessKillOnExit): Ditto. - (winapi_DebugBreakProcess): Ditto. - (winapi_GenerateConsoleCtrlEvent): Ditto. - -2013-07-02 Mircea Gherzan - - * notif.h (notif_event): Add a dummy member to avoid compiler - errors. - -2013-07-01 Pedro Alves - - * hostio.c (HOSTIO_PATH_MAX): Define. - (require_filename, handle_open, handle_unlink, handle_readlink): - Use it. - -2013-07-01 Pedro Alves - - * server.h: Include "pathmax.h". - * linux-low.c: Don't include sys/param.h. - (linux_pid_exe_is_elf_64_file): Use PATH_MAX instead of - MAXPATHLEN. - * win32-low.c: Don't include sys/param.h. - (win32_create_inferior): Use PATH_MAX instead of MAXPATHLEN. - -2013-07-01 Pedro Alves - - * event-loop.c: Don't check HAVE_UNISTD_H before including - . - * gdbreplay.c: Likewise. - * remote-utils.c: Likewise. - * server.c: Likewise. - * configure.ac: Don't check for unistd.h. - * configure: Regenerate. - -2013-06-28 Tom Tromey - - * Makefile.in (version.c): Use version.in, not - common/version.in. - -2013-06-28 Mircea Gherzan - - * configure.ac (version_host, version_target): Set and AC_SUBST them. - * configure: Rebuild. - * Makefile.in (version_host, version_target): Get from configure. - (version.c): Use $(version_host) and $(version_target). - -2013-06-10 Dmitry Kozlov - - Fix trace-status to output user name without trailing colon. - * tracepoint.c (cmd_qtstatus): Remove unnecessary colon from user name. - -2013-06-10 Dmitry Kozlov - - Fix trace-status to output proper start-time and stop-time. - * tracepoint.c (cmd_qtstatus): Modify trace-status output to - output start time and stop time in hex as gdb expects. - -2013-06-26 Pedro Alves - - * tracepoint.c (build_traceframe_info_xml): Output trace state - variables present in the trace buffer. - -2013-06-24 Tom Tromey - - * Makefile.in (version.c): Use bfd/version.h, common/version.in, - create-version.sh. - (version.o): Remove. - * gdbreplay.c: Include version.h. - (version, host_name): Don't declare. - * server.h: Include version.h. - (version, host_name): Don't declare. - -2013-06-12 Pedro Alves - - * linux-x86-low.c (linux_is_elf64): Delete global. - (x86_siginfo_fixup): Replace reference to `linux_is_elf64' global - with local linux_pid_exe_is_elf_64_file use. - -2013-06-11 Pedro Alves - - * linux-low.c (regset_disabled, disable_regset): New functions. - (regsets_fetch_inferior_registers) - (regsets_store_inferior_registers): Use them. - (initialize_regsets_info); Don't allocate the disabled_regsets - array here. - * linux-low.h (struct regsets_info) : Extend - comment. - -2013-06-11 Pedro Alves - - * linux-low.c (initialize_regsets_info): Use xcalloc instead of - xmalloc. - -2013-06-11 Pedro Alves - - * linux-x86-low.c (initialize_low_arch): Call - init_registers_x32_avx_linux. - -2013-06-09 Jan Kratochvil - - Fix compatibility with Android Bionic. - * linux-low.c (linux_qxfer_libraries_svr4): Ignore first entry even if - it is not empty. - -2013-06-07 Pedro Alves - - PR server/14823 - * Makefile.in (OBS): Add tdesc.o. - (IPA_OBJS): Add tdesc-ipa.o. - (tdesc-ipa.o): New rule. - * ax.c (gdb_eval_agent_expr): Adjust register_size call to new - interface. - * linux-low.c (new_inferior): Delete. - (disabled_regsets, num_regsets): Delete. - (linux_add_process): Adjust to set the new per-process - new_inferior flag. - (linux_detach_one_lwp): Adjust to call regcache_invalidate_thread. - (linux_wait_for_lwp): Adjust. Only call arch_setup if the event - was a stop. When calling arch_setup, switch the current inferior - to the thread that got an event. - (linux_resume_one_lwp): Adjust to call regcache_invalidate_thread. - (regsets_fetch_inferior_registers) - (regsets_store_inferior_registers): New regsets_info parameter. - Adjust to use it. - (linux_register_in_regsets): New regs_info parameter. Adjust to - use it. - (register_addr, fetch_register, store_register): New usrregs_info - parameter. Adjust to use it. - (usr_fetch_inferior_registers, usr_store_inferior_registers): New - parameter regs_info. Adjust to use it. - (linux_fetch_registers): Get the current inferior's regs_info, and - adjust to use it. - (linux_store_registers): Ditto. - [HAVE_LINUX_REGSETS] (initialize_regsets_info): New. - (initialize_low): Don't initialize the target_regsets here. Call - initialize_low_arch. - * linux-low.h (target_regsets): Delete declaration. - (struct regsets_info): New. - (struct usrregs_info): New. - (struct regs_info): New. - (struct process_info_private) : New field. - (struct linux_target_ops): Delete the num_regs, regmap, and - regset_bitmap fields. New field regs_info. - [HAVE_LINUX_REGSETS] (initialize_regsets_info): Declare. - * i387-fp.c (num_xmm_registers): Delete. - (i387_cache_to_fsave, i387_fsave_to_cache): Adjust find_regno - calls to new interface. - (i387_cache_to_fxsave, i387_cache_to_xsave, i387_fxsave_to_cache) - (i387_xsave_to_cache): Adjust find_regno calls to new interface. - Infer the number of xmm registers from the regcache's target - description. - * i387-fp.h (num_xmm_registers): Delete. - * inferiors.c (add_thread): Don't install the thread's regcache - here. - * proc-service.c (gregset_info): Fetch the current inferior's - regs_info. Adjust to use it. - * regcache.c: Include tdesc.h. - (register_bytes, reg_defs, num_registers) - (gdbserver_expedite_regs): Delete. - (get_thread_regcache): If the thread doesn't have a regcache yet, - create one, instead of aborting gdbserver. - (regcache_invalidate_one): Rename to ... - (regcache_invalidate_thread): ... this. - (regcache_invalidate_one): New. - (regcache_invalidate): Only invalidate registers of the current - process. - (init_register_cache): Add target_desc parameter, and use it. - (new_register_cache): Ditto. Assert the target description has a - non zero registers_size. - (regcache_cpy): Add assertions. Adjust. - (realloc_register_cache, set_register_cache): Delete. - (registers_to_string, registers_from_string): Adjust. - (find_register_by_name, find_regno, find_register_by_number) - (register_cache_size): Add target_desc parameter, and use it. - (free_register_cache_thread, free_register_cache_thread_one) - (regcache_release, register_cache_size): New. - (register_size): Add target_desc parameter, and use it. - (register_data, supply_register, supply_register_zeroed) - (supply_regblock, supply_register_by_name, collect_register) - (collect_register_as_string, collect_register_by_name): Adjust. - * regcache.h (struct target_desc): Forward declare. - (struct regcache) : New field. - (init_register_cache, new_register_cache): Add target_desc - parameter. - (regcache_invalidate_thread): Declare. - (regcache_invalidate_one): Delete declaration. - (regcache_release): Declare. - (find_register_by_number, register_cache_size, register_size) - (find_regno): Add target_desc parameter. - (gdbserver_expedite_regs, gdbserver_xmltarget): Delete - declarations. - * remote-utils.c: Include tdesc.h. - (outreg, prepare_resume_reply): Adjust. - * server.c: Include tdesc.h. - (gdbserver_xmltarget): Delete declaration. - (get_features_xml, process_serial_event): Adjust. - * server.h [IN_PROCESS_AGENT] (struct target_desc): Forward - declare. - (struct process_info) : New field. - (ipa_tdesc): Declare. - * tdesc.c: New file. - * tdesc.h: New file. - * tracepoint.c: Include tdesc.h. - [IN_PROCESS_AGENT] (ipa_tdesc): Define. - (get_context_regcache): Adjust to pass ipa_tdesc down. - (do_action_at_tracepoint): Adjust to get the register cache size - from the context regcache's description. - (traceframe_walk_blocks): Adjust to get the register cache size - from the current trace frame's description. - (traceframe_get_pc): Adjust to get current trace frame's - description and pass it down. - (gdb_collect): Adjust to get the register cache size from the - IPA's description. - * linux-amd64-ipa.c (tdesc_amd64_linux): Declare. - (gdbserver_xmltarget): Delete. - (initialize_low_tracepoint): Set the ipa's target description. - * linux-i386-ipa.c (tdesc_i386_linux): Declare. - (initialize_low_tracepoint): Set the ipa's target description. - * linux-x86-low.c: Include tdesc.h. - [__x86_64__] (is_64bit_tdesc): New. - (ps_get_thread_area, x86_get_thread_area): Use it. - (i386_cannot_store_register): Rename to ... - (x86_cannot_store_register): ... this. Use is_64bit_tdesc. - (i386_cannot_fetch_register): Rename to ... - (x86_cannot_fetch_register): ... this. Use is_64bit_tdesc. - (x86_fill_gregset, x86_store_gregset): Adjust register_size calls - to new interface. - (target_regsets): Rename to ... - (x86_regsets): ... this. - (x86_get_pc, x86_set_pc): Adjust register_size calls to new - interface. - (x86_siginfo_fixup): Use is_64bit_tdesc. - [__x86_64__] (tdesc_amd64_linux, tdesc_amd64_avx_linux) - (tdesc_x32_avx_linux, tdesc_x32_linux) - (tdesc_i386_linux, tdesc_i386_mmx_linux, tdesc_i386_avx_linux): - Declare. - (x86_linux_update_xmltarget): Delete. - (I386_LINUX_XSAVE_XCR0_OFFSET): Define. - (have_ptrace_getfpxregs, have_ptrace_getregset): New. - (AMD64_LINUX_USER64_CS): New. - (x86_linux_read_description): New, based on - x86_linux_update_xmltarget. - (same_process_callback): New. - (x86_arch_setup_process_callback): New. - (x86_linux_update_xmltarget): New. - (x86_regsets_info): New. - (amd64_linux_regs_info): New. - (i386_linux_usrregs_info): New. - (i386_linux_regs_info): New. - (x86_linux_regs_info): New. - (x86_arch_setup): Reimplement. - (x86_install_fast_tracepoint_jump_pad): Use is_64bit_tdesc. - (x86_emit_ops): Ditto. - (the_low_target): Adjust. Install x86_linux_regs_info, - x86_cannot_fetch_register, and x86_cannot_store_register. - (initialize_low_arch): New. - * linux-ia64-low.c (tdesc_ia64): Declare. - (ia64_fetch_register): Adjust. - (ia64_usrregs_info, regs_info): New globals. - (ia64_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-sparc-low.c (tdesc_sparc64): Declare. - (sparc_fill_gregset_to_stack, sparc_store_gregset_from_stack): - Adjust. - (sparc_arch_setup): New function. - (sparc_regsets_info, sparc_usrregs_info, regs_info): New globals. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-ppc-low.c (tdesc_powerpc_32l, tdesc_powerpc_altivec32l) - (tdesc_powerpc_cell32l, tdesc_powerpc_vsx32l) - (tdesc_powerpc_isa205_32l, tdesc_powerpc_isa205_altivec32l) - (tdesc_powerpc_isa205_vsx32l, tdesc_powerpc_e500l) - (tdesc_powerpc_64l, tdesc_powerpc_altivec64l) - (tdesc_powerpc_cell64l, tdesc_powerpc_vsx64l) - (tdesc_powerpc_isa205_64l, tdesc_powerpc_isa205_altivec64l) - (tdesc_powerpc_isa205_vsx64l): Declare. - (ppc_cannot_store_register, ppc_collect_ptrace_register) - (ppc_supply_ptrace_register, parse_spufs_run, ppc_get_pc) - (ppc_set_pc, ppc_get_hwcap): Adjust. - (ppc_usrregs_info): Forward declare. - (!__powerpc64__) ppc_regmap_adjusted: New global. - (ppc_arch_setup): Adjust to the current process'es target - description. - (ppc_fill_vsxregset, ppc_store_vsxregset, ppc_fill_vrregset) - (ppc_store_vrregset, ppc_fill_evrregset, ppc_store_evrregse) - (ppc_store_evrregset): Adjust. - (target_regsets): Rename to ... - (ppc_regsets): ... this, and make static. - (ppc_usrregs_info, ppc_regsets_info, regs_info): New globals. - (ppc_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-s390-low.c (tdesc_s390_linux32, tdesc_s390_linux32v1) - (tdesc_s390_linux32v2, tdesc_s390_linux64, tdesc_s390_linux64v1) - (tdesc_s390_linux64v2, tdesc_s390x_linux64, tdesc_s390x_linux64v1) - (tdesc_s390x_linux64v2): Declare. - (s390_collect_ptrace_register, s390_supply_ptrace_register) - (s390_fill_gregset, s390_store_last_break): Adjust. - (target_regsets): Rename to ... - (s390_regsets): ... this, and make static. - (s390_get_pc, s390_set_pc): Adjust. - (s390_get_hwcap): New target_desc parameter, and use it. - [__s390x__] (have_hwcap_s390_high_gprs): New global. - (s390_arch_setup): Adjust to set the current process'es target - description. Don't adjust the regmap. - (s390_usrregs_info, s390_regsets_info, regs_info): New globals. - [__s390x__] (s390_usrregs_info_3264, s390_regsets_info_3264) - (regs_info_3264): New globals. - (s390_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-mips-low.c (tdesc_mips_linux, tdesc_mips_dsp_linux) - (tdesc_mips64_linux, tdesc_mips64_dsp_linux): Declare. - [__mips64] (init_registers_mips_linux) - (init_registers_mips_dsp_linux): Delete defines. - [__mips64] (tdesc_mips_linux, tdesc_mips_dsp_linux): New defines. - (have_dsp): New global. - (mips_read_description): New, based on mips_arch_setup. - (mips_arch_setup): Reimplement. - (get_usrregs_info): New function. - (mips_cannot_fetch_register, mips_cannot_store_register) - (mips_get_pc, mips_set_pc, mips_fill_gregset, mips_store_gregset) - (mips_fill_fpregset, mips_store_fpregset): Adjust. - (target_regsets): Rename to ... - (mips_regsets): ... this, and make static. - (mips_regsets_info, mips_dsp_usrregs_info, mips_usrregs_info) - (dsp_regs_info, regs_info): New globals. - (mips_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-arm-low.c (tdesc_arm, tdesc_arm_with_iwmmxt) - (tdesc_arm_with_vfpv2, tdesc_arm_with_vfpv3, tdesc_arm_with_neon): - Declare. - (arm_fill_vfpregset, arm_store_vfpregset): Adjust. - (arm_read_description): New, with bits factored from - arm_arch_setup. - (arm_arch_setup): Reimplement. - (target_regsets): Rename to ... - (arm_regsets): ... this, and make static. - (arm_regsets_info, arm_usrregs_info, regs_info): New globals. - (arm_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-m68k-low.c (tdesc_m68k): Declare. - (target_regsets): Rename to ... - (m68k_regsets): ... this, and make static. - (m68k_regsets_info, m68k_usrregs_info, regs_info): New globals. - (m68k_regs_info): New function. - (m68k_arch_setup): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-sh-low.c (tdesc_sharch): Declare. - (target_regsets): Rename to ... - (sh_regsets): ... this, and make static. - (sh_regsets_info, sh_usrregs_info, regs_info): New globals. - (sh_regs_info, sh_arch_setup): New functions. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-bfin-low.c (tdesc_bfin): Declare. - (bfin_arch_setup): New function. - (bfin_usrregs_info, regs_info): New globals. - (bfin_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-cris-low.c (tdesc_cris): Declare. - (cris_arch_setup): New function. - (cris_usrregs_info, regs_info): New globals. - (cris_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-cris-low.c (tdesc_crisv32): Declare. - (cris_arch_setup): New function. - (cris_regsets_info, cris_usrregs_info, regs_info): New globals. - (cris_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-m32r-low.c (tdesc_m32r): Declare. - (m32r_arch_setup): New function. - (m32r_usrregs_info, regs_info): New globals. - (m32r_regs_info): Adjust. - (initialize_low_arch): New function. - * linux-tic6x-low.c (tdesc_tic6x_c64xp_linux) - (tdesc_tic6x_c64x_linux, tdesc_tic6x_c62x_linux): Declare. - (tic6x_usrregs_info): Forward declare. - (tic6x_read_description): New function, based on ... - (tic6x_arch_setup): ... this. Reimplement. - (target_regsets): Rename to ... - (tic6x_regsets): ... this, and make static. - (tic6x_regsets_info, tic6x_usrregs_info, regs_info): New globals. - (tic6x_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-xtensa-low.c (tdesc_xtensa): Declare. - (xtensa_fill_gregset, xtensa_store_gregset): Adjust. - (target_regsets): Rename to ... - (xtensa_regsets): ... this, and make static. - (xtensa_regsets_info, xtensa_usrregs_info, regs_info): New - globals. - (xtensa_arch_setup, xtensa_regs_info): New functions. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-nios2-low.c (tdesc_nios2_linux): Declare. - (nios2_arch_setup): Set the current process'es tdesc. - (target_regsets): Rename to ... - (nios2_regsets): ... this. - (nios2_regsets_info, nios2_usrregs_info, regs_info): New globals. - (nios2_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-aarch64-low.c (tdesc_aarch64): Declare. - (aarch64_arch_setup): Set the current process'es tdesc. - (target_regsets): Rename to ... - (aarch64_regsets): ... this. - (aarch64_regsets_info, aarch64_usrregs_info, regs_info): New globals. - (aarch64_regs_info): New function. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * linux-tile-low.c (tdesc_tilegx, tdesc_tilegx32): Declare - globals. - (target_regsets): Rename to ... - (tile_regsets): ... this. - (tile_regsets_info, tile_usrregs_info, regs_info): New globals. - (tile_regs_info): New function. - (tile_arch_setup): Set the current process'es tdesc. - (the_low_target): Adjust. - (initialize_low_arch): New function. - * spu-low.c (tdesc_spu): Declare. - (spu_create_inferior, spu_attach): Set the new process'es tdesc. - * win32-arm-low.c (tdesc_arm): Declare. - (arm_arch_setup): New function. - (the_low_target): Install arm_arch_setup instead of - init_registers_arm. - * win32-i386-low.c (tdesc_i386, tdesc_amd64): Declare. - (init_windows_x86): Rename to ... - (i386_arch_setup): ... this. Set `win32_tdesc'. - (the_low_target): Adjust. - * win32-low.c (win32_tdesc): New global. - (child_add_thread): Don't create the thread cache here. - (do_initial_child_stuff): Set the new process'es tdesc. - * win32-low.h (struct target_desc): Forward declare. - (win32_tdesc): Declare. - * lynx-i386-low.c (tdesc_i386): Declare global. - (lynx_i386_arch_setup): Set `lynx_tdesc'. - * lynx-low.c (lynx_tdesc): New global. - (lynx_add_process): Set the new process'es tdesc. - * lynx-low.h (struct target_desc): Forward declare. - (lynx_tdesc): Declare global. - * lynx-ppc-low.c (tdesc_powerpc_32): Declare global. - (lynx_ppc_arch_setup): Set `lynx_tdesc'. - * nto-low.c (nto_tdesc): New global. - (do_attach): Set the new process'es tdesc. - * nto-low.h (struct target_desc): Forward declare. - (nto_tdesc): Declare. - * nto-x86-low.c (tdesc_i386): Declare. - (nto_x86_arch_setup): Set `nto_tdesc'. - -2013-06-04 Gary Benson - - * server.c (handle_query): Add "augmented-libraries-svr4-read+" - to qSupported response when appropriate. - (handle_qxfer_libraries_svr4): Allow qXfer:libraries-svr4:read - with nonzero-length annex. - * linux-low.c (linux_qxfer_libraries_svr4): Parse and handle - arguments supplied in annex. - -2013-05-31 Doug Evans - - PR server/15594 - * linux-x86-low.c (ps_get_thread_area): Properly extend address to - 64 bits in 64-cross-32 environment. - -2013-05-28 Pedro Alves - - * Makefile.in (clean): Remove reference to aarch64-without-fpu.c. - (aarch64-without-fpu.c): Delete rule. - * configure.srv (aarch64*-*-linux*): Remove references to - aarch64-without-fpu.o and aarch64-without-fpu.xml. - * linux-aarch64-low.c (init_registers_aarch64_without_fpu): Remove - declaration. - -2013-05-24 Pedro Alves - - * server.c (handle_v_cont) : Use unpack_varlen_hex - instead of strchr/decode_address. Error if the range isn't split - with a ','. Don't assume there's be a ':' in the action. - -2013-05-23 Yao Qi - Pedro Alves - - * linux-low.c (lwp_in_step_range): New function. - (linux_wait_1): If the thread was range stepping and stopped - outside the stepping range, report the stop to GDB. Otherwise, - continue stepping. Add range stepping debug output. - (linux_set_resume_request): Copy the step range from the resume - request to the lwp. - (linux_supports_range_stepping): New. - (linux_target_ops) : Set to - linux_supports_range_stepping. - * linux-low.h (struct linux_target_ops) - : New field. - (struct lwp_info) : New fields. - * linux-x86-low.c (x86_supports_range_stepping): New. - (the_low_target) : Set to - x86_supports_range_stepping. - * server.c (handle_v_cont): Handle 'r' action. - (handle_v_requests): Append ";r" if the target supports range - stepping. - * target.h (struct thread_resume) : New fields. - (struct target_ops) : - New field. - (target_supports_range_stepping): New macro. - -2013-05-17 Joel Brobecker - - * lynx-low.c (lynx_resume): Fix null_ptid/minus_one_ptid - confusion in comment. - -2013-05-17 Joel Brobecker - - * lynx-low.c (struct process_info_private): New type. - (lynx_add_process): New function. - (lynx_create_inferior, lynx_attach): Replace calls to - add_process by calls to lynx_add_process. - (lynx_resume): If PTID is null, then try using - current_process()->private->last_wait_event_ptid. - Add comments. - (lynx_clear_inferiors): Delete. The contents of that function - has been inlined in lynx_mourn; - (lynx_wait_1): Save the ptid in the process's private data. - (lynx_mourn): Free the process' private data. Replace call - to lynx_clear_inferiors by call to clear_inferiors. - -2013-05-17 Yao Qi - - * i386-low.c (i386_length_and_rw_bits): Move the comment to - the right place. - -2013-05-16 Luis Machado - - * linux-low.c: Move definition checks upwards for PT_TEXT_ADDR, - PT_DATA_ADDR and PT_TEXT_END_ADDR. Update comments. - (linux_read_offsets): Remove PT_TEXT_ADDR, PT_DATA_ADDR and - PT_TEXT_END_ADDR guards. Update comments. - (linux_target_op) : Conditionally define to - linux_read_offsets if the target is UCLIBC and if it defines - PT_TEXT_ADDR, PT_DATA_ADDR and PT_TEXT_END_ADDR. - -2013-05-06 Sandra Loosemore - Andrew Jenner - - * Makefile.in (SFILES): Add linux-nios2-low.c. - (clean): Add action to delete nios2-linux.c. - (nios2-linux.c): New rule. - * configure.srv: Add nios2*-*-linux*. - * linux-nios2-low.c: New. - -2013-05-03 Hafiz Abid Qadeer - - * tracepoint.c (cmd_qtinit): Call 'stop_tracing'. - -2013-04-25 Hui Zhu - - PR gdb/15186 - * ax.c (ax_printf): Add fflush. - -2013-04-22 Tom Tromey - - * Makefile.in (SFILES): Add filestuff.c. - (OBS): Add filestuff.o. - (filestuff.o): New target. - * config.in, configure: Rebuild. - * configure.ac: Check for fdwalk, pipe2. - -2013-04-17 Pedro Alves - - * configure.ac (USE_THREAD_DB): Delete variable. - (if test "$srv_linux_thread_db" = "yes"): AC_DEFINE USE_THREAD_DB. - Don't AC_SUBST USE_THREAD_DB. - * Makefile.in (INTERNAL_CFLAGS): Remove @USE_THREAD_DB@. - * config.in, configure: Regenerate. - -2013-04-16 Pedro Alves - - * linux-low.h (struct lwp_info) : Move under - the USE_THREAD_DB #ifdef. - -2013-04-16 Pedro Alves - - * Makefile.in (INTERNAL_CFLAGS): Add @USE_THREAD_DB@. - (linux-low.o): Delete rule. - * linux-low.h: Always include "gdb_thread_db.h" instead of - conditionally including thread_db.h. - (struct lwp_info) : Guard with #ifdef USE_THREAD_DB instead of - HAVE_THREAD_DB_H. - -2013-04-07 Jan Kratochvil - - * Makefile.in (install-only): Fix make install regression. - -2013-04-05 Jan Kratochvil - - Convert man pages to texinfo, new gdbinit.5 texinfo page. - * Makefile.in (install-only): Remove $(man1dir) and gdbserver.1 - installation. - * gdbserver.1: Remove. - -2013-03-22 Pedro Alves - - * linux-low.c (handle_extended_wait): Don't call - linux_enable_event_reporting. - -2013-03-15 Tony Theodore - - PR build/9098: - * Makefile.in (SHELL): Use @SHELL@. - -2013-03-14 Sergio Durigan Junior - - * tracepoint.c (cmd_qtv): Initialize `val' with zero, silencing - compiler warning. - -2013-03-13 Joel Brobecker - - * linux-low.c (linux_target_ops) [!HAVE_LINUX_BTRACE]: - Remove extraneous NULL element. - -2013-03-13 Yao Qi - - * tracepoint.c (traceframe_read_tsv): Look for the last matched - 'V' block in trace frame. - -2013-03-11 Markus Metzger - - * target.h (struct target_ops): Add btrace ops. - (target_supports_btrace): New macro. - (target_enable_btrace): New macro. - (target_disable_btrace): New macro. - (target_read_btrace): New macro. - * gdbthread.h (struct thread_info): Add btrace field. - * server.c: Include btrace-common.h. - (handle_btrace_general_set): New function. - (handle_btrace_enable): New function. - (handle_btrace_disable): New function. - (handle_general_set): Call handle_btrace_general_set. - (handle_qxfer_btrace): New function. - (struct qxfer qxfer_packets[]): Add btrace entry. - * inferiors.c (remove_thread): Disable btrace. - * linux-low: Include linux-btrace.h. - (linux_low_enable_btrace): New function. - (linux_low_read_btrace): New function. - (linux_target_ops): Add btrace ops. - * configure.srv (i[34567]86-*-linux*): Add linux-btrace.o. - Add srv_linux_btrace=yes. - (x86_64-*-linux*): Add linux-btrace.o. - Add srv_linux_btrace=yes. - * configure.ac: Define HAVE_LINUX_BTRACE. - * config.in: Regenerated. - * configure: Regenerated. - -2013-03-11 Markus Metzger - - * server.c (handle_qxfer): Preserve error message if -3 is - returned. - (qxfer): Document the -3 return value. - -2013-03-11 Markus Metzger - - * Makefile.in (SFILES): Add $(srcdir)/common/linux-btrace.c. - (linux_btrace_h): New variable. - (linux-btrace.o): New rule. - -2013-03-08 Stan Shebs - Hafiz Abid Qadeer - - * tracepoint.c (trace_buffer_size): New global. - (DEFAULT_TRACE_BUFFER_SIZE): New define. - (init_trace_buffer): Change to one-argument function. Allocate - trace buffer memory. - (handle_tracepoint_general_set): Call cmd_bigqtbuffer_size to - handle QTBuffer:size packet. - (cmd_bigqtbuffer_size): New function. - (initialize_tracepoint): Call init_trace_buffer with - DEFAULT_TRACE_BUFFER_SIZE. - * server.c (handle_query): Add QTBuffer:size in the - supported packets. - -2013-03-07 Yao Qi - - * tracepoint.c (cur_action, cur_step_action): Make them unsigned. - (cmd_qtfp): Initialize cur_action and cur_step_action 0 instead - of -1. - (cmd_qtsp): Adjust condition. Do post increment. - Set cur_action and cur_step_action back to 0. - -2013-03-07 Jeremy Bennett - - PR server/15236 - * linux-low.c (linux_write_memory): Return early success if LEN is - zero. - -2013-03-05 Corinna Vinschen - - * configure.srv: Add x86_64-*-cygwin* as target. - -2013-02-28 Tom Tromey - - * configure.ac: Invoke AC_SYS_LARGEFILE. - * configure, config.in: Rebuild. - -2013-02-28 Corinna Vinschen - - * win32-low.c: Throughout, fix format strings and casts of - printf-like functions to avoid type related warnings on all - platforms. - (get_child_debug_event): Print dwDebugEventCode as hex since - that's how it's usually documented. - -2013-02-28 Yao Qi - - * tracepoint.c (cmd_qtbuffer): Call phex_nz instead of - pulongest. - -2013-02-27 Jiong Wang - - * Makefile.in (clean): Remove reg-tilegx.c, reg-tilegx32.c. - (reg-tilegx32.c): New rule. - * configure.srv (tilegx-*-linux*): Add reg-tilegx32.o to srv_regobj. - * linux-tile-low.c (tile_arch_setup): New function. Invoke - different register info initializer according to elf class. - (init_registers_tilgx32): New function. The tilegx32 register info - initializer. - (tile_fill_gregset): Use "uint_reg_t" to represent register size. - (tile_store_gregset): Likewise. - -2013-02-27 Yao Qi - - * server.c (process_point_options): Print debug message when - debug_threads is true. - -2013-02-26 Yao Qi - - * tracepoint.c (cmd_qtbuffer): Don't set '\0' in OWN_BUF. - -2013-02-19 Pedro Alves - Kai Tietz - - PR gdb/15161 - - * server.c (handle_query) : Use unpack_varlen_hex - instead of strtoul to extract address from packet. - (process_serial_event) <'z'>: Likewise. - -2013-02-18 Yao Qi - - * linux-bfin-low.c (the_low_target): Use NULL instead of 0. - -2013-02-14 Pedro Alves - - Plug memory leak. - - * tracepoint.c (cmd_qtnotes): Free TRACING_USER_NAME, - TRACING_NOTES and TRACING_STOP_NOTE before clobbering. - -2013-02-14 Pedro Alves - - * tracepoint.c (cmd_qtdpsrc): Use savestring. - -2013-02-14 Pedro Alves - - * tracepoint.c (save_string): Delete. - (add_tracepoint_action): Use savestring instead of save_string. - -2013-02-12 Pedro Alves - - * linux-xtensa-low.c: Ditto. - * xtensa-xtregs.c: Ditto. - -2013-02-12 Sanimir Agovic - - * thread-db.c (thread_db_get_tls_address): NULL pointer check - thread_db. - -2013-02-07 Marcus Shawcroft - - * linux-aarch64-low.c (aarch64_arch_setup): Clamp - aarch64_num_wp_regs and aarch64_num_bp_regs to - AARCH64_HWP_MAX_NUM and AARCH64_HBP_MAX_NUM respectively. - -2013-02-07 Marcus Shawcroft - - * linux-aarch64-low.c (ps_get_thread_area): Replace - PTRACE_GET_THREAD_AREA with PTRACE_GETREGSET. - -2013-02-04 Jim MacArthur - Marcus Shawcroft - Nigel Stephens - Yufeng Zhang - - * Makefile.in (clean): Remove aarch64.c and aarch64-without-fpu.c. - (aarch64.c, aarch64-without-fpu.c): New targets. - * configure.srv (aarch64*-*-linux*): New. - * linux-aarch64-low.c: New file. - -2013-02-04 Marcus Shawcroft - - * linux-low.c (handle_extended_wait, linux_create_inferior) - (linux_attach_lwp_1, linux_kill_one_lwp, linux_attach_one_lwp) - (dequeue_one_deferred_signal, linux_resume_one_thread) - (fetch_register, linux_write_memory, linux_enable_event_reporting) - (linux_tracefork_grandchild, linux_test_for_tracefork) - (linux_read_offsets, linux_xfer_siginfo, linux_xfer_siginfo): Add - PTRACE_ARG3_TYPE and PTRACE_ARG4_TYPE cast to ptrace arguments - where the argument is 0. - -2013-01-25 Yao Qi - - * event-loop.c: Include "queue.h". - (gdb_event_p): New typedef. - (struct gdb_event) : Remove. - (event_queue): Change to QUEUE(gdb_event_p). - (async_queue_event): Remove. - (gdb_event_xfree): New. - (initialize_event_loop): New. - (process_event): Use API from QUEUE. - (wait_for_event): Likewise. - * server.c (main): Call initialize_event_loop. - * server.h (initialize_event_loop): Declare. - -2013-01-18 Yao Qi - - * ax.h (struct eval_agent_expr_context): New. - (gdb_eval_agent_expr): Update declaration. - * ax.c (gdb_eval_agent_expr): Remove argument REGCACHE and - TFRAME. Add new argument CTX. - * server.h (struct eval_agent_expr_context): Declare. - (agent_mem_read, agent_tsv_read): Update declaration. - (agent_mem_read_string): Likewise. - * tracepoint.c (eval_tracepoint_agent_expr): Remove. - (add_traceframe_block): Add new argument TPOINT. - Increase TPOINT->traceframe_usage. - (do_action_at_tracepoint): Call gdb_eval_agent_expr instead of - eval_tracepoint_agent_expr. - (condition_true_at_tracepoint): Likewise. - (agent_mem_read): Remove argument TFRAME. Add argument CTX. - (agent_mem_read_string, agent_tsv_read): Likewise. - -2013-01-16 Yao Qi - - * linux-low.c (linux_resume_one_lwp): Don't check - 'lwp->bp_reinsert != 0'. - -2013-01-07 Joel Brobecker - Pedro Alves - - * lynx-low.c (ptrace_request_to_str): Define a temporary - macro and use it to simplify this function's implementation. - -2013-01-07 Joel Brobecker - - * lynx-low.c (lynx_resume): Call perror_with_name if lynx_ptrace - sets errno. - -2013-01-07 Joel Brobecker - - * configure.srv (i[34567]86-*-lynxos*): Set srv_xmlfiles. - -2013-01-07 Joel Brobecker - - * configure.srv (powerpc-*-lynxos*): Set srv_xmlfiles. - -2013-01-07 Joel Brobecker - - * lynx-low.c (lynx_resume): Use the resume_info parameter - to determine the ptid for the lynx_ptrace call, unless - it is equal to minus_one_ptid, in which case we use the - ptid of the current_inferior. - (lynx_wait_1): After having received a thread create/exit - event, resume the inferior's execution using the signaling - thread's ptid, rather than the old ptid. - -2013-01-07 Joel Brobecker - - * lynx-low.c (lynx_resume): Delete variable ret. - -2013-01-01 Joel Brobecker - - * gdbreplay.c (gdbreplay_version): Update copyright year. - * server.c (gdbserver_version): Likewise. - -2012-12-17 Joel Brobecker - - * lynx-low.c (lynx_wait_1): Add debug trace before adding - new thread. - -2012-12-17 Joel Brobecker - - * lynx-low.c (ptrace_request_to_str): Add handling for - PTRACE_GETTRACESIG. - -2012-12-17 Joel Brobecker - - * lynx-low.c (lynx_attach): Delete variable new_process. - -2012-12-17 Joel Brobecker - - * lynx-low.c (lynx_create_inferior): Delete variable - new_process. - -2012-12-17 Joel Brobecker - - * lynx-low.c (ptrace_request_to_str): Do not handle - PTRACE_GETTHREADLIST if this macro does not exist. - -2012-12-15 Yao Qi - - * Makefile.in (OBS): Add notif.o. - * notif.c, notif.h: New. - * server.c: Include "notif.h". - (struct vstop_notif) : Remove. - : New field. - (queue_stop_reply): Update. - (push_event, send_next_stop_reply): Remove. - (discard_queued_stop_replies): Update. - (notif_stop): New variable. - (handle_v_stopped): Remove. - (handle_v_requests): Don't call handle_v_stopped. Call - handle_ack_notif instead. - (queue_stop_reply_callback): Call notif_event_enque instead - of queue_stop_reply. - (handle_status): Don't call send_next_stop_reply, call - notif_write_event instead. - (kill_inferior_callback): Likewise. - (detach_or_kill_inferior_callback): Likewise. - (main): Call initialize_notif. - (process_serial_event): Call QUEUE_is_empty. - (handle_target_event): Call notif_push instead of push event. - * server.h (push_event): Remove declaration. - -2012-12-10 Tom Tromey - - * Makefile.in (DEPMODE, DEPDIR, depcomp, COMPILE.pre) - (COMPILE.post, COMPILE, POSTCOMPILE, IPAGENT_COMPILE): New - macros. - (.c.o): Rewrite. - (ax-ipa.o, tracepoint-ipa.o, utils-ipa.o, format-ipa.o) - (common-utils-ipa.o, remote-utils-ipa.o, regcache-ipa.o) - (i386-linux-ipa.o, linux-i386-ipa.o, linux-amd64-ipa.o) - (amd64-linux-ipa.o, ax.o): Rewrite. - (event-loop.o, hostio.o, hostio-errno.o, inferiors.o, mem-break.o) - (proc-service.o, regcache.o, remote-utils.o, server.o, target.o) - (thread-db.o, tracepoint.o, utils.o, gdbreplay.o, dll.o): Remove. - (signals.o, linux-procfs.o, linux-ptrace.o, common-utils.o, vec.o) - (gdb_vecs.o, xml-utils.o, linux-osdata.o, ptid.o, buffer.o) - (format.o, agent.o, vasprintf.o, vsnprintf.o): Rewrite. - (i386-low.o, i387-fp.o, linux-low.o, linux-arm-low.o) - (linux-bfin-low.o, linux-cris-low.o, linux-crisv32-low.o) - (linux-ia64-low.o, linux-m32r-low.o, linux-mips-low.o) - (linux-ppc-low.o, linux-s390-low.o, linux-sh-low.o) - (linux-tic6x-low.o, linux-x86-low.o, linux-xtensa-low.o) - (linux-tile-low.o, lynx-low.o, lynx-ppc-low.o, nto-low.o) - (nto-x86-low.o, linux-low.o, win32-low.o, win32-arm-low.o) - (win32-i386-low.o, spu-low.o, reg-arm.o, arm-with-iwmmxt.o) - (arm-with-vfpv2.o, arm-with-vfpv3.o, arm-with-neon.o, reg-bfin.o) - (reg-cris.o, reg-crisv32.o, i386.o, i386-linux.o, i386-avx.o) - (i386-avx-linux.o, i386-mmx.o, i386-mmx-linux.o, reg-ia64.o) - (reg-m32r.o, reg-m68k.o, reg-cf.o, mips-linux.o, mips-dsp-linux.o) - (mips64-linux.o, mips64-dsp-linux.o, powerpc-32.o, powerpc-32l.o) - (powerpc-altivec32l.o, powerpc-cell32l.o, powerpc-vsx32l.o) - (powerpc-isa205-32l.o, powerpc-isa205-altivec32l.o) - (powerpc-isa205-vsx32l.o, powerpc-e500l.o, powerpc-64l.o) - (powerpc-altivec64l.o, powerpc-cell64l.o, powerpc-vsx64l.o) - (powerpc-isa205-64l.o, powerpc-isa205-altivec64l.o) - (powerpc-isa205-vsx64l.o, s390-linux32.o, s390-linux32v1.o) - (s390-linux32v2.o, s390-linux64.o, s390-linux64v1.o) - (s390-linux64v2.o, s390x-linux64.o, s390x-linux64v1.o) - (s390x-linux64v2.o, tic6x-c64xp-linux.o, tic6x-c64x-linux.o) - (tic6x-c62x-linux.o, reg-sh.o, reg-sparc64.o, reg-spu.o, amd64.o) - (amd64-linux.o, amd64-avx.o, amd64-avx-linux.o, x32.o) - (x32-linux.o, x32-avx.o, x32-avx-linux.o, reg-xtensa.o) - (reg-tilegx.o): Remove. - (all_object_files): New macro. - Include .deps files. - * aclocal.m4, configure: Rebuild. - * acinclude.m4: Include depstand.m4, lead-dot.m4. - * configure.ac: Invoke ZW_CREATE_DEPDIR, - ZW_PROG_COMPILER_DEPENDENCIES. Compute GMAKE condition. - -2012-12-05 Tom Tromey - - PR gdb/14917: - * server.h (current_insn_ptr, emit_error): Declare 'extern'. - -2012-11-28 Markus Metzger - - * configure.ac: Check for linux/perf_event.h. - * config.in: Regenerated. - * configure: Regenerated. - -2012-11-26 Maxime Villard - - * hostio.c (handle_readlink): Decrease buffer size - parameter passed to readlink by one byte. - -2012-11-26 Yao Qi - - * configure.ac (build_warnings): Append '-Wempty-body'. - * configure: Regenerated. - * linux-low.c (linux_create_inferior): Use braces for empty 'if' - body. - -2012-11-15 Pierre Muller - - * configure.ac (AC_CHECK_HEADERS): Add wait.h header. - * config.in: Regenerate. - * configure: Regenerate. - * linux-low.c: Use "gdb_stat.h" header instead of header. - Use "gdb_wait.h" header instead of header. - * lynx-low.c: Use "gdb_wait.h" header instead of header. - * remote-utils.c: Use "gdb_stat.h" header instead of - header. - * server.c: Remove HAVE_WAIT_H conditional. Use "gdb_wait.h" header - instead of header. - * spu-low.c: Use "gdb_wait.h" header instead of header. - -2012-11-13 Markus Metzger - - * Makefile.in: (INTERNAL_CFLAGS): Add -DGDBSERVER - (various make rules): Remove -DGDBSERVER - -2012-11-09 Yao Qi - - * spu-low.c (current_ptid): Move it to .. - * gdbthread.h: ... here. New. - * remote-utils.c (read_ptid): Use macro 'current_ptid'. - * server.c (myresume, process_serial_event): Likewise. - * thread-db.c (thread_db_find_new_threads): Likewise. - * tracepoint.c (run_inferior_command): Likewise. - -2012-10-01 Andrew Burgess - - * server.c (handle_search_memory_1): Include access length in - warning message. - -2012-09-05 Michael Brandt - - * linux-crisv32-low.c: Fix compile errors. - -2012-09-04 Yao Qi - - * tracepoint.c (cmd_qtsv): Adjust debug message. - Don't check CUR_TPOINT. - -2012-08-28 Yao Qi - - * ax.c, tracepoint.c: Replace ATTR_FORMAT with ATTRIBUTE_PRINTF. - * server.h: Include 'libiberty.h' and 'ansidecl.h'. - (ATTR_NORETURN, ATTR_FORMAT, ATTR_MALLOC): Remove. - Remove declarations of xmalloc, xreallloc, xstrdup and - freeargv. - * Makefile.in (libiberty_h): New. - (server_h): Append dependencies 'libiberty.h' and 'ansidecl.h'. - (linux-bfin-low.o): Append dependency 'libiberty.h'. - -2012-08-23 Yao Qi - - * server.h: Remove declaration of 'xsnprintf'. - -2012-08-22 Keith Seitz - - * server.h: Include build-gnulib-gbserver/config.h. - * gdbreplay.c: Likewise. - -2012-08-08 Doug Evans - - * Makefile.in (SFILES): Add gdb_vecs.c. - (OBS): Add gdb_vecs.o. - (gdb_vecs_h, host_defs_h): New variables. - (thread-db.o): Add $(gdb_vecs_h) dependency. - (gdb_vecs.o): New rule. - * thread-db.c: #include "gdb_vecs.h". - (thread_db_load_search): Use a vector to iterate over path elements. - Handle text appearing after "$pdir". - - * configure.ac: Add check for strstr. - * config.in: Regenerate. - * configure: Regenerate. - -2012-08-02 Ulrich Weigand - - * hostio.c (handle_pread): If pread fails, fall back to attempting - lseek/read. - (handle_pwrite): Likewise for pwrite. - -2012-08-01 Ulrich Weigand - - * linux-arm-low.c (arm_linux_hw_point_initialize): Distinguish - between unsupported TYPE and unimplementable ADDR/LEN combination. - (arm_insert_point): Act on new return value. - -2012-07-31 Pedro Alves - - * server.c (process_point_options): Only skip tokens if we find - one that is unrecognized. Don't treat 'X' specially while - skipping unrecognized tokens. - -2012-07-30 Ulrich Weigand - - * linux-arm-low.c (arm_linux_hw_point_initialize): Do not attempt - to 4-byte-align HW breakpoint addresses for Thumb. - -2012-07-27 Yao Qi - - PR remote/14161. - - * server.h: Declare gdb_agent_about_to_close. - * target.c (kill_inferior): Include "agent.h". - New. Send command 'kill'. - * target.h (kill_inferior): Removed macro. - * tracepoint.c (gdb_agent_about_to_close): New. - (gdb_agent_helper_thread): Handle command 'close'. - Wait endlessly until the inferior stops. - Install gdb_agent_remove_socket to atexit hook. - (agent_socket_name): New static variable. - (gdb_agent_socket_init): Replace local variable 'name' with - 'agent_socket_name'. - (gdb_agent_remove_socket): New. - -2012-07-27 Yao Qi - - * server.c (process_point_options): Stop at 'X' when parsing. - -2012-07-19 Michael Eager - - * i386-low.c (Z_packet_to_hw_type): Add Z_PACKET_HW_BP, translate - to hw_execute. - * linux-x86-low.c (x86_insert_point, x86_remove_point): - Call i386_low_insert_watchpoint, i386_low_remove_watchpoint to add/del - hardware breakpoint. - -2012-07-07 Jan Kratochvil - - * gdbserver/linux-low.c (initialize_low): Call - linux_ptrace_init_warnings. - -2012-07-02 Doug Evans - - * mem-break.c (gdb_no_commands_at_breakpoint): Fix cast from - pointer to int. - -2012-07-02 Stan Shebs - - * Makefile.in (WARN_CFLAGS_NO_FORMAT): Define. - (ax.o): Add it to build rule. - (ax-ipa.o): Ditto. - (OBS): Add format.o. - (IPA_OBS): Add format.o. - * server.c (handle_query): Claim support for breakpoint commands. - (process_point_options): Add command case. - (process_serial_event): Leave running if there are printfs in - effect. - * mem-break.h (any_persistent_commands): Declare. - (add_breakpoint_commands): Declare. - (gdb_no_commands_at_breakpoint): Declare. - (run_breakpoint_commands): Declare. - * mem-break.c (struct point_command_list): New struct. - (struct breakpoint): New field command_list. - (any_persistent_commands): New function. - (add_commands_to_breakpoint): New function. - (add_breakpoint_commands): New function. - (gdb_no_commands_at_breakpoint): New function. - (run_breakpoint_commands): New function. - * linux-low.c (linux_wait_1): Test for and run breakpoint commands - locally. - * ax.c: Include format.h. - (ax_printf): New function. - (gdb_eval_agent_expr): Add printf opcode. - -2012-06-13 Yao Qi - - * server.c (start_inferior): Remove duplicated writes to fields - 'last_resume_kind' and 'last_status' of 'current_inferior'. - -2012-06-12 Yao Qi - Pedro Alves - - * linux-low.c (linux_set_resume_request): Simplify predicate. Add - comment. - * server.c (handle_v_cont): Extend comment. - -2012-06-11 Yao Qi - - * linux-low.c (linux_attach): Add 'static'. - -2012-06-06 Yao Qi - - * ax.c (gdb_eval_agent_expr): Print `top' in hex. - -2012-06-01 Jan Kratochvil - - Fix gcc -flto compilation warning. - * server.c (main): Make variable multi_mode and attach volatile. - -2012-05-30 Thiago Jung Bauermann - - * linux-low.c (get_r_debug): Disable code using DT_MIPS_RLD_MAP - if the platform doesn't know about it. - -2012-05-30 Jeff Kenton - - * Makefile.in (SFILES): Add linux-tile-low.c. - (linux-tile-low.o, reg-tilegx.o, reg-tilegx.c): New rules. - * configure.srv: Handle tilegx-*-linux*. - * linux-tile-low.c: New file. - -2012-05-28 Jan Kratochvil - - * linux-low.c (linux_qxfer_libraries_svr4): Return -1 if R_DEBUG is -1. - -2012-05-24 Pedro Alves - - PR gdb/7205 - - Replace TARGET_SIGNAL_ with GDB_SIGNAL_ throughout. - -2012-05-24 Pedro Alves - - PR gdb/7205 - - Replace target_signal with gdb_signal throughout. - -2012-05-22 Maciej W. Rozycki - - * linux-low.c (linux_store_registers): Avoid the copying sequence - when no data has been retrieved by ptrace. - -2012-05-22 Will Deacon - - * linux-low (__UCLIBC__ && !(__UCLIBC_HAS_MMU__ || __ARCH_HAS_MMU__)): - Include asm/ptrace.h. - (PT_TEXT_ADDR, PT_DATA_ADDR, PT_TEXT_END_ADDR): Define only if not - already defined. - -2012-05-21 Maciej W. Rozycki - - * linux-low.c (linux_store_registers): Don't re-retrieve data - with ptrace that has already been obtained from /proc. Always - copy any data retrieved with ptrace to the buffer supplied. - -2012-05-11 Yao Qi - Pedro Alves - - * linux-low.c (enum stopping_threads_kind): New. - (stopping_threads): Change type to `enum stopping_threads_kind'. - (handle_extended_wait): If stopping and suspending threads, leave - the new_lwp suspended too. - (linux_wait_for_event): Adjust. - (stop_all_lwps): Set `stopping_threads' to - STOPPING_AND_SUSPENDING_THREADS or STOPPING_THREADS depending on - whether we're suspending threads or just stopping them. Assert no - recursion happens. - -2012-04-29 Yao Qi - - * server.h: Move some code to ... - * gdbthread.h: ... here. New. - * Makefile.in (inferiors.o, regcache.o): Depends on gdbthread.h - (remote-utils.o, server.o, target.o tracepoint.o): Likewise. - (nto-low.o, win32-low.o): Likewise. - * inferiors.c, linux-low.h, nto-low.c: Include gdbthread.h. - * regcache.c, remote-utils.c, server.c: Likewise. - * target.c, tracepoint.c, win32-low.c: Likewise. - -2012-04-24 Thiago Jung Bauermann - - * linux-low.h (PTRACE_ARG3_TYPE): Move macro from linux-low.c. - (PTRACE_ARG4_TYPE): Likewise. - (PTRACE_XFER_TYPE): Likewise. - * linux-arm-low.c (arm_prepare_to_resume): Cast third argument of - ptrace to PTRACE_ARG3_TYPE. - * linux-low.c (PTRACE_ARG3_TYPE): Move macro to linux-low.h. - (PTRACE_ARG4_TYPE): Likewise. - (PTRACE_XFER_TYPE): Likewise. - (linux_detach_one_lwp): Cast fourth argument of - ptrace to long then PTRACE_ARG4_TYPE. - (regsets_fetch_inferior_registers): Cast third argument of - ptrace to long then PTRACE_ARG3_TYPE. - (regsets_store_inferior_registers): Likewise. - -2012-04-20 Pedro Alves - - * configure: Regenerate. - -2012-04-19 Pedro Alves - - * Makefile.in (GNULIB_BUILDDIR): New. - (LIBGNU, INCGNU, GNULIB_H): Adjust. - (SUBDIRS, CLEANDIRS, REQUIRED_SUBDIRS): New. - (all, install-only, uninstall, clean-info, all-lib, clean): No - longer pass GNULIB_FLAGS_TO_PASS. Use subdir_do. - (maintainer-clean realclean distclean): Use subdir_do. - (subdir_do): New. - (gnulib/import/Makefile): Adjust. Replace gnulib/import with - $(GNULIB_BUILDDIR). Don't pass argument to config.status. - * acinclude.m4: Include acx_configure_dir.m4. - * configure.ac: Remove gl_EARLY, gl_INIT, and AM_INIT_AUTOMAKE - calls. Call AC_PROG_RANLIB. Configure gnulib using - ACX_CONFIGURE_DIR. - (GNULIB): New. - (GNULIB_STDINT_H): Adjust. - (AC_OUTPUT): Don't output gnulib/Makefile anymore. - * gdbreplay.c: Include build-gnulib/config.h. - * server.h: Likewise. - * aclocal.m4: Regenerate. - * config.in: Regenerate. - * configure: Regenerate. - -2012-04-19 Pedro Alves - - * Makefile.in (LIBGNU, INCGNU): Adjust. - (GNULIB_FLAGS_TO_PASS, GNULIB_H): Adjust. - (all, install-only, uninstall, clean-info, all-lib, clean) - (maintainer-clean, Makefile, gnulib/Makefile): Adjust. - * configure.ac: Adjust AC_OUTPUT output. - * aclocal.m4: Regenerate. - * configure: Regenerate. - -2012-04-19 Pedro Alves - - * Makefile.in (generated_files): New. - (server_h): Remove the explicit dependency on config.h, and depend - on $generated_files. - -2012-04-19 Pedro Alves - - * Makefile.in (INCGNU): Add -Ignulib. - -2012-04-19 Pedro Alves - - * Makefile.in (GNULIB_INCLUDE_DIR): Rename to ... - (INCGNU): ... this, and spell out -I here. - (GNULIB_LIB): Rename to ... - (LIBGNU): ... this. - (INCLUDE_CFLAGS, gdbserver$(EXEEXT), $(GNULIB_LIB) rule): Adjust. - -2012-04-19 Pedro Alves - - * config.in: Regenerate. - -2012-04-19 Pedro Alves - - * configure.ac: Remove AC_CHECK_DECLS check for memmem. - * server.h (memmem): Remove declaration. - * config.in: Regenerate. - * configure: Regenerate. - -2012-04-19 Yao Qi - - * Makefile.in (SFILES): Add common/vec.c. - (OBS): Add vec.o. - (vec.o): New rule. - -2012-04-19 Yao Qi - - * remote-utils.c (prepare_resume_reply): Replace with macro - target_core_of_thread. - * server.c (handle_qxfer_threads_proper): Likewise. - * target.h (traget_core_of_thread): New macro. - -2012-04-18 Pedro Alves - - * aclocal.m4: Regenerate. - * configure: Regenerate. - -2012-04-16 Yao Qi - - * tracepoint.c (cmd_qtstart): Download tracepoints even when they are - duplicated on address. - -2012-04-16 Yao Qi - - * tracepoint.c (COPY_FIELD_TO_BUF): New macro. - (struct tracepoint_action_ops) : New field. - (m_tracepoint_action_send, r_tracepoint_action_send): New. - (agent_expr_send, x_tracepoint_action_send): New. - (l_tracepoint_action_send): New. - (cmd_qtdp): Download and install tracepoint - according to `use_agent'. - (run_inferior_command): Add one more parameter `len'. - Update callers. - (tracepoint_send_agent): New. - (cmd_qtdp, cmd_qtstart): Call tracepoint_send_agent. - -2012-04-16 Yao Qi - - * tracepoint.c (download_tracepoints): Moved to ... - (cmd_qtstart): ... here. - -2012-04-14 Yao Qi - - * tracepoint.c: Include inttypes.h. - (struct collect_memory_action): Use sized types. - (struct tracepoint): Likewise. - (cmd_qtdp, stop_tracing): Update print specifiers. - (cmd_qtp, response_tracepoint): Likewise. - (collect_data_at_tracepoint): Likewise. - (collect_data_at_step): Likewise. - -2012-04-14 Yao Qi - - Import gnulib module inttypes. - * aclocal.m4, config.in, configure: Regenerated. - -2012-04-14 Yao Qi - - * Makefile.in (maintainer-clean, realclean, distclean): Remove - Makefile and config.status at last. - -2012-04-13 Yao Qi - - * tracepoint.c: Include stdint.h unconditionally. - -2012-04-13 Thiago Jung Bauermann - - * acinclude.m4 (GDBSERVER_HAVE_THREAD_DB_TYPE): New macro based - on BFD_HAVE_SYS_PROCFS_TYPE. - * configure.ac: Look for lwpid_t and psaddr_t in libthread_db.h. - * configure: Regenerate. - * config.in: Likewise. - -2012-04-13 H.J. Lu - - * Makefile.in (clean): Also remove x32.c x32-linux.c - x32-avx.c x32-avx-linux.c. - (x32.o): New target. - (x32.c): Likewise. - (x32-linux.o): Likewise. - (x32-linux.c): Likewise. - (x32-avx.o): Likewise. - (x32-avx.c): Likewise. - (x32-avx-linux.o): Likewise. - (x32-avx-linux.c): Likewise. - - * configure.srv (srv_amd64_regobj): Add x32.o x32-avx.o. - (srv_amd64_linux_regobj): Add x32-linux.o x32-avx-linux.o. - (srv_i386_64bit_xmlfiles): Add i386/x32-core.xml. - (srv_amd64_xmlfiles): Add i386/x32.xml i386/x32-avx.xml. - (srv_amd64_linux_xmlfiles): Add i386/x32-linux.xml - i386/x32-avx-linux.xml. - - * linux-x86-low.c (init_registers_x32_linux): New prototype. - (init_registers_x32_avx_linux): Likwise. - (x86_linux_update_xmltarget): Call init_registers_x32_linux - or init_registers_x32_avx_linux if linux_is_elf64 is false. - -2012-04-13 Pedro Alves - - * Makefile.in (GNULIB_FLAGS_TO_PASS): New. - (FLAGS_TO_PASS): Don't change or set $top_srcdir, $srcdir and VPATH. - (all, uninstall, clean-info, all-lib, clean, maintainer-clean) - (realclean, distclean): Explicitly pass $GNULIB_FLAGS_TO_PASS to - the sub-make. - -2012-04-12 H.J. Lu - - * linux-x86-low.c (compat_x32_clock_t): New. - (compat_x32_siginfo_t): Likewise. - (compat_x32_siginfo_from_siginfo): Likewise. - (siginfo_from_compat_x32_siginfo): Likewise. - (linux_is_elf64): Likewise. - (x86_siginfo_fixup): Call compat_x32_siginfo_from_siginfo - and siginfo_from_compat_x32_siginfo for x32. - (x86_arch_setup): Set linux_is_elf64. - -2012-04-12 H.J. Lu - - PR gdb/13969 - * linux-low.c (linux_pid_exe_is_elf_64_file): Also return the - e_machine field. - (linux_qxfer_libraries_svr4): Update call to elf_64_file_p. - * linux-low.h (linux_pid_exe_is_elf_64_file): Updated. - * linux-x86-low.c (x86_arch_setup): Check if GDBserver is - compatible with process. - -2012-04-12 Yao Qi - - * Makefile.in: Define abs_top_srcdir and abs_srcdir. - (INCLUDE_CFLAGS): Append GNULIB_INCLUDE_DIR. - (install-only, install-info, clean): Handle sub dir gnulib. - (all-lib, am--refresh): New targets. - (memmem.o): Remove target. - * configure.ac: Remove AC_CONFIG_LIBOBJ_DIR. - Invoke gl_EARLY. Invoke AC_CHECK_PROGS for make. - (AC_REPLACE_FUNCS): Remove memmem. - Invoke gl_INIT and AM_INIT_AUTOMAKE. - (AC_OUTPUT): Generate Makefile in gnulib/. - * aclocal.m4, config.in, configure: Regenerated. - -2012-04-10 Maciej W. Rozycki - - * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP. - -2012-04-05 Pedro Alves - - -Werror=strict-aliasing - - * spu-low.c (parse_spufs_run): Avoid dereferencing type-punned - pointer. - -2012-04-04 Pedro Alves - - * linux-sparc-low.c (sparc_fill_gregset_to_stack) - (sparc_store_gregset_from_stack, sparc_store_gregset) - (sparc_breakpoint_at): Fix formatting. - -2012-03-30 Thiago Jung Bauermann - - * configure.ac: Check whether Elf32_auxv_t and Elf64_auxv_t - are available. - * linux-low.c [HAVE_ELF32_AUXV_T] (Elf32_auxv_t): Add typedef. - [HAVE_ELF64_AUXV_T] (Elf64_auxv_t): Likewise. - * config.in: Regenerate. - * configure: Likewise. - -2012-03-29 Pedro Alves - - * linux-low.c (regsets_store_inferior_registers) [__sparc__]: - Correct ptrace arguments. - -2012-03-28 Pedro Alves - - * linux-ia64-low.c (ia64_regmap): Map IA64_EC_REGNUM to PT_AR_EC. - (IA64_GR0_REGNUM, IA64_FR0_REGNUM) - (IA64_FR1_REGNUM): New defines. - (ia64_fetch_register): New. - (the_low_target): Install it. - * linux-low.h (struct linux_target_ops) : New - field. - * linux-low.c (linux_fetch_registers): Try the - the_low_target.fetch_register hook first. - - * linux-arm-low.c (the_low_target): Adjust. - * linux-bfin-low.c (the_low_target): Adjust. - * linux-cris-low.c (the_low_target): Adjust. - * linux-crisv32-low.c (the_low_target): Adjust. - * linux-m32r-low.c (the_low_target): Adjust. - * linux-m68k-low.c (the_low_target): Adjust. - * linux-mips-low.c (the_low_target): Adjust. - * linux-ppc-low.c (the_low_target): Adjust. - * linux-s390-low.c (the_low_target): Adjust. - * linux-sh-low.c (the_low_target): Adjust. - * linux-sparc-low.c (the_low_target): Adjust. - * linux-tic6x-low.c (the_low_target): Adjust. - * linux-x86-low.c (the_low_target): Adjust. - * linux-xtensa-low.c (the_low_target): Adjust. - -2012-03-26 Pedro Alves - - * server.c (handle_qxfer_libraries): Don't bail early if - the_target->qxfer_libraries_svr4 is not NULL. - -2012-03-26 Pedro Alves - - * linux-low.c (linux_qxfer_libraries_svr4): Fix pasto in comment. - -2012-03-23 Pedro Alves - - * linux-low.c (linux_qxfer_libraries_svr4): Terminate the - "library-list-svr4" element's start tag when the the DSO list is - empty. - -2012-03-23 Pedro Alves - - * linux-low.c (read_one_ptr): Read the inferior's pointer through - a variable whose type size is the same as the inferior's pointer - size. - -2012-03-21 Thomas Schwinge - - * linux-arm-low.c (arm_stopped_by_watchpoint): Use siginfo_t instead of - struct siginfo. - * linux-low.c (siginfo_fixup, linux_xfer_siginfo): Likewise. - * linux-x86-low.c (x86_siginfo_fixup): Likewise. - * linux-low.h: Include . - (struct siginfo): Remove forward declaration. - (struct linux_target_ops) : Use siginfo_t instead of - struct siginfo. - -2012-03-21 Mike Frysinger - - * .gitignore: Ignore more files. - -2012-03-19 Pedro Alves - Jan Kratochvil - - * server.c (cont_thread, general_thread): Add describing comments. - (start_inferior): Clear `cont_thread'. - (handle_v_cont): Don't set `cont_thread' if resuming all threads - of a process. - -2012-03-15 Yao Qi - - * tracepoint.c (install_tracepoint): Move duplicated tracepoint - handling to ... - (cmd_qtdp): ... here. - -2012-03-15 Yao Qi - - * tracepoint.c (struct tracepoint_action_ops): New. - (struct tracepoint_action) [!IN_PROCESS_AGENT] : New field. - (m_tracepoint_action_download): New. - (r_tracepoint_action_download): New. - (x_tracepoint_action_download): New. - (l_tracepoint_action_download): New. - (add_tracepoint_action): Install `action->ops' according type. - (download_tracepoint_1): Move code `download' function pointer - of various tracepoint_action_ops. - -2012-03-13 Jan Kratochvil - - * linux-low.c (linux_attach_lwp_1): New variable buffer. Call - linux_ptrace_attach_warnings. - -2012-03-13 Jan Kratochvil - - * Makefile.in (linux-ptrace.o): New. - * configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*) - (cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*) - (m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*) - (s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux) - (x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ - of these targets. - * linux-low.c (linux_attach_lwp_1): Remove redundent else clause. - -2012-03-08 Yao Qi - Pedro Alves - - Fix PR server/13392. - * linux-x86-low.c (amd64_install_fast_tracepoint_jump_pad): Check - offset of JMP insn. - * tracepoint.c (remove_tracepoint): New. - (cmd_qtdp): Call remove_tracepoint when failed to install. - -2012-03-07 Pedro Alves - - * linux-low.c (get_detach_signal): New. - (linux_detach_one_lwp): Get rid of a pending SIGSTOP with SIGCONT. - Pass on pending signals to PTRACE_DETACH. Check the result of the - ptrace call. - * server.c (program_signals, program_signals_p): New. - (handle_general_set): Handle QProgramSignals. - * server.h (program_signals, program_signals_p): Declare. - -2012-03-05 Pedro Alves - Jan Kratochvil - - * linux-low.c (get_dynamic): Don't warn when PT_PHDR isn't found. - New comment why. - -2012-03-03 Yao Qi - - * tracepoint.c (tracepoint_look_up_symbols): Update call to - agent_look_up_symbols. - -2012-03-03 Yao Qi - - * Makefile.in (linux-low.o): Keep dependence on agent.h. - (linux-x86-low.o): Likewise. - * server.h: Remove in_process_agent_loaded. - * tracepoint.c (in_process_agent_loaded): Removed. Moved it - common/agent.c. - Update callers. - -2012-03-03 Yao Qi - - * tracepoint.c (gdb_agent_capability): New global. - (in_process_agent_loaded_ust): Renamed to - `in_process_agent_supports_ust'. - Update callers. - (in_process_agent_supports_ust): Call agent_capability_check. - (clear_installed_tracepoints): Assert that agent supports - agent. - -2012-03-03 Yao Qi - - * linux-low.c (linux_supports_agent): New. - (linux_target_ops): Initialize field `supports_agent' with - linux_supports_agent. - * target.h (struct target_ops) : New. - (target_supports_agent): New macro. - * server.c (handle_general_set): Handle packet 'QAgent'. - (handle_query): Send `QAgent+'. - * Makefile.in (server.o): Depends on agent.h. - -2012-03-03 Yao Qi - - * Makefile.in (OBS): Add agent.o. - Add new rule for agent.o. - Track dependence of tracepoint.c on agent.h. - * tracepoint.c (run_inferior_command_1): - (run_inferior_command): Call agent_run_command. - (gdb_ust_connect_sync_socket): Deleted. Move it to - common/agent.c. - (resume_thread, stop_thread): Likewise. - (gdb_ust_socket_init): Renamed to ... - (gdb_agent_socket_init): ... New. - (gdb_ust_thread): Renamed to ... - (gdb_agent_helper_thread): ... New. - (gdb_ust_init): Move some code to ... - (gdb_agent_init): ... here. New. - [HAVE_UST]: Call gdb_ust_init. - (initialize_tracepoint_ftlib): Call gdb_agent_init. - * configure.ac: Add `sys/un.h' to AC_CHECK_HEADERS. - * config.in, configure: Regenerated. - -2012-03-02 Pedro Alves - - * inferiors.c (add_pid_to_list, pull_pid_from_list): Delete. - * linux-low.c (struct simple_pid_list): New. - (stopped_pids): New a struct simple_pid_list pointer. - (add_to_pid_list, pull_pid_from_list): New. - (handle_extended_wait): Don't assume the first signal new children - report is SIGSTOP. Adjust call to pull_pid_from_list. - (linux_wait_for_lwp): Adjust. - -2012-03-02 Yao Qi - - * tracepoint.c (do_action_at_tracepoint): Write `stop_pc' in - debug log. - -2012-03-02 Yao Qi - - * tracepoint.c (collect_ust_data_at_tracepoint): Remove parameters - `stop_pc' and `tpoint'. Update caller. - -2012-03-01 Maciej W. Rozycki - - * linux-low.h (linux_target_ops): Add regset_bitmap member. - * linux-low.c (use_linux_regsets): New macro. - [!HAVE_LINUX_REGSETS] (regsets_fetch_inferior_registers): Likewise. - [!HAVE_LINUX_REGSETS] (regsets_store_inferior_registers): Likewise. - (linux_register_in_regsets): New function. - (usr_fetch_inferior_registers): Skip registers covered by - regsets. - (usr_store_inferior_registers): Likewise. - (usr_fetch_inferior_registers): New macro. - (usr_store_inferior_registers): Likewise. - (linux_fetch_registers): Handle mixed regset/non-regset targets. - (linux_store_registers): Likewise. - * linux-mips-low.c (init_registers_mips_dsp_linux): New - prototype. - (init_registers_mips64_dsp_linux): Likewise. - (init_registers_mips_linux): New macro. - (init_registers_mips_dsp_linux): Likewise. - (mips_dsp_num_regs): Likewise. - (DSP_BASE, DSP_CONTROL): New fallback macros. - (mips_base_regs): New macro. - (mips_regmap): Use it. Fix the size. - (mips_dsp_regmap): New variable. - (mips_dsp_regset_bitmap): Likewise. - (mips_arch_setup): New function. - (mips_cannot_fetch_register): Use the_low_target.regmap rather - than mips_regmap. - (mips_cannot_store_register): Likewise. - (the_low_target): Update .arch_setup, .num_regs and .regmap - initializers. Add .regset_bitmap initializer. - * linux-arm-low.c (the_low_target): Add .regset_bitmap - initializer. - * linux-bfin-low.c (the_low_target): Likewise. - * linux-cris-low.c (the_low_target): Likewise. - * linux-crisv32-low.c (the_low_target): Likewise. - * linux-ia64-low.c (the_low_target): Likewise. - * linux-m32r-low.c (the_low_target): Likewise. - * linux-m68k-low.c (the_low_target): Likewise. - * linux-ppc-low.c (the_low_target): Likewise. - * linux-s390-low.c (the_low_target): Likewise. - * linux-sh-low.c (the_low_target): Likewise. - * linux-sparc-low.c (the_low_target): Likewise. - * linux-tic6x-low.c (the_low_target): Likewise. - * linux-x86-low.c (the_low_target): Likewise. - * linux-xtensa-low.c (the_low_target): Likewise. - * configure.srv : Add mips-dsp-linux.o and - mips64-dsp-linux.o to srv_regobj. Add mips-dsp-linux.xml, - mips64-dsp-linux.xml, mips-dsp.xml and mips64-dsp.xml to - srv_xmlfiles. - * Makefile.in (mips-dsp-linux.o, mips-dsp-linux.c): New targets. - (mips64-dsp-linux.o, mips64-dsp-linux.c): Likewise. - -2012-02-29 Yao Qi - Pedro Alves - - * linux-low.c: (linux_wait_1): Call unsuspend_all_lwps when - `step_over_finished' is true. - -2012-02-27 Pedro Alves - - * linux-low.c (pid_is_stopped): Delete, moved to common/. - (linux_attach_lwp_1): Adjust to use linux_proc_pid_is_stopped. - -2012-02-27 Pedro Alves - - PR server/9684 - * linux-low.c (pid_is_stopped): New. - (linux_attach_lwp_1): Handle attaching to 'T (stopped)' processes. - -2012-02-25 Luis Machado - - * mem-break.c (clear_gdb_breakpoint_conditions): Fix de-allocation - of conditions. - -2012-02-24 Maciej W. Rozycki - - * linux-mips-low.c (mips_regmap): Correct the index of $f9. - -2012-02-24 Luis Machado - - * server.c (handle_query): Advertise support for target-side - breakpoint condition evaluation. - (process_point_options): New function. - (process_serial_event): When inserting a breakpoint, check for - a target-side condition that should be evaluated. - - * mem-break.c: Include regcache.h and ax.h. - (point_cond_list_t): New data structure. - (breakpoint) : New field. - (find_gdb_breakpoint_at): Make non-static. - (delete_gdb_breakpoint_at): Clear any target-side - conditions. - (clear_gdb_breakpoint_conditions): New function. - (add_condition_to_breakpoint): Likewise. - (add_breakpoint_condition): Likewise. - (gdb_condition_true_at_breakpoint): Likewise. - (gdb_breakpoint_here): Return result directly instead - of going through a local variable. - - * mem-break.h (find_gdb_breakpoint_at): New prototype. - (clear_gdb_breakpoint_conditions): Likewise. - (add_breakpoint_condition): Likewise. - (gdb_condition_true_at_breakpoint): Likewise. - - * linux-low.c (linux_wait_1): Evaluate target-side breakpoint condition. - (need_step_over_p): Take target-side breakpoint condition into - consideration. - -2012-02-24 Luis Machado - - * server.h: Include tracepoint.h. - (agent_mem_read, agent_get_trace_state_variable_value, - agent_set_trace_state_variable_value, - agent_tsv_read, agent_mem_read_string, get_get_tsv_func_addr, - get_set_tsv_func_addr): New prototypes. - - * ax.h: New include file. - * ax.c: New source file. - - * tracepoint.c: Include ax.h. - (gdb_agent_op, gdb_agent_op_names, gdb_agent_op_sizes, - agent_expr, eval_result_type): Move to ax.h. - (parse_agent_expr): Rename to ... - (gdb_parse_agent_expr): ... this, make it non-static and move - to ax.h. - (unparse_agent_expr) Rename to ... - (gdb_unparse_agent_expr): ... this, make it non-static and move - to ax.h. - (eval_agent_expr): Rename to ... - (eval_tracepoint_agent_expr): ... this. - (agent_mem_read, agent_mem_read_string, agent_tsv_read): Remove - forward declarations. - (add_tracepoint_action): Call gdb_parse_agent_expr (...). - (agent_get_trace_state_variable_value): New function. - (agent_set_trace_state_variable_value): New function. - (cmd_qtdp): Call gdb_parse_agent_expr (...). - (response_tracepoint): Call gdb_unparse_agent_expr (...). - (do_action_at_tracepoint): Call eval_tracepoint_agent_expr (...). - (condition_true_at_tracepoint): Likewise. - (parse_agent_expr): Rename to ... - (gdb_parse_agent_expr): ... this and move to ax.c. - (unparse_agent_expr): Rename to ... - (gdb_unparse_agent_expr): ... this and move to ax.c. - (gdb_agent_op_name): Move to ax.c. - (eval_agent_expr): Rename to ... - (gdb_eval_agent_expr): ... this, use regcache passed as parameter - and move to ax.c. - (eval_tracepoint_agent_expr): New function. - (agent_mem_read, agent_mem_read_string, agent_tsv_read): Make - non-static. - (current_insn_ptr, emit_error, struct bytecode_address): Move to - ax.c. - (emit_prologue, emit_epilogue, emit_add, emit_sub, emit_mul, emit_lsh, - emit_rsh_signed, emit_rsh_unsigned, emit_ext, emit_log_not, - emit_bit_and, emit_bit_or, emit_bit_xor, emit_bit_not, emit_equal, - emit_less_signed, emit_less_unsigned, emit_ref, emit_if_goto, - emit_goto, write_goto_address, emit_const, emit_reg, emit_pop, - emit_stack, emit_zero_ext, emit_swap, emit_stack_adjust, - emit_int_call_1, emit_void_call_2, emit_eq_goto, emit_ne_goto, - emit_lt_goto, emit_ge_goto, emit_gt_goto, emit_le_goto): Move to ax.c. - (get_get_tsv_func_addr, get_set_tsv_func_addr): New functions. - (compile_bytecodes): Remove forward declaration. - (is_goto_target): Move to ax.c. - (compile_bytecodes): Move to ax.c and call - agent_get_trace_state_variable_value (...) and - agent_set_trace_state_variable_value (...). - - * Makefile.in: Update ax.c and IPA dependencies. - -2012-02-24 Pedro Alves - - * tracepoint.c (cmd_bigqtbuffer): Rename as ... - (cmd_bigqtbuffer_circular): ... this. Only handle - 'QTBuffer:circular:'. - (handle_tracepoint_general_set): Adjust. - -2012-02-16 Yao Qi - - * inferiors.c: Move code to ... - * dll.c: .... here. New. - * server.h: Declare clear_dlls. - * Makefile.in (SFILES): Add dll.c. - (OBS): Add dll.o - (dll.o): New rule. - -2012-02-11 Yao Qi - - * server.c: (handle_monitor_command): Add a new parameter - `own_buf'. - (handle_query): Update caller. - -2012-02-09 Joel Brobecker - - * configure.ac: Add readlink to AC_CHECK_FUNCS list. - * configure, config.in: Regenerate. - * hostio.c: Provide an alternate implementation if HAVE_READLINK - is not defined. - -2012-02-02 Pedro Alves - - Try SIGKILL first, then PTRACE_KILL. - * linux-low.c (linux_kill_one_lwp): New. - (linux_kill_one_lwp): Rename to ... - (kill_one_lwp_callback): ... this. Use the new - linux_kill_one_lwp. - -2012-02-02 Pedro Alves - - * tracepoint.c (cmd_qtminftpilen): Return 0 if there's no current - inferior. - -2012-01-27 Pedro Alves - - * linux-low.c (linux_child_pid_to_exec_file): Delete. - (elf_64_file_p): Make static. - (linux_pid_exe_is_elf_64_file): New. - * linux-low.h (linux_child_pid_to_exec_file, elf_64_file_p): - Delete declarations. - (linux_pid_exe_is_elf_64_file): Declare. - * linux-x86-low.c (x86_arch_setup): Use - linux_pid_exe_is_elf_64_file. - -2012-01-25 Jan Kratochvil - - * linux-low.c (linux_wait_for_event_1): Rename to ... - (linux_wait_for_event): ... here and merge it with former - linux_wait_for_event - new variable wait_ptid, use it. - (linux_wait_for_event): Remove - merge it to linux_wait_for_event_1. - -2012-01-23 Pedro Alves - - * server.c (main): Avoid yet another case of infinite loop while - detaching/killing after a longjmp. - -2012-01-20 Jan Kratochvil - - Code cleanup. - * linux-low.c (linux_wait_for_event_1): Use ptid_is_pid. - -2012-01-20 Ulrich Weigand - - * hostio.c (handle_readlink): New function. - (handle_vFile): Call it to handle "vFile:readlink" packets. - -2012-01-20 Pedro Alves - Ulrich Weigand - - * server.c (handle_v_requests): Only support vAttach and vRun to - start multiple processes when in extended protocol mode. - -2012-01-17 Pedro Alves - - * tracepoint.c (initialize_tracepoint): Use mmap instead of - memalign plus mprotect to allocate the scratch buffer. - -2012-01-13 Pedro Alves - - * server.c (attach_inferior): Clear `cont_thread'. - -2012-01-13 Pedro Alves - - * server.c (main): Avoid infinite loop while detaching/killing - after a longjmp. - -2012-01-09 Doug Evans - - * server.c (start_inferior): Set last_ptid in --wrapper case. - -2012-01-06 Yao Qi - - * tracepoint.c [IN_PROCESS_AGENT] (debug_threads): Macro - defined. - [IN_PROCESS_AGENT] (debug_agent): New global variable. - -2012-01-04 Yao Qi - - * tracepoint.c (cmd_qtdp): Print debug message - for static tracepoint. - -2012-01-04 Yao Qi - - * tracepoint.c (trace_vdebug): Differentiate debug message - between gdbserver and IPA. - -2012-01-03 Yao Qi - - * tracepoint.c (tracepoint_was_hit): Don't collect for - static tracepoint. - -2012-01-02 Joel Brobecker - - * terminal.h: Reformat copyright header. - -2012-01-02 Joel Brobecker - - * server.c (gdbserver_version): Update copyright year. - * gdbreplay.c (gdbreplay_version): Likewise. - -2011-12-18 Jan Kratochvil - - * linux-low.c (linux_create_inferior): Put empty if clause for write. - - Revert: - 2011-12-18 Hui Zhu - * linux-low.c (linux_create_inferior): Save return value to ret. - -2011-12-18 Hui Zhu - - * linux-low.c (linux_create_inferior): Save return value to ret. - -2011-12-16 Doug Evans - - * linux-low.c (linux_create_inferior): If stdio connection, - redirect stdin from /dev/null, stdout to stderr. - * remote-utils.c (remote_is_stdio): New static global. - (remote_connection_is_stdio): New function. - (remote_prepare): Handle stdio connection. - (remote_open): Ditto. - (remote_close): Don't close stdin for stdio connections. - (read_prim,write_prim): New functions. Replace all calls to - read/write to these. - * server.c (main): Watch for "-" argument. Move call to - remote_prepare before start_inferior. - * server.h (STDIO_CONNECTION_NAME): New macro. - (remote_connection_is_stdio): Declare. - - * remote-utils.c (prepare_resume_reply): Remove extraneous \n - in debugging output. - -2011-12-15 Yao Qi - - * tracepoint.c: Include sys/syscall.h. - (gdb_ust_thread): Remove preprocessor conditional. - -2011-12-14 Pedro Alves - - * linux-low.c (linux_detach_one_lwp): Call - the_low_target.prepare_to_resume before detaching. - -2011-12-14 Yao Qi - - * tracepoint.c (gdb_ust_thread): Don't ignore return value - of write. - -2011-12-14 Yao Qi - - * i386-low.c (i386_low_stopped_data_address): Initialize local - variable `control'. - -2011-12-13 Pedro Alves - - PR remote/13492 - - * i386-low.c (i386_low_stopped_data_address): Avoid fetching - DR_CONTROL unless necessary. Extend comments. - * linux-x86-low.c (x86_linux_prepare_to_resume): Don't write to - DR0-3 if not used. If any watchpoint was set, clear DR_STATUS. - -2011-12-13 Yao Qi - - * tracepoint.c (trace_buffer_alloc): Replace magic numbers with - macros. - (upload_fast_traceframes, upload_fast_traceframes): Likewise. - -2011-12-08 Jan Kratochvil - - * linux-low.c (linux_kill): Skip PTRACE_KILL if LWP does not exist. - Print new debug message for such case. - -2011-12-06 Jan Kratochvil - - Fix overlapping memcpy. - * mem-break.c (set_raw_breakpoint_at): New variable buf. Use it for - the read_inferior_memory transfer. - (delete_fast_tracepoint_jump): New variable buf. Use it for the - write_inferior_memory transfer. - (set_fast_tracepoint_jump): New variable buf. Use it for the - read_inferior_memory and write_inferior_memory transfers. - (uninsert_fast_tracepoint_jumps_at, reinsert_fast_tracepoint_jumps_at) - (delete_raw_breakpoint, uninsert_raw_breakpoint): New variable buf. - Use it for the write_inferior_memory transfer. - (check_mem_read, check_mem_write): New gdb_asserts for overlapping - buffers. - -2011-12-06 Maciej W. Rozycki - - * linux-low.c (fetch_register, store_register): Make code - consistent, fix formatting. - -2011-12-06 Maciej W. Rozycki - - * linux-low.c (usr_store_inferior_registers): Factor out code - to handle individual registers into... - (store_register): ... this new function. - -2011-12-06 Ulrich Weigand - - * Makefile.in (s390-linux32v1.o, s390-linux32v1.c): New rules. - (s390-linux32v2.o, s390-linux32v2.c): Likewise. - (s390-linux64v1.o, s390-linux64v1.c): Likewise. - (s390-linux64v2.o, s390-linux64v2.c): Likewise. - (s390x-linux64v1.o, s390x-linux64v1.c): Likewise. - (s390x-linux64v2.o, s390x-linux64v2.c): Likewise. - * configure.srv [s390*-*-linux*] (srv_regobj): Add new objects. - (srv_xmlfiles): Add new XML files. - - * linux-s390-low.c: Include "elf/common.h", , - and . - (PTRACE_GETREGSET, PTRACE_SETREGSET): Define if undefined. - (init_registers_s390_linux32v1): Add prototype. - (init_registers_s390_linux32v2): Likewise. - (init_registers_s390_linux64v1): Likewise. - (init_registers_s390_linux64v2): Likewise. - (init_registers_s390x_linux64v1): Likewise. - (init_registers_s390x_linux64v2): Likewise. - (s390_num_regs): Increment to 52. - (s390_regmap): Add orig_r2 register. - (s390_num_regs_3264): Increment to 68. - (s390_regmap_3264): Add orig_r2 register. - (s390_collect_ptrace_register): Handle orig_r2 register. - (s390_supply_ptrace_register): Likewise. - (s390_fill_last_break): New function. - (s390_store_last_break): Likewise. - (s390_fill_system_call): New function. - (s390_store_system_call): Likewise. - (target_regsets): Handle NT_S390_LAST_BREAK and NT_S390_SYSTEM_CALL - register sets. - (s390_check_regset): New function. - (s390_arch_setup): Check for presence of NT_S390_LAST_BREAK and - NT_S390_SYSTEM_CALL regsets and use appropriate description. - Update target_regsets for available register sets. - -2011-12-02 Paul Pluzhnikov - Jan Kratochvil - - * linux-low.c (get_phdr_phnum_from_proc_auxv, get_dynamic, get_r_debug) - (read_one_ptr, struct link_map_offsets, linux_qxfer_libraries_svr4): - New. - (struct linux_target_ops): Install linux_qxfer_libraries_svr4. - * linux-low.h (struct process_info_private): New member r_debug. - * server.c (handle_qxfer_libraries): Call - the_target->qxfer_libraries_svr4. - (handle_qxfer_libraries_svr4): New function. - (qxfer_packets): New entry "libraries-svr4". - (handle_query): Check QXFER_LIBRARIES_SVR4 and report libraries-svr4. - * target.h (struct target_ops): New member qxfer_libraries_svr4. - * remote.c (remote_xfer_partial): Call add_packet_config_cmd for - PACKET_qXfer_libraries_svr4. - -2011-11-30 Ulrich Weigand - - * linux-s390-low.c (s390_collect_ptrace_register): Fully convert - PSW address/mask between 8-byte and 16-byte formats. - (s390_supply_ptrace_register): Likewise. - (s390_get_pc, s390_set_pc): 4-byte PSW address always includes - basic addressing mode bit. - -2011-11-24 Stan Shebs - - * tracepoint.c (cmd_qtstatus): Use plongest instead of %llx. - -2011-11-17 Stan Shebs - - * tracepoint.c (struct tracepoint): New field traceframe_usage. - (tracing_start_time): New global. - (tracing_stop_time): New global. - (tracing_user_name): New global. - (tracing_notes): New global. - (tracing_stop_note): New global. - (cmd_qtstart): Set traceframe_usage, start_time. - (stop_tracing): Set stop_time. - (cmd_qtstatus): Report additional status. - (cmd_qtp): New function. - (handle_tracepoint_query): Call it. - (cmd_qtnotes): New function. - (handle_tracepoint_general_set): Call it. - (get_timestamp): Rename from tsv_get_timestamp. - -2011-11-14 Stan Shebs - Kwok Cheung Yeung - - * linux-x86-low.c (small_jump_insn): New. - (i386_install_fast_tracepoint_jump_pad): Add arguments for - trampoline and error message, build a trampoline and issue a small - jump instruction to it. - (x86_install_fast_tracepoint_jump_pad): Add arguments for - trampoline and error message. - (x86_get_min_fast_tracepoint_insn_len): New. - (the_low_target): Add call to x86_get_min_fast_tracepoint_insn_len. - * linux-low.h (struct linux_target_ops): Add arguments to - install_fast_tracepoint_jump_pad operation, add new operation. - * linux-low.c (linux_install_fast_tracepoint_jump_pad): Add - arguments. - (linux_get_min_fast_tracepoint_insn_len): New function. - (linux_target_op): Add new operation. - * tracepoint.c (gdb_trampoline_buffer): New IPA variable. - (gdb_trampoline_buffer_end): Ditto. - (gdb_trampoline_buffer_error): Ditto. - (struct ipa_sym_addresses): Add fields for new IPA variables. - (symbol_list): Add entries for new IPA variables. - (struct tracepoint): Add fields to hold the address range of the - trampoline used by the tracepoint. - (trampoline_buffer_head): New static variable. - (trampoline_buffer_tail): Ditto. - (claim_trampoline_space): New function. - (have_fast_tracepoint_trampoline_buffer): New function. - (clone_fast_tracepoint): Fill in trampoline fields of tracepoint - structure. - (install_fast_tracepoint): Ditto, also add error buffer argument. - (cmd_qtminftpilen): New function. - (handle_tracepoint_query): Add response to qTMinFTPILen packet. - (fast_tracepoint_from_trampoline_address): New function. - (fast_tracepoint_collecting): Handle trampoline as part of jump - pad space. - (set_trampoline_buffer_space): New function. - (initialize_tracepoint): Initialize new IPA variables. - * target.h (struct target_ops): Add arguments to - install_fast_tracepoint_jump_pad operation, add new - get_min_fast_tracepoint_insn_len operation. - (target_get_min_fast_tracepoint_insn_len): New. - (install_fast_tracepoint_jump_pad): Add arguments. - * server.h (IPA_BUFSIZ): Define. - * linux-i386-ipa.c: Include extra header files. - (initialize_fast_tracepoint_trampoline_buffer): New function. - (initialize_low_tracepoint): Call it. - * server.h (set_trampoline_buffer_space): Declare. - (claim_trampoline_space): Ditto. - (have_fast_tracepoint_trampoline_buffer): Ditto. - -2011-11-14 Yao Qi - - * server.c (handle_query): Handle InstallInTrace for qSupported. - * tracepoint.c (add_tracepoint): Sort list. - (install_tracepoint, download_tracepoint): New. - (cmd_qtdp): Call them to install and download tracepoints. - (sort_tracepoints): Removed. - (cmd_qtstart): Update. - -2011-11-14 Yao Qi - - * mem-break.c (inc_ref_fast_tracepoint_jump): New. - * mem-break.h: Declare. - * tracepoint.c (cmd_qtstart): Move some code to ... - (clone_fast_tracepoint, install_fast_tracepoint): ... here. - New. - (download_tracepoints): Move some code to ... - (download_tracepoint_1): ... here. New. - -2011-11-08 Yao Qi - - * remote-utils.c (relocate_instruction): A comment fix. - -2011-11-07 Joel Brobecker - - * win32-i386-low.c (dr_status_mirror, dr_control_mirror): Delete. - (i386_dr_low_get_control, i386_dr_low_get_status): Use - dr_status_mirror and dr_control_mirror from debug_reg_state. - (i386_dr_low_get_status): Use debug_reg_state.dr_status_mirror - (i386_initial_stuff): Remove use of deleted globals. - (i386_get_thread_context, i386_set_thread_context, - i386_thread_added): Use dr_status_mirror and dr_control_mirror - from debug_reg_state. - -2011-11-05 Yao Qi - - * tracepoint.c (gdb_collect): Loop over tracepoints of same - address as TPOINT's. - -2011-11-02 Stan Shebs - - * tracepoint.c (agent_mem_read_string): New function. - (eval_agent_expr): Call it for tracenz. - * server.c (handle_query): Report support for tracenz. - -2011-11-02 Yao Qi - - * tracepoint.c (cmd_qtstart): Remove unused local variables. - -2011-11-02 Yao Qi - - * target.h: Fix a typo in comment. - -2011-10-31 Pedro Alves - - * mem-break.c (check_mem_write): Add `myaddr' parameter. Don't - clobber the breakpoints' shadows with fast tracepoint jumps. - * mem-break.h (check_mem_write): Add `myaddr' parameter. - * target.c (write_inferior_memory): Also pass MYADDR down to - check_mem_write. - -2011-10-07 Ulrich Weigand - - * configure.ac: Check support for personality routine. - * configure: Regenerate. - * config.in: Likewise. - * linux-low.c: Include . - Define ADDR_NO_RANDOMIZE if necessary. - (linux_create_inferior): Disable address space randomization when - forking inferior, if requested. - (linux_supports_disable_randomization): New function. - (linux_target_ops): Install it. - * server.h (disable_randomization): Declare. - * server.c (disable_randomization): New global variable. - (handle_general_set): Handle QDisableRandomization. - (handle_query): Likewise for qSupported. - (main): Support --disable-randomization and --no-disable-randomization - command line arguments. - * target.h (struct target_ops): Add supports_disable_randomization. - (target_supports_disable_randomization): New macro. - -2011-09-29 Mike Frysinger - - * linux-low.c (target_loadseg): Add defined PTRACE_GETFDPIC to the - ifdef check. - [PT_GETDSBT] (target_loadmap): Wrap in a defined PT_GETDSBT check. - [!PT_GETDSBT] (target_loadmap): New definition. - (LINUX_LOADMAP, LINUX_LOADMAP_EXEC, LINUX_LOADMAP_INTERP): Define. - (linux_read_loadmap): Change PTRACE_GETDSBT_EXEC to - LINUX_LOADMAP_EXEC, PTRACE_GETDSBT_INTERP to LINUX_LOADMAP_INTERP, - and PT_GETDSBT to LINUX_LOADMAP. - [!PT_GETDSBT] (linux_read_loadmap): Define to NULL. - (linux_target_ops): Delete unnecessary ifdef PT_GETDSBT check. - -2011-09-21 Ulrich Weigand - - * linux-arm-low.c (struct arm_linux_hwbp_cap): Remove. - (arm_linux_hwbp_cap): New static variable. - (arm_linux_get_hwbp_cap): Replace by ... - (arm_linux_init_hwbp_cap): ... this new function. - (arm_linux_get_hw_breakpoint_count): Use arm_linux_hwbp_cap. - (arm_linux_get_hw_watchpoint_count): Likewise. - (arm_linux_get_hw_watchpoint_max_length): Likewise. - (arm_arch_setup): Call arm_linux_init_hwbp_cap. - (arm_prepare_to_resume): Use perror_with_name instead of error. - -2011-09-21 Ulrich Weigand - - * linux-arm-low.c: Include . - (PTRACE_GETHBPREGS, PTRACE_SETHBPREGS): Define if necessary. - (struct arm_linux_hwbp_cap): New data type. - (arm_hwbp_type, arm_hwbp_control_t): New typedefs. - (struct arm_linux_hw_breakpoint): New data type. - (MAX_BPTS, MAX_WPTS): Define. - (struct arch_process_info, struct arch_lwp_info): New data types. - (arm_linux_get_hwbp_cap): New function. - (arm_linux_get_hw_breakpoint_count): Likewise. - (arm_linux_get_hw_watchpoint_count): Likewise. - (arm_linux_get_hw_watchpoint_max_length): Likewise. - (arm_hwbp_control_initialize): Likewise. - (arm_hwbp_control_is_enabled): Likewise. - (arm_hwbp_control_is_initialized): Likewise. - (arm_hwbp_control_disable): Likewise. - (arm_linux_hw_breakpoint_equal): Likewise. - (arm_linux_hw_point_initialize): Likewise. - (struct update_registers_data): New data structure. - (update_registers_callback: New function. - (arm_insert_point): Likewise. - (arm_remove_point): Likewise. - (arm_stopped_by_watchpoint): Likewise. - (arm_stopped_data_address): Likewise. - (arm_new_process): Likewise. - (arm_new_thread): Likewise. - (arm_prepare_to_resume): Likewise. - (the_low_target): Register arm_insert_point, arm_remove_point, - arm_stopped_by_watchpoint, arm_stopped_data_address, arm_new_process, - arm_new_thread, and arm_prepare_to_resume. - -2011-09-15 Stan Shebs - - * server.h (struct emit_ops): Add compare-goto fields. - * tracepoint.c (gdb_agent_op_sizes): New table. - (emit_eq_goto): New function. - (emit_ne_goto): New function. - (emit_lt_goto): New function. - (emit_le_goto): New function. - (emit_gt_goto): New function. - (emit_ge_goto): New function. - (is_goto_target): New function. - (compile_bytecodes): Recognize special cases of compare-goto - combinations and call specialized emitters for them. - * linux-x86-low.c (amd64_emit_eq_goto): New function. - (amd64_emit_ne_goto): New function. - (amd64_emit_lt_goto): New function. - (amd64_emit_le_goto): New function. - (amd64_emit_gt_goto): New function. - (amd64_emit_ge_goto): New function. - (amd64_emit_ops): Add the new functions. - (i386_emit_eq_goto): New function. - (i386_emit_ne_goto): New function. - (i386_emit_lt_goto): New function. - (i386_emit_le_goto): New function. - (i386_emit_gt_goto): New function. - (i386_emit_ge_goto): New function. - (i386_emit_ops): Add the new functions. - -2011-09-08 Stan Shebs - - * linux-x86-low.c (i386_emit_prologue): Save %ebx. - (i386_emit_epilogue): Restore %ebx. - -2011-08-31 Jie Zhang - - * server.c (step_thread): Remove definition. - (process_serial_event): Don't handle Hs. - * server.h (step_thread): Remove declaration. - * target.c (set_desired_inferior): Remove use of step_thread. - -2011-08-24 Luis Machado - - * linux-low.c: Include linux-procfs.h. - (linux_attach_lwp_1): Update comments. - (linux_attach): Scan for existing threads when attaching to a - process that is the tgid. - * Makefile.in: Update dependencies. - -2011-08-24 Luis Machado - - * configure.srv: Add linux-procfs.o dependencies. - -2011-08-14 Yao Qi - - * target.h (struct target_ops): Fix indent. - * win32-low.c (win32_target_ops): Fix comment. - -2011-08-14 Andrew Jenner - Yao Qi - - * Makefile.in (clean): Remove tic6x-*.c files. - (linux-tic6x-low.o, tic6x-c62x-linux.o, tic6x-c64x-linux.o): New rules. - (tic6x-c64xp-linux.o, tic6x-c62x-linux.c, tic6x-c64x-linux.c): Likewise. - (tic6x-c64xp-linux.c): Likewise. - * configure.srv: Add support for tic6x-*-uclinux. - * linux-tic6x-low.c: New. - * linux-low.c (PT_TEXT_ADDR, PT_DATA_ADDR, PT_TEXT_END_ADDR): Define. - -2011-08-14 Andrew Stubbs - Yao Qi - - * target.h (struct target_ops): Add read_loadmap. - * linux-low.c (struct target_loadseg): New type. - (struct target_loadmap): New type. - (linux_read_loadmap): New function. - (linux_target_ops): Add linux_read_loadmap. - * server.c (handle_query): Support qXfer:fdpic:read packet. - * win32-low.c (win32_target_ops): Initialize field `read_loadmap' - to NULL. - -2011-08-05 Eli Zaretskii - - * win32-low.c: Include . - -2011-07-22 Pedro Alves - - * i386-low.c (i386_insert_aligned_watchpoint): Don't pass the info - to the inferior here. - (i386_remove_aligned_watchpoint): Ditto. - (i386_handle_nonaligned_watchpoint): Return immediate on fail to - fit part of the watchpoint in the debug registers. - (i386_update_inferior_debug_regs): New. - (i386_low_insert_watchpoint): Work on a local mirror of the debug - registers, and only update the inferior on success. - (i386_low_remove_watchpoint): Ditto. - -2011-07-22 Kwok Cheung Yeung - - * linux-low.c (compare_ints, unique, list_threads, show_process, - linux_core_of_thread): Delete. - (linux_target_ops): Change linux_core_of_thread to - linux_common_core_of_thread. - (linux_qxfer_osdata): Defer to linux_common_xfer_osdata. - * utils.c (malloc_failure): Change type of argument. - (xmalloc, xrealloc, xcalloc, xsnprintf): Delete. - * Makefile.in (SFILES): Add common/common-utils.c, common/xml-utils.c, - common/linux-osdata.c, common/ptid.c and common/buffer.c. - (OBS): Add xml-utils.o, common-utils.o, ptid.o and buffer.o. - (IPA_OBJS): Add common-utils-ipa.o. - (ptid_h, linux_osdata_h): New macros. - (server_h): Add common/common-utils.h, common/xml-utils.h, - common/buffer.h, common/gdb_assert.h, common/gdb_locale.h and - common/ptid.h. - (common-utils-ipa.o, common-utils.o, xml-utils.o, linux-osdata.o, - ptid.o, buffer.o): New rules. - (linux-low.o): Add common/linux-osdata.h as a dependency. - * configure.srv (srv_tgtobj): Add linux-osdata.o to Linux targets. - * configure.ac: Add AC_HEADER_DIRENT check. - * config.in: Regenerate. - * configure: Regenerate. - * remote-utils.c (xml_escape_text): Delete. - (buffer_grow, buffer_free, buffer_init, buffer_finish, - buffer_xml_printf): Move to common/buffer.c. - * server.c (main): Remove call to initialize_inferiors. - * server.h (struct ptid, ptid_t, minus_one_ptid, null_ptid, - ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp, ptid_get_tid, - ptid_equal, ptid_is_pid, initialize_inferiors, xml_escape_text, - internal_error, gdb_assert, gdb_assert_fail): Delete. - (struct buffer, buffer_grow, buffer_free, buffer_init, buffer_finish, - buffer_xml_printf, buffer_grow_str, buffer_grow_str0): Move to - common/buffer.h. - * inferiors.c (null_ptid, minus_one_ptid, ptid_build, pid_to_ptid, - ptid_get_pid, ptid_get_lwp, ptid_get_tid, ptid_equal, ptid_is_pid, - initialize_inferiors): Delete. - -2011-07-20 Pedro Alves - - * tracepoint.c (tracepoint_look_up_symbols): Return upon the first - symbol error. - -2011-05-31 Pedro Alves - - * linux-x86-low.c (i386_dr_low_get_addr): Fix off by one in - assertion. - * win32-i386-low.c (i386_dr_low_get_addr): Ditto. - -2011-05-26 Yao Qi - - * Makefile.in (thread-db.o): Track dependence to - common/gdb_thread_db.h. - * thread-db.c: include gdb_thread_db.h from right place. - -2011-05-16 Adrian Cornish - - * linux-i386-ipa.c (supply_static_tracepoint_registers): Pass - __FILE__ and __LINE__ to internal_error. - -2011-05-13 Doug Evans - - * thread-db.c (try_thread_db_load_from_sdir): New function. - (try_thread_db_load_from_dir): New function. - (thread_db_load_search): Handle $sdir, ignore $pdir. - Remove trying of system directories if search of - libthread-db-search-path fails, that is now done via $sdir. - -2011-05-12 Kwok Cheung Yeung - - * server.c (handle_query): Add EnableDisableTracepoints to the list - of supported features. - * tracepoint.c (clear_installed_tracepoints): Uninstall disabled - tracepoints. - (cmd_qtenable_disable): New. - (cmd_qtstart): Install tracepoints even if disabled. - (handle_tracepoint_general_set): Add call to cmd_qtenable_disable on - receiving a QTEnable or QTDisable packet. - (gdb_collect): Skip data collection if fast tracepoint is disabled. - (ust_marker_to_static_tracepoint): Do not ignore disabled static - tracepoints. - (gdb_probe): Skip data collection if static tracepoint is disabled. - -2011-05-10 Doug Evans - - * thread-db.c (thread_db_handle_monitor_command): Handle elided path. - -2011-05-04 Doug Evans - - * linux-low.c (linux_join): Skip process lookup. - * spu-low.c (spu_join): Ditto. - * server.c (join_inferiors_callback): Delete. - (process_serial_event): For 'D' packet (detach) call join_inferior - directly. - -2011-05-04 Joseph Myers - - * README: Don't mention xscale*-*-linux*. - * configure.srv (xscale*-*-linux*): Don't handle target. - -2011-04-27 Nathan Froyd - - * linux-x86-low.c (amd64_emit_const): Call memcpy instead of - casting pointers. - (amd64_emit_reg, amd64_emit_int_call_1, amd64_emit_void_call_2): - (i386_emit_const, i386_emit_reg, i386_emit_int_call_1): - (i386_emit_void_call_2): Likewise. - -2011-04-26 Yao Qi - - * linux-low.c: Move common macros to linux-ptrace.h. - Include linux-ptrace.h. - * Makefile.in (linux_ptrace_h): New. - (linux-low.o): Depends on linux-ptrace.h. - -2011-04-24 Jan Kratochvil - - * remote-utils.c (handle_accept_event): Close LISTEN_DESC only if - RUN_ONCE. Comment for the LISTEN_DESC delete_file_handler call. - (remote_prepare): New function with most of the TCP code from ... - (remote_open): ... here. Detect PORT here unconditionally. Move also - setting transport_is_reliable. - * server.c (run_once): New variable. - (gdbserver_usage): Document it. - (main): Set run_once for `--once'. Call remote_prepare. Exit after - the first run if RUN_ONCE. - * server.h (run_once, remote_prepare): New declarations. - -2011-04-19 Tom Tromey - - * win32-low.c (handle_load_dll): Remove duplicate "the". - -2011-04-07 Pierre Muller - - Remove support for old Cygwin 1.5 versions. - * win32-low.c (win32_create_inferior): Use new cygwin_path_list - function to avoid warning. - (win32_add_one_solib): Use cygwin_conv_path function to avoid - warning. - -2011-03-18 Pierre Muller - - * gdbserver/server.h (Macro _): Define it if not available. - -2011-03-14 Michael Snyder - - * hostio.c (handle_close): Remove unnecessary null test. - -2011-03-10 Joel Brobecker - - * Makefile.in (maintainer-clean realclean distclean): Remove - "make ... subdir_do" command. - -2011-03-10 Michael Snyder - - * tracepoint.c (tracepoint_finish_step): Fix loop variable. - - * server.c (handle_v_run): Free alloced buffer on early return. - -2011-03-09 Yao Qi - - Revert: - 2011-03-04 Yao Qi - - * Makefile.in: Remove GNU make feature --directory. - - 2011-03-05 Yao Qi - - * Makefile.in (CLEANDIRS, REQUIRED_SUBDIRS): New variable. - (subdir_do): New make target. Copied from gdb/Makefile. - (maintainer-clean, realclean, distclean, clean): Call corresponding - make targets in common/Makefile. - - 2011-02-11 Yao Qi - - * configure.ac: Call AC_PROG_RANLIB. - * Makefile.in: Remove signals.o from OBS. Link libcommon.a. - * configure: Regenerate. - -2011-03-07 Jan Kratochvil - - * remote-utils.c (putpkt_binary_1): Calculate BUF2 size dynamically. - -2011-03-06 Yao Qi - - * Makefile.in (REQUIRED_SUBDIRS): Remove $(LIBCOMMON_DIR). - -2011-03-05 Yao Qi - - * Makefile.in (CLEANDIRS, REQUIRED_SUBDIRS): New variable. - (subdir_do): New make target. Copied from gdb/Makefile. - (maintainer-clean, realclean, distclean, clean): Call corresponding - make targets in common/Makefile. - -2011-03-04 Yao Qi - - * Makefile.in: Remove GNU make feature --directory. - -2011-03-04 Michael Snyder - - * server.c (queue_stop_reply): Call xmalloc not malloc. - -2011-03-02 Michael Snyder - - * linux-arm-low.c (arm_arch_setup): Replace malloc with xmalloc. - -2011-02-28 Michael Snyder - - * tracepoint.c (cmd_qtv): Discard unused value 'packet'. - (cmd_qtframe): Ditto. - (cmd_qtbuffer): Ditto. - (cmd_bigqtbuffer): Ditto. - - * utils.c (decimal2str): Initialize 'width' to nine, then - don't mess with it. - -2011-02-28 Ulrich Weigand - - * hostio.c (require_data): Free *data, not data. - -2011-02-28 Jan Kratochvil - - * hostio.c (require_data): Use free, not xfree. - -2011-02-27 Michael Snyder - - * server.c (handle_query): Discard unused value. - - * hostio.c (require_data): Free malloc memory before returning - error. - -2011-02-26 Michael Snyder - - * linux-low.c (list_threads): Call closedir for dirent. - -2011-02-27 Michael Snyder - - * i386-low.c (i386-length_and_rw_bits): Comment the fact that - a case statement falls through. - - * linux-low.c (linux_xfer_siginfo): Fix fencepost error. - - * linux-amd64-ipa.c (gdb_agent_get_raw_reg): Fix fencepost error - in comparison. - -2011-02-26 Michael Snyder - - * utils.c (decimal2str): Eliminate dead code and dead param. - (pulongest): Drop dead param from call to decimal2str. - (plongest): Ditto. - -2011-02-24 Joel Brobecker - - Revert the following patch (not approved yet): - 2011-02-21 Hui Zhu - * tracepoint.c (tp_printf): New function. - (eval_agent_expr): Handle gdb_agent_op_printf. - -2011-02-21 Hui Zhu - - * tracepoint.c (tp_printf): New function. - (eval_agent_expr): Handle gdb_agent_op_printf. - -2011-02-18 Tom Tromey - - * Makefile.in (tracepoint-ipa.o): Depend on ax.def. - (tracepoint.o): Likewise. - * tracepoint.c (enum gdb_agent_op): Use ax.def. - (gdb_agent_op_names): Likewise. - -2011-02-18 Tom Tromey - - * tracepoint.c (enum gdb_agent_op) : New constants. - (gdb_agent_op_names): Add pick and roll. - (eval_agent_expr) : New - cases. - -2011-02-15 Jan Kratochvil - - * aclocal.m4: Regenerated with aclocal-1.11.1. - -2011-02-14 Pedro Alves - - * server.c (handle_qxfer_traceframe_info): New. - (qxfer_packets): Register "traceframe-info". - (handle_query): Report support for qXfer:traceframe-info:read+. - * tracepoint.c (match_blocktype): New. - (traceframe_find_block_type): Rename to ... - (traceframe_walk_blocks): ... this. Add callback filter argument, - and use it. - (traceframe_find_block_type): New, reimplemented on top of - traceframe_walk_blocks. - (build_traceframe_info_xml): New. - (traceframe_read_info): New. - * server.h (traceframe_read_info): Declare. - -2011-02-11 Yao Qi - - * configure.ac: Call AC_PROG_RANLIB. - * Makefile.in: Remove signals.o from OBS. Link libcommon.a. - * configure: Regenerate. - -2011-02-07 Pedro Alves - - * server.c (gdb_read_memory): Change return semantics to allow - partial transfers. - (handle_search_memory_1): Adjust. - (process_serial_event) <'m' packet>: Handle partial transfers. - * tracepoint.c (traceframe_read_mem): Handle partial transfers. - -2011-01-28 Pedro Alves - - * regcache.c (init_register_cache): Initialize - regcache->register_status. - (free_register_cache): Release regcache->register_status. - (regcache_cpy): Copy register_status. - (registers_to_string): Print 'x's for unavailable registers. - (supply_register): Mark the register's status valid or - unavailable, depending on whether a buffer was passed in or not. - (supply_register_zeroed): New. - (supply_regblock): Mark the registers' status valid or - unavailable, depending on whether a buffer was passed in or not. - * regcache.h (REG_UNAVAILABLE, REG_VALID): New defines. - (struct regcache): New `register_status' field. - (supply_register_zeroed): Declare. - * i387-fp.c (i387_xsave_to_cache): Zero out registers using - supply_register_zeroed, rather than passing a NULL buffer to - supply_register. - * tracepoint.c (fetch_traceframe_registers): Update comment. - -2011-01-28 Pedro Alves - - * i387-fp.c (i387_xsave_to_cache): Make passing NULL as register - buffer explicit. - -2011-01-25 Pedro Alves - - * server.h (decode_xfer_write): Change prototype. - * remote-utils.c (decode_xfer_write): Remove `annex' parameter, - and don't extract the annex here. - * server.c (decode_xfer_read): Remove `annex' parameter, - and don't extract the annex here. - (decode_xfer): New. - (struct qxfer): New. - (handle_qxfer_auxv, handle_qxfer_features, handle_qxfer_libraries) - (handle_qxfer_osdata, handle_qxfer_siginfo, handle_qxfer_spu) - (handle_qxfer_statictrace): New functions, abstracted out from - handle_query, and made to use the struct qxfer interface. - (handle_threads_qxfer_proper): Rename to ... - (handle_qxfer_threads_proper): ... this. - (handle_threads_qxfer): Rename to ... - (handle_qxfer_threads): ... this. Adjust. - (qxfer_packets): New array. - (handle_qxfer): New function. - (handle_query): Use handle_qxfer. - -2011-01-05 Michael Snyder - - * gdbreplay.c: Shorten lines of >= 80 columns. - * linux-low.c: Ditto. - * linux-ppc-low.c: Ditto. - * linux-s390-low.c: Ditto. - * linux-sparc-low.c: Ditto. - * linux-x86-low.c: Ditto. - * linux-xtensa-low.c: Ditto. - * mem-break.c: Ditto. - * nto-low.c: Ditto. - * regcache.h: Ditto. - * remote-utils.c: Ditto. - * server.c: Ditto. - * server.h: Ditto. - * thread-db.c: Ditto. - * tracepoint.c: Ditto. - * utils.c: Ditto. - * win32-low.h: Ditto. - -2011-01-05 Joel Brobecker - - * gdbserver/configure.ac, gdbserver/gdbserver.1: Copyright year - update. - -2011-01-01 Joel Brobecker - - * server.c (gdbserver_version): Update copyright year in version - output. - * gdbreplay.c (gdbreplay_version): Ditto. - -2010-12-29 Jie Zhang - - * configure.srv (bfin-*-*linux*): Handle Blackfin/Linux targets. - * linux-bfin-low.c: New file. - * linux-low.c: Define PT_TEXT_ADDR, PT_TEXT_END_ADDR, and - PT_DATA_ADDR for BFIN targets. - * Makefile.in (SFILES): Add linux-bfin-low.c. - (clean): Remove reg-bfin.c. - (linux-bfin-low.o, reg-bfin.o, reg-bfin.c): New targets. - * README: Mention supported Blackfin targets. - -2010-12-23 Mike Frysinger - - * .gitignore: New file. - -2010-11-16 Mike Frysinger - - * linux-low.c (linux_tracefork_child): Add char* cast to arg. - -2010-10-22 Jie Zhang - - * Makefile.in: Add FLAGS_TO_PASS variable. - (install): Remove dependency of install-only and recursively - invoke make for install-only. - -2010-10-04 Doug Evans - - * Makefile.in (uninstall): Use $(DESTDIR). - -2010-09-24 Pedro Alves - - PR gdb/11842 - - * linux-x86-low.c (compat_siginfo_from_siginfo) - (siginfo_from_compat_siginfo): Also copy si_pid and si_uid when - si_code is < 0. Check for si_code == SI_TIMER before checking for - si_code < 0. - -2010-09-13 Joel Brobecker - - * lynx-i386-low.c: New file. - * configure.srv: Add handling of i[34567]86-*-lynxos* targets. - -2010-09-13 Joel Brobecker - - * lynx-low.c (ptrace_request_to_str): Remove handling for - request values that have been removed in LynxOS 5.x. - -2010-09-13 Joel Brobecker - - * lynx-low.c, lynx-ppc-loc.c: Include instead of - - -2010-09-09 Nathan Sidwell - - * configure.ac: Add --enable-inprocess-agent option. - * configure: Rebuilt. - -2010-09-06 Yao Qi - - * linux-low.c (linux_kill): Remove unused variable. - (linux_stabilize_threads): Likewise. - * server.c (start_inferior): Likewise. - (queue_stop_reply_callback): Likewise. - * tracepoint.c (do_action_at_tracepoint): Likewise. - -2010-09-06 Yao Qi - - * linux-low.c (maybe_move_out_of_jump_pad): Restore current_inferior - on return. - -2010-09-06 Jan Kratochvil - - * target.c (mywait) : Fix to use INTEGER. - -2010-09-06 Pedro Alves - - * Makefile.in (install-only): Replace $IPA_DEPFILES with - "$(IPA_DEPFILES)". - -2010-09-01 Joel Brobecker - - * gdbserver/lynx-low.c, gdbserver/lynx-low.h, - gdbserver/lynx-ppc-low.c: New files. - * Makefile.in (lynx_low_h): New variable. - (lynx-low.o, lynx-ppc-low.o): New rules. - * configure.ac: On LynxOS, link with -lnetinet. - * configure.srv: Add handling of powerpc-*-lynxos* targets. - * configure: regenerate. - -2010-09-01 Joel Brobecker - - * Makefile.in (vasprintf.o, vsnprintf.o): New rules. - * configure.ac: Add check for vasprintf and vsnprintf. - * configure, config.in: Regenerate. - * server.h (vasprintf, vsnprintf): Add conditional declarations. - -2010-09-01 Joel Brobecker - - * gdbreplay.c: Move include of alloca.h up, next to include of - malloc.h. - * server.h: Add include of malloc.h. - * mem-break.c: Remove include of malloc.h. - * server.c, tracepoint.c, utils.c, win32-low.c: Likewise. - -2010-09-01 Joel Brobecker - - * Makefile.in (memmem.o): Build with -Wno-error. - -2010-09-01 Joel Brobecker - - * utils.c (xsnprintf): Make non-static. - * server.h: Add xsnprintf declaration. - * linux-low.c, nto-low.c, target.c, thread-db.c, tracepoint.c: - replace calls to snprintf by calls to xsnprintf throughout. - -2010-09-01 Joel Brobecker - - * configure.ac: Add configure check for alloca. - * configure, config.in: Regenerate. - * server.h: Include alloca.h if it exists. - * gdbreplay.c: Include alloca.h if it exists. - -2010-08-28 Pedro Alves - - * linux-low.c (__SIGRTMIN): Define if not already defined. - (linux_create_inferior): Check for __ANDROID__ rather than - __SIGRTMIN. - (enqueue_one_deferred_signal): Don't requeue non-RT signals that - are already deferred. - (linux_wait_1): Check for __ANDROID__ rather than __SIGRTMIN. - (linux_resume_one_thread): Don't queue a SIGSTOP if the lwp is - stopped and already has a pending signal to report. - (proceed_one_lwp): : Don't queue a SIGSTOP if the lwp already has - a pending signal to report or is moving out of a jump pad. - (linux_init_signals): Check for __ANDROID__ rather than - __SIGRTMIN. - -2010-08-28 Pedro Alves - - * linux-low.c (linux_stabilize_threads): Wrap debug output in a - debug_threads check. Avoid a linear search when not doing debug - output. - -2010-08-27 Pedro Alves - - * event-loop.c (event_handle_func): Adjust to use gdb_fildes_t. - (struct gdb_event) : Change type to gdb_fildes_t. - (struct file_handler) : Change type to gdb_fildes_t. - (process_event): Change local fd's type to gdb_fildes_t. - (create_file_handler): Adjust prototype. - (delete_file_handler): Adjust prototype. - (handle_file_event): Adjust prototype. Use pfildes. - (create_file_event): Adjsut prototype. - * remote-utils.c (remote_desc, listen_desc): Change type to - gdb_fildes_t. - * server.h: New gdb_fildes_t typedef. - [USE_WIN32API]: Include winsock2.h. - (delete_file_handler, add_file_handler): Adjust prototypes. - (pfildes): Declare. - * utils.c (pfildes): New. - -2010-08-27 Pedro Alves - - * configure.ac (build_warnings): Add -Wno-char-subscripts. - * configure: Regenerate. - -2010-08-27 Pedro Alves - - * linux-low.c (linux_unprepare_to_access_memory): Rename to ... - (linux_done_accessing_memory): ... this. - (linux_target_ops): Adjust. - * linux-x86-low.c (x86_insert_point, x86_remove_point): Adjust. - * nto-low.c (nto_target_ops): Adjust comment. - * server.c (gdb_read_memory, gdb_write_memory): Adjust. - * spu-low.c (spu_target_ops): Adjust comment. - * target.h (target_ops): Rename unprepare_to_access_memory field - to done_accessing_memory. - (unprepare_to_access_memory): Rename to ... - (done_accessing_memory): ... this. - -2010-08-26 Pedro Alves - - * linux-low.c (linux_prepare_to_access_memory): New. - (linux_unprepare_to_access_memory): New. - (linux_target_ops): Install them. - * server.c (read_memory): Rename to ... - (gdb_read_memory): ... this. Use - prepare_to_access_memory/prepare_to_access_memory. - (write_memory): Rename to ... - (gdb_write_memory): ... this. Use - prepare_to_access_memory/prepare_to_access_memory. - (handle_search_memory_1): Adjust. - (process_serial_event): Adjust. - * target.h (struct target_ops): New fields - prepare_to_access_memory and unprepare_to_access_memory. - (prepare_to_access_memory, unprepare_to_access_memory): New. - * linux-x86-low.c (x86_insert_point, x86_remove_point): Use - prepare_to_access_memory/prepare_to_access_memory. - * nto-low.c (nto_target_ops): Adjust. - * spu-low.c (spu_target_ops): Adjust. - * win32-low.c (win32_target_ops): Adjust. - -2010-08-26 Pedro Alves - - * Makefile.in (WARN_CFLAGS): Get it from configure. - (WERROR_CFLAGS): New. - (INTERNAL_CFLAGS): Add WERROR_CFLAGS. - * configure.ac: Introduce --enable-werror, which adds -Werror to - the compiler command line. Enabled by default. Disable with - --disable-werror. Add -Wdeclaration-after-statement - Wpointer-arith and -Wformat-nonliteral to warning flags. - * configure: Regenerate. - -2010-08-26 Pedro Alves - - * mem-break.c [HAVE_MALLOC_H]: Include malloc.h. - -2010-08-26 Pedro Alves - - * gdbreplay.c (remote_error): New. - (gdbchar): New. - (expect): Use gdbchar. Check for error reading from GDB. - Clarify sync error output. - (play): Check for errors writing to GDB. - * linux-low.c (sigchld_handler): Really ignore `write' errors. - * remote-utils.c (getpkt): Check for errors writing to the remote - descriptor. - -2010-08-25 Pedro Alves - - * linux-low.c (linux_wait_1): Move non-debugging code out of - `debug_threads' control. - -2010-08-25 Pedro Alves - - * linux-low.c (linux_wait_1): Don't set last_status here. - * server.c (push_event, queue_stop_reply_callback): Assert we're - not pushing a TARGET_WAITKIND_IGNORE event. - (start_inferior, start_inferior, attach_inferior, handle_v_cont) - (myresume, handle_target_event): Set the thread's last_resume_kind - and last_status from the target returned status. - -2010-08-25 Pedro Alves - - PR threads/10729 - - * linux-x86-low.c (update_debug_registers_callback): New. - (i386_dr_low_set_addr): Use it. - (i386_dr_low_get_addr): New. - (i386_dr_low_set_control): Use update_debug_registers_callback. - (i386_dr_low_get_control): New. - (i386_dr_low_get_status): Adjust. - * linux-low.c (linux_stop_lwp): New. - * linux-low.h (linux_stop_lwp): Declare. - - * i386-low.c (I386_DR_GET_RW_LEN): Take the dr7 contents as - argument instead of a i386_debug_reg_state. - (I386_DR_WATCH_HIT): Take the dr6 contents as argument instead of - a i386_debug_reg_state. - (i386_insert_aligned_watchpoint): Adjust. - (i386_remove_aligned_watchpoint): Adjust. - (i386_low_stopped_data_address): Read the debug registers from the - inferior instead of from the mirrors. - * i386-low.h (struct i386_debug_reg_state): Extend comment. - (i386_dr_low_get_addr): Declare. - (i386_dr_low_get_control): Declare. - (i386_dr_low_get_status): Change prototype. - - * win32-i386-low.c (dr_status_mirror, dr_control_mirror): New globals. - (i386_dr_low_get_addr): New. - (i386_dr_low_get_control): New. - (i386_dr_low_get_status): Adjust prototype. Return - dr_status_mirror. - (i386_initial_stuff): Clear dr_status_mirror and - dr_control_mirror. - (i386_get_thread_context): Adjust. - (i386_set_thread_context): Adjust. - (i386_thread_added): Adjust. - -2010-08-24 Pedro Alves - - * linux-low.h (linux_thread_area): Delete declaration. - -2010-08-11 Thomas Schwinge - - * linux-low.c (linux_wait_1): Correctly return the ptid of the child - after its termination. - -2010-08-09 Pedro Alves - - * linux-low.c (gdb_wants_lwp_stopped): Delete. - (gdb_wants_all_stopped): Delete. - (linux_wait_1): Don't call them. - * server.c (handle_v_cont): Tag all threads as want-stopped. - (gdb_wants_thread_stopped): Fix comments. Tag the thread that - stopped as "client-wants-stopped". - -2010-07-31 Pedro Alves - - * Makefile.in (signals_h): New. - (server_h): Depend on it. - (server.o): Don't depend on $(signals_def). - (signals.o): Depend on $(signals_def). - -2010-07-31 Jan Kratochvil - - * Makefile.in (signals_def): New. - (server_h): Append include/gdb/signals.h and signals_def. - (server.o): Append signals_def. - -2010-07-25 Jan Kratochvil - - * server.c (handle_target_event): Use target_signal_to_host for - resume_info.sig initialization. - * target.h (struct thread_resume) : New comment. - -2010-07-20 Ozkan Sezer - - * server.c (handle_query): strcpy() the returned string from paddress() - instead of sprintf(). - * utils.c (paddress): Return phex_nz(). - -2010-07-07 Joel Brobecker - - * server.c (handle_v_cont): Call mourn_inferior if process - just exited. - (myresume): Likewise. - -2010-07-01 Pedro Alves - - Static tracepoints, and integration with UST. - - * configure.ac: Handle --with-ust. substitute ustlibs and ustinc. - * mem-break.c (uninsert_all_breakpoints) - (reinsert_all_breakpoints): New. - * mem-break.h (reinsert_all_breakpoints, uninsert_all_breakpoints): - * tracepoint.c (ust_loaded, helper_thread_id, cmd_buf): New. - (gdb_agent_ust_loaded, helper_thread_id) - (gdb_agent_helper_thread_id): New macros. - (struct ipa_sym_addresses): Add addr_ust_loaded, - addr_helper_thread_id, addr_cmd_buf. - (symbol_list): Add ust_loaded, helper_thread_id, cmd_buf. - (in_process_agent_loaded_ust): New. - (write_e_ust_not_loaded): New. - (maybe_write_ipa_ust_not_loaded): New. - (struct collect_static_trace_data_action): New. - (enum tracepoint_type) : New. - (struct tracepoint) : Mention static tracepoints. - (struct static_tracepoint_ctx): New. - (CMD_BUF_SIZE): New. - (add_tracepoint_action): Handle static tracepoint actions. - (unprobe_marker_at): New. - (clear_installed_tracepoints): Handle static tracepoints. - (cmd_qtdp): Handle static tracepoints. - (probe_marker_at): New. - (cmd_qtstart): Handle static tracepoints. - (response_tracepoint): Handle static tracepoints. - (cmd_qtfstm, cmd_qtsstm, cmd_qtstmat): New. - (handle_tracepoint_query): Handle qTfSTM, qTsSTM and qTSTMat. - (get_context_regcache): Handle static tracepoints. - (do_action_at_tracepoint): Handle static tracepoint actions. - (traceframe_find_block_type): Handle static trace data blocks. - (traceframe_read_sdata): New. - (download_tracepoints): Download static tracepoint actions. - [HAVE_UST] Include ust/ust.h, dlfcn.h, sys/socket.h, and sys/un.h. - (GDB_PROBE_NAME): New. - (ust_ops): New. - (GET_UST_SYM): New. - (USTF): New. - (dlsym_ust): New. - (ust_marker_to_static_tracepoint): New. - (gdb_probe): New. - (collect_ust_data_at_tracepoint): New. - (gdb_ust_probe): New. - (UNIX_PATH_MAX, SOCK_DIR): New. - (gdb_ust_connect_sync_socket): New. - (resume_thread, stop_thread): New. - (run_inferior_command): New. - (init_named_socket): New. - (gdb_ust_socket_init): New. - (cstr_to_hexstr): New. - (next_st): New. - (first_marker, next_marker): New. - (response_ust_marker): New. - (cmd_qtfstm, cmd_qtsstm): New. - (unprobe_marker_at, probe_marker_at): New. - (cmd_qtstmat, gdb_ust_thread): New. - (gdb_ust_init): New. - (initialize_tracepoint_ftlib): Call gdb_ust_init. - * linux-amd64-ipa.c [HAVE_UST]: Include ust/processor.h - (ST_REGENTRY): New. - (x86_64_st_collect_regmap): New. - (X86_64_NUM_ST_COLLECT_GREGS): New. - (AMD64_RIP_REGNUM): New. - (supply_static_tracepoint_registers): New. - * linux-i386-ipa.c [HAVE_UST]: Include ust/processor.h - (ST_REGENTRY): New. - (i386_st_collect_regmap): New. - (i386_NUM_ST_COLLECT_GREGS): New. - (supply_static_tracepoint_registers): New. - * server.c (handle_query): Handle qXfer:statictrace:read. - : Report support for StaticTracepoints, and - qXfer:statictrace:read features. - * server.h (traceframe_read_sdata) - (supply_static_tracepoint_registers): Declare. - * remote-utils.c (convert_int_to_ascii, hexchars, ishex, tohex) - (unpack_varlen_hex): Include in IPA build. - * Makefile.in (ustlibs, ustinc): New. - (IPA_OBJS): Add remote-utils-ipa.o. - ($(IPA_LIB)): Link -ldl and -lpthread. - (UST_CFLAGS): New. - (IPAGENT_CFLAGS): Add UST_CFLAGS. - * config.in, configure: Regenerate. - -2010-06-20 Ian Lance Taylor - Pedro Alves - - * linux-x86-low.c (always_true): Delete. - (EMIT_ASM, EMIT_ASM32): Use an uncondition asm jmp instead of - trying to fool the compiler with always_true. - -2010-06-20 Pedro Alves - - * tracepoint.c (condition_true_at_tracepoint): Don't run compiled - conditions in gdbserver. - -2010-06-19 Ulrich Weigand - - * spu-low.c (spu_read_memory): Wrap around local store limit. - (spu_write_memory): Likewise. - -2010-06-15 Pedro Alves - - * linux-x86-low.c (amd64_emit_const, amd64_emit_void_call_2) - (i386_emit_const, i386_emit_void_call_2): Replace int64_t uses with - LONGEST uses. - * server.h (struct emit_ops): Replace int64_t uses with LONGEST - uses. - * tracepoint.c (emit_const, emit_void_call_2): Replace int64_t - uses with LONGEST uses. - -2010-06-14 Stan Shebs - Pedro Alves - - Bytecode compiler. - - * linux-x86-low.c: Include limits.h. - (add_insns): New. - (always_true): New. - (EMIT_ASM): New. - (EMIT_ASM32): New. - (amd64_emit_prologue, amd64_emit_epilogue, amd64_emit_add) - (amd64_emit_sub, amd64_emit_mul, amd64_emit_lsh) - (amd64_emit_rsh_signed, amd64_emit_rsh_unsigned, amd64_emit_ext, - (amd64_emit_log_not, amd64_emit_bit_and, amd64_emit_bit_or) - (amd64_emit_bit_xor, amd64_emit_bit_not, amd64_emit_equal, - (amd64_emit_less_signed, amd64_emit_less_unsigned, amd64_emit_ref, - (amd64_emit_if_goto, amd64_emit_goto, amd64_write_goto_address) - (amd64_emit_const, amd64_emit_call, amd64_emit_reg) - (amd64_emit_pop, amd64_emit_stack_flush, amd64_emit_zero_ext) - (amd64_emit_swap, amd64_emit_stack_adjust, amd64_emit_int_call_1) - (amd64_emit_void_call_2): New. - (amd64_emit_ops): New. - (i386_emit_prologue, i386_emit_epilogue, i386_emit_add) - (i386_emit_sub,i386_emit_mul, i386_emit_lsh, i386_emit_rsh_signed) - (i386_emit_rsh_unsigned, i386_emit_ext, i386_emit_log_not) - (i386_emit_bit_and, i386_emit_bit_or, i386_emit_bit_xor) - (i386_emit_bit_not, i386_emit_equal, i386_emit_less_signed) - (i386_emit_less_unsigned, i386_emit_ref, i386_emit_if_goto) - (i386_emit_goto, i386_write_goto_address, i386_emit_const) - (i386_emit_call, i386_emit_reg, i386_emit_pop) - (i386_emit_stack_flush, i386_emit_zero_ext, i386_emit_swap) - (i386_emit_stack_adjust, i386_emit_int_call_1) - (i386_emit_void_call_2): New. - (i386_emit_ops): New. - (x86_emit_ops): New. - (the_low_target): Install x86_emit_ops. - * server.h (struct emit_ops): New. - (get_raw_reg_func_addr): Declare. - (current_insn_ptr, emit_error): Declare. - * tracepoint.c (get_raw_reg, get_trace_state_variable_value) - (set_trace_state_variable_value): New defines. - (struct ipa_sym_addresses): New fields addr_get_raw_reg, - addr_get_trace_state_variable_value and - addr_set_trace_state_variable_value. - (symbol_list): New fields for get_raw_reg, - get_trace_state_variable_value and set_trace_state_variable_value. - (condfn): New typedef. - (struct tracepoint): New field `compiled_cond'. - (do_action_at_tracepoint): Clear compiled_cond. - (get_trace_state_variable_value, set_trace_state_variable_value): - Export in the IPA. - (condition_true_at_tracepoint): If there's a compiled condition, - run that. - (current_insn_ptr, emit_error): New globals. - (struct bytecode_address): New. - (get_raw_reg_func_addr): New. - (emit_prologue, emit_epilogue, emit_add, emit_sub, emit_mul) - (emit_lsh, emit_rsh_signed, emit_rsh_unsigned, emit_ext) - (emit_log_not, emit_bit_and, emit_bit_or, emit_bit_xor) - (emit_bit_not, emit_equal, emit_less_signed, emit_less_unsigned) - (emit_ref, emit_if_goto, emit_goto, write_goto_address, emit_const) - (emit_reg, emit_pop, emit_stack_flush, emit_zero_ext, emit_swap) - (emit_stack_adjust, emit_int_call_1, emit_void_call_2): New. - (compile_tracepoint_condition, compile_bytecodes): New. - * target.h (emit_ops): Forward declare. - (struct target_ops): New field emit_ops. - (target_emit_ops): New. - * linux-amd64-ipa.c (gdb_agent_get_raw_reg): New. - * linux-i386-ipa.c (gdb_agent_get_raw_reg): New. - * linux-low.c (linux_emit_ops): New. - (linux_target_ops): Install it. - * linux-low.h (struct linux_target_ops): New field emit_ops. - -2010-06-14 Ulrich Weigand - - * linux-ppc-low.c (ppc_arch_setup): Use private regcache to test MSR. - * linux-s390-low.c (ppc_arch_setup): Use private regcache to test PSW. - -2010-06-01 Pedro Alves - Stan Shebs - - * Makefile.in (IPA_DEPFILES, extra_libraries): New. - (all): Depend on $(extra_libraries). - (install-only): Install the IPA. - (IPA_OBJS, IPA_LIB): New. - (clean): Remove the IPA lib. - (IPAGENT_CFLAGS): New. - (tracepoint-ipa.o, utils-ipa.o, remote-utils-ipa.o) - (regcache-ipa.o, i386-linux-ipa.o, linux-i386-ipa.o) - (linux-amd64-ipa.o, amd64-linux-ipa.o): New rules. - * linux-amd64-ipa.c, linux-i386-ipa.c: New files. - * configure.ac: Check for atomic builtins support in the compiler. - (IPA_DEPFILES, extra_libraries): Define. - * configure.srv (ipa_obj): Add description. - (ipa_i386_linux_regobj, ipa_amd64_linux_regobj): Define. - (i[34567]86-*-linux*): Set ipa_obj. - (x86_64-*-linux*): Set ipa_obj. - * linux-low.c (stabilizing_threads): New. - (supports_fast_tracepoints): New. - (linux_detach): Stabilize threads before detaching. - (handle_tracepoints): Handle internal tracing breakpoints. Assert - the lwp is either not stabilizing, or is moving out of a jump pad. - (linux_fast_tracepoint_collecting): New. - (maybe_move_out_of_jump_pad): New. - (enqueue_one_deferred_signal): New. - (dequeue_one_deferred_signal): New. - (linux_wait_for_event_1): If moving out of a jump pad, defer - pending signals to later. - (linux_stabilize_threads): New. - (linux_wait_1): Check if threads need moving out of jump pads, and - do it if so. - (stuck_in_jump_pad_callback): New. - (move_out_of_jump_pad_callback): New. - (lwp_running): New. - (linux_resume_one_lwp): Handle moving out of jump pads. - (linux_set_resume_request): Dequeue deferred signals. - (need_step_over_p): Also step over fast tracepoint jumps. - (start_step_over): Also uninsert fast tracepoint jumps. - (finish_step_over): Also reinsert fast tracepoint jumps. - (linux_install_fast_tracepoint_jump): New. - (linux_target_ops): Install linux_stabilize_threads and - linux_install_fast_tracepoint_jump_pad. - * linux-low.h (linux_target_ops) : New fields. - (struct lwp_info) : New fields. - (linux_get_thread_area): Declare. - * linux-x86-low.c (jump_insn): New. - (x86_get_thread_area): New. - (append_insns): New. - (push_opcode): New. - (amd64_install_fast_tracepoint_jump_pad): New. - (i386_install_fast_tracepoint_jump_pad): New. - (x86_install_fast_tracepoint_jump_pad): New. - (the_low_target): Install x86_get_thread_area and - x86_install_fast_tracepoint_jump_pad. - * mem-break.c (set_raw_breakpoint_at): Use read_inferior_memory. - (struct fast_tracepoint_jump): New. - (fast_tracepoint_jump_insn): New. - (fast_tracepoint_jump_shadow): New. - (find_fast_tracepoint_jump_at): New. - (fast_tracepoint_jump_here): New. - (delete_fast_tracepoint_jump): New. - (set_fast_tracepoint_jump): New. - (uninsert_fast_tracepoint_jumps_at): New. - (reinsert_fast_tracepoint_jumps_at): New. - (set_breakpoint_at): Use write_inferior_memory. - (uninsert_raw_breakpoint): Use write_inferior_memory. - (check_mem_read): Mask out fast tracepoint jumps. - (check_mem_write): Mask out fast tracepoint jumps. - * mem-break.h (struct fast_tracepoint_jump): Forward declare. - (set_fast_tracepoint_jump): Declare. - (delete_fast_tracepoint_jump) - (fast_tracepoint_jump_here, uninsert_fast_tracepoint_jumps_at) - (reinsert_fast_tracepoint_jumps_at): Declare. - * regcache.c: Don't compile many functions when building the - in-process agent library. - (init_register_cache) [IN_PROCESS_AGENT]: Don't allow allocating - the register buffer in the heap. - (free_register_cache): If the register buffer isn't owned by the - regcache, don't free it. - (set_register_cache) [IN_PROCESS_AGENT]: Don't re-alocate - pre-existing register caches. - * remote-utils.c (convert_int_to_ascii): Constify `from' parameter - type. - (convert_ascii_to_int): : Constify `from' parameter type. - (decode_M_packet, decode_X_packet): Replace the `to' parameter by - a `to_p' pointer to pointer parameter. If TO_P is NULL, malloc - the needed buffer in-place. - (relocate_instruction): New. - * server.c (handle_query) : If the target supports - tracepoints, give it a chance of looking up symbols. Report - support for fast tracepoints. - (handle_status): Stabilize threads. - (process_serial_event): Adjust. - * server.h (struct fast_tracepoint_jump): Forward declare. - (struct process_info) : New field. - (convert_ascii_to_int, convert_int_to_ascii): Adjust. - (decode_X_packet, decode_M_packet): Adjust. - (relocate_instruction): Declare. - (in_process_agent_loaded): Declare. - (tracepoint_look_up_symbols): Declare. - (struct fast_tpoint_collect_status): Declare. - (fast_tracepoint_collecting): Declare. - (force_unlock_trace_buffer): Declare. - (handle_tracepoint_bkpts): Declare. - (initialize_low_tracepoint) - (supply_fast_tracepoint_registers) [IN_PROCESS_AGENT]: Declare. - * target.h (struct target_ops) : New fields. - (stabilize_threads, install_fast_tracepoint_jump_pad): New. - * tracepoint.c [HAVE_MALLOC_H]: Include malloc.h. - [HAVE_STDINT_H]: Include stdint.h. - (trace_debug_1): Rename to ... - (trace_vdebug): ... this. - (trace_debug): Rename to ... - (trace_debug_1): ... this. Add `level' parameter. - (trace_debug): New. - (ATTR_USED, ATTR_NOINLINE): New. - (IP_AGENT_EXPORT): New. - (gdb_tp_heap_buffer, gdb_jump_pad_buffer, gdb_jump_pad_buffer_end) - (collecting, gdb_collect, stop_tracing, flush_trace_buffer) - (about_to_request_buffer_space, trace_buffer_is_full) - (stopping_tracepoint, expr_eval_result, error_tracepoint) - (tracepoints, tracing, trace_buffer_ctrl, trace_buffer_ctrl_curr) - (trace_buffer_lo, trace_buffer_hi, traceframe_read_count) - (traceframe_write_count, traceframes_created) - (trace_state_variables) - New renaming defines. - (struct ipa_sym_addresses): New. - (STRINGIZE_1, STRINGIZE, IPA_SYM): New. - (symbol_list): New. - (ipa_sym_addrs): New. - (all_tracepoint_symbols_looked_up): New. - (in_process_agent_loaded): New. - (write_e_ipa_not_loaded): New. - (maybe_write_ipa_not_loaded): New. - (tracepoint_look_up_symbols): New. - (debug_threads) [IN_PROCESS_AGENT]: New. - (read_inferior_memory) [IN_PROCESS_AGENT]: New. - (UNKNOWN_SIDE_EFFECTS): New. - (stop_tracing): New. - (flush_trace_buffer): New. - (stop_tracing_bkpt): New. - (flush_trace_buffer_bkpt): New. - (read_inferior_integer): New. - (read_inferior_uinteger): New. - (read_inferior_data_pointer): New. - (write_inferior_data_pointer): New. - (write_inferior_integer): New. - (write_inferior_uinteger): New. - (struct collect_static_trace_data_action): Delete. - (enum tracepoint_type): New. - (struct tracepoint) : New field `type'. - : Only include in - GDBserver. - - : New fields. - (tracepoints): Use IP_AGENT_EXPORT. - (last_tracepoint): Don't include in the IPA. - (stopping_tracepoint): Use IP_AGENT_EXPORT. - (trace_buffer_is_full): Use IP_AGENT_EXPORT. - (alloced_trace_state_variables): New. - (trace_state_variables): Use IP_AGENT_EXPORT. - (traceframe_t): Delete unused variable. - (circular_trace_buffer): Don't include in the IPA. - (trace_buffer_start): Delete. - (struct trace_buffer_control): New. - (trace_buffer_free): Delete. - (struct ipa_trace_buffer_control): New. - (GDBSERVER_FLUSH_COUNT_MASK, GDBSERVER_FLUSH_COUNT_MASK_PREV) - (GDBSERVER_FLUSH_COUNT_MASK_CURR, GDBSERVER_UPDATED_FLUSH_COUNT_BIT): - New. - (trace_buffer_ctrl): New. - (TRACE_BUFFER_CTRL_CURR): New. - (trace_buffer_start, trace_buffer_free, trace_buffer_end_free): - Reimplement as macros. - (trace_buffer_wrap): Delete. - (traceframe_write_count, traceframe_read_count) - (traceframes_created, tracing): Use IP_AGENT_EXPORT. - (struct tracepoint_hit_ctx) : New field. - (struct fast_tracepoint_ctx): New. - (memory_barrier): New. - (cmpxchg): New. - (record_tracepoint_error): Update atomically in the IPA. - (clear_inferior_trace_buffer): New. - (about_to_request_buffer_space): New. - (trace_buffer_alloc): Handle GDBserver and inferior simulatenous - updating the same buffer. - (add_tracepoint): Default the tracepoint's type to trap - tracepoint, and orig_size to -1. - (get_trace_state_variable) [IN_PROCESS_AGENT]: Handle allocated - internal variables. - (create_trace_state_variable): New parameter `gdb'. Handle it. - (clear_installed_tracepoints): Clear fast tracepoint jumps. - (cmd_qtdp): Handle fast tracepoints. - (cmd_qtdv): Adjust. - (max_jump_pad_size): New. - (gdb_jump_pad_head): New. - (get_jump_space_head): New. - (claim_jump_space): New. - (sort_tracepoints): New. - (MAX_JUMP_SIZE): New. - (cmd_qtstart): Handle fast tracepoints. Sync tracepoints with the - IPA. - (stop_tracing) [IN_PROCESS_AGENT]: Don't include the tdisconnected - support. Upload fast traceframes, and delete internal IPA - breakpoints. - (stop_tracing_handler): New. - (flush_trace_buffer_handler): New. - (cmd_qtstop): Upload fast tracepoints. - (response_tracepoint): Handle fast tracepoints. - (tracepoint_finished_step): Upload fast traceframes. Set the - tracepoint hit context's tracepoint type. - (handle_tracepoint_bkpts): New. - (tracepoint_was_hit): Set the tracepoint hit context's tracepoint - type. Add comment about fast tracepoints. - (collect_data_at_tracepoint) [IN_PROCESS_AGENT]: Don't access the - non-existing action_str field. - (get_context_regcache): Handle fast tracepoints. - (do_action_at_tracepoint) [!IN_PROCESS_AGENT]: Don't write the PC - to the regcache. - (fast_tracepoint_from_jump_pad_address): New. - (fast_tracepoint_from_ipa_tpoint_address): New. - (collecting_t): New. - (force_unlock_trace_buffer): New. - (fast_tracepoint_collecting): New. - (collecting): New. - (gdb_collect): New. - (write_inferior_data_ptr): New. - (target_tp_heap): New. - (target_malloc): New. - (download_agent_expr): New. - (UALIGN): New. - (download_tracepoints): New. - (download_trace_state_variables): New. - (upload_fast_traceframes): New. - (IPA_FIRST_TRACEFRAME): New. - (IPA_NEXT_TRACEFRAME_1): New. - (IPA_NEXT_TRACEFRAME): New. - [IN_PROCESS_AGENT]: Include sys/mman.h and fcntl.h. - [IN_PROCESS_AGENT] (gdb_tp_heap_buffer, gdb_jump_pad_buffer) - (gdb_jump_pad_buffer_end): New. - [IN_PROCESS_AGENT] (initialize_tracepoint_ftlib): New. - (initialize_tracepoint): Adjust. - [IN_PROCESS_AGENT]: Allocate the IPA heap, and jump pad scratch - buffer. Initialize the low module. - * utils.c (PREFIX, TOOLNAME): New. - (malloc_failure): Use PREFIX. - (error): In the IPA, an error causes an exit. - (fatal, warning): Use PREFIX. - (internal_error): Use TOOLNAME. - (NUMCELLS): Increase to 10. - * configure, config.in: Regenerate. - -2010-06-01 Pedro Alves - - * server.c (handle_query) : Do two passes over the - qSupported string to avoid nesting strtok. - -2010-05-28 Jan Kratochvil - - * Makefile.in (SFILES): Add $(srcdir)/proc-service.list. - (CDEPS): New. - * configure.ac (RDYNAMIC): New AC_MSG_CHECKING wrapping. Test also - -Wl,--dynamic-list. - * configure: Regenerate. - * proc-service.list: New. - -2010-05-28 Jan Kratochvil - - * linux-low.c (linux_core_of_thread): Fix crash on invalid CONTENT. - New comment. - -2010-05-26 Ozkan Sezer - - * gdbreplay.c (remote_open): Check error return from socket() call by - its equality to -1 not by it being negative. - * remote-utils.c (remote_open): Likewise. - -2010-05-23 Pedro Alves - - * config.h: Regenerate. - -2010-05-19 Maxim Kuvyrkov - - * linux-m68k-low.c (ps_get_thread_area): Don't define if kernel - doesn't provide PTRACE_GET_THREAD_AREA. - -2010-05-19 Maxim Kuvyrkov - - * linux-m68k-low.c: Include - (ps_get_thread_area): Implement. - -2010-05-03 Doug Evans - - * event-loop.c (struct callback_event): New struct. - (callback_list): New global. - (append_callback_event, delete_callback_event): New functions. - (process_callback): New function. - (start_event_loop): Call it. - * remote-utils.c (NOT_SCHEDULED): Define. - (readchar_buf, readchar_bufcnt, readchar_bufp): New static globals, - moved out of readchar. - (readchar): Rewrite. Call reschedule before returning. - (reset_readchar): New function. - (remote_close): Call it. - (process_remaining, reschedule): New functions. - * server.h (callback_handler_func): New typedef. - (append_callback_event, delete_callback_event): Declare. - -2010-05-03 Pedro Alves - - * proc-service.c (ps_pglobal_lookup): Use - thread_db_look_up_one_symbol. - * remote-utils.c (look_up_one_symbol): Add new `may_ask_gdb' - parameter. Use it instead of all_symbols_looked_up. - * server.h (struct process_info) : Delete - field. - (all_symbols_looked_up): Don't declare. - (look_up_one_symbol): Add new `may_ask_gdb' parameter. - * thread-db.c (struct thread_db) : New - field. - (thread_db_look_up_symbols): Adjust call to look_up_one_symbol. - Set all_symbols_looked_up here. - (thread_db_look_up_one_symbol): New. - (thread_db_get_tls_address): Adjust. - (thread_db_load_search, try_thread_db_load_1): Always allocate the - thread_db object on the heap, and tentatively set it in the - process structure. - (thread_db_init): Don't set all_symbols_looked_up here. - * linux-low.h (thread_db_look_up_one_symbol): Declare. - -2010-05-03 Pedro Alves - - * linux-low.c (linux_kill, linux_detach): Adjust. - (status_pending_p_callback): Remove redundant statement. Check - for !TARGET_WAITIKIND_IGNORE, instead of - TARGET_WAITKIND_STOPPED. - (handle_tracepoints): Make sure LWP is locked. Adjust. - (linux_wait_for_event_1): Adjust. - (linux_cancel_breakpoints): New. - (unsuspend_one_lwp): New. - (unsuspend_all_lwps): New. - (linux_wait_1): If finishing a step-over, unsuspend all lwps. - (send_sigstop_callback): Change return type to int, add new - `except' parameter and handle it. - (suspend_and_send_sigstop_callback): New. - (stop_all_lwps): Add new `suspend' and `expect' parameters, and - pass them down. If SUSPEND, also increment the lwp's suspend - count. - (linux_resume_one_lwp): Add notice about resuming a suspended LWP. - (need_step_over_p): Don't consider suspended LWPs. - (start_step_over): Adjust. - (proceed_one_lwp): Change return type to int, add new `except' - parameter and handle it. - (unsuspend_and_proceed_one_lwp): New. - (proceed_all_lwps): Use find_inferior instead of - for_each_inferior. - (unstop_all_lwps): Add `unsuspend' parameter. If UNSUSPEND, them - also decrement the suspend count of LWPs. Pass `except' down, - instead of hacking its suspend count. - (linux_pause_all): Add `freeze' parameter. Adjust. - (linux_unpause_all): New. - (linux_target_ops): Install linux_unpause_all. - * server.c (handle_status): Adjust. - * target.h (struct target_ops): New fields `unpause_all' and - `cancel_breakpoints'. Add new parameter to `pause_all'. - (pause_all): Add new `freeze' parameter. - (unpause_all): New. - (cancel_breakpoints): New. - * tracepoint.c (clear_installed_tracepoints): Pause threads, and - cancel breakpoints. - (cmd_qtstart): Pause threads. - (stop_tracing): Pause threads, and cancel breakpoints. - * win32-low.c (win32_target_ops): Adjust. - -2010-05-03 Pedro Alves - - * linux-low.c (linux_wait_for_event_1): Move passing the signal to - the inferior right away from here... - (linux_wait_1): ... to here, and adjust to check the thread's - last_resume_kind instead of the lwp's step or stop_expected flags. - -2010-05-02 Pedro Alves - - * README: Use consistent `GDB' and `GDBserver' spellings. - -2010-05-02 Pedro Alves - - * linux-low.c (linux_kill_one_lwp): Assume the lwp is stopped. - (linux_kill): Stop all lwps here. Don't delete the main lwp here. - (linux_detach_one_lwp): Assume the lwp is stopped. - (any_thread_of): Delete. - (linux_detach): Stop all lwps here. Don't blindly delete all - breakpoints. - (delete_lwp_callback): New. - (linux_mourn): Delete all lwps of the process that is gone. - (linux_wait_1): Don't delete the last lwp of the process here. - * mem-break.h (mark_breakpoints_out): Declare. - * mem-break.c (mark_breakpoints_out): New. - (free_all_breakpoints): Use it. - * server.c (handle_target_event): If the process is gone, mark - breakpoints out. - * thread-db.c (struct thread_db) : New field. - (thread_db_enable_reporting): Fix prototype. Store a thread event - breakpoint reference in the thread_db struct. - (thread_db_load_search): Clear the thread_db object. - (try_thread_db_load_1): Ditto. - (switch_to_process): New. - (disable_thread_event_reporting): Use it. - (remove_thread_event_breakpoints): New. - (thread_db_detach, thread_db_mourn): Use it. - -2010-05-01 Pedro Alves - - * linux-low.c (linux_enable_event_reporting): New. - (linux_wait_for_event_1, handle_extended_wait): Use it. - -2010-04-30 Pedro Alves - - * linux-low.c (linux_kill_one_lwp, linux_kill) - (linux_detach_one_lwp): Adjust to send_sigstop interface change. - (send_sigstop): Take an lwp_info as parameter instead. Queue a - SIGSTOP even if the LWP is stopped. - (send_sigstop_callback): New. - (stop_all_lwps): Use send_sigstop_callback instead. - (linux_resume_one_thread): Adjust. - (proceed_one_lwp): Still proceed an LWP that the client has - requested to stop, if we haven't reported it as stopped yet. Make - sure that LWPs the client want stopped, have a pending SIGSTOP. - -2010-04-26 Doug Evans - - * server.c (handle_general_set): Make static. - - * remote-utils.c (putpkt_binary_1): Call readchar instead of read. - Print received char after testing for error/eof instead of before. - (input_interrupt): Tweak comment. - -2010-04-23 Doug Evans - - * server.c (start_inferior): Print inferior argv if --debug. - -2010-04-21 Aleksandar Ristovski - - * Makefile.in (nto_low_h nto-low.o nto-x86-low.o): New dependency lists. - * nto-x86-low.c: Include server.h - -2010-04-20 Pierre Muller - - * win32-i386-low.c: Use __x86_64__ macro instead of __x86_64 to - be consistent with other sources of this directory. - (init_registers_amd64): Correct name of source file of this function - in the comment. - -2010-04-19 Pierre Muller - - * configure.srv (x86_64-*-mingw*): New configuration for Windows - 64-bit executables. - -2010-04-19 Pierre Muller - - * win32-i386-low.c: Add 64-bit support. - (CONTEXT_EXTENDED_REGISTERS): Set macro to zero if not exisiting. - (init_registers_amd64): Declare. - (mappings): Add 64-bit version of array. - (init_windows_x86): New function. - (the_low_target): Change init_arch field to init_windows_x86. - -2010-04-19 Pierre Muller - - * win32-low.c: Adapt to support also 64-bit architecture. - (child_xfer_memory): Use uintptr_t type for local variable `addr'. - (get_image_name): Use SIZE_T type for local variable `done'. - (psapi_get_dll_name): Use LPVOID type for parameter `BaseAddress'. - (toolhelp_get_dll_name): Idem. - (handle_load_dll): Use CORE_ADDR type for local variable `load_addr'. - Use uintptr_t typecast to avoid warning. - (handle_unload_dll): Use uintptr_t typecast to avoid warning. - (handle_exception): Use phex_nz to avoid warning. - (win32_wait): Remove unused local variable `process'. - -2010-04-19 Pierre Muller - - * configure.srv (srv_amd64_regobj): Replace `x86-64-avx.o' by - `amd64-avx.o'. - -2010-04-17 Pierre Muller - - * configure.ac: Use `ws2_32' library for srv_mingw. - * configure: Regenerate. - * gdbreplay.c: Include winsock2.h instead of winsock.h. - * remote-utils.c: Likewise. - -2010-04-17 H.J. Lu - - * linux-x86-low.c (xmltarget_amd64_linux_no_xml): Define only - if __x86_64__ is defined. - -2010-04-16 Pierre Muller - - * configure: Regenerate. - -2010-04-16 Pierre Muller - - * server.c (handle_query): Handle 'qGetTIBAddr' query. - * target.h (target_ops): New get_tib_address field. - * win32-low.h (win32_thread_info): Add thread_local_base field. - * win32-low.c (child_add_thread): Add tlb argument. - Set thread_local_base field to TLB. - (get_child_debug_event): Adapt to child_add_thread change. - (win32_get_tib_address): New function. - (win32_target_ops): Set get_tib_address field to - win32_get_tib_address. - * linux-low.c (linux_target_ops): Set get_tib_address field to NULL. - -2010-04-12 Pedro Alves - - * linux-low.c (linux_mourn): Also remove the process. - * server.c (handle_target_event): Don't remove the process here. - * nto-low.c (nto_mourn): New. - (nto_target_ops): Install it. - * spu-low.c (spu_mourn): New. - (spu_target_ops): Install it. - * win32-low.c (win32_mourn): New. - (win32_target_ops): Install it. - -2010-04-12 Pedro Alves - - * server.h (buffer_xml_printf): Remove redundant `;'. - -2010-04-12 Pedro Alves - - * regcache.c (set_register_cache): Invalidate regcaches before - changing the register cache layout. - (regcache_invalidate_one): Allow a NULL regcache. - * linux-x86-low.c (x86_linux_update_xmltarget): Invalidate - regcaches before changing the register cache layout or the target - regsets. - -2010-04-12 H.J. Lu - - * linux-x86-low.c (x86_linux_update_xmltarget): Avoid unused - variable warning on Linux/x86-64. - -2010-04-11 Pedro Alves - - GDBserver disconnected tracing support. - - * linux-low.c (linux_remove_process): Delete. - (add_lwp): Don't set last_resume_kind here. - (linux_kill): Use `mourn'. - (linux_detach): Use `thread_db_detach', and `mourn'. - (linux_mourn): New. - (linux_attach_lwp_1): Adjust comment. - (linux_attach): last_resume_kind moved the thread_info; adjust. - (status_pending_p_callback): Adjust. - (linux_wait_for_event_1): Adjust. - (count_events_callback, select_singlestep_lwp_callback) - (select_event_lwp_callback, cancel_breakpoints_callback) - (db_wants_lwp_stopped, linux_wait_1, need_step_over_p) - (proceed_one_lwp): Adjust. - (linux_async): Add debug output. - (linux_thread_stopped): New. - (linux_pause_all): New. - (linux_target_ops): Install linux_mourn, linux_thread_stopped and - linux_pause_all. - * linux-low.h (struct lwp_info): Delete last_resume_kind field. - (thread_db_free): Delete declaration. - (thread_db_detach, thread_db_mourn): Declare. - * thread-db.c (thread_db_init): Use thread_db_mourn. - (thread_db_free): Delete, split in two. - (disable_thread_event_reporting): New. - (thread_db_detach): New. - (thread_db_mourn): New. - - * server.h (struct thread_info) : New field. - : Add comment. - : New field. - (handler_func): Change return type to int. - (handle_serial_event, handle_target_event): Ditto. - (gdb_connected): Declare. - (tracing): Delete. - (disconnected_tracing): Declare. - (stop_tracing): Declare. - - * server.c (handle_query) : Report support for - disconnected tracing. - (queue_stop_reply_callback): Account for running threads. - (gdb_wants_thread_stopped): New. - (gdb_wants_all_threads_stopped): New. - (gdb_reattached_process): New. - (handle_status): Clear the `gdb_detached' flag of all processes. - In all-stop, stop all threads. - (main): Be sure to leave tfind mode. Handle disconnected tracing. - (process_serial_event): If the remote connection breaks, or if an - exit was forced with "monitor exit", force an event loop exit. - Handle disconnected tracing on detach. - (handle_serial_event): Adjust. - (handle_target_event): If GDB isn't connected, forward events back - to the inferior, unless the last process exited, in which case, - exit gdbserver. Adjust interface. - - * remote-utils.c (remote_open): Don't block in accept. Instead - register an event loop source on the listen socket file - descriptor. Refactor bits into ... - (listen_desc): ... this new global. - (gdb_connected): ... this new function. - (enable_async_notification): ... this new function. - (handle_accept_event): ... this new function. - (remote_close): Clear remote_desc. - - * inferiors.c (add_thread): Set the new thread's last_resume_kind. - - * target.h (struct target_ops) : - New fields. - (mourn_inferior): Define. - (target_process_qsupported): Avoid the dangling else problem. - (thread_stopped): Define. - (pause_all): Define. - (target_waitstatus_to_string): Declare. - * target.c (target_waitstatus_to_string): New. - - * tracepoint.c (tracing): Make extern. - (disconnected_tracing): New. - (stop_tracing): Make extern. Handle tracing stops due to GDB - disconnecting. - (cmd_qtdisconnected): New. - (cmd_qtstatus): Report disconnected tracing status in trace reply. - (handle_tracepoint_general_set): Handle QTDisconnected. - - * event-loop.c (event_handler_func): Change return type to int. - (process_event): Bail out if the event handler wants the event - loop to stop. - (handle_file_event): Ditto. - (start_event_loop): Bail out if the event handler wants the event - loop to stop. - - * nto-low.c (nto_target_ops): Adjust. - * spu-low.c (spu_wait): Don't remove the process here. - (spu_target_ops): Adjust. - * win32-low.c (win32_wait): Don't remove the process here. - (win32_target_ops): Adjust. - -2010-04-11 Pedro Alves - - * regcache.c (realloc_register_cache): Invalidate inferior's - regcache before recreating it. - -2010-04-09 Pedro Alves - - * tracepoint.c (cmd_qtstatus): Report trace buffer circularity. - -2010-04-09 Stan Shebs - Pedro Alves - - * server.h (LONGEST): New. - (struct thread_info) : New field. - (unpack_varlen_hex, xrealloc, pulongest, plongest, phex_nz): - Declare. - (initialize_tracepoint, handle_tracepoint_general_set) - (handle_tracepoint_query, tracepoint_finished_step) - (tracepoint_was_hit, release_while_stepping_state_list): - (current_traceframe): Declare. - * server.c (handle_general_set): Handle tracepoint packets. - (read_memory): New. - (write_memory): New. - (handle_search_memory_1): Use read_memory. - (handle_query): Report support for conditional tracepoints, trace - state variables, and tracepoint sources. Handle tracepoint - queries. - (main): Initialize the tracepoints module. - (process_serial_event): Handle traceframe reads/writes. - - * linux-low.c (handle_tracepoints): New. - (linux_wait_1): Call it. - (linux_resume_one_lwp): Handle while-stepping. - (linux_supports_tracepoints, linux_read_pc, linux_write_pc): New. - (linux_target_ops): Install them. - * linux-low.h (struct linux_target_ops) : - New field. - * linux-x86-low.c (x86_supports_tracepoints): New. - (the_low_target). Install it. - - * mem-break.h (delete_breakpoint): Declare. - * mem-break.c (delete_breakpoint): Make external. - - * target.h (struct target_ops): Add `supports_tracepoints', - `read_pc', and `write_pc' fields. - (target_supports_tracepoints): Define. - * utils.c (xrealloc, decimal2str, pulongest, plongest, thirty_two) - (phex_nz): New. - - * regcache.h (struct regcache) : New field. - (init_register_cache, regcache_cpy): Declare. - (regcache_read_pc, regcache_write_pc): Declare. - (register_cache_size): Declare. - (supply_regblock): Declare. - * regcache.c (init_register_cache): New. - (new_register_cache): Use it. - (regcache_cpy): New. - (register_cache_size): New. - (supply_regblock): New. - (regcache_read_pc, regcache_write_pc): New. - - * tracepoint.c: New. - - * Makefile.in (OBS): Add tracepoint.o. - (tracepoint.o): New rule. - -2010-04-08 H.J. Lu - - * Makefile.in (clean): Also remove i386-mmx.c i386-mmx-linux.c. - (i386-mmx.o): New. - (i386-mmx.c): Likewise. - (i386-mmx-linux.o): Likewise. - (i386-mmx-linux.c): Likewise. - - * configure.srv (srv_i386_regobj): Add i386-mmx.o. - (srv_i386_linux_regobj): Add i386-mmx-linux.o. - (srv_i386_xmlfiles): Add i386/i386-mmx.xml. - (srv_i386_linux_xmlfiles): Add i386/i386-mmx-linux.xml. - - * linux-x86-low.c (init_registers_i386_mmx_linux): New. - (x86_linux_update_xmltarget): Call init_registers_i386_mmx_linux - and return if ptrace PTRACE_GETFPXREGS failed in 32bit. - -2010-04-07 H.J. Lu - - * Makefile.in (clean): Updated. - (i386-avx.o): New. - (i386-avx.c): Likewise. - (i386-avx-linux.o): Likewise. - (i386-avx-linux.c): Likewise. - (amd64-avx.o): Likewise. - (amd64-avx.c): Likewise. - (amd64-avx-linux.o): Likewise. - (amd64-avx-linux.c): Likewise. - - * configure.srv (srv_i386_regobj): Add i386-avx.o. - (srv_i386_linux_regobj): Add i386-avx-linux.o. - (srv_amd64_regobj): Add amd64-avx.o. - (srv_amd64_linux_regobj): Add amd64-avx-linux.o. - (srv_i386_32bit_xmlfiles): Add i386/32bit-avx.xml. - (srv_i386_64bit_xmlfiles): Add i386/64bit-avx.xml. - (srv_i386_xmlfiles): Add i386/i386-avx.xml. - (srv_amd64_xmlfiles): Add i386/amd64-avx.xml. - (srv_i386_linux_xmlfiles): Add i386/i386-avx-linux.xml. - (srv_amd64_linux_xmlfiles): Add i386/amd64-avx-linux.xml. - - * i387-fp.c: Include "i386-xstate.h". - (i387_xsave): New. - (i387_cache_to_xsave): Likewise. - (i387_xsave_to_cache): Likewise. - (x86_xcr0): Likewise. - - * i387-fp.h (i387_cache_to_xsave): Likewise. - (i387_xsave_to_cache): Likewise. - (x86_xcr0): Likewise. - - * linux-arm-low.c (target_regsets): Initialize nt_type to 0. - * linux-crisv32-low.c (target_regsets): Likewise. - * linux-m68k-low.c (target_regsets): Likewise. - * linux-mips-low.c (target_regsets): Likewise. - * linux-ppc-low.c (target_regsets): Likewise. - * linux-s390-low.c (target_regsets): Likewise. - * linux-sh-low.c (target_regsets): Likewise. - * linux-sparc-low.c (target_regsets): Likewise. - * linux-xtensa-low.c (target_regsets): Likewise. - - * linux-low.c: Include . - (regsets_fetch_inferior_registers): Support nt_type. - (regsets_store_inferior_registers): Likewise. - (linux_process_qsupported): New. - (linux_target_ops): Add linux_process_qsupported. - - * linux-low.h (regset_info): Add nt_type. - (linux_target_ops): Add process_qsupported. - - * linux-x86-low.c: Include "i386-xstate.h", "elf/common.h" - and . - (init_registers_i386_avx_linux): New. - (init_registers_amd64_avx_linux): Likewise. - (xmltarget_i386_linux_no_xml): Likewise. - (xmltarget_amd64_linux_no_xml): Likewise. - (PTRACE_GETREGSET): Likewise. - (PTRACE_SETREGSET): Likewise. - (x86_fill_xstateregset): Likewise. - (x86_store_xstateregset): Likewise. - (use_xml): Likewise. - (x86_linux_update_xmltarget): Likewise. - (x86_linux_process_qsupported): Likewise. - (target_regsets): Add NT_X86_XSTATE entry and Initialize nt_type. - (x86_arch_setup): Don't call init_registers_amd64_linux nor - init_registers_i386_linux here. Call - x86_linux_update_xmltarget. - (the_low_target): Add x86_linux_process_qsupported. - - * server.c (handle_query): Call target_process_qsupported. - - * target.h (target_ops): Add process_qsupported. - (target_process_qsupported): New. - -2010-04-03 Pedro Alves - - * inferiors.c (add_thread): Set last_status kind to - TARGET_WAITKIND_IGNORE. - * linux-low.c (cancel_breakpoint): Remove unnecessary regcache - fetch. Use ptid_of. Avoid unnecessary get_lwp_thread calls. - (linux_wait_1): Move `thread' local definition to block that uses - it. Don't NULL initialize `event_child'. - (linux_resume_one_thread): Avoid unnecessary get_lwp_thread calls. - Alway set the thread's last_status to TARGET_WAITKIND_IGNORE. - * linux-x86-low.c (x86_breakpoint_at): Read raw memory. - -2010-04-01 Pedro Alves - - * linux-low.c (get_stop_pc): Don't adjust the PC if stopped with - an extended waitstatus, or by a watchpoint. - (cancel_breakpoints_callback): Don't cancel a breakpoint if the - thread was stepping or has been stopped by a watchpoint. - -2010-04-01 Pedro Alves - - * mem-break.c (struct raw_breakpoint): New field shlib_disabled. - (set_gdb_breakpoint_at): If GDB is inserting a breakpoint on top - of another, then delete the previous, and validate all - breakpoints. - (validate_inserted_breakpoint): New. - (delete_disabled_breakpoints): New. - (validate_breakpoints): New. - (check_mem_read): Validate breakpoints before trusting their - shadow. Delete disabled breakpoints. - (check_mem_write): Validate breakpoints before trusting they - should be inserted. Delete disabled breakpoints. - * mem-break.h (validate_breakpoints): - * server.c (handle_query): Validate breakpoints when we see a - qSymbol query. - -2010-04-01 Pedro Alves - - * linux-low.c (linux_wait_1): Avoid setting need_step_over is - there's a GDB breakpoint at stop_pc. Always report a trap to GDB - if we could tell there's a GDB breakpoint at stop_pc. - (need_step_over_p): Don't do a step over if we find a GDB - breakpoint at the resume PC. - - * mem-break.c (struct raw_breakpoint): New. - (enum bkpt_type): New type `gdb_breakpoint'. - (struct breakpoint): Delete the `PC', `old_data' and `inserted' - fields. New field `raw'. - (find_raw_breakpoint_at): New. - (set_raw_breakpoint_at): Handle refcounting. Create a raw - breakpoint instead. - (set_breakpoint_at): Adjust. - (delete_raw_breakpoint): New. - (release_breakpoint): New. - (delete_breakpoint): Rename to... - (delete_breakpoint_1): ... this. Add proc parameter. Use - release_breakpoint. Return ENOENT. - (delete_breakpoint): Reimplement. - (find_breakpoint_at): Delete. - (find_gdb_breakpoint_at): New. - (delete_breakpoint_at): Delete. - (set_gdb_breakpoint_at): New. - (delete_gdb_breakpoint_at): New. - (gdb_breakpoint_here): New. - (set_reinsert_breakpoint): Use release_breakpoint. - (uninsert_breakpoint): Rename to ... - (uninsert_raw_breakpoint): ... this. - (uninsert_breakpoints_at): Adjust to handle raw breakpoints. - (reinsert_raw_breakpoint): Change parameter type to - raw_breakpoint. - (reinsert_breakpoints_at): Adjust to handle raw breakpoints - instead. - (check_breakpoints): Adjust. Use release_breakpoint. - (breakpoint_here): Rewrite using find_raw_breakpoint_at. - (breakpoint_inserted_here): Ditto. - (check_mem_read): Adjust to iterate over raw breakpoints instead. - Don't trust the breakpoint's shadow if it is not inserted. - (check_mem_write): Adjust to iterate over raw breakpoints instead. - (delete_all_breakpoints): Adjust. - (free_all_breakpoints): Mark all breakpoints as uninserted, and - use delete_breakpoint_1. - - * mem-break.h (breakpoints_supported): Delete declaration. - (set_gdb_breakpoint_at): Declare. - (gdb_breakpoint_here): Declare. - (delete_breakpoint_at): Delete. - (delete_gdb_breakpoint_at): Declare. - - * server.h (struct raw_breakpoint): Forward declare. - (struct process_info): New field `raw_breakpoints'. - - * linux-x86-low.c (x86_insert_point, x86_remote_point): Handle Z0 - breakpoints. - -2010-03-24 Pedro Alves - - * linux-low.c (status_pending_p_callback): Fix comment. - (linux_wait_for_event_1): Move most of the internal breakpoint - handling from here... - (linux_wait_1): ... to here. - (count_events_callback): New. - (select_singlestep_lwp_callback): New. - (select_event_lwp_callback): New. - (cancel_breakpoints_callback): New. - (select_event_lwp): New. - (linux_wait_1): Simplify internal breakpoint handling. Give equal - priority to all LWPs that have had events that should be reported - to the client. Cancel breakpoints when about to reporting the - event to the client, not while stopping lwps. No longer cancel - finished single-steps here. - (cancel_finished_single_step): Delete. - (cancel_finished_single_steps): Delete. - -2010-03-24 Pedro Alves - - * mem-break.c (enum bkpt_type): New. - (struct breakpoint): New field `type'. - (set_breakpoint_at): Change return type to struct breakpoint - pointer. Set type to `other_breakpoint' by default. - (delete_breakpoint): Rewrite, supporting more than one breakpoint - in the breakpoint list. - (delete_reinsert_breakpoints): Only delete reinsert breakpoints. - (reinsert_breakpoint): Rename to ... - (reinsert_raw_breakpoint): ... this. - (reinsert_breakpoints_at): Adjust. - * mem-break.h (struct breakpoint): Declare. - (set_breakpoint_at): Change return type to struct breakpoint - pointer. - -2010-03-24 Pedro Alves - - * server.c (handle_query): Assign, not compare. - -2010-03-24 Pedro Alves - - Teach linux gdbserver to step-over-breakpoints. - - * linux-low.c (can_hardware_single_step): New. - (supports_breakpoints): New. - (handle_extended_wait): If stopping threads, read the stop pc of - the new cloned LWP. - (get_pc): New. - (get_stop_pc): Add `lwp' parameter. Handle it. Bail out if the - low target doesn't support retrieving the PC. - (add_lwp): Set last_resume_kind to resume_continue. - (linux_attach_lwp_1): Adjust comments. Always set stop_expected. - (linux_attach): Don't clear stop_expected. Set the lwp's - last_resume_kind to resume_stop. - (linux_detach_one_lwp): Don't check for removed breakpoints. - (check_removed_breakpoint): Delete. - (status_pending_p): Rename to ... - (status_pending_p_callback): ... this. Don't check for removed - breakpoints. Don't consider threads that are stopped from GDB's - perspective. - (linux_wait_for_lwp): Always read the stop_pc here. - (cancel_breakpoint): New. - (step_over_bkpt): New global. - (linux_wait_for_event_1): Implement stepping over breakpoints. - (gdb_wants_lwp_stopped): New. - (gdb_wants_all_stopped): New. - (linux_wait_1): Tag threads as gdb-wants-stopped. Cancel finished - single-step traps here. Store the thread's last reported target - wait status. - (send_sigstop): Don't clear stop_expected. Always set it, - instead. - (mark_lwp_dead): Remove reference to pending_is_breakpoint. - (cancel_finished_single_step): New. - (cancel_finished_single_steps): New. - (wait_for_sigstop): Don't cancel finished single-step traps here. - (linux_resume_one_lwp): Don't check for removed breakpoints. - Don't set `step' on non-hardware step archs. - (linux_set_resume_request): Ignore resume_stop requests if already - stopping or stopped. Set the lwp's last_resume_kind. - (resume_status_pending_p): Don't check for removed breakpoints. - (need_step_over_p): New. - (start_step_over): New. - (finish_step_over): New. - (linux_resume_one_thread): Always queue a sigstop for resume_stop - requests. Clear the thread's last reported target waitstatus. - Don't use the `suspended' flag. Don't consider pending breakpoints. - (linux_resume): Start a step-over if necessary. - (proceed_one_lwp): New. - (proceed_all_lwps): New. - (unstop_all_lwps): New. - * linux-low.h (struct lwp_info): Rewrite comment for the - `suspended' flag. Add the `stop_pc' field. Delete the - `pending_stop_pc' field. Tweak the `stepping' flag's comment. - Add `'last_resume_kind' and `need_step_over' fields. - * inferiors.c (struct thread_info): Delete, moved elsewhere. - * mem-break.c (struct breakpoint): Delete `reinserting' flag. - Delete `breakpoint_to_reinsert' field. New flag `inserted'. - (set_raw_breakpoint_at): New. - (set_breakpoint_at): Rewrite to use it. - (reinsert_breakpoint_handler): Delete. - (set_reinsert_breakpoint): New. - (reinsert_breakpoint_by_bp): Delete. - (delete_reinsert_breakpoints): New. - (uninsert_breakpoint): Rewrite. - (uninsert_breakpoints_at): New. - (reinsert_breakpoint): Rewrite. - (reinsert_breakpoints_at): New. - (check_breakpoints): Rewrite. - (breakpoint_here): New. - (breakpoint_inserted_here): New. - (check_mem_read): Adjust. - * mem-break.h (breakpoints_supported, breakpoint_here) - (breakpoint_inserted_here, set_reinsert_breakpoint): Declare. - (reinsert_breakpoint_by_bp): Delete declaration. - (delete_reinsert_breakpoints): Declare. - (reinsert_breakpoint): Delete declaration. - (reinsert_breakpoints_at): Declare. - (uninsert_breakpoint): Delete declaration. - (uninsert_breakpoints_at): Declare. - (check_breakpoints): Adjust prototype. - * server.h: Adjust include order. - (struct thread_info): Declare here. Add a `last_status' field. - -2010-03-23 Michael Snyder - - * server.c (crc32): New function. - (handle_query): Add handling for 'qCRC:' request. - -2010-03-23 Pedro Alves - - * linux-x86-low.c (x86_linux_prepare_to_resume): Clear DR6 if the - lwp had been stopped by a watchpoint. - -2010-03-16 Pedro Alves - - * server.h (internal_error): Declare. - (gdb_assert, ASSERT_FUNCTION, gdb_assert_fail): Define. - * utils.c (internal_error): New function. - -2010-03-15 Andreas Schwab - - * configure.srv: Fix typo setting srv_regobj. - -2010-03-15 Pedro Alves - - * linux-low.c (fetch_register): Avoid passing a non string literal - format to `error'. - (usr_store_inferior_registers): Ditto. - -2010-03-14 Pedro Alves - - * linux-low.c (linux_write_memory): Bail out early if peeking - memory failed. - -2010-03-14 Pedro Alves - - * linux-low.h (struct lwp_info): New fields - `stopped_by_watchpoint' and `stopped_data_address'. - * linux-low.c (linux_wait_for_lwp): Check for watchpoint triggers - here, and cache them in the lwp object. - (wait_for_sigstop): Check stopped_by_watchpoint lwp field - directly. - (linux_resume_one_lwp): Clear the lwp's stopped_by_watchpoint - field. - (linux_stopped_by_watchpoint): Rewrite. - (linux_stopped_data_address): Rewrite. - -2010-03-06 Simo Melenius - - * linux-low.c (linux_wait_for_lwp): Fetch the regcache after - switching the current inferior, not before. - -2010-03-01 H.J. Lu - - * Makefile.in (clean): Replace reg-i386.c, reg-x86-64.c, - reg-i386-linux.c and reg-x86-64-linux.c with i386.c, amd64.c, - i386-linux.c and amd64-linux.c. - (reg-i386.o): Removed. - (reg-i386.c): Likewise. - (reg-i386-linux.o): Likewise. - (reg-i386-linux.c): Likewise. - (reg-x86-64.o): Likewise. - (reg-x86-64.c): Likewise. - (reg-x86-64-linux.o): Likewise. - (reg-x86-64-linux.c): Likewise. - (i386.o): New. - (i386.c): Likewise. - (i386-linux.o): Likewise. - (i386-linux.c): Likewise. - (amd64.o): Likewise. - (amd64.c): Likewise. - (amd64-linux.o): Likewise. - (amd64-linux.c): Likewise. - - * configure.srv (srv_i386_regobj): New. - (srv_i386_linux_regobj): Likewise. - (srv_amd64_regobj): Likewise. - (srv_amd64_linux_regobj): Likewise. - (srv_i386_32bit_xmlfiles): Likewise. - (srv_i386_64bit_xmlfiles): Likewise. - (srv_i386_xmlfiles): Likewise. - (srv_amd64_xmlfiles): Likewise. - (srv_i386_linux_xmlfiles): Likewise. - (srv_amd64_linux_xmlfiles): Likewise. - (i[34567]86-*-cygwin*): Set srv_regobj to $srv_i386_regobj. Set - srv_xmlfiles to $srv_i386_xmlfiles. - (i[34567]86-*-mingw32ce*): Likewise. - (i[34567]86-*-mingw*): Likewise. - (i[34567]86-*-nto*): Likewise. - (i[34567]86-*-linux*): Set srv_regobj to $srv_i386_linux_regobj - and $srv_amd64_linux_regobj. Set srv_xmlfiles to - $srv_i386_linux_xmlfiles and $srv_amd64_linux_xmlfiles. - (x86_64-*-linux*): Likewise. - - * linux-x86-low.c (init_registers_x86_64_linux): Removed. - (init_registers_amd64_linux): New. - (x86_arch_setup): Replace init_registers_x86_64_linux with - init_registers_amd64_linux. - -2010-02-23 Maxim Kuvyrkov - - * configure.ac: Check for libdl. If it is not available link against - static libthread_db. - * configure: Regenerate. - -2010-02-22 Pedro Alves - - PR9605 - - * i386-low.c (i386_length_and_rw_bits): Throw a fatal error if - handing a read watchpoint. - (i386_low_insert_watchpoint): Read watchpoints aren't supported. - -2010-02-12 Doug Evans - - * linux-low.c (linux_supports_tracefork_flag): Document. - (linux_look_up_symbols): Add comment. - -2010-02-03 H.J. Lu - - * regcache.c (supply_register): Clear regcache if buf is NULL. - -2010-02-02 Nicolas Roche - Joel Brobecker - - * inferiors.c (find_inferior): Add function documentation. - (unloaded_dll): Handle the case where the unloaded dll has not - been previously registered in the dll list. - -2010-02-01 Daniel Jacobowitz - - * linux-arm-low.c (thumb_breakpoint_len): Delete. - (thumb2_breakpoint): New. - (arm_breakpoint_at): Check for Thumb-2 breakpoints. - -2010-01-29 Daniel Jacobowitz - - * linux-low.c (get_stop_pc): Check for SIGTRAP. - (linux_wait_for_event_1): Handle SIGILL and SIGSEGV as possible - breakpoints. - -2010-01-21 Pedro Alves - - * linux-ppc-low.c (ppc_arch_setup): Adjust to regcache changes. - -2010-01-21 Jan Kratochvil - - * linux-s390-low.c (s390_collect_ptrace_register) - (s390_supply_ptrace_register): Adjust it for the new regcache parameter. - -2010-01-21 Doug Evans - - * linux-low.c (PTRACE_ARG3_TYPE): Change from long to void*. - (PTRACE_ARG4_TYPE): New macro. - (handle_extended_wait): Cast ptrace arg4 to PTRACE_ARG4_TYPE. - (linux_wait_for_event_1, linux_resume_one_lwp): Ditto. - (fetch_register): Cast to uintptr_t before casting to PTRACE_ARG3_TYPE. - (usr_store_inferior_registers): Ditto. - (linux_read_memory, linux_write_memory): Ditto. - (linux_test_for_tracefork): Ditto. - - * linux-arm-low.c: Remove redundant include of gdb_proc_service.h. - Only include elf.h if gdb_proc_service.h didn't include linux/elf.h. - -2010-01-21 Pedro Alves - - * proc-service.c (ps_lgetregs): Don't refetch registers from the - target. - -2010-01-21 Pedro Alves - - * spu-low.c (spu_fetch_registers, spu_store_registers): Change - prototype to take a regcache. Adjust. - -2010-01-20 Pedro Alves - - * regcache.h (struct thread_info): Forward declare. - (struct regcache): New. - (new_register_cache): Adjust prototype. - (get_thread_regcache): Declare. - (free_register_cache): Adjust prototype. - (registers_to_string, registers_from_string): Ditto. - (supply_register, supply_register_by_name, collect_register) - (collect_register_as_string, collect_register_by_name): Ditto. - * regcache.c (struct inferior_regcache_data): Delete. - (get_regcache): Rename to ... - (get_thread_regcache): ... this. Adjust. Switch inferior before - fetching registers. - (regcache_invalidate_one): Adjust. - (regcache_invalidate): Fix prototype. - (new_register_cache): Return the new register cache. - (free_register_cache): Change prototype. - (realloc_register_cache): Adjust. - (registers_to_string): Change prototype to take a regcache. Adjust. - (registers_from_string): Ditto. - (register_data): Ditto. - (supply_register): Ditto. - (supply_register_by_name): Ditto. - (collect_register): Ditto. - (collect_register_as_string): Ditto. - (collect_register_by_name): Ditto. - * server.c (process_serial_event): Adjust. - * linux-low.h (regset_fill_func, regset_store_func): Change - prototype. - (get_pc, set_pc, collect_ptrace_register, supply_ptrace_register): - Change prototype. - * linux-low.c (get_stop_pc): Adjust. - (check_removed_breakpoint): Adjust. - (linux_wait_for_event): Adjust. - (linux_resume_one_lwp): Adjust. - (fetch_register): Add regcache parameter. Adjust. - (usr_store_inferior_registers): Ditto. - (regsets_fetch_inferior_registers): Ditto. - (regsets_store_inferior_registers): Ditto. - (linux_fetch_registers, linux_store_registers): Ditto. - * i387-fp.c (i387_cache_to_fsave): Change prototype to take a - regcache. Adjust. - (i387_fsave_to_cache, i387_cache_to_fxsave, i387_fxsave_to_cache): - Ditto. - * i387-fp.h (i387_cache_to_fsave, i387_fsave_to_cache): Change - prototype to take a regcache. - (i387_cache_to_fxsave, i387_fxsave_to_cache): Ditto. - * remote-utils.c (convert_ascii_to_int, outreg) - (prepare_resume_reply): Change prototype to take a regcache. - Adjust. - * target.h (struct target_ops) : - Change prototype to take a regcache. - (fetch_inferior_registers, store_inferior_registers): Change - prototype to take a regcache. Adjust. - * proc-service.c (ps_lgetregs): Adjust. - * linux-x86-low.c (x86_fill_gregset, x86_store_gregset) - (x86_fill_fpregset, x86_store_fpregset, x86_fill_fpxregset) - (x86_store_fpxregset, x86_get_pc, x86_set_pc): Change prototype to - take a regcache. Adjust. - * linux-arm-low.c (arm_fill_gregset, arm_store_gregset) - (arm_fill_wmmxregset, arm_store_wmmxregset, arm_fill_vfpregset) - (arm_store_vfpregset, arm_get_pc, arm_set_pc): - (arm_breakpoint_at): Change prototype to take a regcache. Adjust. - * linux-cris-low.c (cris_get_pc, cris_set_pc) - (cris_cannot_fetch_register): - (cris_breakpoint_at): Change prototype to take a regcache. - Adjust. - * linux-crisv32-low.c (cris_get_pc, cris_set_pc, - cris_reinsert_addr, cris_write_data_breakpoint): Change prototype - to take a regcache. Adjust. - (cris_breakpoint_at, cris_insert_point, cris_remove_point): - Adjust. - * linux-m32r-low.c (m32r_get_pc, m32r_set_pc): Change prototype to - take a regcache. Adjust. - * linux-m68k-low.c (m68k_fill_gregset, m68k_store_gregset) - (m68k_fill_fpregset, m68k_store_fpregset, m68k_get_pc, - (m68k_set_pc): Change prototype to take a regcache. Adjust. - * linux-mips-low.c (mips_get_pc): - (mips_set_pc): Change prototype to take a regcache. Adjust. - (mips_reinsert_addr): Adjust. - (mips_collect_register): Change prototype to take a regcache. - Adjust. - (mips_supply_register): - (mips_collect_register_32bit, mips_supply_register_32bit) - (mips_fill_gregset, mips_store_gregset, mips_fill_fpregset) - (mips_store_fpregset): Ditto. - * linux-ppc-low.c (ppc_supply_ptrace_register) - (ppc_supply_ptrace_register): Ditto. - (parse_spufs_run): Adjust. - (ppc_get_pc, ppc_set_pc, ppc_fill_gregset, ppc_fill_vsxregset) - (ppc_store_vsxregset, ppc_fill_vrregset, ppc_store_vrregset) - (ppc_fill_evrregset, ppc_store_evrregset): Change prototype to - take a regcache. Adjust. - * linux-s390-low.c (s390_collect_ptrace_register) - (s390_supply_ptrace_register, s390_fill_gregset, s390_get_pc) - (s390_set_pc): Change prototype to take a regcache. Adjust. - (s390_arch_setup): Adjust. - * linux-sh-low.c (sh_get_pc, sh_breakpoint_at) - (sh_fill_gregset): Change prototype to take a regcache. Adjust. - * linux-sparc-low.c (sparc_fill_gregset_to_stack) - (sparc_fill_gregset, sparc_store_gregset_from_stack) - (sparc_store_gregset, sparc_get_pc): Change prototype to take a - regcache. Adjust. - (sparc_breakpoint_at): Adjust. - * linux-xtensa-low.c (xtensa_fill_gregset): - (xtensa_store_gregset): - (xtensa_fill_xtregset, xtensa_store_xtregset, xtensa_get_pc) - (xtensa_set_pc): Change prototype to take a regcache. Adjust. - * nto-low.c (nto_fetch_registers, nto_store_registers): Change - prototype to take a regcache. Adjust. - * win32-arm-low.c (arm_fetch_inferior_register) - (arm_store_inferior_register): Change prototype to take a - regcache. Adjust. - * win32-i386-low.c (i386_fetch_inferior_register) - (i386_store_inferior_register): Change prototype to take a - regcache. Adjust. - * win32-low.c (child_fetch_inferior_registers) - (child_store_inferior_registers): Change prototype to take a - regcache. Adjust. - (win32_wait): Adjust. - (win32_fetch_inferior_registers): Change prototype to take a - regcache. Adjust. - (win32_store_inferior_registers): Adjust. - * win32-low.h (struct win32_target_ops) : Change prototype to take a regcache. - -2010-01-20 Doug Evans - - * linux-low.c (linux_create_inferior): Wrap use of __SIGRTMIN in - #ifdef. - (linux_wait_for_event1, linux_init_signals): Ditto. - (W_STOPCODE): Provide definition if missing. - -2010-01-13 Vladimir Prus - - * linux-low.c (linux_core_of_thread): New. - (compare_ints, show_process, list_threads): New. - (linux_qxfer_osdata): Report threads and cores. - (linux_target_op): Register linux_core_of_thread. - * remote-utils.c (prepare_resume_reply): Report the core. - (buffer_xml_printf): Support %d specifier. - * server.c (handle_threads_qxfer_proper, handle_threads_qxfer): - New. - (handle_query): Handle qXfer:threads. Announce availability - thereof. - * target.h (struct target_ops): New field core_of_thread. - -2010-01-04 Ulrich Weigand - - * Makefile.in (clean): Remove new generated files. - (reg-s390.o, reg-s390.c): Remove rules. - (reg-s390x.o, reg-s390x.c): Likewise. - (s390-linux32.o, s390-linux32.c): Add rules. - (s390-linux64.o, s390-linux64.c): Likewise. - (s390x-linux64.o, s390x-linux64.c): Likewise. - * configure.srv (s390*-*-linux*): Update srv_regobj and srv_xmlfiles. - * linux-s390-low.c: Include . - (HWCAP_S390_HIGH_GPRS): Define if undefined. - (init_registers_s390): Remove prototype. - (init_registers_s390x): Likewise. - (init_registers_s390_linux32): Add prototype. - (init_registers_s390_linux64): Likewise. - (init_registers_s390x_linux64): Likewise. - (s390_num_regs_3264): New define. - (s390_regmap_3264): New global variable. - (s390_cannot_fetch_register): Remove obsolete check. - (s390_cannot_store_register): Likewise. - (s390_collect_ptrace_register): Handle upper/lower register halves. - (s390_supply_ptrace_register): Likewise. - (s390_fill_gregset): Update to register number changes. - (s390_get_hwcap): New routine. - (s390_arch_setup): Detect 32-bit process running on 64-bit system. - Install appropriate regmap and register set. - -2010-01-01 Joel Brobecker - - * server.c (gdbserver_version): Update copyright year to 2010. - * gdbreplay.c (gdbreplay_version): Likewise. - -2009-12-28 Doug Evans - - * linux-low.c: Delete inclusion of ansidecl.h, elf/common.h, - elf/external.h. Include instead but only if necessary. - -2009-12-28 Pedro Alves - - * linux-low.c (linux_remove_process): Remove `detaching' - parameter. Don't release/detach from thread_db here. - (linux_kill): Release/detach from thread_db here, ... - (linux_detach): ... and here, before actually detaching. - (linux_wait_1): ... and here, when a process exits. - * thread-db.c (any_thread_of): New. - (thread_db_free): Switch the current inferior to a thread of the - passed in process. - -2009-12-21 Doug Evans - - * linux-x86-low.c: Delete outdated comment about Elf32_Phdr. - - * linux-low.c (kill_lwp): Use __NR_tkill instead of SYS_tkill. - Move definition of tkill_failed to ifdef __NR_tkill to avoid gcc - warning ifndef __NR_tkill. Move setting of errno there too. - Delete unnecessary resetting of errno after syscall. - Minor comment changes to match gdb/linux-nat.c:kill_lwp. - - * configure.ac: Check for dladdr. - * config.in: Regenerate. - * configure: Regenerate. - * thread-db.c (dladdr_to_soname): Only define ifdef HAVE_DLADDR. - (try_thread_db_load): Update. - - * linux-low.c (my_waitpid): Delete unnecessary prototype. - -2009-12-18 Doug Evans - - * event-loop.c: Include unistd.h if it exists. - - * linux-low.c (my_waitpid): Move definition away from being in - between linux_tracefork_child/linux_test_for_tracefork. - - * gdb_proc_service.h (psaddr_t): Fix type. - * thread-db.c (thread_db_info.td_thr_tls_get_addr_p): Fix - signature to match glibc. - -2009-12-16 Doug Evans - - * linux-low.c (linux_read_memory): Fix argument to read. - -2009-11-26 Pedro Alves - - * win32-low.c (get_child_debug_event): On EXIT_THREAD_DEBUG_EVENT - events, don't leave current_inferior pointing at null. - -2009-11-26 Pedro Alves - - * win32-low.c (LOG): Delete. - (OUTMSG): Output to stderr. - (OUTMSG2): Conditionalize on `debug_threads' variable, instead of - on compile time LOG macro. - (win32_wait): Fix debug output. - -2009-11-26 Pedro Alves - - * win32-low.c (win32_add_one_solib): If the dll name is - "ntdll.dll", prepend the system directory to the dll path. - -2009-11-17 Daniel Jacobowitz - - * m68k-tdep.c (m68k_gdbarch_init): Reuse previous initialization. - -2009-11-17 Nathan Sidwell - Vladimir Prus - - * Makefile.in (reg-cf.o, reg-cf.c): New targets. - * configure.ac: Check for __mcoldfire__ and set - gdb_cv_m68k_is_coldfire. - * configure.srv: Use gdb_cv_m68k_is_coldfire to select between - reg-cf.o and reg-m68k.o. - * configure: Regenerated. - -2009-11-16 Pedro Alves - - * linux-low.c (linux_remove_process): Add `detaching' parameter. - Pass it to thread_db_free. - (linux_kill, linux_detach, linux_wait_1): Adjust to pass the - proper `detaching' argument to linux_remove_process. - * linux-low.h (thread_db_free): Add `detaching' parameter. - * thread-db.c (thread_db_init): Pass false as `detaching' argument - to thread_db_free. - (thread_db_free): Add `detaching' parameter. Only - call td_ta_clear_event if detaching from process. - -2009-11-12 Maxim Kuvyrkov - - * thread-db.c (thread_db_free): Fix typo. - -2009-11-11 Paul Pluzhnikov - - PR gdb/10838 - * thread-db.c (thread_db_free): Call td_ta_clear_event. - -2009-11-03 Nathan Sidwell - - * configure.ac (i[34567]86-*): Check if we're targetting x86-64 - with an i686 compiler. - * configure.srv (i[34567]86-*-linux*): Pull in x86-64 handling if - needed. - * configure: Rebuilt. - -2009-10-29 Sandra Loosemore - - PR gdb/10783 - - * server.c (handle_search_memory_1): Correct read_addr initialization - in loop for searching subsequent chunks. - -2009-10-29 Paul Pluzhnikov - - * configure.ac: New --with-libthread-db option. - * thread-db.c: Allow direct dependence on libthread_db. - (thread_db_free): Adjust. - * config.in: Regenerate. - * configure: Likewise. - -2009-10-28 Paul Pluzhnikov - - PR gdb/10757 - * thread-db.c (attach_thread): New function. - (maybe_attach_thread): Return success/failure. - (find_new_threads_callback): Adjust. - (thread_db_find_new_threads): Loop until no new threads. - -2009-10-13 Pedro Alves - - * proc-service.c (ps_lgetregs): Formatting. - -2009-10-08 Paul Pluzhnikov - - * acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove. - * configure.ac: Adjust. - * linux-low.h (struct process_info_private): Move members to struct - thread_db. - (thread_db_free, thread_db_handle_monitor_command): New prototype. - * linux-low.c (linux_remove_process): Adjust. - (linux_wait_for_event_1, linux_look_up_symbols): Likewise. - * server.c (handle_query): Move code ... - (handle_monitor_command): ... here. New function. - * target.h (struct target_ops): New member. - * thread-db.c (struct thread_db): New. - (libthread_db_search_path): New variable. - (thread_db_create_event, thread_db_enable_reporting) - (find_one_thread, maybe_attach_thread, find_new_threads_callback) - (thread_db_find_new_threads, (thread_db_get_tls_address): Adjust. - (try_thread_db_load_1, dladdr_to_soname): New functions. - (try_thread_db_load, thread_db_load_search): New functions. - (thread_db_init): Search for libthread_db. - (thread_db_free): New function. - (thread_db_handle_monitor_command): Likewise. - * config.in: Regenerate. - * configure: Regenerate. - -2009-09-27 Ulrich Weigand - - * spu-low.c (spu_kill): Wait for inferior to terminate. - Call clear_inferiors. - (spu_detach): Call clear_inferiors. - -2009-08-22 Ralf Wildenhues - - * aclocal.m4: Regenerate. - * config.in: Likewise. - * configure: Likewise. - -2009-07-31 Ulrich Weigand - - * linux-ppc-low.c (INSTR_SC, NR_spu_run): Define. - (parse_spufs_run): New function. - (ppc_get_pc, ppc_set_pc): Detect and handle SPU PC. - (ppc_breakpoint_at): Handle SPU breakpoints. - -2009-07-31 Ulrich Weigand - - * linux-low.c: Include and . - (SPUFS_MAGIC): Define. - (spu_enumerate_spu_ids): New function. - (linux_qxfer_spu): New function. - (linux_target_ops): Install linux_qxfer_spu. - -2009-07-31 Ulrich Weigand - - * configure.srv (powerpc*-*-linux*): Add powerpc-cell32l.o - and powerpc-cell64l.o to srv_regobj. Add rs6000/powerpc-cell32l.xml - and rs6000/powerpc-cell64l.xml to srv_xmlfiles. - * Makefile.in (powerpc-cell32l.o, powerpc-cell32l.c): New rules. - (powerpc-cell64l.o, powerpc-cell64l.c): Likewise. - (clean): Handle powerpc-cell32l.c and powerpc-cell64l.c. - * linux-ppc-low.c (PPC_FEATURE_CELL): Define. - (init_registers_powerpc_cell32l): Add prototype. - (init_registers_powerpc_cell64l): Likewise. - (ppc_arch_setup): Detect Cell/B.E. architecture. - -2009-07-30 Ralf Wildenhues - - * Makefile.in (datarootdir): New variable. - -2009-07-28 Daniel Jacobowitz - - * linux-low.c (linux_write_memory): Update debugging output. - * Makefile.in (clean): Add new descriptions. - (arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o) - (arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules. - * configure.srv: Add new files for arm*-*-linux*. - * linux-arm-low.c: Add new declarations. - (PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined. - (arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3) - (HWCAP_VFPv3D16): New. - (arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT - instead of __IWMMXT__. - (arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap) - (arm_arch_setup): New. - (target_regsets): Remove #ifdef. Add VFP regset. - (the_low_target): Use arm_arch_setup. - -2009-07-28 Daniel Jacobowitz - - * linux-low.c (linux_kill_one_lwp): Adjust kernel workaround to skip - the main thread again. - -2009-07-06 Aleksandar Ristovski - - Adding Neutrino gdbserver. - * configure: Regenerated. - * configure.ac: Add case for srv_qnx and set LIBS accordingly. - * configure.srv (i[34567]86-*-nto*): New target. - * nto-low.c, nto-low.h, nto-x86-low.c: New files. - * remote-utils.c [__QNX__]: Include sys/iomgr.h - (nto_comctrl) [__QNX__]: New function. - (enable_async_io, disable_async_io) [__QNX__]: Call nto_comctrl. - -2009-07-05 Danny Backx - - * configure.srv (i[34567]86-*-mingw32ce*): Add i386-low.o to - srv_tgtobj. - -2009-07-04 Danny Backx - Pedro Alves - - * win32-i386-low.c (i386_get_thread_context): Handle systems that - don't support CONTEXT_EXTENDED_REGISTERS. - (i386_win32_breakpoint, i386_win32_breakpoint_len): New. - (the_low_target): Install them. - * win32-low.c (get_child_debug_event): Handle WaitForDebugEvent - failing with ERROR_PIPE_NOT_CONNECTED. - -2009-06-30 Doug Evans - Pierre Muller - - Add h/w watchpoint support to x86-linux, win32-i386. - * Makefile.in (SFILES): Add i386-low.c - (i386_low_h): Define. - (i386-low.o): Add dependencies. - (linux-x86-low.o): Add i386-low.h dependency. - (win32-i386-low.o): Ditto. - * i386-low.c: New file. - * i386-low.h: New file. - * configure.srv (i[34567]86-*-cygwin*): Add i386-low.o to srv_tgtobj. - (i[34567]86-*-linux*, i[34567]86-*-mingw*, x86_64-*-linux*): Ditto. - * linux-low.c (linux_add_process): Initialize arch_private. - (linux_remove_process): Free arch_private. - (add_lwp): Initialize arch_private. - (delete_lwp): Free arch_private. - (linux_resume_one_lwp): Call the_low_target.prepare_to_resume if - provided. - * linux-low.h (process_info_private): New member arch_private. - (lwp_info): New member arch_private. - (linux_target_ops): New members new_process, new_thread, - prepare_to_resume. - (ptid_of): New macro. - * linux-x86-low.c: Include stddef.h, i386-low.h. - (arch_process_info): New struct. - (arch_lwp_info): New struct. - (x86_linux_dr_get, x86_linux_dr_set): New functions. - (i386_dr_low_set_addr, i386_dr_low_set_control): New functions. - (i386_dr_low_get_status): New function. - (x86_insert_point, x86_remove_point): New functions. - (x86_stopped_by_watchpoint): New function. - (x86_stopped_data_address): New function. - (x86_linux_new_process, x86_linux_new_thread): New functions. - (x86_linux_prepare_to_resume): New function. - (the_low_target): Add entries for insert_point, remove_point, - stopped_by_watchpoint, stopped_data_address, new_process, new_thread, - prepare_to_resume. - * server.c (debug_hw_points): New global. - (monitor_show_help): Document set debug-hw-points. - (handle_query): Process "set debug-hw-points". - * server.h (debug_hw_points): Declare. - (paddress): Declare. - * utils.c (NUMCELLS, CELLSIZE): New macros. - (get_sell, xsnprintf, paddress): New functions. - * win32-arm-low.c (the_low_target): Add entries for insert_point, - remove_point, stopped_by_watchpoint, stopped_data_address. - * win32-i386-low.c: Include i386-low.h. - (debug_reg_state): Replaces dr. - (i386_dr_low_set_addr, i386_dr_low_set_control): New functions. - (i386_dr_low_get_status): New function. - (i386_insert_point, i386_remove_point): New functions. - (i386_stopped_by_watchpoint): New function. - (i386_stopped_data_address): New function. - (i386_initial_stuff): Update. - (get_thread_context,set_thread_context,i386_thread_added): Update. - (the_low_target): Add entries for insert_point, - remove_point, stopped_by_watchpoint, stopped_data_address. - * win32-low.c (win32_insert_watchpoint): New function. - (win32_remove_watchpoint): New function. - (win32_stopped_by_watchpoint): New function. - (win32_stopped_data_address): New function. - (win32_target_ops): Add entries for insert_watchpoint, - remove_watchpoint, stopped_by_watchpoint, stopped_data_address. - * win32-low.h (win32_target_ops): New members insert_point, - remove_point, stopped_by_watchpoint, stopped_data_address. - -2009-06-25 Pedro Alves - - * server.c (process_serial_event): Re-return unsupported, not - error, if the type isn't recognized. Re-allow supporting only - insert or remove packets. Also call require_running for - breakpoints. Add missing break statement to default case. Tidy. - * target.h (struct target_ops): Rename insert_watchpoint to - insert_point, and remove_watchpoint to remove_point. - - * linux-low.h (struct linux_target_ops): Likewise. - * linux-low.c (linux_insert_watchpoint): Rename to ... - (linux_insert_point): ... this. Adjust. - (linux_remove_watchpoint): Rename to ... - (linux_remove_point): ... this. Adjust. - (linux_target_ops): Adjust. - * linux-crisv32-low.c (cris_insert_watchpoint): Rename to ... - (cris_insert_point): ... this. - (cris_remove_watchpoint): Rename to ... - (cris_remove_point): ... this. - (the_low_target): Adjust. - -2009-06-24 Pierre Muller - - * server.c (handle_v_kill): Pass signal_pid to - kill_inferior if multi_process is zero. - -2009-06-23 Aleksandar Ristovski - - * server.c (process_serial_event): Add support for Z0 and Z1 packet. - * target.h (target_ops): Comment for *_watchpoint to make it clear - the functions can get types '0' and '1'. - -2009-06-22 Aleksandar Ristovski - - * linux-low.c (usr_fetch_inferior_registers): Remove check for regno 0. - * proc-service.c (ps_lgetregs): Pass -1 to fetch all registers. - * regcache.c (get_regcache): Likewise. - * spu-low.c (spu_fetch_registers): Remove 0 to -1 conversion. - * win32-low.c (child_fetch_inferior_registers): Remove check for - regno 0. - -2009-06-19 Aleksandar Ristovski - Pedro Alves - - * target.h (struct target_ops) : New - callback. - (target_supports_multi_process): New. - * server.c (handle_query): Even if GDB reports support, only - enable multi-process if the target also supports it. Report - multi-process support only if the target backend supports it. - * linux-low.c (linux_supports_multi_process): New function. - (linux_target_ops): Install it as target_supports_multi_process - callback. - -2009-05-24 Doug Evans - - Global renaming of find_thread_pid to find_thread_ptid. - * server.h (find_thread_ptid): Renamed from find_thread_pid. - * inferiors.c (find_thread_ptid): Renamed from find_thread_pid. - All callers updated. - - * linux-low.c (handle_extended_wait): Use linux_resume_one_lwp - to resume the newly created thread, don't call ptrace (PTRACE_CONT) - directly. - - * linux-low.c (get_stop_pc): Print pc if debug_threads. - (check_removed_breakpoint, linux_wait_for_lwp): Ditto. - (linux_resume_one_lwp): Ditto. - -2009-05-23 Doug Evans - - * linux-low.c (linux_resume_one_lwp): Change type of first arg - from struct inferior_list_entry * to struct lwp_info *. - All callers updated. - -2009-05-13 Doug Evans - - * linux-x86-low.c: Don't include assert.h. - (x86_siginfo_fixup): Use fatal, not assert. - (x86_arch_setup): Fix comment. - -2009-05-12 Doug Evans - - Biarch support for i386/amd64 gdbserver. - * Makefile.in (SFILES): Remove linux-i386-low.c, linux-x86-64-low.c. - Add linux-x86-low.c. - (linux-i386-low.o, linux-x86-64-low.o): Delete. - (linux-x86-low.o): Add. - * linux-x86-64-low.c: Delete. - * linux-i386-low.c: Delete. - * linux-x86-low.c: New file. - * configure.srv (i?86-linux srv_tgtobj): Replace linux-i386-low.o with - linux-x86-low.o. - (x86_64-linux srv_tgtobj): Replace linux-x86-64-low.o with - linux-x86-low.o. - (x86_64-linux srv_regobj): Add reg-i386-linux.o. - * linux-low.c: Include ansidecl.h, elf/common.h, elf/external.h. - (linux_child_pid_to_exec_file): New function. - (elf_64_header_p, elf_64_file_p): New functions. - (siginfo_fixup): New function. - (linux_xfer_siginfo): New local inf_siginfo. Call siginfo_fixup to - give target a chance to convert layout. - * linux-low.h (linux_target_ops): New member siginfo_fixup. - (linux_child_pid_to_exec_file, elf_64_file_p): Declare. - -2009-05-07 Doug Evans - - * linux-low.c (regsets_fetch_inferior_registers): Fix memory leak. - (regsets_store_inferior_registers): Ditto. - -2009-05-06 Pedro Alves - - PR server/10048 - - * linux-low.c (must_set_ptrace_flags): Delete. - (linux_create_inferior): Set `lwp->must_set_ptrace_flags' instead - of the global. - (linux_attach_lwp_1): Don't set PTRACE_SETOPTIONS here. Set - `lwp->must_set_ptrace_flags' instead. - (linux_wait_for_event_1): Set ptrace options here. - (linux_wait_1): ... not here. - -2009-04-30 Doug Evans - - * inferiors.c (started_inferior_callback): New function. - (attached_inferior_callback): New function. - (have_started_inferiors_p, have_attached_inferiors_p): New functions. - * server.c (print_started_pid, print_attached_pid): New functions. - (detach_or_kill_for_exit): New function. - (main): Call it instead of for_each_inferior (kill_inferior_callback). - * server.h (have_started_inferiors_p): Declare. - (have_attached_inferiors_p): Declare. - - * inferiors.c (remove_process): Fix memory leak, free process. - * linux-low.c (linux_remove_process): New function. - (linux_kill): Call it instead of remove_process. - (linux_detach, linux_wait_1): Ditto. - -2009-04-19 Danny Backx - - * configure.srv: Add x86 Windows CE target. - -2009-04-03 Ulrich Weigand - - * inferiors.c (get_thread_process): Make global. - * server.h (get_thread_process): Add prototype. - * thread-db.c (find_one_thread): Use get_thread_process - instead of current_process. - (thread_db_get_tls_address): Do not crash if called when - thread layer is not yet initialized. - -2009-04-03 Ulrich Weigand - - * remote-utils.c (prepare_resume_reply): Null-terminate packet. - * spu-low.c (current_tid): Rename to ... - (current_ptid): ... this. - (fetch_ppc_register, fetch_ppc_memory, store_ppc_memory, - spu_proc_xfer_spu, spu_resume, spu_request_interrupt): Use - ptid_get_lwp (current_ptid) instead of current_tid. - (spu_kill, spu_detach, spu_join, spu_wait): Use pid argument - instead of current_tid. Use find_process_pid to verify pid - argument is valid. Pass proper argument to remove_process. - (spu_thread_alive): Compare current_ptid instead of current_tid. - (spu_resume): Likewise. - -2009-04-02 Pedro Alves - - * linux-low.c (usr_store_inferior_registers): Declare local `pid' - variable. - -2009-04-01 Pedro Alves - - Implement the multiprocess extensions, and add linux multiprocess - support. - - * server.h (ULONGEST): Declare. - (struct ptid, ptid_t): New. - (minus_one_ptid, null_ptid): Declare. - (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) - (ptid_get_tid, ptid_equal, ptid_is_pid): Declare. - (struct inferior_list_entry): Change `id' type from unsigned from - to ptid_t. - (struct sym_cache, struct breakpoint, struct - process_info_private): Forward declare. - (struct process_info): Declare. - (current_process): Declare. - (all_processes): Declare. - (initialize_inferiors): Declare. - (add_thread): Adjust to use ptid_t. - (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto. - (add_process, remove_process, find_thread_pid): Declare. - (find_inferior_id): Adjust to use ptid_t. - (cont_thread, general_thread, step_thread): Change type to ptid_t. - (multi_process): Declare. - (push_event): Adjust to use ptid_t. - (read_ptid, write_ptid): Declare. - (prepare_resume_reply): Adjust to use ptid_t. - (clear_symbol_cache): Declare. - * inferiors.c (all_processes): New. - (null_ptid, minus_one_ptid): New. - (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) - (ptid_get_tid, ptid_equal, ptid_is_pid): New. - (add_thread): Change unsigned long to ptid. Remove gdb_id - parameter. Adjust. - (thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid. - (gdb_id_to_thread): Rename to ... - (find_thread_pid): ... this. Change unsigned long to ptid. - (gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid. - (loaded_dll, pull_pid_from_list): Adjust. - (add_process, remove_process, find_process_pid) - (get_thread_process, current_process, initialize_inferiors): New. - * target.h (struct thread_resume) : Change type to ptid_t. - (struct target_waitstatus) : Ditto. - (struct target_ops) : Add `pid' argument. Change - return type to int. - (struct target_ops) : Add `pid' argument. - (struct target_ops) : Change pid's type to ptid_t. - (struct target_ops) : Add `ptid' field. Change return type - to ptid. - (kill_inferior, detach_inferior, join_inferior): Add `pid' argument. - (mywait): Add `ptid' argument. Change return type to ptid_t. - (target_pid_to_str): Declare. - * target.c (set_desired_inferior): Adjust to use ptids. - (mywait): Add new `ptid' argument. Adjust. - (target_pid_to_str): New. - * mem-break.h (free_all_breakpoints): Declare. - * mem-break.c (breakpoints): Delelete. - (set_breakpoint_at, delete_breakpoint, find_breakpoint_at) - (check_mem_read, check_mem_write, delete_all_breakpoints): Adjust - to use per-process breakpoint list. - (free_all_breakpoints): New. - * remote-utils.c (struct sym_cache) : Drop `const'. - (symbol_cache, all_symbols_looked_up): Delete. - (hexchars): New. - (ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one, - read_ptid): New. - (prepare_resume_reply): Change ptid argument's type from unsigned - long to ptid_t. Adjust. Implement W;process and X;process. - (free_sym_cache, clear_symbol_cache): New. - (look_up_one_symbol): Adjust to per-process symbol cache. * - * server.c (cont_thread, general_thread, step_thread): Change type - to ptid_t. - (attached): Delete. - (multi_process): New. - (last_ptid): Change type to ptid_t. - (struct vstop_notif) : Change type to ptid_t. - (queue_stop_reply, push_event): Change `ptid' argument's type to - ptid_t. - (discard_queued_stop_replies): Add `pid' argument. - (start_inferior): Adjust to use ptids. Adjust to mywait interface - changes. Don't reference the `attached' global. - (attach_inferior): Adjust to mywait interface changes. - (handle_query): Adjust to use ptids. Parse GDB's qSupported - features. Handle and report "multiprocess+". Handle - "qAttached:PID". - (handle_v_cont): Adjust to use ptids. Adjust to mywait interface - changes. - (handle_v_kill): New. - (handle_v_stopped): Adjust to use target_pid_to_str. - (handle_v_requests): Allow multiple attaches and runs when - multiprocess extensions are in effect. Handle "vKill". - (myresume): Adjust to use ptids. - (queue_stop_reply_callback): Add `arg' parameter. Handle it. - (handle_status): Adjust to discard_queued_stop_replies interface - change. - (first_thread_of, kill_inferior_callback) - (detach_or_kill_inferior_callback, join_inferiors_callback): New. - (main): Call initialize_inferiors. Adjust to use ptids, killing - and detaching from all inferiors. Handle multiprocess packet - variants. - * linux-low.h: Include gdb_proc_service.h. - (struct process_info_private): New. - (struct linux_target_ops) : Use ptid_get_pid. - : Use ptid_get_lwp. - (get_lwp_thread): Adjust. - (struct lwp_info): Add `dead' member. - (find_lwp_pid): Declare. - * linux-low.c (thread_db_active): Delete. - (new_inferior): Adjust comment. - (inferior_pid): Delete. - (linux_add_process): New. - (handle_extended_wait): Adjust. - (add_lwp): Change unsigned long to ptid. - (linux_create_inferior): Add process to processes table. Adjust - to use ptids. Don't set new_inferior here. - (linux_attach_lwp): Rename to ... - (linux_attach_lwp_1): ... this. Add `initial' argument. Handle - it. Adjust to use ptids. - (linux_attach_lwp): New. - (linux_attach): Add process to processes table. Don't set - new_inferior here. - (struct counter): New. - (second_thread_of_pid_p, last_thread_of_process_p): New. - (linux_kill_one_lwp): Add `args' parameter. Handle it. Adjust to - multiple processes. - (linux_kill): Add `pid' argument. Handle it. Adjust to multiple - processes. Remove process from process table. - (linux_detach_one_lwp): Add `args' parameter. Handle it. Adjust - to multiple processes. - (any_thread_of): New. - (linux_detach): Add `pid' argument, and handle it. Remove process - from processes table. - (linux_join): Add `pid' argument. Handle it. - (linux_thread_alive): Change unsighed long argument to ptid_t. - Consider dead lwps as not being alive. - (status_pending_p): Rename `dummy' argument to `arg'. Filter out - threads we're not interested in. - (same_lwp, find_lwp_pid): New. - (linux_wait_for_lwp): Change `pid' argument's type from int to - ptid_t. Adjust. - (linux_wait_for_event): Rename to ... - (linux_wait_for_event_1): ... this. Change `pid' argument's type - from int to ptid_t. Adjust. - (linux_wait_for_event): New. - (linux_wait_1): Add `ptid' argument. Change return type to - ptid_t. Adjust. Use last_thread_of_process_p. Remove processes - that exit from the process table. - (linux_wait): Add `ptid' argument. Change return type to ptid_t. - Adjust. - (mark_lwp_dead): New. - (wait_for_sigstop): Adjust to use ptids. If a process exits while - stopping all threads, mark its main lwp as dead. - (linux_set_resume_request, linux_resume_one_thread): Adjust to use - ptids. - (fetch_register, usr_store_inferior_registers) - (regsets_fetch_inferior_registers) - (regsets_store_inferior_registers, linux_read_memory) - (linux_write_memory): Inline `inferior_pid'. - (linux_look_up_symbols): Adjust to use per-process - `thread_db_active'. - (linux_request_interrupt): Adjust to use ptids. - (linux_read_auxv): Inline `inferior_pid'. - (initialize_low): Don't reference thread_db_active. - * gdb_proc_service.h (struct ps_prochandle) : Remove. - * proc-service.c (ps_lgetregs): Use find_lwp_pid. - (ps_getpid): Return the pid of the current inferior. - * thread-db.c (proc_handle, thread_agent): Delete. - (thread_db_create_event, thread_db_enable_reporting): Adjust to - per-process data. - (find_one_thread): Change argument type to ptid_t. Adjust to - per-process data. - (maybe_attach_thread): Adjust to per-process data and ptids. - (thread_db_find_new_threads): Ditto. - (thread_db_init): Ditto. - * spu-low.c (spu_create_inferior, spu_attach): Add process to - processes table. Adjust to use ptids. - (spu_kill, spu_detach): Adjust interface. Remove process from - processes table. - (spu_join, spu_thread_alive): Adjust interface. - (spu_wait): Adjust interface. Remove process from processes - table. Adjust to use ptids. - * win32-low.c (current_inferior_tid): Delete. - (current_inferior_ptid): New. - (debug_event_ptid): New. - (thread_rec): Take a ptid. Adjust. - (child_add_thread): Add `pid' argument. Adjust to use ptids. - (child_delete_thread): Ditto. - (do_initial_child_stuff): Add `attached' argument. Add process to - processes table. - (child_fetch_inferior_registers, child_store_inferior_registers): - Adjust. - (win32_create_inferior): Pass 0 to do_initial_child_stuff. - (win32_attach): Pass 1 to do_initial_child_stuff. - (win32_kill): Adjust interface. Remove process from processes - table. - (win32_detach): Ditto. - (win32_join): Adjust interface. - (win32_thread_alive): Take a ptid. - (win32_resume): Adjust to use ptids. - (get_child_debug_event): Ditto. - (win32_wait): Adjust interface. Remove exiting process from - processes table. - -2009-04-01 Pedro Alves - - Non-stop mode support. - - * server.h (non_stop): Declare. - (gdb_client_data, handler_func): Declare. - (delete_file_handler, add_file_handler, start_event_loop): - Declare. - (handle_serial_event, handle_target_event, push_event) - (putpkt_notif): Declare. - * target.h (enum resume_kind): New. - (struct thread_resume): Replace `step' field by `kind' field. - (TARGET_WNOHANG): Define. - (struct target_ops) : Add `options' argument. - : New fields. - (target_supports_non_stop, target_async): New. - (start_non_stop): Declare. - (mywait): Add `options' argument. - * target.c (mywait): Add `options' argument. Print child exit - notifications here. - (start_non_stop): New. - * server.c (non_stop, own_buf, mem_buf): New globals. - (struct vstop_notif): New. - (notif_queue): New global. - (queue_stop_reply, push_event, discard_queued_stop_replies) - (send_next_stop_reply): New. - (start_inferior): Adjust to use resume_kind. Adjust to mywait - interface changes. - (attach_inferior): In non-stop mode, don't wait for the target - here. - (handle_general_set): Handle QNonStop. - (handle_query): When handling qC, return the current general - thread, instead of the first thread of the list. - (handle_query): If the backend supports non-stop mode, include - QNonStop+ in the qSupported query response. - (handle_v_cont): Adjust to use resume_kind. Handle resume_stop - and non-stop mode. - (handle_v_attach, handle_v_run): Handle non-stop mode. - (handle_v_stopped): New. - (handle_v_requests): Report support for vCont;t. Handle vStopped. - (myresume): Adjust to use resume_kind. Handle non-stop. - (queue_stop_reply_callback): New. - (handle_status): Handle non-stop mode. - (main): Clear non_stop flag on reconnection. Use the event-loop. - Refactor serial protocol handling from here ... - (process_serial_event): ... to this new function. When GDB - selects any thread, select one here. In non-stop mode, wait until - GDB acks all pending events before exiting. - (handle_serial_event, handle_target_event): New. - * remote-utils.c (remote_open): Install remote_desc in the event - loop. - (remote_close): Remove remote_desc from the event loop. - (putpkt_binary): Rename to... - (putpkt_binary_1): ... this. Add `is_notic' argument. Handle it. - (putpkt_binary): New as wrapper around putpkt_binary_1. - (putpkt_notif): New. - (prepare_resume_reply): In non-stop mode, don't change the - general_thread. - * event-loop.c: New. - * Makefile.in (OBJ): Add event-loop.o. - (event-loop.o): New rule. - - * linux-low.h (pid_of): Moved here. - (lwpid_of): New. - (get_lwp_thread): Use lwpid_of. - (struct lwp_info): Delete `lwpid' field. Add `suspended' field. - * linux-low.c (pid_of): Delete. - (inferior_pid): Use lwpid_of. - (linux_event_pipe): New. - (target_is_async_p): New. - (delete_lwp): New. - (handle_extended_wait): Use lwpid_of. - (add_lwp): Don't set lwpid field. - (linux_attach_lwp): Adjust debug output. Use lwpid_of. - (linux_kill_one_lwp): If killing a running lwp, stop it first. - Use lwpid_of. Adjust to linux_wait_for_event interface changes. - (linux_detach_one_lwp): If detaching from a running lwp, stop it - first. Adjust to linux_wait_for_event interface changes. Use - lwpid_of. - (linux_detach): Don't delete the main lwp here. - (linux_join): Use my_waitpid. Avoid signal_pid. Use lwpid_of. - (status_pending_p): Don't consider explicitly suspended lwps. - (linux_wait_for_lwp): Take an integer pid instead of a lwp_info - pointer. Add OPTIONS argument. Change return type to int. Use - my_waitpid instead of sleeping. Handle WNOHANG. Use lwpid_of. - (linux_wait_for_event): Take an integer pid instead of a lwp_info - pointer. Add status pointer argument. Return a pid instead of a - status. Use lwpid_of. Adjust to linux_wait_for_lwp interface - changes. In non-stop mode, don't switch to a random thread. - (linux_wait): Rename to... - (linux_wait_1): ... this. Add target_options argument, and handle - it. Adjust to use resume_kind. Use lwpid_of. In non-stop mode, - don't handle the continue thread. Handle TARGET_WNOHANG. Merge - clean exit and signal exit code. Don't stop all threads in - non-stop mode. In all-stop mode, only stop all threads when - reporting a stop to GDB. Handle explicit thread stop requests. - (async_file_flush, async_file_mark): New. - (linux_wait): New. - (send_sigstop): Use lwpid_of. - (wait_for_sigstop): Use lwpid_of. Adjust to linux_wait_for_event - interface changes. In non-stop mode, don't switch to a random - thread. - (linux_resume_one_lwp): Use lwpid_of. - (linux_continue_one_thread, linux_queue_one_thread): Merge into ... - (linux_resume_one_thread): ... this. Handle resume_stop. In - non-stop mode, don't look for pending flag in all threads. - (resume_status_pending_p): Don't consider explicitly suspended - threads. - (my_waitpid): Reimplement. Emulate __WALL. - (linux_request_interrupt, linux_read_offsets, linux_xfer_siginfo): - Use lwpid_of. - (sigchld_handler, linux_supports_non_stop, linux_async) - (linux_start_non_stop): New. - (linux_target_ops): Register linux_supports_non_stop, linux_async - and linux_start_non_stop. - (initialize_low): Install SIGCHLD handler. - * thread-db.c (thread_db_create_event, find_one_thread) - (thread_db_get_tls_address): Use lwpid_of. - * win32-low.c (win32_detach): Adjust to use resume_kind. - (win32_wait): Add `options' argument. - * spu-low.c (spu_resume): Adjust to use resume_kind. - (spu_wait): Add `options' argument. - -2009-04-01 Pedro Alves - - Decouple target code from remote protocol. - - * target.h (enum target_waitkind): New. - (struct target_waitstatus): New. - (struct target_ops) : Return an unsigned long. Take a - target_waitstatus pointer instead of a char pointer. - (mywait): Likewise. - * target.c (mywait): Change prototype to return an unsigned long. - Take a target_waitstatus pointer instead of a char pointer. Adjust. - * server.h (thread_from_wait, old_thread_from_wait): Delete - declarations. - (prepare_resume_reply): Change prototype to take a - target_waitstatus. - * server.c (thread_from_wait, old_thread_from_wait): Delete. - (last_status, last_ptid): New. - (start_inferior): Remove "statusptr" argument. Adjust. Return a - pid instead of a signal. - (attach_inferior): Remove "status" and "signal" parameters. - Adjust. - (handle_query): For qGetTLSAddr, parse the thread id with strtol, - not as an address. - (handle_v_cont, handle_v_attach, handle_v_run, handle_v_kill) - (handle_v_requests, myresume): Remove "status" and "signal" - parameters. Adjust. - (handle_status): New. - (main): Delete local `status'. Adjust. - * remote-utils.c: Include target.h. - (prepare_resume_reply): Change prototype to take a - target_waitstatus. Adjust. - - * linux-low.c (linux_wait): Adjust to new target_ops->wait - interface. - * spu-low.c (spu_wait): Adjust. - * win32-low.c (enum target_waitkind, struct target_waitstatus): - Delete. - (win32_wait): Adjust. - -2009-04-01 Pedro Alves - - * target.h (struct thread_resume): Delete leave_stopped member. - (struct target_ops): Add a `n' argument to the `resume' callback. - * server.c (start_inferior): Adjust. - (handle_v_cont, myresume): Adjust. - * linux-low.c (check_removed_breakpoint): Adjust to resume - interface change, and to removed leave_stopped field. - (resume_ptr): Delete. - (struct thread_resume_array): New. - (linux_set_resume_request): Add new `arg' parameter. Adjust to - resume interface change. - (linux_continue_one_thread, linux_queue_one_thread) - (resume_status_pending_p): Check if the resume field is NULL - instead of checking the leave_stopped member. - (linux_resume): Adjust to the target resume interface change. - * spu-low.c (spu_resume): Adjust to the target resume interface - change. - * win32-low.c (win32_detach, win32_resume): Ditto. - -2009-04-01 Pedro Alves - - * linux-low.c (linux_wait_for_event): Don't clear the `stepping' - flag. - (wait_for_sigstop): Don't leave a finished single-step SIGTRAP - pending. - (linux_continue_one_thread): Only preserve the stepping flag if - there's a pending breakpoint. - -2009-03-31 Pedro Alves - - * server.c (main): After the inferior having exited, call - remote_close before exiting gdbserver. - -2009-03-25 Thiago Jung Bauermann - - Fix size of FPSCR in Power 7 processors. - * linux-ppc-low.c (PPC_FEATURE_ARCH_2_05): Remove #define. - (PPC_FEATURE_HAS_DFP): New #define. - (ppc_arch_setup): Check for DFP feature instead of ISA 2.05 to decide on - size of the FPSCR. - -2009-03-23 Pedro Alves - - * server.c (handle_query) Whitespace and formatting. - -2009-03-22 Pedro Alves - - * i387-fp.c, linux-arm-low.c, linux-cris-low.c, - linux-crisv32-low.c, linux-i386-low.c, linux-low.c, - linux-mips-low.c, linux-s390-low.c, linux-sparc-low.c, - linux-x86-64-low.c, linux-xtensa-low.c, proc-service.c, - regcache.c, remote-utils.c, server.c, spu-low.c, target.h, - thread-db.c, win32-low.c, xtensa-xtregs.c, gdbreplay.c, - Makefile.in, configure.ac: Fix whitespace throughout. - * configure: Regenerate. - -2009-03-22 Pedro Alves - - * inferiors.c (find_inferior): Make it safe for the callback - function to delete the currently iterated inferior. - -2009-03-22 Pedro Alves - - * Makefile.in (linuw_low_h): Move higher. - (thread-db.o): Depend on $(linux_low_h). - -2009-03-17 Pedro Alves - - Rename "process" to "lwp" throughout. - - * linux-low.c (all_processes): Rename to... - (all_lwps): ... this. - (inferior_pid, handle_extended_wait, get_stop_pc): Adjust. - (add_process): Rename to ... - (add_lwp): ... this. Adjust. - (linux_create_inferior): Adjust. - (linux_attach_lwp): Adjust. - (linux_attach): Adjust. - (linux_kill_one_process): Rename to ... - (linux_kill_one_lwp): ... this. Adjust. - (linux_kill): Adjust. - (linux_detach_one_process): Rename to ... - (linux_detach_one_lwp): ... this. Adjust. - (linux_detach): Adjust. - (check_removed_breakpoint): Adjust. - (status_pending_p): Adjust. - (linux_wait_for_process): Rename to ... - (linux_wait_for_lwp): ... this. Adjust. - (linux_wait_for_event): Adjust. - (send_sigstop): Adjust. - (wait_for_sigstop): Adjust. - (stop_all_processes): Rename to ... - (stop_all_lwps): ... this. - (linux_resume_one_process): Rename to ... - (linux_resume_one_lwp): ... this. Adjust. - (linux_set_resume_request, linux_continue_one_thread) - (linux_queue_one_thread, resume_status_pending_p) - (usr_store_inferior_registers, regsets_store_inferior_registers) - (linux_request_interrupt, linux_read_offsets, linux_xfer_siginfo): - Adjust. - * linux-low.h (get_process): Rename to ... - (get_lwp): ... this. Adjust. - (get_thread_process): Rename to ... - (get_thread_lwp): ... this. Adjust. - (get_process_thread): Rename to ... - (get_lwp_thread): ... this. Adjust. - (struct process_info): Rename to ... - (struct lwp_info): ... this. - (all_processes): Rename to ... - (all_lwps): ... this. - * proc-service.c (ps_lgetregs): Adjust. - * thread-db.c (thread_db_create_event, find_one_thread) - (maybe_attach_thread, thread_db_get_tls_address): Adjust. - -2009-03-14 Pedro Alves - - * server.c (handle_query): Handle "qAttached". - -2009-03-13 Nathan Sidwell - - * Makefile.in, hostio-errno.c, errno.c, xtensa-xtregs.c: Change to - GPLv3, update license URL. - -2009-03-01 Doug Evans - - * Makefile.in (INCLUDE_CFLAGS): Add -I$(srcdir)/../common. - (server_h): Add gdb_signals.h. - (signals.o): Update. - * server.h (target_signal_from_host,target_signal_to_host_p) - (target_signal_to_host,target_signal_to_name): Moved to gdb_signals.h. - -2009-02-14 Pierre Muller - - * remote-utils.c (getpkt): Also generate remote-debug - information if noack_mode is set. - -2009-02-06 Pedro Alves - - * server.c (handle_query): Report qXfer:siginfo:read and - qXfer:siginfo:write as supported and handle them. - * target.h (struct target_ops) : New field. - * linux-low.c (linux_xfer_siginfo): New. - (linux_target_ops): Set it. - -2009-01-26 Pedro Alves - - * server.c (gdbserver_usage): Mention --remote-debug. - (main): Accept '--remote-debug' switch. - -2009-01-18 Doug Evans - - * regcache.c (new_register_cache): No need to check result of xcalloc. - * server.c (handle_search_memory): Back out calls to xmalloc, - result is checked and error is returned to user upon failure. - (handle_query): Ditto. Add more checks for result of malloc. - (handle_v_cont): Check result of malloc, report error back to - user upon failure. - (handle_v_run): Ditto. Call freeargv. - * server.h (freeargv): Declare. - * utils.c (freeargv): New fn. - -2009-01-15 Doug Evans - - * gdbreplay.c (perror_with_name): Make arg const char *. - * server.h (target_signal_to_name): Make return type const char *. - * thread-db.c (thread_db_err_str): Make return type const char *. - * utils.c (perror_with_name): Make arg const char *. - -2009-01-14 Pedro Alves - - * win32-low.c (get_child_debug_event): Issue a final DBG_CONTINUE - when handling a EXIT_PROCESS_DEBUG_EVENT. - -2009-01-06 Joel Brobecker - - * gdbreplay.c (gdbreplay_version): Update copyright year. - * server.c (gdbserver_version): Likewise. - -2009-01-05 Doug Evans - - * linux-low.c (linux_attach_lwp): Add some comments/fixmes. - (handle_extended_wait): Improve comment. - -2008-12-13 Doug Evans - - * utils.c (xmalloc,xcalloc,xstrdup): New fns. - * server.h (ATTR_MALLOC): New macro. - (xmalloc,xcalloc,xstrdup): Declare. - * hostio.c: Replace malloc,calloc,strdup with xmalloc,xcalloc,xstrdup. - * inferiors.c: Ditto. - * linux-low.c: Ditto. - * mem-break.c: Ditto. - * regcache.c: Ditto. - * remote-utils.c: Ditto. - * server.c: Ditto. - * target.c: Ditto. - * win32-low.c: Ditto. - -2008-12-12 Doug Evans - - * linux-low.c (linux_wait_for_process): Don't clobber current_inferior - in debugging printf. - - * linux-low.c (handle_extended_wait): Simplify, use my_waitpid. - -2008-12-09 Doug Evans - - * linux-low.h (struct process_info): Delete member tid, unused. - * thread-db.c (find_one_thread): Update. - (maybe_attach_thread): Update. - -2008-12-02 Pedro Alves - - * target.h (struct target_ops): Add qxfer_osdata member. - * linux-low.c: Include ctype.h and pwd.h and sys/types.h - and dirent.h. - (linux_qxfer_osdata): New functions. - (linux_target_ops): Register linux_qxfer_osdata as qxfer_osdata - callback. - * server.c (handle_query): Handle "qXfer:osdata:read:". - * remote-utils.c (buffer_grow, buffer_free, buffer_init, buffer_finish) - (buffer_xml_printf): New functions. - * server.h (struct buffer): New. - (buffer_grow_str, buffer_grow_str0): New macros. - (buffer_grow, buffer_free, buffer_init, buffer_finish) - (buffer_xml_printf): Declare. - -2008-11-24 Doug Evans - - * Makefile.in (VERSION,DIST,LINT,LINTFLAGS): Delete, unused. - -2008-11-24 Daniel Jacobowitz - - * server.c (handle_v_run): Always use the supplied argument list. - -2008-11-19 Bob Wilson - - * xtensa-xtregs.c (XTENSA_ELF_XTREG_SIZE): Change to 4. - (xtensa_regmap_table): Add entry for scompare1. - -2008-11-18 Thiago Jung Bauermann - - * Makefile.in (powerpc-isa205-32l.o, powerpc-isa205-32l.c, - powerpc-isa205-altivec32l.o, powerpc-isa205-altivec32l.c, - powerpc-isa205-vsx32l.o, powerpc-isa205-vsx32l.c, - powerpc-isa205-64l.o, powerpc-isa205-64l.c, - powerpc-isa205-altivec64l.o, powerpc-isa205-altivec64l.c, - powerpc-isa205-vsx64l.o, powerpc-isa205-vsx64l.c): New targets. - * configure.srv (powerpc*-*-linux*): Add ISA 2.05 object files and - XML target descriptions. - * linux-ppc-low.c (ppc_arch_setup): Init registers with 64-bit FPSCR - when inferior is running on an ISA 2.05 or later processor. Add - special case to return offset for full 64-bit slot of FPSCR when - in 32-bits. - -2008-11-14 Daniel Gutson - - * Makefile.in (SFILES, clean): Added sparc64 files. - (reg-sparc64.o, reg-sparc64.c): New. - * configure.srv (sparc*-*-linux*): New configuration. - * linux-low.c (regsets_fetch_inferior_registers): Swap ptrace - syscall arguments for SPARC. - (regsets_store_inferior_registers): Likewise. - * linux-sparc-low.c: New file. - -2008-10-21 Doug Evans - - * Makefile.in (BFD_DIR,BFD,BFD_SRC,BFD_CFLAGS): Delete. - (READLINE_DIR,READLINE_DEP): Delete. - (INTERNAL_CFLAGS): Update. - (LINTFLAGS): Update. - -2008-10-10 Pedro Alves - - * server.c (handle_v_run): If GDB didn't specify an argv, use the - whole argv from the last run, not just argv[0]. - -2008-09-08 Pedro Alves - - * regcache.c (new_register_cache): Return NULL if the register - cache size isn't known yet. - (free_register_cache): Avoid dereferencing a NULL regcache. - -2008-09-04 Daniel Jacobowitz - - * configure.srv: Merge MIPS and MIPS64. - -2008-08-24 Maciej W. Rozycki - - * Makefile.in (uninstall): Apply $(EXEEXT) too. - -2008-08-18 Luis Machado - - * Makefile.in: Add required vsx dependencies. - - * linux-ppc-low: Define PPC_FEATURE_HAS_VSX. - Declare init_registers_powerpc_vsx32l. - Declare init_registers_powerpc_vsx64l. - Define PTRACE_GETVSXREGS and PTRACE_SETVSXREGS. - (ppc_arch_setup): Check for VSX in hwcap. - (ppc_fill_vsxregset): New function. - (ppc_store_vsxregset): New function. - Add new VSX entry in regset_info target_regsets. - - * configure.srv: Add new VSX dependencies. - -2008-08-12 Pedro Alves - - * remote-utils.c (noack_mode, transport_is_reliable): New globals. - (remote_open): Set or clear transport_is_reliable. - (putpkt_binary): Don't expect acks in noack mode. - (getpkt): Don't send ack/nac in noack mode. - * server.c (handle_general_set): Handle QStartNoAckMode. - (handle_query): If connected by tcp pass QStartNoAckMode+ in - qSupported. - (main): Reset noack_mode on every connection. - * server.h (noack_mode): Declare. - -2008-08-07 Ralf Wildenhues - - * Makefile.in (GDBREPLAY_OBS): New variable. - (gdbreplay$(EXEEXT)): Use it to avoid unportable $^. - -2008-08-05 Ulrich Weigand - Daniel Jacobowitz - - * linux-low.c (linux_resume_one_process): Ignore ESRCH. - (usr_store_inferior_registers): Likewise. - (regsets_store_inferior_registers): Likewise. - -2008-07-31 Rolf Jansen - Pedro Alves - - * configure.ac: Check for memmem declaration. - * server.c [HAVE_MALLOC_H]: Include malloc.h. - (disable_packet_vCont, disable_packet_Tthread, disable_packet_qC) - (disable_packet_qfThreadInfo): Unconditionally compile. - * server.h [!HAVE_DECL_MEMMEM]: Declare memmem. - * configure, config.in: Regenerate. - -2008-07-28 Doug Kwan - - * linux-low.c (sys/dir.h, sys/user.h): Remove includes. - (linux_write_memory): Remove declaration of errno. - -2008-07-12 Ulrich Weigand - - * linux-low.c (handle_extended_wait): Do not use "status" - variable uninitialized. - -2008-07-07 Pedro Alves - - * server.c (handle_v_attach): Inhibit reporting dll changes. - -2008-06-27 Pedro Alves - - * remote-utils.c (prepare_resume_reply): If requested, don't - output "thread:TID" in the T stop reply. - - * server.c (disable_packet_vCont, disable_packet_Tthread) - (disable_packet_qC, disable_packet_qfThreadInfo): New globals. - (handle_query): If requested, disable support for qC, qfThreadInfo - and qsThreadInfo. - (handle_v_requests): If requested, disable support for vCont. - (gdbserver_show_disableable): New. - (main): Handle --disable-packet and --disable-packet=LIST. - - * server.h (disable_packet_vCont, disable_packet_Tthread) - (disable_packet_qC, disable_packet_qfThreadInfo): Declare. - -2008-06-20 Carlos O'Donell - - * server.c (gdbserver_usage): Mention --version. - -2008-06-06 Daniel Jacobowitz - - * Makefile.in (gdbreplay.o): New rule. - -2008-06-06 Joseph Myers - - * gdbreplay.c (gdbreplay_version): Say gdbreplay in version - message, not gdbserver. - -2008-06-05 Vladimir Prus - Nathan Sidwell - Joseph Myers - - * acinclude.m4: Include ../../config/acx.m4. - * configure.ac: Use ACX_PKGVERSION and ACX_BUGURL. - * configure, config.in: Regenerate. - * Makefile.in (gdbreplay$(EXEEXT)): Add version.o. - * server.c (gdbserver_version): Print PKGVERSION. - (gdbsrever_usage): Add stream parameter. Print REPORT_BUGS_TO. - (main): Adjust gdbserver_usage calls. - * gdbreplay.c (version, host_name): Add declarations. - (gdbreplay_version, gdbreplay_usage): New. - (main): Accept --version and --help options. - -2008-06-04 Daniel Jacobowitz - - * linux-arm-low.c (thumb_breakpoint, thumb_breakpoint_len): New. - (arm_breakpoint_at): Handle Thumb. - (the_low_target): Add comment. - -2008-05-29 Ulrich Weigand - - * linux-ppc-low.c (ppc_collect_ptrace_register): Clear buffer. - -2008-05-09 Doug Evans - - * server.h (decode_search_memory_packet): Declare. - * remote-utils.c (decode_search_memory_packet): New fn. - * server.c (handle_search_memory_1): New fn. - (handle_search_memory): New fn. - (handle_query): Process qSearch:memory packets. - -2008-05-08 Ulrich Weigand - - * regcache.c (registers_length): Remove. - (set_register_cache): Verify that PBUFSIZ is large enough to hold a - full register packet. - * regcache.h (registers_length): Remove prototype. - * server.h (PBUFSIZ): Define to 16384. - -2008-05-03 Ulrich Weigand - - * configure.srv (powerpc*-*-linux*): Set srv_regobj to - powerpc-32l.o, powerpc-altivec32l.o, powerpc-e500l.o, - powerpc-64l.o, and powerpc-altivec64l.o. - Remove rs6000/powerpc-32.xml, rs6000/powerpc-64.xml, and - rs6000/powerpc-e500.xml; add rs6000/powerpc-32l.xml, - rs6000/powerpc-altivec32l.xml, rs6000/powerpc-e500l.xml, - rs6000/powerpc-64l.xml, rs6000/powerpc-altivec64l.xml, - rs6000/power-linux.xml, and rs6000/power64-linux.xml - to srv_xmlfiles. - - * Makefile.in (reg-ppc.o, reg-ppc.c): Remove, replace by ... - (powerpc-32l.o, powerpc-32l.c): ... these new rules. - (powerpc-32.o, powerpc-32.c): Remove, replace by ... - (powerpc-altivec32l.o, powerpc-altivec32l.c): ... these new rules. - (powerpc-e500.o, powerpc-e500.c): Remove, replace by ... - (powerpc-e500l.o, powerpc-e500l.c): ... these new rules. - (reg-ppc64.o, reg-ppc64.c): Remove, replace by ... - (powerpc-64l.o, powerpc-64l.c): ... these new rules. - (powerpc-64.o, powerpc-64.c): Remove, replace by ... - (powerpc-altivec64l.o, powerpc-altivec64l.c): ... these new rules. - (clean): Update. - - * linux-ppc-low.c (init_registers_ppc): Remove, replace by ... - (init_registers_powerpc_32l): ... this new prototype. - (init_registers_powerpc_32): Remove, replace by ... - (init_registers_powerpc_altivec32l): ... this new prototype. - (init_registers_powerpc_e500): Remove, replace by ... - (init_registers_powerpc_e500l): ... this new prototype. - (init_registers_ppc64): Remove, replace by ... - (init_registers_powerpc_64l): ... this new prototype. - (init_registers_powerpc_64): Remove, replace by ... - (init_registers_powerpc_altivec64l): ... this new prototype. - (ppc_num_regs): Set to 73. - (PT_ORIG_R3, PT_TRAP): Define if necessary. - (ppc_regmap, ppc_regmap_e500): Add values for orig_r3 and trap. - (ppc_cannot_store_register): Handle orig_r3 and trap. - (ppc_arch_setup): Update init_registers_... calls. - (ppc_fill_gregset): Handle orig_r3 and trap. - - * inferiors.c (clear_inferiors): Reset current_inferior. - -2008-04-23 Paolo Bonzini - - * acinclude.m4: Add override.m4. - * configure: Regenerate. - -2008-04-21 Ulrich Weigand - - * linux-ppc-low.c (ppc_arch_setup): Reset ppc_hwcap after the - initial call to init_register_ppc64. - -2008-04-21 Ulrich Weigand - - * configure.srv (powerpc64-*-linux*, powerpc-*-linux*): Merge into - single powerpc*-*-linux* case. - (s390-*-linux*, s390x-*-linux*): Merge into single s390*-*-linux* case. - -2008-04-17 Ulrich Weigand - - * configure.srv [powerpc64-*-linux*]: Remove powerpc-e500.o from - srv_regobj. Remove rs6000/powerpc-e500.xml and rs6000/power-spe.xml - from reg_xmlfiles. - * linux-ppc-low.c: Include . - (PPC_FEATURE_HAS_ALTIVEC, PPC_FEATURE_HAS_SPE): Define. - (ppc_hwcap): New global variable. - (ppc_regmap): Remove __SPE__ #ifdef sections. - (ppc_regmap_e500): New global variable. - (ppc_cannot_store_register): Update __SPE__ special case. - (ppc_get_hwcap): New function. - (ppc_arch_setup): Use it to determine whether inferior supports - AltiVec or SPE registers. Set the_low_target.regmap if appropriate. - (ppc_fill_vrregset, ppc_store_vrregset): Define unconditionally. - Do not access registers if target does not support AltiVec. - (ppc_fill_evrregset, ppc_store_evrregset): Define unconditionally. - Do not access registers if target does not support SPE. - (target_regsets): Unconditionally include AltiVec and SPE regsets. - -2008-04-17 Daniel Jacobowitz - - * linux-low.c (disabled_regsets, num_regsets): New. - (use_regsets_p): Delete. - (linux_wait_for_process): Clear disabled_regsets. - (regsets_fetch_inferior_registers): Check and set it. - (regsets_store_inferior_registers): Likewise. - (linux_fetch_registers, linux_store_registers): Do not use - use_regsets_p. - (initialize_low): Allocate disabled_regsets. - -2008-04-14 Daniel Jacobowitz - - * Makefile.in (LIBOBJS): New. - (OBS): Use LIBOBJS. - (memmem.o): New rule. - * configure.ac: Use AC_CONFIG_LIBOBJ_DIR and check for memmem. - * configure: Regenerated. - -2008-04-04 Ulrich Weigand - - * server.c (handle_query): Never return "unsupported" for - qXfer:features:read queries. - -2008-03-27 Ulrich Weigand - - * server.c (get_features_xml): Fix inverted condition. - (handle_query): Always support qXfer:feature:read. - -2008-03-10 Daniel Jacobowitz - - * server.c (wrapper_argv): New. - (start_inferior): Handle wrapper_argv. If set, expect an extra - trap. - (gdbserver_usage): Document --wrapper. - (main): Parse --wrapper. - -2008-02-28 Ulrich Weigand - - * configure.srv [powerpc64-*-linux*]: Add all files mentioned for - powerpc-*-linux* to srv_regobj and reg_xmlfiles. - * linux-ppc-low.c (ppc_get_pc): Support bi-arch operation. - (ppc_set_pc): Likewise. - (ppc_arch_setup): New function. - (ppc_fill_gregset): Call ppc_collect_ptrace_register instead - of collect_register. - (the_low_target): Use ppc_arch_setup as arch_setup initializer. - -2008-02-28 Ulrich Weigand - - * configure.srv [powerpc64-*-linux*]: Use linux-ppc-low.o - instead of linux-ppc64-low.o. - * linux-ppc64-low.c: Remove file. - * Makefile.in (SFILES): Remove linux-ppc64-low.c. - (linux-ppc64-low.o): Remove rule. - - * linux-ppc-low.c (init_registers_ppc64): Add prototype. - (init_registers_powerpc_64): Likewise. - (ppc_regmap): Conditionally define depending on __powerpc64__. - (ppc_cannot_store_register): Do not special-case "fpscr" when - compiled on __powerpc64__. - (ppc_collect_ptrace_register): New function. - (ppc_supply_ptrace_register): New function. - (ppc_breakpoint): Change type to "unsigned int". - (ppc_breakpoint_at): Change type of "insn" to "unsigned int". - (the_low_target): Conditionally provide initializers for the - arch_setup member depending on __powerpc64__. Install - collect_ptrace_register and supply_ptrace_register members. - -2008-02-28 Ulrich Weigand - - * regcache.h (gdbserver_xmltarget): Add extern declaration. - * server.c (gdbserver_xmltarget): Define. - (get_features_xml): Use it to replace "target.xml" and arch_string. - - * configure.srv: Remove srv_xmltarget. Add XML files that were - mentioned there to srv_xmlfiles instead. Remove conditional tests - on gdb_cv_arm_iwmmxt, gdb_cv_ppc_altivec, gdb_cv_ppc_spe; set - srv_xmlfiles and srv_regobj to include all possible choices. - * configure.ac (srv_xmltarget): Remove. - (srv_xmlfiles): Do not add "target.xml". - (gdb_cv_arm_iwmmxt, gdb_cv_ppc_altivec, gdb_cv_ppc_spe): Remove - checks for supplementary target information. - * configure: Regenerate. - * Makefile.in (XML_TARGET): Remove. - (target.xml): Remove rule. - (clean): Do not clean up target.xml. - (.PRECIOUS): Do not mention target.xml. - - * target.h (struct target_ops): Remove arch_string member. - * linux-low.c (linux_arch_string): Remove. - (linux_target_ops): Remove arch_string initializer. - * linux-low.h (struct linux_target_ops): Remove arch_string member. - * linux-i386-low.c (the_low_target): Remove arch_string initializer. - * linux-x86-64-low.c (the_low_target): Remove arch_string initializer. - * spu-low.c (spu_arch_string): Remove. - (spu_target_ops): Remove arch_string initializer. - * win32-low.c (win32_arch_string): Remove. - (win32_target_ops): Remove arch_string initializer. - * win32-low.h (struct win32_target_ops): Remove arch_string member. - * win32-arm-low.c (the_low_target): Remove arch_string initializer. - * win32-i368-low.c (the_low_target): Remove arch_string initializer. - -2008-02-27 Ulrich Weigand - - * linux-low.h (struct linux_target_ops): Replace left_pad_xfer field - by collect_ptrace_register and supply_ptrace_register hooks. - * linux-low.c (fetch_register): Use supply_ptrace_register callback - instead of checking for the_low_target.left_pad_xfer. - (usr_store_inferior_registers): Use collect_ptrace_register callback - instead of checking for the_low_target.left_pad_xfer. - - * linux-s390-low.c (s390_collect_ptrace_register): New function. - (s390_supply_ptrace_register): Likewise. - (s390_fill_gregset): Call s390_collect_ptrace_register. - (the_low_target): Update. - - * linux-ppc64-low.c (ppc_collect_ptrace_register): New function. - (ppc_supply_ptrace_register): Likewise. - (the_low_target): Update. - - * linux-i386-low.c (the_low_target): Update. - * linux-x86-64-low.c (the_low_target): Update. - -2008-02-27 Ulrich Weigand - - * configure.srv [s390x-*-linux*]: Set srv_regobj to include both - reg-s390.o and reg-s390x.o. - - * linux-low.c (new_inferior): New global variable. - (linux_create_inferior, linux_attach): Set it. - (linux_wait_for_process): Call the_low_target.arch_setup after the - target has stopped for the first time. - (initialize_low): Do not call the_low_target.arch_setup. - - * linux-s390-low.c (s390_get_pc): Support bi-arch operation. - (s390_set_pc): Likewise. - (s390_arch_setup): New function. - (the_low_target): Use s390_arch_setup as arch_setup routine. - - * regcache.c (realloc_register_cache): New function. - (set_register_cache): Call it for each existing regcache. - -2008-02-27 Ulrich Weigand - - * server.h (init_registers): Remove prototype. - - * linux-low.h (struct linux_target_ops): Add arch_setup field. - * linux-low.c (initialize_low): Call the_low_target.arch_setup () - instead of init_registers (). - * linux-arm-low.c (init_registers_arm): Add prototype. - (init_registers_arm_with_iwmmxt): Likewise. - (the_low_target): Add initializer for arch_setup field. - * linux-cris-low.c (init_registers_cris): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-crisv32-low.c (init_registers_crisv32): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-i386-low.c (init_registers_i386_linux): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-ia64-low.c (init_registers_ia64): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-m32r-low.c (init_registers_m32r): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-m68k-low.c (init_registers_m68k): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-mips-low.c (init_registers_mips_linux): Add prototype. - (init_registers_mips64_linux): Likewise. - (the_low_target): Add initializer for arch_setup field. - * linux-ppc-low.c (init_registers_ppc): Add prototype. - (init_registers_powerpc_32, init_registers_powerpc_e500): Likewise. - (the_low_target): Add initializer for arch_setup field. - * linux-ppc64-low.c (init_registers_ppc64): Add prototype. - (init_registers_powerpc_64): Likewise. - (the_low_target): Add initializer for arch_setup field. - * linux-s390-low.c (init_registers_s390): Add prototype. - (init_registers_s390x): Likewise. - (the_low_target): Add initializer for arch_setup field. - * linux-sh-low.c (init_registers_sh): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-x86-64-low.c (init_registers_x86_64_linux): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * linux-xtensa-low.c (init_registers_xtensa): Add prototype. - (the_low_target): Add initializer for arch_setup field. - - * win32-low.h (struct win32_target_ops): Add arch_setup field. - * win32-low.c (initialize_low): Call the_low_target.arch_setup () - instead of init_registers (). - * win32-arm-low.c (init_registers_arm): Add prototype. - (the_low_target): Add initializer for arch_setup field. - * win32-i386-low.c (init_registers_i386): Add prototype. - (the_low_target): Add initializer for arch_setup field. - - * spu-low.c (init_registers_spu): Add prototype. - (initialize_low): Call initialie_registers_spu () instead of - initialize_registers (). - -2008-02-19 Pedro Alves - - * server.c (handle_v_requests): When handling the vRun and vAttach - packets, if already debugging a process, don't kill it. Return an - error instead. - -2008-02-17 Daniel Jacobowitz - - * server.c (handle_query): Correct length check. - -2008-02-14 Pedro Alves - - * win32-low.c (do_initial_child_stuff): Add process handle - parameter. Set current_process_handle and current_process_id from the - parameters. Clear globals. - (win32_create_inferior): Don't set current_process_handle and - current_process_id here. Instead pass them on the call to - do_initial_child_stuff. - (win32_attach): Likewise. - (win32_clear_inferiors): New. - (win32_kill): Don't close the current process handle or the - current thread handle here. Instead call win32_clear_inferiors. - (win32_detach): Don't open a new handle to the process. Call - win32_clear_inferiors. - (win32_join): Don't rely on current_process_handle; open a new - handle using the process id. - (win32_wait): Call win32_clear_inferiors when the inferior process - has exited. - -2008-02-14 Daniel Jacobowitz - - * server.c (monitor_show_help): Add "exit". - -2008-02-11 Maxim Grigoriev - - * Makefile.in (SFILES): Add linux-xtensa-low.c. - (clean): Add reg-xtensa.c. - (linux-xtensa-low.o, reg-xtensa.o, reg-xtensa.c): New dependencies. - * configure.srv (xtensa*-*-linux*) New target. - * linux-xtensa-low.c: New. - * xtensa-xtregs.c: New. - -2008-02-01 Pedro Alves - - * hostio.c: Don't include errno.h. - (errno_to_fileio_errno): Move to hostio-errno. - * hostio.c: (hostio_error): Remove the error parameter. Defer the - error number outputting to the target->hostio_last_error callback. - (hostio_packet_error): Use FILEIO_EINVAL directly. - (handle_open, handle_pread, hostio_error, handle_unlink): Update - calls to hostio_error. - * hostio-errno.c: New. - * server.h (hostio_last_error_from_errno): Declare. - * target.h (target_ops): Add hostio_last_error member. - * linux-low.c (linux_target_op): Register hostio_last_error_from_errno - as hostio_last_error handler. - * spu-low.c (spu_target_ops): Likewise. - * win32-low.c [_WIN32_WCE] (win32_error_to_fileio_error) - (wince_hostio_last_error): New functions. - (win32_target_ops) [_WIN32_WCE]: Register wince_hostio_last_error - as hostio_last_error handler. - (win32_target_ops) [!_WIN32_WCE]: Register - hostio_last_error_from_errno as hostio_last_error handler. - * Makefile.in (SFILES): Add hostio.c and hostio-errno.c. - (hostio-errno.o): New rule. - * configure.ac (GDBSERVER_DEPFILES): Add $srv_hostio_err_objs. - * configure.srv (srv_hostio_err_objs): New variable. Default to - hostio-errno.o. - (arm*-*-mingw32ce*): Set srv_hostio_err_objs to "". - * configure: Regenerate. - -2008-01-29 Daniel Jacobowitz - - * linux-low.c (linux_attach_lwp): Do not _exit after errors. - (linux_kill, linux_detach): Clean up the process list. - * remote-utils.c (remote_open): Improve port number parsing. - (putpkt_binary, input_interrupt): Only send interrupts if the target - is running. - * server.c (extended_protocol): Make static. - (attached): Define earlier. - (exit_requested, response_needed, program_argv): New variables. - (target_running): New. - (start_inferior): Clear attached here. - (attach_inferior): Set attached here. - (require_running): Define. - (handle_query): Use require_running and target_running. Implement - "monitor exit". - (handle_v_attach, handle_v_run): New. - (handle_v_requests): Use require_running. Handle vAttach and vRun. - (gdbserver_usage): Update. - (main): Redo argument parsing. Handle --debug and --multi. Handle - --attach along with other options or after the port. Save - program_argv. Support no initial program. Resynchronize - communication with GDB after an error. Handle "monitor exit". - Use require_running and target_running. Always allow the extended - protocol. Do not error out for Hc0 or Hc-1. Do not automatically - restart in extended mode. - * README: Refer to the GDB manual. Update --attach usage. - -2007-12-20 Andreas Schwab - - * linux-low.c (STACK_SIZE): Define. - (linux_tracefork_child): Use it. Use __clone2 on ia64. - (linux_test_for_tracefork): Likewise. - -2007-12-18 Daniel Jacobowitz - - * linux-low.c (linux_wait_for_event): Update messages. Do not - reinsert auto-delete breakpoints. - * mem-break.c (struct breakpoint): Change return type of handler to - int. - (set_breakpoint_at): Update handler type. - (reinsert_breakpoint_handler): Return 1 instead of calling - delete_breakpoint. - (reinsert_breakpoint_by_bp): Check for the original breakpoint before - setting a new one. - (check_breakpoints): Delete auto-delete breakpoints and return 2. - * mem-break.h (set_breakpoint_at): Update handler type. - * thread-db.c (thread_db_create_event, thread_db_create_event): Update. - * win32-low.c (auto_delete_breakpoint): New. - (get_child_debug_event): Use it. - -2007-12-16 Daniel Jacobowitz - - * configure.ac: Check for pread and pwrite. - * hostio.c (handle_pread): Fall back to lseek and read. - (handle_pwrite): Fall back to lseek and write. - * config.in, configure: Regenerated. - -2007-12-07 Daniel Jacobowitz - - * server.c (myresume): Add own_buf argument. - (main): Update calls. - -2007-12-06 Daniel Jacobowitz - - * linux-low.c (linux_wait, linux_resume): Do not handle async I/O. - * remote-utils.c (remote_open): Do not call disable_async_io. - (block_async_io): Delete. - (unblock_async_io): Make static. - (initialize_async_io): New. - * server.c (handle_v_cont): Handle async I/O here. - (myresume): Likewise. Move other common resume tasks here... - (main): ... from here. Call initialize_async_io. Disable async - I/O before the main loop. - * server.h (initialize_async_io): Declare. - (block_async_io, unblock_async_io): Delete prototypes. - * spu-low.c (spu_resume, spu_wait): Do not handle async I/O here. - -2007-12-06 Mick Davis - - * remote-utils.c (readchar): Allow binary data in received messages. - -2007-12-03 Pedro Alves - - * win32-low.c (attaching): New global. - (win32_create_inferior): Clear the `attaching' global. - (win32_attach): Set the `attaching' global. - (get_child_debug_event) [_WIN32_WCE]: Stop the inferior when - attaching. Only set a breakpoint at the entry point if not - attaching. - -2007-12-03 Pedro Alves - - * server.c (main): Don't report dll events on the initial - connection on attaches. - -2007-12-03 Pedro Alves - - * server.c (main): Relax numerical bases supported for the pid of - the --attach command line argument. - -2007-12-03 Pedro Alves - - * win32-low.c (win32_attach): Call OpenProcess before - DebugActiveProcess, not after. Add last error output to error - call. - -2007-12-03 Pedro Alves - - * win32-low.c (win32_get_thread_context) - (win32_set_thread_context): New functions. - (thread_rec): Use win32_get_thread_context. - (continue_one_thread, win32_resume): Use win32_set_thread_context. - * win32-low.h (win32_thread_info) [_WIN32_WCE]: Add `base_context' - field. - -2007-12-03 Leo Zayas - Pedro Alves - - * win32-low.c (soft_interrupt_requested, faked_breakpoint): New - global variables. - (child_add_thread): Minor cleanup. - (child_continue): Resume artificially suspended threads before - calling ContinueDebugEvent. - (suspend_one_thread): New. - (fake_breakpoint_event): New. - (get_child_debug_event): Change return type to int. Check here if - gdb sent an interrupt request. If a soft interrupt was requested, - fake a breakpoint event. Return 0 if there is no event to handle, - and 1 otherwise. - (win32_wait): Don't check here if gdb sent an interrupt request. - Ensure there is a valid event to handle. - (win32_request_interrupt): Add soft interruption method as last - resort. - -2007-12-03 Leo Zayas - Pedro Alves - - * win32-low.h (win32_thread_info): Add descriptions to the - structure members. Replace `suspend_count' counter by a - `suspended' flag. - * win32-low.c (thread_rec): Update condition of when to get the - context from the inferior. Rely on ContextFlags being set if it - has already been retrieved. Only suspend the inferior thread if - we haven't already. Warn if that fails. - (continue_one_thread): s/suspend_count/suspended/. Only call - ResumeThread once. Warn if that fails. - -2007-12-02 Pedro Alves - - * win32-low.c (win32_wait): Don't read from the inferior when it - has already exited. - -2007-12-02 Pedro Alves - - * Makefile.in (win32_low_h): New variable. - (win32-low.o): Add dependency on $(win32_low_h). - (win32-arm-low.o, win32-i386-low.o): New rules. - -2007-11-30 Daniel Jacobowitz - - * hostio.c: Correct copyright year. - -2007-11-30 Daniel Jacobowitz - - * Makefile.in (OBS): Add hostio.o. - (hostio.o): New rule. - * server.h (handle_vFile): Declare. - * hostio.c: New file. - * server.c (handle_v_requests): Take packet_len and new_packet_len - for binary packets. Call handle_vFile. - (main): Update call to handle_v_requests. - -2007-11-05 Daniel Jacobowitz - - * linux-low.c: Include . - -2007-11-01 Daniel Jacobowitz - - * linux-low.c (linux_tracefork_grandchild): New. - (linux_tracefork_child): Use clone. - (linux_test_for_tracefork): Use clone; allocate and free a stack. - -2007-10-31 Joel Brobecker - - * Makefile.in: Use $(SHELL) instead of "sh" to call regdat.sh. - -2007-10-24 Daniel Jacobowitz - - * linux-low.c (handle_extended_wait): Handle unexpected signals. - -2007-10-23 Daniel Jacobowitz - - * inferiors.c (change_inferior_id): Delete. - (add_pid_to_list, pull_pid_from_list): New. - * linux-low.c (PTRACE_SETOPTIONS, PTRACE_GETEVENTMSG) - (PTRACE_O_TRACESYSGOOD, PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) - (PTRACE_O_TRACECLONE, PTRACE_O_TRACEEXEC, PTRACE_O_TRACEVFORKDONE) - (PTRACE_O_TRACEEXIT, PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK) - (PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC, PTRACE_EVENT_VFORK_DONE) - (PTRACE_EVENT_EXIT, __WALL): Provide default definitions. - (stopped_pids, thread_db_active, must_set_ptrace_flags): New variables. - (using_threads): Always set to 1. - (handle_extended_wait): New. - (add_process): Do not set TID. - (linux_create_inferior): Set must_set_ptrace_flags. - (linux_attach_lwp): Remove TID argument. Do not check using_threads. - Use PTRACE_SETOPTIONS. Call new_thread_notify. Update all callers. - (linux_thread_alive): Rename TID argument to LWPID. - (linux_wait_for_process): Handle unknown processes. Do not use TID. - (linux_wait_for_event): Do not use TID or check using_threads. Update - call to dead_thread_notify. Call handle_extended_wait. - (linux_create_inferior): Use PTRACE_SETOPTIONS. - (send_sigstop): Delete sigstop_sent. - (wait_for_sigstop): Avoid TID. - (linux_supports_tracefork_flag, linux_tracefork_child, my_waitpid) - (linux_test_for_tracefork): New. - (linux_lookup_signals): Use thread_db_active and - linux_supports_tracefork_flag. - (initialize_low): Use thread_db_active and linux_test_for_tracefork. - * linux-low.h (get_process_thread): Avoid TID. - (struct process_ifo): Move thread_known and tid to the end. Remove - sigstop_sent. - (linux_attach_lwp, thread_db_init): Update prototypes. - * server.h (change_inferior_id): Delete prototype. - (add_pid_to_list, pull_pid_from_list): New prototypes. - * thread-db.c (thread_db_use_events): New. - (find_first_thread): Rename to... - (find_one_thread): ...this. Update callers and messages. Do not - call fatal. Check thread_db_use_events. Do not call - change_inferior_id or new_thread_notify. - (maybe_attach_thread): Update. Do not call new_thread_notify. - (thread_db_init): Set thread_db_use_events. Check use_events. - * utils.c (fatal, warning): Correct message prefix. - -2007-10-15 Daniel Jacobowitz - - * Makefile.in (clean): Remove new files. - (powerpc-32.o, powerpc-32.c, powerpc-e500.o, powerpc-e500.c) - (powerpc-64.o, powerpc-64.c): New rules. - * configure.srv: Use alternate register sets for powerpc64-*-linux* - with AltiVec, powerpc-*-linux* with AltiVec, and powerpc-*-linux* - with SPE. - * linux-ppc-low.c (ppc_regmap): Do not fetch the FP registers for - SPE targets. - (ppc_cannot_store_register): Do not check for FPSCR for SPE targets. - (PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS, ppc_fill_vrregset) - (ppc_store_vrregset, PTRACE_GETEVRREGS, PTRACE_SETEVRREGS) - (struct gdb_evrregset_t, ppc_fill_evrregset, ppc_store_evrregset): New. - (target_regsets): Add AltiVec and SPE register sets. - * configure.ac: Check for AltiVec and SPE. - * linux-ppc64-low.c (PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS) - (ppc_fill_vrregset, ppc_store_vrregset): New. - (target_regsets): Add AltiVec register set. - * configure: Regenerated. - -2007-09-19 Daniel Jacobowitz - - * linux-low.c (O_LARGEFILE): Define. - (linux_read_memory): Use /proc/PID/mem. - * configure.ac: Use AC_GNU_SOURCE. Check for pread64. - * configure, config.in: Regenerated. - -2007-09-04 Daniel Jacobowitz - - * linux-low.c (linux_wait_for_event): Do not pass signals while - single-stepping. - -2007-09-03 Pedro Alves - - * win32-low.c (create_process): New. - (win32_create_inferior): Use create_process instead of - CreateProcess. If create_process failed retry appending an ".exe" - suffix. Store the GetLastError result immediatelly after - create_process calls and use it on the call to error. - -2007-09-03 Pedro Alves - - * win32-low.c (handle_load_dll): Don't use toolhelp when waiting. - -2007-08-23 Joel Brobecker - - * configure.ac: Switch license to GPLv3. - -2007-08-01 Michael Snyder - - * remote-utils.c (putpkt_binary): Memory leak, free buf2. - -2007-07-31 Pedro Alves - - * win32-low.c (winapi_CloseToolhelp32Snapshot) [_WIN32_WCE]: New - typedef. - (win32_CloseToolhelp32Snapshot) [_WIN32_WCE]: New global var. - (load_toolhelp) [_WIN32_WCE]: Load TOOLHELP.DLL. Get - CloseToolhelp32Snapshot. - (toolhelp_get_dll_name) [_WIN32_WCE]: Close the snapshot with - CloseToolhelp32Snapshot. - -2007-07-27 Michael Snyder - - * server.c (main): Check for inferior exit before main loop. - -2007-07-18 Pedro Alves - - * remote-utils.c (remote_open): Set SO_KEEPALIVE on remote_desc - instead of on tmp_desc. - -2007-07-17 Pedro Alves - Daniel Jacobowitz - - * inferiors.c (all_dlls, dlls_changed, get_dll): New. - (add_thread): Minor cleanups. - (clear_inferiors): Move lower in the file. Clear the DLL - list. - (free_one_dll, match_dll, loaded_dll, unloaded_dll, clear_list): New. - * remote-utils.c (prepare_resume_reply): Check dlls_changed. - (xml_escape_text): New. - * server.c (handle_query): Handle qXfer:libraries:read. Report it - for qSupported. - (handle_v_cont): Report errors. - (gdbserver_version): Update. - (main): Correct size of own_buf. Do not report initial DLL events. - * server.h (struct dll_info, all_dlls, dlls_changed, loaded_dll) - (unloaded_dll, xml_escape_text): New. - * win32-low.c (enum target_waitkind): Update comments. - (win32_add_one_solib, get_image_name, winapi_EnumProcessModules) - (winapi_GetModuleInformation, winapi_GetModuleFileNameExA) - (win32_EnumProcessModules, win32_GetModuleInformation) - (win32_GetModuleFileNameExA, load_psapi, psapi_get_dll_name) - (winapi_CreateToolhelp32Snapshot, winapi_Module32First) - (winapi_Module32Next, win32_CreateToolhelp32Snapshot) - (win32_Module32First, win32_Module32Next, load_toolhelp) - (toolhelp_get_dll_name, handle_load_dll, handle_unload_dll): New. - (get_child_debug_event): Handle DLL events. - (win32_wait): Likewise. - -2007-07-12 Daniel Jacobowitz - - * configure.srv: Set srv_linux_regsets for sh*-*-linux*. - * linux-sh-low.c (sh_fill_gregset, target_regsets): New. - -2007-07-08 Pedro Alves - - * win32-low.c (handle_output_debug_string): Ignore event if not - waiting. - -2007-07-08 Pedro Alves - - * win32-arm-low.c (arm_wince_breakpoint): Fix typo. - -2007-07-03 Daniel Jacobowitz - - * remote-utils.c (look_up_one_symbol): Handle 'm' packets. - -2007-07-02 Daniel Jacobowitz - - * inferiors.c (change_inferior_id): Add comment. - * linux-low.c (check_removed_breakpoint): Add an early - prototype. Improve debug output. - (linux_attach): Doc update. - (linux_detach_one_process, linux_detach): Clean up before releasing - each process. - (send_sigstop, wait_for_sigstop): Improve comments and debug output. - * linux-low.h (struct process_info): Doc improvement. - * mem-break.c (delete_all_breakpoints): New. - * mem-break.h (delete_all_breakpoints): New prototype. - * thread-db.c (find_first_thread): New. - (thread_db_create_event): Call it instead of - thread_db_find_new_threads. Clean up unused variables. - (maybe_attach_thread): Remove first thread handling. - (thread_db_find_new_threads): Use find_first_thread. - (thread_db_get_tls_address): Likewise. - -2007-06-27 Daniel Jacobowitz - - * thread-db.c (thread_db_find_new_threads): Add prototype. - (thread_db_create_event): Check for the main thread before adding - a new thread. - (maybe_attach_thread): Only enable event reporting if TID == 0. - (thread_db_get_tls_address): Check for new threads. - -2007-06-20 Daniel Jacobowitz - - * linux-low.c (linux_create_inferior): Try execv before execvp. - * spu-low.c (spu_create_inferior): Likewise. - -2007-06-13 Mike Frysinger - - * linux-low.c (linux_create_inferior): Change execv to execvp. - * spu-low.c (spu_create_inferior): Likewies. - -2007-06-13 Daniel Jacobowitz - - * Makefile.in (clean): Clean new files instead of deleted ones. - (reg-mips.o, reg-mips.c, reg-mips64.o, reg-mips64.c): Delete. - (mips-linux.o, mips-linux.c, mips64-linux.o, mips64-linux.c): New - rules. - * configure.srv: Specify XML files and new regformats for MIPS and - MIPS64 GNU/Linux. - * linux-mips-low.c (mips_num_regs): Set to only used registers. - (mips_regmap): Do not fetch $0. Remove unused registers. Add - an entry for the restart register. - (mips_cannot_fetch_register, mips_cannot_store_register) - (mips_reinsert_addr, mips_fill_fpregset, mips_store_fpregset): Update - register names to match the XML descriptions. - (mips_fill_gregset, mips_store_gregset): Likewise. Handle the - restart register instead of $0. - -2007-06-12 Ulrich Weigand - Markus Deuling - - * remote-utils.c (decode_xfer_write): New function. - * server.h (decode_xfer_write): Add prototype. - * server.c (handle_query): Add PACKET_LEN argument. Support - qXfer:spu:read and qXfer:spu:write packets. - (main): Pass packet_len to handle_query. - * spu-low.c (spu_target_ops): Add spu_proc_xfer_spu. - * target.h (target_ops): Add qxfer_spu. - -2007-06-12 Ulrich Weigand - - * spu-low.c (spu_proc_xfer_spu): Do not return failure when - accessing non-seekable spufs files. - -2007-05-16 Markus Deuling - - * server.c (handle_query): Add reply for qC packet. - -2007-05-10 Pedro Alves - Leo Zayas - - * server.h (check_remote_input_interrupt_request): New function. - * remote_utils.c (INVALID_DESCRIPTOR): New define. - (remote_desc): Initialize with INVALID_DESCRIPTOR. - (input_interrupt): Expose on USE_WIN32API too. Fix whitespace. - (check_remote_input_interrupt_request): New function. - * server.h (check_remote_input_interrupt_request): Declare. - * win32-low.c (winapi_DebugBreakProcess, - winapi_GenerateConsoleCtrlEvent): New typedefs. - (get_child_debug_event): Lower Win32 debug event polling from 1 sec - to 250 ms. - (win32_wait): Check for remote interrupt request - with check_remote_input_interrupt_request. - (win32_request_interrupt): New function. - (win32_target_op): Set request_interrupt to win32_request_interrupt. - -2007-05-10 Pedro Alves - - * win32-low.c (debug_registers_changed, - debug_registers_used, CONTEXT_EXTENDED_REGISTERS, - CONTEXT_FLOATING_POINT, CONTEXT_DEBUG_REGISTERS, - CONTEXT_DEBUGGER, CONTEXT_DEBUGGER_DR): Delete. - (thread_rec): Get context using the low target. - (child_add_thread): Call thread_added on the low target, - which does the same thing. - (regptr): Delete. - (do_initial_child_stuff): Remove debug registers references. - Set context using the low target. Resume threads after - setting the contexts. - (child_continue): Remove dead variable. Remove debug - registers references. - (child_fetch_inferior_registers): Go through the low target. - (do_child_store_inferior_registers): Remove. - (child_store_inferior_registers): Go through the low target. - (win32_resume): Remove debug registers references. - Set context using the low target. - (handle_exception): Change return type to void. Don't record - context here. Set status to TARGET_WAITKIND_SPURIOUS on a - first chance exception. - (get_child_debug_event): Change return type to void. Remove - goto loop. Always return after waiting for debug event. - (win32_wait): Convert to switch statement. Handle spurious - events. - - * win32-i386-low.c (debug_registers_changed, - debug_registers_used): New. - (initial_stuff): Rename to ... - (i386_initial_stuff): ... this. Clear debug registers - state variables. - (store_debug_registers): Delete. - (i386_get_thread_context): New. - (load_debug_registers): Delete. - (i386_set_thread_context): New. - (i386_thread_added): New. - (single_step): Rename to ... - (i386_single_step): ... this. - (do_fetch_inferior_registers): Rename to ... - (i386_fetch_inferior_register): ... this. - (i386_store_inferior_register): New. - (the_low_target): Adapt to new interface. - - * win32-arm-low.c (CONTEXT_FLOATING_POINT): Define. - (arm_get_thread_context): New. - (arm_set_thread_context): New. - (regptr): New. - (do_fetch_inferior_registers): Rename to ... - (arm_fetch_inferior_register): ... this. - (arm_store_inferior_register): New. - (arm_wince_breakpoint): Reimplement as unsigned long. - (arm_wince_breakpoint_len): Define. - (the_low_target): Adapt to new interface. - - * win32-low.h (target_ops): Remove regmap, store_debug_registers and - load_debug_registers. Add get_thread_context, set_thread_context, - thread_added and store_inferior_register. Rename - fetch_inferior_registers to fetch_inferior_register. - (regptr): Remove declaration. - -2007-05-10 Pedro Alves - - * linux-low.c (linux_detach): Change return type to int. Return 0. - * spu-low.c (spu_detach): Likewise. - -2007-05-10 Pedro Alves - - * target.h (target_ops): Change return type of detach to int. - Add join. - (join_inferior): New. - * server.c (main): Don't skip detach support on mingw32. - If the inferior doesn't support detaching return error. - Call join_inferior instead of using waitpid. - * linux-low.c (linux_join): New. - (linux_target_op): Add linux_join. - * spu-low.c (spu_join): New. - (spu_target_ops): Add spu_join. - * win32-low.c (win32_detach): Adapt to new interface. - Reopen current_process_handle before detaching. Issue a child - resume before detaching. - (win32_join): New. - (win32_target_op): Add win32_join. - -2007-05-10 Pedro Alves - - * win32-low.c (win32-attach): Fix return value. - * target.h (target_ops): Describe ATTACH return values. - -2007-05-10 Pedro Alves - - * win32-low.c (GETPROCADDRESS): Define. - (winapi_DebugActiveProcessStop): Add WINAPI. typedef as pointer. - (winapi_DebugSetProcessKillOnExit): Likewise. - (win32_create_inferior): Force usage of ansi CreateProcessA. - (win32_attach): Use GETPROCADDRESS. - (win32_detach): Likewise. - -2007-05-10 Pedro Alves - - * win32-low.c (win32_wait): Don't use WSTOPSIG. - -2007-03-30 Pedro Alves - - * win32-low.c: Commit leftover changes from 2007-03-29. - -2007-03-30 Daniel Jacobowitz - - * i387-fp.c (struct i387_fsave, struct i387_fxsave): Make 16-bit - fields short instead of int. Add explicit padding. - (i387_cache_to_fsave): Remove unnecessary casts. - (i387_fsave_to_cache): Doc fix. - (i387_cache_to_fxsave): Remove unnecessary casts and masking. - -2007-03-30 Daniel Jacobowitz - - * i387-fp.c (i387_cache_to_fxsave): Reinitialize val2 before use. - (i387_fxsave_to_cache): Check fp->ftag while building ftag value. - -2007-03-29 Pedro Alves - - * configure.srv (arm*-*-mingw32ce*): Move near the other - arm targets. - -2007-03-29 Pedro Alves - - * configure.ac: Add errno checking. - (AC_CHECK_HEADERS): Add errno.h, fcntl.h, signal.h, - sys/file.h and malloc.h. - (AC_CHECK_DECLS): Add perror. - (srv_mingwce): Handle. - * configure.srv (i[34567]86-*-cygwin*): Add - win32-i386-low.o to srv_tgtobj. - (i[34567]86-*-mingw*): Likewise. - (arm*-*-mingw32ce*): Add case. - * gdbreplay.c [HAVE_SYS_FILE_H, HAVE_SIGNAL_H, - HAVE_FCNTL_H, HAVE_ERRNO_H, HAVE_MALLOC_H]: Check. - [__MINGW32CE__] (strerror): New function. - [__MINGW32CE__] (errno): Define to GetLastError. - [__MINGW32CE__] (COUNTOF): New macro. - (remote_open): Remove extra close call. - * mem-break.c (delete_breakpoint_at): New function. - * mem-break.h (delete_breakpoint_at): Declare. - * remote-utils.c [HAVE_SYS_FILE_H, HAVE_SIGNAL_H, - HAVE_FCNTL_H, HAVE_UNISTD_H, HAVE_ERRNO_H]: Check. - [USE_WIN32API] (read, write): Add char* casts. - * server.c [HAVE_UNISTD_H, HAVE_SIGNAL_H]: Check. - * server.h: Include wincecompat.h on Windows CE. - [HAVE_ERRNO_H]: Check. - (perror): Declare if not declared. - * utils.c: Add stdlib.h, errno.h and malloc.h includes. - (perror_with_name): Remove errno declaration. - * wincecompat.h: New. - * wincecompat.c: New. - * win32-low.h: New. - * win32-arm-low.c: New. - * win32-i386-low.c: New. - (win32-low.c): Include mem-break.h and win32-low.h, and winnt.h. - (OUTMSG2): Make it safe. - (_T): New macro. - (COUNTOF): New macro. - (NUM_REGS): Get it from the low target. - (CONTEXT_EXTENDED_REGISTERS, CONTEXT_FLOATING_POINT, - CONTEXT_DEBUG_REGISTERS): Add fallbacks to 0. - (thread_rec): Let low target handle debug registers. - (child_add_thread): Likewise. - (child_init_thread_list): Likewise. - (continue_one_thread): Likewise. - (regptr): New. - (do_child_fetch_inferior_registers): Move to ... - * win32-i386-low.c: ... here, and rename to ... - (do_fetch_inferior_registers): ... this. - * win32-low.c (child_fetch_inferior_registers): - Go through the low target. - (do_child_store_inferior_registers): Use regptr. - (strwinerror): New function. - (win32_create_inferior): Handle Windows CE. - Use strwinerror instead of strerror on Windows error - codes. Add program to the error output. - Don't close the main thread handle on Windows CE. - (win32_attach): Use coredll.dll on Windows CE. - (win32_kill): Close current process and current - thread handles. - (win32_detach): Use coredll.dll on Windows CE. - (win32_resume): Let low target handle debug registers, and - step request. - (handle_exception): Add/Remove initial breakpoint. Avoid - non-existant WSTOPSIG on Windows CE. - (win32_read_inferior_memory): Cast to remove warning. - (win32_arch_string): Go through the low target. - (initialize_low): Call set_breakpoint_data with the low - target's breakpoint. - * win32-low.c (dr, FLAG_TRACE_BIT, FCS_REGNUM, - FOP_REGNUM, mappings): Move to ... - * win32-i386-low.c: ... here. - * win32-low.c (win32_thread_info): Move to ... - * win32-low.h: ... here. - * Makefile.in (SFILES): Add win32-low.c, win32-i386-low.c, - win32-arm-low.c and wincecompat.c. - (all:): Add $EXEEXT. - (install-only:): Likewise. - (gdbserver:): Likewise. - (gdbreplay:): Likewise. - * config.in: Regenerate. - * configure: Regenerate. - -2007-03-28 Pedro Alves - - * win32-low.c: Rename typedef thread_info to - win32_thread_info throughout. - -2007-03-28 Pedro Alves - - * win32-i386-low.c: Rename to ... - * win32-low.c: ... this. - * configure.srv: Replace win32-i386-low.o with win32-low.o. - * Makefile.in: Likewise. - -2007-03-27 Pedro Alves - - * remote-utils.c (monitor_output): Constify msg parameter. - * server.h (monitor_output): Likewise. - * win32-i386-low.c (handle_output_debug_string): New. - (win32_kill): Handle OUTPUT_DEBUG_STRING_EVENT events using - handle_output_debug_string. - (get_child_debug_event): Likewise. - -2007-03-27 Mat Hostetter - - * server.c (main): Correct strtoul check. - -2007-03-27 Jon Ringle - - * linux-low.c: Check __ARCH_HAS_MMU__ also. - -2007-03-27 Brooks Moses - - * Makefile.in: Add dummy "pdf" and "install-pdf" targets. - -2007-02-27 Daniel Jacobowitz - - * terminal.h: Check HAVE_SGTTY_H. - -2007-02-27 Mat Hostetter - - * remote-utils.c (remote_open): Print out the assigned port number. - -2007-02-26 Daniel Jacobowitz - - * remote-utils.c (monitor_output): New function. - * server.c (debug_threads): Define here. - (monitor_show_help): New function. - (handle_query): Handle qRcmd. - (main): Do not handle 'd' packet. - * server.h (debug_threads, remote_debug, monitor_output): Declare. - * linux-low.c, spu-low.c, win32-i386-low.c: Remove definitions - of debug_threads. - -2007-02-25 Pedro Alves - - * Makefile.in (EXEEXT): New. - (clean): Use $(EXEEXT). - -2007-02-25 Pedro Alves - - * target.h (target_ops): Rename send_signal to request_interrupt, - and remove enum target_signal parameter. - * linux-low.c (linux_request_interrupt): Rename from - linux_send_signal, and always send SIGINT. - * spu-low.c (spu_request_interrupt): Rename from spu_send_signal, - and always send SIGINT. - * remote-utils.c (putpkt_binary): Call request_interrupt, instead - of send_signal. - (input_interrupt): Likewise. - -2007-02-25 Pedro Alves - - * server.c (get_features_xml): Check if target implemented - arch_string. - * win32-i386-low.c (win32_arch_string): New. - (win32_target_ops): Add win32_arch_string as arch_string member. - -2007-02-22 Markus Deuling - - * spu-low.c (spu_arch_string): New. - (spu_target_ops): Add spu_arch_string. - -2007-02-16 Daniel Jacobowitz - - * remote-utils.c: Remove HAVE_TERMINAL_H check. - * configure.ac: Do not check for terminal.h. - * configure, config.in: Regenerated. - -2007-02-08 Daniel Jacobowitz - - * Makefile.in (OBS): Add $(XML_BUILTIN). - (XML_DIR, XML_TARGET, XML_FILES, XML_BUILTIN): New. - (clean): Update. - (target.xml, xml-builtin.c, stamp-xml, arm-with-iwmmxt.o) - (arm-with-iwmmxt.c): New. - * config.in, configure: Regenerate. - * configure.ac: Check for iWMMXt. Handle srv_xmltarget, - srv_xmlbuiltin, and srv_xmlfiles. Define USE_XML. - * configure.srv: Mention srv_xmltarget and srv_xmlfiles. - (arm*-*-linux*): Add iWMMXt and regset support. - * linux-arm-low.c (PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS): Define. - (arm_fill_gregset, arm_store_gregset, arm_fill_wmmxregset) - (arm_store_wmmxregset, target_regsets): New. - * server.c (get_features_xml): Take annex argument. Check builtin - XML documents. - (handle_query): Handle multiple annexes. - -2007-01-29 Daniel Jacobowitz - - * remote-utils.c [USE_WIN32API] (read, write): Define. - (putpkt_binary, input_interrupt, readchar, getpkt): Use read and - write. - -2007-01-09 Daniel Jacobowitz - - * linux-i386-low.c (the_low_target): Set arch_string. - * linux-x86-64-low.c (the_low_target): Likewise. - * linux-low.c (linux_arch_string): New. - (linux_target_ops): Add it. - * linux-low.h (struct linux_target_ops): Add arch_string. - * server.c (write_qxfer_response): Use const void * for DATA. - (get_features_xml): New. - (handle_query): Handle qXfer:features:read. Report it for qSupported. - * target.h (struct target_ops): Add arch_string method. - -2007-01-03 Denis Pilat - Daniel Jacobowitz - - * linux-low.c (linux_kill): Handle being called with no threads. - * win32-i386-low.c (win32_kill): Likewise. - (get_child_debug_event): Clear current_process_handle. - -2006-12-30 Denis PILAT - Daniel Jacobowitz - - * remote-utils.c (remote_open): Check the type of specified - serial port devices before opening them. - * server.c (main): Kill the inferior if an error occurs during - the first remote_open. - -2006-12-05 Markus Deuling - - * README: Update supported targets. - -2006-11-28 Daniel Jacobowitz - - * Makefile.in (clean): Remove reg-mips64.c. - (reg-mips64.c, reg-mips64.o): New rules. - * configure.srv: Handle mips64. Include regset support for mips. - * linux-mips-low.c (union mips_register): New. - (mips_get_pc, mips_set_pc, mips_reinsert_addr): Use it. - (mips_breakpoint, mips_breakpoint_at): Use int. - (mips_collect_register, mips_supply_register) - (mips_collect_register_32bit, mips_supply_register_32bit) - (mips_fill_gregset, mips_store_gregset, mips_fill_fpregset) - (mips_store_fpregset, target_regsets): New. - * thread-db.c (thread_db_get_tls_address): Use uintptr_t. - -2006-11-22 Ulrich Weigand - - * configure.srv: Add target "spu*-*-*". - * Makefile.in (clean): Remove reg-spu.c. - (reg-spu.c, reg-spu.o, spu-low.o): Add dependencies. - * spu-low.c: New file. - -2006-11-16 Daniel Jacobowitz - - * configure.ac: Correct td_thr_tls_get_addr test. - * configure: Regenerated. - -2006-11-16 Daniel Jacobowitz - - * linux-low.c (linux_wait_for_event): Reformat. Use the - pass_signals array. - * remote-utils.c (decode_address_to_semicolon): New. - * server.c (pass_signals, handle_general_set): New. - (handle_query): Mention QPassSignals for qSupported. - (main): Call handle_general_set. - * server.h (pass_signals, decode_address_to_semicolon): New. - -2006-11-06 Daniel Jacobowitz - - * server.c (handle_query): Correct error handling for read_auxv. - -2005-10-19 Ulrich Weigand - - * configure.srv [s390-*-linux*, s390x-*-linux*]: Set srv_linux_regsets - and srv_linux_thread_db to yes. - * linux-s390-low.c (s390_fill_gregset): New function. - (target_regsets): Define data structure. - -2006-10-17 Daniel Jacobowitz - - * acinclude.m4 (SRV_CHECK_TLS_GET_ADDR): New. - * configure.ac: Use it. Define HAVE_TD_THR_TLS_GET_ADDR. - * config.in, configure: Regenerated. - * inferiors.c (gdb_id_to_thread): New function. - (gdb_id_to_thread_id): Use it. - * linux-low.c (linux_target_ops): Use thread_db_get_tls_address. - * linux-low.h (struct process_info): Add th member. - (thread_db_get_tls_address): New prototype. - * remote-utils.c (decode_address): Make non-static. - * server.c (handle_query): Handle qGetTLSAddr. - * server.h (gdb_id_to_thread, decode_address): New prototypes. - * target.h (struct target_ops): Add get_tls_address. - * thread-db.c (maybe_attach_thread): Save the thread handle. - (thread_db_get_tls_address): New. - -2006-09-28 Daniel Jacobowitz - - * linux-low.c (PTRACE_GETSIGINFO, PTRACE_SETSIGINFO): Define. - (linux_resume_one_process): Take a siginfo_t *. Update all - callers. Queue it if necessary. Use PTRACE_SETSIGINFO. - (struct pending_signals): Add a siginfo_t. - (linux_wait_for_process): Always set last_status. - (linux_wait_for_event): Use PTRACE_GETSIGINFO. - (linux_queue_one_thread): Use PTRACE_GETSIGINFO. - * linux-low.h (struct process_info): Add last_status. - -2006-09-21 Daniel Jacobowitz - - * remote-utils.c (try_rle): New function. - (putpkt_binary): Use it. - -2006-08-19 Daniel Jacobowitz - - * Makefile.in (clean): Clean reg-x86-64-linux.c. - (reg-x86-64-linux.o, reg-x86-64-linux.c): New. - * configure.srv (x86_64-*-linux*): Use reg-x86-64-linux.o. - * linux-x86-64-low.c (x86_64_regmap): Include ORIG_RAX. - (x86_64_fill_gregset, x86_64_store_gregset): Skip floating - point registers. - -2006-08-08 Richard Sandiford - - * server.c (terminal_fd): New variable. - (old_foreground_pgrp): Likewise. - (restore_old_foreground_pgrp): New function. - (start_inferior): Record the terminal file descriptor in terminal_fd - and its original foreground group in old_foreground_pgrp. Register - restore_old_foreground_pgrp with atexit(). - -2006-07-26 Daniel Jacobowitz - - * server.c (handle_query): Correct qPart to qXfer. - -2006-07-22 Daniel Jacobowitz - - * configure.ac: Check for more headers which are missing on - Windows. Automatically supply -lwsock32 and USE_WIN32API. - * configure.srv: Add Cygwin and mingw32. - * remote-utils.c: Don't include headers unconditionally which - are missing on mingw32. Include for mingw32. - (remote_open): Adjust for mingw32 support. Flush - standard error after writing to it. - (remote_close, putpkt_binary, input_interrupt, block_async_io) - (unblock_async_io, enable_async_io, disable_async_io) - (readchar, getpkt): Update for Winsock support. - (prepare_resume_reply): Expect a protocol signal number. - * server.c: Disable on mingw32. - (start_inferior): Adjust for mingw32 support. Flush - standard error after writing to it. - (attach_inferior): Likewise. Use protocol signal - numbers. - (main): Skip 'D' packet on mingw32. Use protocol signal numbers - and names. - * win32-i386-low.c: New file. - * Makefile.in (XM_CLIBS): Set. - (gdbserver, gdbreplay): Use $(INTERNAL_CFLAGS). - (win32-i386-low.o): New dependency rule. - * linux-low.c (linux_wait): Use target signal numbers. - * target.h (struct target_ops): Doc fix. - * server.h (target_signal_to_name): New prototype. - * gdbreplay.c: Don't include headers unconditionally which - are missing on mingw32. Include for mingw32. - (remote_close, remote_open): Adjust for Winsock support. - * configure, config.in: Regenerated. - -2006-07-12 Daniel Jacobowitz - - * server.c (decode_xfer_read, write_qxfer_response): New. - (handle_query): Take a packet length argument. Handle - qXfer:auxv:read instead of qPart:auxv:read. Mention it in - the qSupported response. - (main): Update call to handle_query. - -2006-06-22 Daniel Jacobowitz - - * remote-utils.c (remote_escape_output, remote_unescape_input): New. - (putpkt_binary): Renamed from putpkt and adjusted for binary - data. - (putpkt): New wrapper for putpkt_binary. - (readchar): Don't mask off the high bit. - (decode_X_packet): New function. - * server.c (main): Call putpkt_binary if a handler sets the packet - length. Save the length of the incoming packet. Handle 'X'. - * server.h (gdb_byte, remote_escape_output, decode_X_packet): New. - -2006-06-21 Daniel Jacobowitz - - * server.c (handle_query): Handle qSupported. - -2006-05-30 Daniel Jacobowitz - - * remote-utils.c (all_symbols_looked_up): New variable. - (look_up_one_symbol): Check it. - * server.h (look_up_one_symbol): New declaration. - * thread-db.c (thread_db_init): Set all_symbols_looked_up. - -2006-05-30 Daniel Jacobowitz - - * Makefile.in (linux-arm-low.o): Update dependencies. - * linux-arm-low.c: Include "gdb_proc_service.h". - (PTRACE_GET_THREAD_AREA): Define. - (ps_get_thread_area): New function. - -2006-05-09 Nathan Sidwell - - * configure.srv (m68k*-*-uclinux*): New target. - * linux-low.c (linux_create_inferior): Use vfork on mmuless systems. - (linux_resume_one_process): Remove extraneous cast. - (linux_read_offsets): New. - (linux_target_op): Add linux_read_offsets on mmuless systems. - * server.c (handle_query): Add qOffsets logic. - * target.h (struct target_ops): Add read_offsets. - -2006-03-15 Daniel Jacobowitz - - * linux-mips-low.c: Include and "gdb_proc_service.h". - (PTRACE_GET_THREAD_AREA): Define. - (ps_get_thread_area): New function. - * Makefile.in (linux-i386-low.o, linux-mips-low.o) - (linux-x86-64-low.o): Update. - -2006-03-15 Daniel Jacobowitz - - * configure.ac: Remove checks for prfpregset_t. - * gdb_proc_service.h: New file. - * linux-i386-low.c, linux-x86-64-low.c, thread-db.c: Use the - new "gdb_proc_service.h". - * proc-service.c: Likewise. - (ps_pglobal_lookup, ps_pdread, ps_pdwrite): Use psaddr_t. - (ps_lgetfpregs, ps_lsetfpregs): Use a void* argument. - * Makefile.in (gdb_proc_service_h): Updated. - * configure, config.in: Regenerated. - -2006-03-03 Daniel Jacobowitz - - * remote-utils.c (prepare_resume_reply): Move declaration - of gdb_id_from_wait to the top of the block. - -2006-02-15 Daniel Jacobowitz - - * linux-low.c (regsets_store_inferior_registers): Read the regset - from the target before filling it. - -2006-02-08 Daniel Jacobowitz - - * server.c (attach_inferior): Return SIGTRAP for a successful - attach. - -2006-02-01 Daniel Jacobowitz - - * Makefile.in (OBS): Add version.o. - (STAGESTUFF): Delete. - (version.o): Add dependencies. - (version.c): Replace rule. - (clean): Remove version.c. - * server.c (gdbserver_version): New. - (gdbserver_usage): Use printf. - (main): Handle --version and --help. - * server.h (version, host_name): Add declarations. - -2005-12-23 Eli Zaretskii - - * linux-arm-low.c: - * linux-arm-low.c: - * inferiors.c: - * i387-fp.h: - * i387-fp.c: - * gdbreplay.c: - * regcache.c: - * proc-service.c: - * mem-break.h: - * mem-break.c: - * linux-x86-64-low.c: - * linux-sh-low.c: - * linux-s390-low.c: - * linux-ppc64-low.c: - * linux-ppc-low.c: - * linux-mips-low.c: - * linux-m68k-low.c: - * linux-m32r-low.c: - * linux-low.h: - * linux-low.c: - * linux-ia64-low.c: - * linux-i386-low.c: - * linux-crisv32-low.c: - * thread-db.c: - * terminal.h: - * target.h: - * target.c: - * server.h: - * server.c: - * remote-utils.c: - * regcache.h: - * utils.c: - * Makefile.in: - * configure.ac: - * gdbserver.1: Add (C) after Copyright. Update the FSF - address. - -2005-11-13 Daniel Jacobowitz - - * linux-arm-low.c (arm_eabi_breakpoint): New variable. - (arm_breakpoint_at): Recognize both breakpoints. - (the_low_target): Use the correct breakpoint instruction. - -2005-11-02 Daniel Jacobowitz - - * configure.srv (x86_64-*-linux*): Turn on thread_db support. - * linux-x86-64-low.c (x86_64_breakpoint, x86_64_breakpoint_len) - (x86_64_get_pc, x86_64_set_pc, x86_64_breakpoint_at): New. - (the_low_target): Update. - -2005-10-25 Andreas Schwab - - * server.c (main): Allocate mem_buf with PBUFSIZ bytes. - - * linux-ia64-low.c (ia64_regmap): Remove NAT registers. - (ia64_num_regs): Reduce to 462. - -2005-09-17 Daniel Jacobowitz - - * acinclude.m4: Correct quoting. - * aclocal.m4: Regenerated. - - Suggested by SZOKOVACS Robert : - * thread-db.c (thread_db_err_str): Handle TD_VERSION. - (thread_db_init): Call thread_db_err_str. - * configure.ac: Check for TD_VERSION. - * config.in, configure: Regenerated. - -2005-07-31 Kaveh R. Ghazi - - * server.h (error, fatal, warning): Add ATTR_FORMAT. - -2005-07-13 Daniel Jacobowitz - - * configure.ac: Define HAVE_LINUX_REGSETS even if PTRACE_GETREGS - is not available. Define HAVE_PTRACE_GETREGS if it is. - * config.in, configure: Regenerated. - * configure.srv: Set srv_linux_regsets for PowerPC and PowerPC64. - * linux-i386-low.c, linux-m68k-low.c: Update to use - HAVE_PTRACE_GETREGS. - * linux-low.c (regsets_fetch_inferior_registers) - (regsets_store_inferior_registers): Only return 0 if we processed - GENERAL_REGS. - * linux-ppc-low.c (ppc_fill_gregset, target_regsets): New. - * linux-ppc64-low.c (ppc_fill_gregset, target_regsets): New. - -2005-07-13 Daniel Jacobowitz - - * inferiors.c (struct thread_info): Add gdb_id. - (add_thread): Add gdb_id argument. - (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): New. - * linux-low.c (linux_create_inferior, linux_attach_lwp): Update - calls to add_thread. - * remote-utils.c (prepare_resume_reply: Use thread_to_gdb_id. - * server.c (handle_query): Use thread_to_gdb_id. - (handle_v_cont, main): Use gdb_id_to_thread_id. - * server.h (add_thread): Update prototype. - (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): New - prototypes. - -2005-07-13 Daniel Jacobowitz - - * linux-low.c (fetch_register, usr_store_inferior_registers): Handle - left-padded registers. - * linux-low.h (struct linux_target_ops): Add left_pad_xfer. - * linux-ppc64-low.c (the_low_target): Set left_pad_xfer. - -2005-07-01 Steve Ellcey - - * configure.ac (BFD_NEED_DECLARATION): Replace with AC_CHECK_DECLS. - * configure: Regenerate. - * config.in: Regenerate. - * server.h (NEED_DECLARATION_STRERROR): - Replace with !HAVE_DECL_STRERROR. - -2005-06-16 Daniel Jacobowitz - - * linux-low.c (linux_wait, linux_send_signal): Don't test - an unsigned long variable for > 0 if it could be MAX_ULONG. - * server.c (myresume): Likewise. - * target.c (set_desired_inferior): Likewise. - -2005-06-13 Mark Kettenis - - * configure.ac: Simplify and improve check for socklen_t. - * configure, config.in: Regenerate. - -2005-06-12 Daniel Jacobowitz - - * acconfig.h: Remove. - * configure.ac: Add a test for socklen_t. Use three-argument - AC_DEFINE throughout. - * config.in: Regenerated using autoheader 2.59. - * configure: Regenerated. - - * gdbreplay.c (socklen_t): Provide a default. - (remote_open): Use socklen_t. - * remote-utils.c (socklen_t): Provide a default. - (remote_open): Use socklen_t. - (convert_int_to_ascii, convert_ascii_to_int, decode_M_packet): Use - unsigned char. - - * i387-fp.c (struct i387_fsave, struct i387_fxsave): Use unsigned - char for buffers. - * linux-low.c (linux_read_memory, linux_write_memory) - (linux_read_auxv): Likewise. - * mem-break.c (breakpoint_data, set_breakpoint_data, check_mem_read) - (check_mem_write): Likewise. - * mem-break.h (set_breakpoint_data, check_mem_read, check_mem_write): - Likewise. - * regcache.c (struct inferior_rgcache_data, registers_to_string) - (registers_from_string, register_data): Likewise. - * server.c (handle_query, main): Likewise. - * server.h (convert_ascii_to_int, convert_int_to_ascii) - (decode_M_packet): Likewise. - * target.c (read_inferior_memory, write_inferior_memory): Likewise. - * target.h (struct target_ops): Update read_memory, write_memory, - and read_auxv. - (read_inferior_memory, write_inferior_memory): Update. - * linux-low.h (struct linux_target_ops): Change type of breakpoint - to unsigned char *. - * linux-arm-low.c, linux-cris-low.c, linux-crisv32-low.c, - linux-i386-low.c, linux-m32r-low.c, linux-m68k-low.c, - linux-mips-low.c, linux-ppc-low.c, linux-ppc64-low.c, - linux-s390-low.c, linux-sh-low.c: Update for changes in - read_inferior_memory and the_low_target->breakpoint. - -2005-05-28 Daniel Jacobowitz - - * Makefile.in (SFILES): Add linux-ppc64-low.c. - (linux-ppc64-low.o, reg-ppc64.c, reg-ppc64.o): New targets. - * configure.srv: Add powerpc64-*-linux*. - * linux-ppc64-low.c: New file. - -2005-05-23 Orjan Friberg - - * linux-cris-low.c: New file with support for CRIS. - * linux-crisv32-low.c: Ditto for CRISv32. - * Makefile.in (SFILES): Add linux-cris-low.c, linux-crisv32-low.c. - (clean): Add reg-cris.c and reg-crisv32.c. - Add linux-cris-low.o, linux-crisv32-low.o, reg-cris.o, reg-cris.c, - reg-crisv32.o, and reg-crisv32.c to make rules. - * configure.srv: Add cris-*-linux* and crisv32-*-linux* to list of - recognized targets. - -2005-05-16 Ulrich Weigand - - * linux-low.c (fetch_register): Ensure buffer size is a multiple - of sizeof (PTRACE_XFER_TYPE). - (usr_store_inferior_registers): Likewise. Zero out excess bytes. - -2005-05-12 Orjan Friberg - - * target.h (struct target_ops): Add insert_watchpoint, - remove_watchpoint, stopped_by_watchpoint, stopped_data_address function - pointers for hardware watchpoint support. - * linux-low.h (struct linux_target_ops): Ditto. - * linux-low.c (linux_insert_watchpoint, linux_remove_watchpoint) - (linux_stopped_by_watchpoint, linux_stopped_data_address): New. Add - to linux_target_ops. - * remote-utils.c (prepare_resume_reply): Add watchpoint information to - reply packet. - * server.c (main): Recognize 'Z' and 'z' packets. - -2005-05-10 Ulrich Weigand - - * linux-s390-low.c (s390_breakpoint, s390_breakpoint_len): Define. - (s390_get_pc, s390_set_pc, s390_breakpoint_at): New functions. - (the_low_target): Add new members. - -2005-05-04 Daniel Jacobowitz - - * proc-service.c (ps_lgetregs): Search all_processes instead of - all_threads. - -2005-05-04 Daniel Jacobowitz - - * server.c (start_inferior): Change return type to int. - (attach_inferior): Change sigptr to int *. - (handle_v_cont, handle_v_requests): Change signal to int *. - (main): Change signal to int. - -2005-04-15 Kei Sakamoto - - * Makefile.in: Add linux-m32r-low.o, reg-m32r.c and reg-m32r.o. - * configure.srv: Add m32r*-*-linux*. - * linux-m32r-low.c: New file. - -2005-03-04 Daniel Jacobowitz - - * Makefile.in (stamp-h): Set CONFIG_HEADERS explicitly. - -2005-03-03 Daniel Jacobowitz - - * inferiors.c (change_inferior_id, add_thread, find_inferior_id): - Take unsigned long arguments for PIDs. - * linux-low.c (add_process, linux_attach_lwp, linux_attach) - (linux_thread_alive, linux_wait_for_event, kill_lwp, send_sigstop) - (wait_for_sigstop, linux_resume_one_process) - (regsets_fetch_inferior_registers, linux_send_signal) - (linux_read_auxv): Likewise. Update the types of variables holding - PIDs. Update format string specifiers. - * linux-low.h (struct process_info, linux_attach_lwp): Likewise. - * remote-utils.c (prepare_resume_reply): Likewise. - * server.c (cont_thread, general_thread, step_thread) - (thread_from_wait, old_thread_from_wait, signal_pid): Change type to - unsigned long. - (handle_query): Update format specifiers. - (handle_v_cont, main): Use strtoul for thread IDs. - * server.h (struct inferior_list_entry): Use unsigned long for ID. - (add_thread, find_inferior_id, change_inferior_id, cont_thread) - (general_thread, step_thread, thread_from_wait) - (old_thread_from_wait): Update. - * target.h (struct thread_resume): Use unsigned long for THREAD. - (struct target_ops): Use unsigned long for arguments to attach and - thread_alive. - -2005-02-24 Daniel Jacobowitz - - * acinclude.m4: Include bfd/bfd.m4 directly. - * configure.ac: Use AC_ARG_PROGRAM. Suggested by Aron Griffis - . - * aclocal.m4, configure: Regenerated. - -2005-01-07 Andrew Cagney - - * configure.ac: Rename configure.in, require autoconf 2.59. - * configure: Re-generate. - -2004-12-08 Daniel Jacobowitz - - * acinclude.m4 (SRV_CHECK_THREAD_DB): Add ps_get_thread_area. Reset - LIBS when finished. - * aclocal.m4: Regenerated. - * configure: Regenerated. - -2004-11-21 Andreas Schwab - - * linux-m68k-low.c (m68k_num_gregs): Define. - (m68k_fill_gregset, m68k_store_gregset, m68k_fill_fpregset) - (m68k_store_fpregset, target_regsets) [HAVE_LINUX_REGSETS]: New. - (m68k_breakpoint, m68k_breakpoint_len, m68k_get_pc, m68k_set_pc) - (m68k_breakpoint_at): New. Add to the_low_target. - - * configure.srv (m68*-*-linux*): Set srv_linux_regsets and - srv_linux_thread_db to yes. - -2004-10-20 Joel Brobecker - - * linux-x86-64-low.c (ARCH_SET_GS): Add definition if missing. - (ARCH_SET_FS): Likewise. - (ARCH_GET_FS): Likewise. - (ARCH_GET_GS): Likewise. - -2004-10-16 Daniel Jacobowitz - - * linux-i386-low.c (ps_get_thread_area): New. - * linux-x86-64-low.c (ps_get_thread_area): New. - * linux-low.c: Include . - (linux_kill_one_process): Don't kill the first thread here. - (linux_kill): Kill the first thread here. - (kill_lwp): New function. - (send_sigstop, linux_send_signal): Use it. - * proc-service.c: Clean up #ifdefs. - (fpregset_info): Delete. - (ps_lgetregs): Update and enable implementation. - (ps_lsetregs, ps_lgetfpregs, ps_lsetfpregs): Remove disabled - implementations. - * remote-utils.c (struct sym_cache, symbol_cache): New. - (input_interrupt): Print a clearer message. - (async_io_enabled): New variable. - (enable_async_io, disable_async_io): Use it. Update comments. - (look_up_one_symbol): Use the symbol cache. - * thread-db.c (thread_db_look_up_symbols): New function. - (thread_db_init): Update comments. Call thread_db_look_up_symbols. - -2004-10-16 Daniel Jacobowitz - - * configure.in: Test for -rdynamic. - * configure: Regenerated. - * Makefile (INTERNAL_LDFLAGS): New. - (gdbserver, gdbreplay): Use it. - -2004-09-02 Andrew Cagney - - * Makefile.in (TAGS): Replace TM_FILE with DEPRECATED_TM_FILE. - -2004-03-23 Daniel Jacobowitz - - * linux-low.c (linux_wait): Clear all_processes list also. - -2004-03-12 Daniel Jacobowitz - - * linux-low.c: Include . Remove extern declaration of - errno. - -2004-03-12 Daniel Jacobowitz - - * gdbreplay.c, server.h, utils.c: Update copyright years. - -2004-03-04 Nathan J. Williams - - * server.c (main): Print child status or termination signal from - variable 'signal', not 'sig'. - -2004-03-04 Nathan J. Williams - - * linux-low.c (linux_read_memory): Change return type to - int. Check for and return error from ptrace(). - * target.c (read_inferior_memory): Change return type to int. Pass - back return status from the_target->read_memory(). - * target.h (struct target_ops): Adapt *read_memory() prototype. - Update comment. - (read_inferior_memory): Adapt prototype. - * server.c (main): Return an error packet if - read_inferior_memory() returns an error. - -2004-03-04 Daniel Jacobowitz - - * Makefile.in (distclean): Remove config.h, stamp-h, and config.log. - Unify with other clean targets. - -2004-02-29 Daniel Jacobowitz - - * server.c (handle_v_cont): Call set_desired_inferior. - -2004-02-29 Daniel Jacobowitz - - * remote-utils.c (prepare_resume_reply): Always supply "thread:". - -2004-02-29 Daniel Jacobowitz - - * linux-low.c (linux_wait): Unblock async I/O. - (linux_resume): Block and enable async I/O. - * remote-utils.c (block_async_io, unblock_async_io): New functions. - * server.h (block_async_io, unblock_async_io): Add prototypes. - -2004-02-29 Daniel Jacobowitz - - * remote-utils.c (remote_open): Print a status notice after - opening a TCP port. - * server.c (attach_inferior): Print a status notice after - attaching. - -2004-02-29 Daniel Jacobowitz - - * linux-arm-low.c (arm_get_pc): Print out stop PC in debug mode. - -2004-02-26 Daniel Jacobowitz - - * remote-utils.c (write_enn): Use "E01" instead of "ENN" for the - error packet. - * server.c, target.h: Update copyright years. - -2004-02-25 Roland McGrath - - * target.h (struct target_ops): New member `read_auxv'. - * server.c (handle_query): Handle qPart:auxv:read: query using that. - * linux-low.c (linux_read_auxv): New function. - (linux_target_ops): Initialize `read_auxv' member to that. - -2004-02-17 Ulrich Weigand - - Committed by Jim Blandy . - - * linux-s390-low.c (s390_num_regs): Update. - (s390_regmap): Remove control registers. Use __s390x__ predefine - instead of GPR_SIZE to distiguish s390 and s390x targets. - -2004-01-31 Daniel Jacobowitz - - * linux-low.c: Update copyright year. - (check_removed_breakpoint): Clear pending_is_breakpoint. - (linux_set_resume_request, linux_queue_one_thread) - (resume_status_pending_p): New functions. - (linux_continue_one_thread): Use process->resume. - (linux_resume): Only resume threads if there are no pending events. - * linux-low.h (struct process_info): Add resume request - pointer. - -2004-01-30 Daniel Jacobowitz - - * regcache.c (new_register_cache): Clear the allocated register - buffer. Suggested by Atsushi Nemoto . - -2003-10-13 Daniel Jacobowitz - - * linux-low.c (linux_resume): Take a struct thread_resume * - argument. - (linux_wait): Update call. - (resume_ptr): New static variable. - (linux_continue_one_thread): Renamed from - linux_continue_one_process. Use resume_ptr. - (linux_resume): Use linux_continue_one_thread. - * server.c (handle_v_cont, handle_v_requests): New functions. - (myresume): New function. - (main): Handle 'v' case. - * target.h (struct thread_resume): New type. - (struct target_ops): Change argument of "resume" to struct - thread_resume *. - (myresume): Delete macro. - -2003-08-08 H.J. Lu - - * Makefile.in (install-only): Create dest dir. Support DESTDIR. - (uninstall): Support DESTDIR. - -Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy - - * configure.srv: Add xscale*linux copy of arm*linux entry. - -2003-07-24 Daniel Jacobowitz - - * linux-arm-low.c (arm_reinsert_addr): New function. - (the_low_target): Add arm_reinsert_addr. - -2003-07-08 Mark Kettenis - - * mem-break.c: Remove whitespace at end of file. - -2003-06-28 Daniel Jacobowitz - - * configure.in: Check whether we need to prototype strerror. - * server.h: Optionally prototype strerror. - * gdbreplay.c (perror_with_name): Use strerror. - * linux-low.c (linux_attach_lwp): Use strerror. - * utils.c (perror_with_name): Use strerror. - * config.in, configure: Regenerated. - -2003-06-28 Daniel Jacobowitz - - * linux-sh-low.c (sh_regmap): Fix FP register offsets, reported by - SUGIOKA Toshinobu . - -2003-06-20 Daniel Jacobowitz - - * Makefile.in (SFILES): Update. - * low-hppabsd.c, low-lynx.c, low-nbsd.c, low-sim.c, low-sparc.c, - low-sun3.c: Remove files. - -2003-06-17 Daniel Jacobowitz - - * linux-low.c: Move comment to linux_thread_alive where it belonged. - (linux_detach_one_process, linux_detach): New functions. - (linux_target_ops): Add linux_detach. - * server.c (main): Handle 'D' packet. - * target.h (struct target_ops): Add "detach" member. - (detach_inferior): Define. - -2003-06-13 Mark Kettenis - - From Kelley Cook : - * configure.srv: Accept i[34567]86 variants. - -2003-06-05 Daniel Jacobowitz - - * linux-low.c (linux_wait_for_event): Correct comment typos. - (linux_resume_one_process): Call check_removed_breakpoint. - (linux_send_signal): New function. - (linux_target_ops): Add linux_send_signal. - * remote-utils.c (putpkt, input_interrupt): Use send_signal instead - of kill. - * target.h (struct target_ops): Add send_signal. - -2003-05-29 Jim Blandy - - * linux-low.c (usr_store_inferior_registers): Transfer buf in - PTRACE_XFER_TYPE-sized chunks, not int-sized chunks. Otherwise, - if 'int' is smaller than PTRACE_XFER_TYPE, you end up throwing - away part of the register's value. - -2003-03-26 Daniel Jacobowitz - - * linux-low.c (linux_create_inferior): Use __SIGRTMIN. - (linux_wait_for_event, linux_init_signals): Likewise. - -2003-03-17 Daniel Jacobowitz - - * configure.in: Check for stdlib.h. - * configure: Regenerated. - * config.in: Regenerated. - -2003-01-04 Andreas Schwab - - * linux-m68k-low.c (m68k_num_regs): Define to 29 instead of 31. - -2003-01-02 Andrew Cagney - - * Makefile.in: Remove obsolete code. - -2002-11-20 Daniel Jacobowitz - - * linux-s390-low.c (s390_regmap): Check GPR_SIZE instead of - defined(PT_FPR0_HI). - -2002-11-17 Stuart Hughes - - * linux-arm-low.c (arm_num_regs): Increase. - (arm_regmap): Include status register. - -2002-11-17 Daniel Jacobowitz - - * linux-low.c (register_addr): Remove incorrect -1 check. - -2002-08-29 Daniel Jacobowitz - - * linux-low.c (linux_create_inferior): Call setpgid. Return - the new PID. - (unstopped_p, linux_signal_pid): Remove. - (linux_target_ops): Remove linux_signal_pid. - * remote-utils.c (putpkt, input_interrupt): Use signal_pid - global instead of target method. - * target.h (struct target_ops): Remove signal_pid. Update comment - for create_inferior. - * server.c (signal_pid): New variable. - (create_inferior): Set signal_pid. Block SIGTTOU and SIGTTIN in - gdbserver. Set the child to be the foreground process group. - (attach_inferior): Set signal_pid. - -2002-08-23 Daniel Jacobowitz - - * ChangeLog: New file, with entries from gdb/ChangeLog after GDB 5.2. - -2002-08-20 Jim Blandy - - * Makefile.in (LDFLAGS): Allow the configure script to establish a - default for this. - -2002-08-01 Andrew Cagney - - * Makefile.in: Make chill references obsolete. - -2002-07-24 Kevin Buettner - - * configure.in (unistd.h): Add to AC_CHECK_HEADERS list. - * configure: Regenerate. - * config.in: Regenerate. - -2002-07-09 David O'Brien - - * gdbreplay.c (stdlib.h, unistd.h): Conditionaly include. - (perror_with_name, remote_close, remote_open, expect, play): Static. - -2002-07-04 Michal Ludvig - - * linux-x86-64-low.c (x86_64_regmap): Make it an array of - byte offsets instead of an array of indexes. - (x86_64_store_gregset, x86_64_store_fpregset): Parameter made const. - -2002-06-13 Daniel Jacobowitz - - * regcache.c: Add comment. - -2002-06-11 Daniel Jacobowitz - - * thread-db.c: New file. - * proc-service.c: New file. - * acinclude.m4: New file. - * Makefile.in: Add GDBSERVER_LIBS, gdb_proc_service_h, - proc-service.o, and thread-db.o. - (linux-low.o): Add USE_THREAD_DB. - * acconfig.h: Add HAVE_PRGREGSET_T, HAVE_PRFPREGSET_T, - HAVE_LWPID_T, HAVE_PSADDR_T, and PRFPREGSET_T_BROKEN. - * aclocal.m4: Regenerated. - * config.in: Regenerated. - * configure: Regenerated. - * configure.in: Check for proc_service.h, sys/procfs.h, - thread_db.h, and linux/elf.h headrs. - Check for lwpid_t, psaddr_t, prgregset_t, prfpregset_t, and - PRFPREGSET_T_BROKEN. Introduce srv_thread_depfiles and USE_THREAD_DB. - Check for -lthread_db and thread support. - * configure.srv: Enable thread_db support for ARM, i386, MIPS, - PowerPC, and SuperH. - * i387-fp.c: Constify arguments. - * i387-fp.h: Likewise. - * inferiors.c: (struct thread_info): Renamed from - `struct inferior_info'. Remove PID member. Use generic inferior - list header. All uses updated. - (inferiors, signal_pid): Removed. - (all_threads): New variable. - (get_thread): Define. - (add_inferior_to_list): New function. - (for_each_inferior): New function. - (change_inferior_id): New function. - (add_inferior): Removed. - (remove_inferior): New function. - (add_thread): New function. - (free_one_thread): New function. - (remove_thread): New function. - (clear_inferiors): Use for_each_inferior and free_one_thread. - (find_inferior): New function. - (find_inferior_id): New function. - (inferior_target_data): Update argument type. - (set_inferior_target_data): Likewise. - (inferior_regcache_data): Likewise. - (set_inferior_regcache_data): Likewise. - * linux-low.c (linux_bp_reinsert): Remove. - (all_processes, stopping_threads, using_thrads) - (struct pending_signals, debug_threads, pid_of): New. - (inferior_pid): Replace with macro. - (struct inferior_linux_data): Remove. - (get_stop_pc, add_process): New functions. - (linux_create_inferior): Restore SIGRTMIN+1 before calling exec. - Use add_process and add_thread. - (linux_attach_lwp): New function, based on old linux_attach. Use - add_process and add_thread. Set stop_expected for new threads. - (linux_attach): New function. - (linux_kill_one_process): New function. - (linux_kill): Kill all LWPs. - (linux_thread_alive): Use find_inferior_id. - (check_removed_breakpoints, status_pending_p): New functions. - (linux_wait_for_process): Renamed from linux_wait_for_one_inferior. - Update. Use WNOHANG. Wait for cloned processes also. Update process - struct for the found process. - (linux_wait_for_event): New function. - (linux_wait): Use it. Support LWPs. - (send_sigstop, wait_for_sigstop, stop_all_processes) - (linux_resume_one_process, linux_continue_one_process): New functions. - (linux_resume): Support LWPs. - (REGISTER_RAW_SIZE): Remove. - (fetch_register): Use register_size instead. Call supply_register. - (usr_store_inferior_registers): Likewise. Call collect_register. - Fix recursive case. - (regsets_fetch_inferior_registers): Improve error message. - (regsets_store_inferior_registers): Add debugging. - (linux_look_up_symbols): Call thread_db_init if USE_THREAD_DB. - (unstopped_p, linux_signal_pid): New functions. - (linux_target_ops): Add linux_signal_pid. - (linux_init_signals): New function. - (initialize_low): Call it. Initialize using_threads. - * regcache.c (inferior_regcache_data): Add valid - flag. - (get_regcache): Fetch registers lazily. Add fetch argument - and update all callers. - (regcache_invalidate_one, regcache_invalidate): New - functions. - (new_register_cache): Renamed from create_register_cache. - Return the new regcache. - (free_register_cache): Change argument to a void *. - (registers_to_string, registers_from_string): Call get_regcache - with fetch flag set. - (register_data): Make static. Pass fetch flag to get_regcache. - (supply_register): Call get_regcache with fetch flag clear. - (collect_register): Call get_regcache with fetch flag set. - (collect_register_as_string): New function. - * regcache.h: Update. - * remote-utils.c (putpkt): Flush after debug output and use - stderr. - Handle input interrupts while waiting for an ACK. - (input_interrupt): Use signal_pid method. - (getpkt): Flush after debug output and use stderr. - (outreg): Use collect_register_as_string. - (new_thread_notify, dead_thread_notify): New functions. - (prepare_resume_reply): Check using_threads. Set thread_from_wait - and general_thread. - (look_up_one_symbol): Flush after debug output. - * server.c (step_thread, server_waiting): New variables. - (start_inferior): Don't use signal_pid. Update call to mywait. - (attach_inferior): Update call to mywait. - (handle_query): Handle qfThreadInfo and qsThreadInfo. - (main): Don't fetch/store registers explicitly. Use - set_desired_inferior. Support proposed ``Hs'' packet. Update - calls to mywait. - * server.h: Update. - (struct inferior_list, struct_inferior_list_entry): New. - * target.c (set_desired_inferior): New. - (write_inferior_memory): Constify. - (mywait): New function. - * target.h: Update. - (struct target_ops): New signal_pid method. - (mywait): Removed macro, added prototype. - - * linux-low.h (regset_func): Removed. - (regset_fill_func, regset_store_func): New. - (enum regset_type): New. - (struct regset_info): Add type field. Use new operation types. - (struct linux_target_ops): stop_pc renamed to get_pc. - Add decr_pc_after_break and breakpoint_at. - (get_process, get_thread_proess, get_process_thread) - (strut process_info, all_processes, linux_attach_lwp) - (thread_db_init): New. - - * linux-arm-low.c (arm_get_pc, arm_set_pc, - arm_breakpoint, arm_breakpoint_len, arm_breakpoint_at): New. - (the_low_target): Add new members. - * linux-i386-low.c (i386_store_gregset, i386_store_fpregset) - (i386_store_fpxregset): Constify. - (target_regsets): Add new kind identifier. - (i386_get_pc): Renamed from i386_stop_pc. Simplify. - (i386_set_pc): Add debugging. - (i386_breakpoint_at): New function. - (the_low_target): Add new members. - * linux-mips-low.c (mips_get_pc, mips_set_pc) - (mips_breakpoint, mips_breakpoint_len, mips_reinsert_addr) - (mips_breakpoint_at): New. - (the_low_target): Add new members. - * linux-ppc-low.c (ppc_get_pc, ppc_set_pc) - (ppc_breakpoint, ppc_breakpoint_len, ppc_breakpoint_at): New. - (the_low_target): Add new members. - * linux-sh-low.c (sh_get_pc, sh_set_pc) - (sh_breakpoint, sh_breakpoint_len, sh_breakpoint_at): New. - (the_low_target): Add new members. - * linux-x86-64-low.c (target_regsets): Add new kind - identifier. - -2002-05-15 Daniel Jacobowitz - - From Martin Pool : - * server.c (gdbserver_usage): New function. - (main): Call it. - -2002-05-14 Daniel Jacobowitz - - * mem-break.c (reinsert_breakpoint_by_bp): Correct typo - stop_at -> stop_pc. - -2002-05-04 Andrew Cagney - - * Makefile.in: Remove obsolete code. - -2002-04-24 Michal Ludvig - - * linux-low.c (regsets_fetch_inferior_registers), - (regsets_store_inferior_registers): Removed cast to int from - ptrace() calls. - * regcache.h: Added declaration of struct inferior_info. - -2002-04-20 Daniel Jacobowitz - - * inferiors.c (struct inferior_info): Add regcache_data. - (add_inferior): Call create_register_cache. - (clear_inferiors): Call free_register_cache. - (inferior_regcache_data, set_inferior_regcache_data): New functions. - * regcache.c (struct inferior_regcache_data): New. - (registers): Remove. - (get_regcache): New function. - (create_register_cache, free_register_cache): New functions. - (set_register_cache): Don't initialize the register cache here. - (registers_to_string, registers_from_string, register_data): Call - get_regcache. - * regcache.h: Add prototypes. - * server.h: Likewise. - -2002-04-20 Daniel Jacobowitz - - * mem-break.c: New file. - * mem-break.h: New file. - * Makefile.in: Add mem-break.o rule; update server.h - dependencies. - * inferiors.c (struct inferior_info): Add target_data - member. - (clear_inferiors): Free target_data member if set. - (inferior_target_data, set_inferior_target_data): New functions. - * linux-i386-low.c (i386_breakpoint, i386_breakpoint_len) - (i386_stop_pc, i386_set_pc): New. Add to the_low_target. - * linux-low.c (linux_bp_reinsert): New variable. - (struct inferior_linux_data): New. - (linux_create_inferior): Use set_inferior_target_data. - (linux_attach): Likewise. Call add_inferior. - (linux_wait_for_one_inferior): New function. - (linux_wait): Call it. - (linux_write_memory): Add const. - (initialize_low): Call set_breakpoint_data. - * linux-low.h (struct linux_target_ops): Add breakpoint - handling members. - * server.c (attach_inferior): Remove extra add_inferior - call. - * server.h: Include mem-break.h. Update inferior.c - prototypes. - * target.c (read_inferior_memory) - (write_inferior_memory): New functions. - * target.h (read_inferior_memory) - (write_inferior_memory): Change macros to prototypes. - (struct target_ops): Update comments. Add const to write_memory - definition. - -2002-04-11 Daniel Jacobowitz - - * linux-low.c (usr_store_inferior_registers): Support - registers which are allowed to fail to store. - * linux-low.h (linux_target_ops): Likewise. - * linux-ppc-low.c (ppc_regmap): Support FPSCR. - (ppc_cannot_store_register): FPSCR may not be storable. - -2002-04-09 Daniel Jacobowitz - - * server.h: Include if HAVE_STRING_H. - * ChangeLog: Correct paths in last ChangeLog entry. - -2002-04-09 Daniel Jacobowitz - - * linux-low.h: Remove obsolete prototypes. - (struct linux_target_ops): New. - (extern the_low_target): New. - * linux-low.c (num_regs, regmap): Remove declarations. - (register_addr): Use the_low_target explicitly. - (fetch_register): Likewise. - (usr_fetch_inferior_registers): Likewise. - (usr_store_inferior_registers): Likewise. - * linux-arm-low.c (num_regs): Remove. - (arm_num_regs): Define. - (arm_regmap): Renamed from regmap, made static. - (arm_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (arm_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-i386-low.c (num_regs): Remove. - (i386_num_regs): Define. - (i386_regmap): Renamed from regmap, made static. - (i386_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (i386_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-ia64-low.c (num_regs): Remove. - (ia64_num_regs): Define. - (ia64_regmap): Renamed from regmap, made static. - (ia64_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (ia64_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-m68k-low.c (num_regs): Remove. - (m68k_num_regs): Define. - (m68k_regmap): Renamed from regmap, made static. - (m68k_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (m68k_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-mips-low.c (num_regs): Remove. - (mips_num_regs): Define. - (mips_regmap): Renamed from regmap, made static. - (mips_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (mips_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-ppc-low.c (num_regs): Remove. - (ppc_num_regs): Define. - (ppc_regmap): Renamed from regmap, made static. - (ppc_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (ppc_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-s390-low.c (num_regs): Remove. - (s390_num_regs): Define. - (s390_regmap): Renamed from regmap, made static. - (s390_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (s390_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-sh-low.c (num_regs): Remove. - (sh_num_regs): Define. - (sh_regmap): Renamed from regmap, made static. - (sh_cannot_fetch_register): Renamed from cannot_fetch_register, - made static. - (sh_cannot_store_register): Renamed from cannot_store_register, - made static. - (the_low_target): New. - * linux-x86-64-low.c (x86_64_regmap): Renamed from regmap. - (the_low_target): New. - -2002-04-09 Daniel Jacobowitz - - * Makefile.in: Add stamp-h target. - * configure.in: Create stamp-h. - * configure: Regenerated. - -2002-04-09 Daniel Jacobowitz - - * inferiors.c: New file. - * target.c: New file. - * target.h: New file. - * Makefile.in: Add target.o and inferiors.o. Update - dependencies. - * linux-low.c (inferior_pid): New static variable, - moved from server.c. - (linux_create_inferior): Renamed from create_inferior. - Call add_inferior. Return 0 on success instead of a PID. - (linux_attach): Renamed from myattach. - (linux_kill): Renamed from kill_inferior. Call clear_inferiors (). - (linux_thread_alive): Renamed from mythread_alive. - (linux_wait): Renamed from mywait. Call clear_inferiors () if the - child dies. - (linux_resume): Renamed from myresume. Add missing ``return 0''. - (regsets_store_inferior_registers): Correct error message. - Add missing ``return 0''. - (linux_fetch_registers): Renamed from fetch_inferior_registers. - (linux_store_registers): Renamed from store_inferior_registers. - (linux_read_memory): Renamed from read_inferior_memory. - (linux_write_memory): Renamed from write_inferior_memory. - (linux_target_ops): New structure. - (initialize_low): Call set_target_ops (). - * remote-utils.c (unhexify): New function. - (hexify): New function. - (input_interrupt): Send signals to ``signal_pid''. - * server.c (inferior_pid): Remove. - (start_inferior): Update create_inferior call. - (attach_inferior): Call add_inferior. - (handle_query): New function. - (main): Call handle_query for `q' packets. - * server.h: Include "target.h". Remove obsolete prototypes. - Add prototypes for "inferiors.c", "target.c", hexify, and unhexify. - -2002-04-09 Daniel Jacobowitz - - * Makefile.in: Add WARN_CFLAGS. Update configury - dependencies. - * configure.in: Check for - * configure: Regenerate. - * config.in: Regenerate. - * gdbreplay.c: Include needed system headers. - (remote_open): Remove strchr prototype. - * linux-low.h: Correct #ifdef to HAVE_LINUX_USRREGS. - * regcache.c (supply_register): Change buf argument to const void *. - (supply_register_by_name): Likewise. - (collect_register): Change buf argument to void *. - (collect_register_by_name): Likewise. - * regcache.h: Add missing prototypes. - * remote-utils.c: Include for inet_ntoa. - * server.c (handle_query): New function. - (attached): New static variable, moved out of main. - (main): Quiet longjmp clobber warnings. - * server.h: Add ATTR_NORETURN and ATTR_FORMAT. Update prototypes. - * utils.c (error): Remove NORETURN. - (fatal): Likewise. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in deleted file mode 100644 index 3922b5231c4..00000000000 --- a/gdb/gdbserver/Makefile.in +++ /dev/null @@ -1,719 +0,0 @@ -# Copyright (C) 1989-2020 Free Software Foundation, Inc. - -# This file is part of GDB. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 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, see . - -# Please keep lists in this file sorted alphabetically, with one item per line. -# See gdb/Makefile.in for guidelines on ordering files and directories. - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -host_alias = @host_noncanonical@ -target_alias = @target_noncanonical@ -program_transform_name = @program_transform_name@ -bindir = @bindir@ -libdir = @libdir@ -tooldir = $(libdir)/$(target_alias) - -datarootdir = @datarootdir@ -datadir = @datadir@ -mandir = @mandir@ -man1dir = $(mandir)/man1 -man2dir = $(mandir)/man2 -man3dir = $(mandir)/man3 -man4dir = $(mandir)/man4 -man5dir = $(mandir)/man5 -man6dir = $(mandir)/man6 -man7dir = $(mandir)/man7 -man8dir = $(mandir)/man8 -man9dir = $(mandir)/man9 -infodir = @infodir@ -htmldir = $(prefix)/html -includedir = @includedir@ -CONFIG_SRC_SUBDIR = @CONFIG_SRC_SUBDIR@ - -install_sh = @install_sh@ - -SHELL = @SHELL@ -EXEEXT = @EXEEXT@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ -RANLIB = @RANLIB@ - -CC = @CC@ -CXX = @CXX@ -CXX_DIALECT = @CXX_DIALECT@ -AR = @AR@ -AR_FLAGS = rc -STRIP = @STRIP@ - -# Dependency tracking information. -DEPMODE = @CCDEPMODE@ -DEPDIR = @DEPDIR@ -depcomp = $(SHELL) $(srcdir)/../../depcomp - -# Directory containing source files. Don't clean up the spacing, -# this exact string is matched for by the "configure" script. -srcdir = @srcdir@ -abs_top_srcdir = @abs_top_srcdir@ -abs_srcdir = @abs_srcdir@ -VPATH = @srcdir@ - -include $(srcdir)/../silent-rules.mk - -# Note that these are overridden by GNU make-specific code below if -# GNU make is used. The overrides implement dependency tracking. -COMPILE.pre = $(CXX) -x c++ $(CXX_DIALECT) -COMPILE.post = -c -o $@ -COMPILE = $(ECHO_CXX) $(COMPILE.pre) $(INTERNAL_CFLAGS) $(COMPILE.post) -POSTCOMPILE = @true - -# It is also possible that you will need to add -I/usr/include/sys to the -# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which -# is where it should be according to Posix). - -# Set this up with gcc if you have gnu ld and the loader will print out -# line numbers for undefinded refs. -#CC_LD = g++ -static -CC_LD = $(CXX) $(CXX_DIALECT) - -# Where is the "include" directory? Traditionally ../include or ./include -INCLUDE_DIR = ${srcdir}/../../include -INCLUDE_DEP = $$(INCLUDE_DIR) - -LIBIBERTY_BUILDDIR = build-libiberty-gdbserver -LIBIBERTY = $(LIBIBERTY_BUILDDIR)/libiberty.a - -# Where is ust? These will be empty if ust was not available. -ustlibs = @ustlibs@ -ustinc = @ustinc@ - -# gnulib -GNULIB_BUILDDIR = build-gnulib-gdbserver -LIBGNU = $(GNULIB_BUILDDIR)/import/libgnu.a -INCGNU = -I$(srcdir)/../../gnulib/import -I$(GNULIB_BUILDDIR)/import - -# Generated headers in the gnulib directory. These must be listed -# so that they are generated before other files are compiled. -GNULIB_H = $(GNULIB_BUILDDIR)/import/string.h @GNULIB_STDINT_H@ - -INCSUPPORT = -I$(srcdir)/../.. -I../.. - -# All the includes used for CFLAGS and for lint. -# -I. for config files. -# -I${srcdir} for our headers. -# -I$(srcdir)/../regformats for regdef.h. -# -# We do not include ../target or ../nat in here because headers -# in those directories should be included with the subdirectory. -# e.g.: "target/wait.h". -# -INCLUDE_CFLAGS = -I. -I${srcdir} \ - -I$(srcdir)/../regformats -I$(srcdir)/.. -I$(INCLUDE_DIR) \ - $(INCGNU) $(INCSUPPORT) - -# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS -# from the config/ directory. -GLOBAL_CFLAGS = ${MT_CFLAGS} ${MH_CFLAGS} -#PROFILE_CFLAGS = -pg - -WARN_CFLAGS = @WARN_CFLAGS@ -WERROR_CFLAGS = @WERROR_CFLAGS@ - -WARN_CFLAGS_NO_FORMAT = `echo " $(WARN_CFLAGS) " \ - | sed "s/ -Wformat-nonliteral / -Wno-format-nonliteral /g"` - -# These are specifically reserved for setting from the command line -# when running make. I.E. "make CFLAGS=-Wmissing-prototypes". -CFLAGS = @CFLAGS@ -CXXFLAGS = @CXXFLAGS@ -CPPFLAGS = @CPPFLAGS@ - -PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ -PTHREAD_LIBS = @PTHREAD_LIBS@ - -# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros. -INTERNAL_CFLAGS_BASE = ${CXXFLAGS} ${GLOBAL_CFLAGS} \ - ${PROFILE_CFLAGS} ${INCLUDE_CFLAGS} ${CPPFLAGS} $(PTHREAD_CFLAGS) -INTERNAL_WARN_CFLAGS = ${INTERNAL_CFLAGS_BASE} $(WARN_CFLAGS) -INTERNAL_CFLAGS = ${INTERNAL_WARN_CFLAGS} $(WERROR_CFLAGS) -DGDBSERVER - -# LDFLAGS is specifically reserved for setting from the command line -# when running make. -LDFLAGS = @LDFLAGS@ -INTERNAL_LDFLAGS = $(LDFLAGS) @RDYNAMIC@ - -# All source files that go into linking GDB remote server. - -SFILES = \ - $(srcdir)/debug.c \ - $(srcdir)/dll.c \ - $(srcdir)/gdbreplay.c \ - $(srcdir)/hostio.c \ - $(srcdir)/hostio-errno.c \ - $(srcdir)/i387-fp.c \ - $(srcdir)/inferiors.c \ - $(srcdir)/linux-aarch64-low.c \ - $(srcdir)/linux-arm-low.c \ - $(srcdir)/linux-bfin-low.c \ - $(srcdir)/linux-cris-low.c \ - $(srcdir)/linux-crisv32-low.c \ - $(srcdir)/linux-ia64-low.c \ - $(srcdir)/linux-low.c \ - $(srcdir)/linux-m32r-low.c \ - $(srcdir)/linux-m68k-low.c \ - $(srcdir)/linux-mips-low.c \ - $(srcdir)/linux-nios2-low.c \ - $(srcdir)/linux-ppc-low.c \ - $(srcdir)/linux-s390-low.c \ - $(srcdir)/linux-sh-low.c \ - $(srcdir)/linux-sparc-low.c \ - $(srcdir)/linux-tile-low.c \ - $(srcdir)/linux-x86-low.c \ - $(srcdir)/linux-xtensa-low.c \ - $(srcdir)/mem-break.c \ - $(srcdir)/proc-service.c \ - $(srcdir)/proc-service.list \ - $(srcdir)/regcache.c \ - $(srcdir)/remote-utils.c \ - $(srcdir)/server.c \ - $(srcdir)/symbol.c \ - $(srcdir)/target.c \ - $(srcdir)/thread-db.c \ - $(srcdir)/utils.c \ - $(srcdir)/win32-arm-low.c \ - $(srcdir)/win32-i386-low.c \ - $(srcdir)/win32-low.c \ - $(srcdir)/wincecompat.c \ - $(srcdir)/x86-low.c \ - $(srcdir)/../alloc.c \ - $(srcdir)/../arch/arm.c \ - $(srcdir)/../arch/arm-get-next-pcs.c \ - $(srcdir)/../arch/arm-linux.c \ - $(srcdir)/../arch/ppc-linux-common.c \ - $(srcdir)/../../gdbsupport/btrace-common.c \ - $(srcdir)/../../gdbsupport/buffer.c \ - $(srcdir)/../../gdbsupport/cleanups.c \ - $(srcdir)/../../gdbsupport/common-debug.c \ - $(srcdir)/../../gdbsupport/common-exceptions.c \ - $(srcdir)/../../gdbsupport/common-inferior.c \ - $(srcdir)/../../gdbsupport/common-regcache.c \ - $(srcdir)/../../gdbsupport/common-utils.c \ - $(srcdir)/../../gdbsupport/errors.c \ - $(srcdir)/../../gdbsupport/environ.c \ - $(srcdir)/../../gdbsupport/fileio.c \ - $(srcdir)/../../gdbsupport/filestuff.c \ - $(srcdir)/../../gdbsupport/job-control.c \ - $(srcdir)/../../gdbsupport/gdb-dlfcn.c \ - $(srcdir)/../../gdbsupport/gdb_tilde_expand.c \ - $(srcdir)/../../gdbsupport/gdb_vecs.c \ - $(srcdir)/../../gdbsupport/gdb_wait.c \ - $(srcdir)/../../gdbsupport/netstuff.c \ - $(srcdir)/../../gdbsupport/new-op.c \ - $(srcdir)/../../gdbsupport/pathstuff.c \ - $(srcdir)/../../gdbsupport/print-utils.c \ - $(srcdir)/../../gdbsupport/ptid.c \ - $(srcdir)/../../gdbsupport/rsp-low.c \ - $(srcdir)/../../gdbsupport/safe-strerror.c \ - $(srcdir)/../../gdbsupport/tdesc.c \ - $(srcdir)/../../gdbsupport/xml-utils.c \ - $(srcdir)/../nat/aarch64-sve-linux-ptrace.c \ - $(srcdir)/../nat/linux-btrace.c \ - $(srcdir)/../nat/linux-namespaces.c \ - $(srcdir)/../nat/linux-osdata.c \ - $(srcdir)/../nat/linux-personality.c \ - $(srcdir)/../nat/mips-linux-watch.c \ - $(srcdir)/../nat/ppc-linux.c \ - $(srcdir)/../nat/fork-inferior.c \ - $(srcdir)/../target/waitstatus.c - -DEPFILES = @GDBSERVER_DEPFILES@ - -LIBOBJS = @LIBOBJS@ - -SOURCES = $(SFILES) -TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} - -OBS = \ - alloc.o \ - ax.o \ - gdbsupport/agent.o \ - gdbsupport/btrace-common.o \ - gdbsupport/buffer.o \ - gdbsupport/cleanups.o \ - gdbsupport/common-debug.o \ - gdbsupport/common-exceptions.o \ - gdbsupport/common-inferior.o \ - gdbsupport/job-control.o \ - gdbsupport/common-regcache.o \ - gdbsupport/common-utils.o \ - gdbsupport/errors.o \ - gdbsupport/environ.o \ - gdbsupport/fileio.o \ - gdbsupport/filestuff.o \ - gdbsupport/format.o \ - gdbsupport/gdb-dlfcn.o \ - gdbsupport/gdb_tilde_expand.o \ - gdbsupport/gdb_vecs.o \ - gdbsupport/gdb_wait.o \ - gdbsupport/netstuff.o \ - gdbsupport/new-op.o \ - gdbsupport/pathstuff.o \ - gdbsupport/print-utils.o \ - gdbsupport/ptid.o \ - gdbsupport/rsp-low.o \ - gdbsupport/safe-strerror.o \ - gdbsupport/signals.o \ - gdbsupport/signals-state-save-restore.o \ - gdbsupport/tdesc.o \ - gdbsupport/xml-utils.o \ - debug.o \ - dll.o \ - event-loop.o \ - hostio.o \ - inferiors.o \ - mem-break.o \ - notif.o \ - regcache.o \ - remote-utils.o \ - server.o \ - symbol.o \ - target.o \ - tdesc.o \ - tracepoint.o \ - utils.o \ - version.o \ - target/waitstatus.o \ - $(DEPFILES) \ - $(LIBOBJS) \ - $(XML_BUILTIN) - -GDBREPLAY_OBS = \ - gdbsupport/cleanups.o \ - gdbsupport/common-exceptions.o \ - gdbsupport/common-utils.o \ - gdbsupport/rsp-low.o \ - gdbsupport/errors.o \ - gdbsupport/netstuff.o \ - gdbsupport/print-utils.o \ - gdbsupport/safe-strerror.o \ - gdbreplay.o \ - utils.o \ - version.o - -GDBSERVER_LIBS = @GDBSERVER_LIBS@ $(PTHREAD_LIBS) -XM_CLIBS = @LIBS@ -CDEPS = $(srcdir)/proc-service.list - -# XML files to compile in to gdbserver, if any. -XML_DIR = $(srcdir)/../features -XML_FILES = @srv_xmlfiles@ -XML_BUILTIN = @srv_xmlbuiltin@ - -IPA_DEPFILES = @IPA_DEPFILES@ -extra_libraries = @extra_libraries@ - -SUBDIRS = $(GNULIB_BUILDDIR) $(LIBIBERTY_BUILDDIR) -CLEANDIRS = $(SUBDIRS) - -# List of subdirectories in the build tree that must exist. -# This is used to force build failures in existing trees when -# a new directory is added. -# The format here is for the `case' shell command. -REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR) | $(LIBIBERTY_BUILDDIR) - -FLAGS_TO_PASS = \ - "prefix=$(prefix)" \ - "exec_prefix=$(exec_prefix)" \ - "infodir=$(infodir)" \ - "datarootdir=$(datarootdir)" \ - "docdir=$(docdir)" \ - "htmldir=$(htmldir)" \ - "pdfdir=$(pdfdir)" \ - "libdir=$(libdir)" \ - "mandir=$(mandir)" \ - "datadir=$(datadir)" \ - "includedir=$(includedir)" \ - "against=$(against)" \ - "DESTDIR=$(DESTDIR)" \ - "AR=$(AR)" \ - "AR_FLAGS=$(AR_FLAGS)" \ - "CC=$(CC)" \ - "CFLAGS=$(CFLAGS)" \ - "CXX=$(CXX)" \ - "CXXFLAGS=$(CXXFLAGS)" \ - "DLLTOOL=$(DLLTOOL)" \ - "LDFLAGS=$(LDFLAGS)" \ - "RANLIB=$(RANLIB)" \ - "MAKEINFO=$(MAKEINFO)" \ - "MAKEHTML=$(MAKEHTML)" \ - "MAKEHTMLFLAGS=$(MAKEHTMLFLAGS)" \ - "INSTALL=$(INSTALL)" \ - "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ - "INSTALL_DATA=$(INSTALL_DATA)" \ - "RUNTEST=$(RUNTEST)" \ - "RUNTESTFLAGS=$(RUNTESTFLAGS)" - -# All generated files which can be included by another file. -generated_files = config.h $(GNULIB_H) - -all: gdbserver$(EXEEXT) gdbreplay$(EXEEXT) $(extra_libraries) - @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do - -# Traditionally "install" depends on "all". But it may be useful -# not to; for example, if the user has made some trivial change to a -# source file and doesn't care about rebuilding or just wants to save the -# time it takes for make to check that all is up to date. -# install-only is intended to address that need. -install: all - @$(MAKE) $(FLAGS_TO_PASS) install-only - -install-only: - n=`echo gdbserver | sed '$(program_transform_name)'`; \ - if [ x$$n = x ]; then n=gdbserver; else true; fi; \ - if [ x"$(IPA_DEPFILES)" != x ]; then \ - $(SHELL) $(srcdir)/../../mkinstalldirs $(DESTDIR)$(libdir); \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $(IPA_LIB) $(DESTDIR)$(libdir)/$(IPA_LIB); \ - fi; \ - $(SHELL) $(srcdir)/../../mkinstalldirs $(DESTDIR)$(bindir); \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) gdbserver$(EXEEXT) $(DESTDIR)$(bindir)/$$n$(EXEEXT) - # Note that we run install and not install-only, as the latter - # is not part of GNU standards and in particular not provided - # in libiberty. - @$(MAKE) $(FLAGS_TO_PASS) DO=install "DODIRS=$(SUBDIRS)" subdir_do - -install-strip: - $(MAKE) $(FLAGS_TO_PASS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install-only - -uninstall: force - n=`echo gdbserver | sed '$(program_transform_name)'`; \ - if [ x$$n = x ]; then n=gdbserver; else true; fi; \ - rm -f $(DESTDIR)/$(bindir)/$$n$(EXEEXT) $(DESTDIR)$(man1dir)/$$n.1 - @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do - -installcheck: -check: -info dvi pdf: -install-info: -install-pdf: -html: -install-html: -clean-info: force - @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do - -gdbserver$(EXEEXT): $(sort $(OBS)) ${CDEPS} $(LIBGNU) $(LIBIBERTY) - $(SILENCE) rm -f gdbserver$(EXEEXT) - $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) \ - -o gdbserver$(EXEEXT) $(OBS) $(LIBGNU) $(LIBIBERTY) \ - $(GDBSERVER_LIBS) $(XM_CLIBS) - -$(LIBGNU) $(LIBIBERTY) $(GNULIB_H): all-lib -all-lib: $(GNULIB_BUILDDIR)/Makefile $(LIBIBERTY_BUILDDIR)/Makefile - @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS="$(SUBDIRS)" subdir_do -.PHONY: all-lib - -gdbreplay$(EXEEXT): $(sort $(GDBREPLAY_OBS)) $(LIBGNU) $(LIBIBERTY) - $(SILENCE) rm -f gdbreplay$(EXEEXT) - $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) \ - -o gdbreplay$(EXEEXT) $(GDBREPLAY_OBS) $(XM_CLIBS) $(LIBGNU) \ - $(LIBIBERTY) - -IPA_OBJS = \ - alloc-ipa.o \ - ax-ipa.o \ - gdbsupport/common-utils-ipa.o \ - gdbsupport/errors-ipa.o \ - gdbsupport/format-ipa.o \ - gdbsupport/print-utils-ipa.o \ - gdbsupport/rsp-low-ipa.o \ - gdbsupport/safe-strerror-ipa.o \ - gdbsupport/tdesc-ipa.o \ - regcache-ipa.o \ - remote-utils-ipa.o \ - tdesc-ipa.o \ - tracepoint-ipa.o \ - utils-ipa.o \ - ${IPA_DEPFILES} - -IPA_LIB = libinproctrace.so - -$(IPA_LIB): $(sort $(IPA_OBJS)) ${CDEPS} - $(SILENCE) rm -f $(IPA_LIB) - $(ECHO_CXXLD) $(CC_LD) -shared -fPIC -Wl,--soname=$(IPA_LIB) \ - -Wl,--no-undefined $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) \ - -o $(IPA_LIB) ${IPA_OBJS} -ldl -pthread - -# Put the proper machine-specific files first, so M-. on a machine -# specific routine gets the one for the correct machine. -# The xyzzy stuff below deals with empty DEPFILES -TAGS: ${TAGFILES} - etags \ - `for i in yzzy ${DEPFILES}; do \ - if [ x$$i != xyzzy ]; then \ - echo ${srcdir}/$$i | sed -e 's/\.o$$/\.c/' \ - -e 's,/\(arch\|nat\|target\)/,/../\1/,' \ - -e 's,/\(gdbsupport\)/,/../../\1/,'; \ - fi; \ - done` \ - ${TAGFILES} -tags: TAGS - -clean: - rm -f *.o ${ADD_FILES} *~ - rm -f gdbserver$(EXEEXT) gdbreplay$(EXEEXT) core make.log - rm -f $(IPA_LIB) - rm -f *-generated.c - rm -f stamp-xml - rm -f $(DEPDIR)/*.Po - for i in $(CONFIG_SRC_SUBDIR); do \ - rm -f $$i/*.o; \ - rm -f $$i/$(DEPDIR)/*; \ - done - @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do - -maintainer-clean realclean distclean: clean - @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do - rm -rf $(GNULIB_BUILDDIR) - rm -f Makefile config.status config.h stamp-h config.log - rm -f Makefile - for i in $(CONFIG_SRC_SUBDIR); do \ - rmdir $$i/$(DEPDIR); \ - done - -subdir_do: force - @for i in $(DODIRS); do \ - case $$i in \ - $(REQUIRED_SUBDIRS)) \ - if [ ! -f ./$$i/Makefile ] ; then \ - echo "Missing $$i/Makefile" >&2 ; \ - exit 1 ; \ - fi ;; \ - esac ; \ - if [ -f ./$$i/Makefile ] ; then \ - if (cd ./$$i; \ - $(MAKE) $(FLAGS_TO_PASS) $(DO)) ; then true ; \ - else exit 1 ; fi ; \ - else true ; fi ; \ - done - -config.h: stamp-h ; @true -stamp-h: config.in config.status - $(SHELL) ./config.status config.h - -Makefile: Makefile.in config.status - $(SHELL) ./config.status $@ - -$(GNULIB_BUILDDIR)/Makefile: $(srcdir)/../../gnulib/Makefile.in config.status - @cd $(GNULIB_BUILDDIR); CONFIG_FILES="Makefile" \ - CONFIG_COMMANDS="depfiles" \ - CONFIG_HEADERS= \ - CONFIG_LINKS= \ - $(SHELL) config.status - -config.status: configure configure.srv $(srcdir)/../../bfd/development.sh - $(SHELL) ./config.status --recheck - -# automatic rebuilding in automake-generated Makefiles requires -# this rule in the toplevel Makefile, which, with GNU make, causes -# the desired updates through the implicit regeneration of the Makefile -# and all of its prerequisites. -am--refresh: - @: - -force: - -version-generated.c: Makefile $(srcdir)/../version.in $(srcdir)/../../bfd/version.h $(srcdir)/../../gdbsupport/create-version.sh - $(ECHO_GEN) $(SHELL) $(srcdir)/../../gdbsupport/create-version.sh $(srcdir)/.. \ - $(host_alias) $(target_alias) $@ - -xml-builtin-generated.c: stamp-xml; @true -stamp-xml: $(XML_DIR)/feature_to_c.sh Makefile $(XML_FILES) - $(SILENCE) rm -f xml-builtin.tmp - $(ECHO_GEN_XML_BUILTIN_GENERATED) $(SHELL) $(XML_DIR)/feature_to_c.sh \ - xml-builtin.tmp $(XML_FILES) - $(SILENCE) $(SHELL) $(srcdir)/../../move-if-change xml-builtin.tmp xml-builtin-generated.c - $(SILENCE) echo stamp > stamp-xml - -.PRECIOUS: xml-builtin.c - -# GNU Make has an annoying habit of putting *all* the Makefile variables -# into the environment, unless you include this target as a circumvention. -# Rumor is that this will be fixed (and this target can be removed) -# in GNU Make 4.0. -.NOEXPORT: - -# GNU Make 3.63 has a different problem: it keeps tacking command line -# overrides onto the definition of $(MAKE). This variable setting -# will remove them. -MAKEOVERRIDES = - -regdat_sh = $(srcdir)/../regformats/regdat.sh - -UST_CFLAGS = $(ustinc) -DCONFIG_UST_GDB_INTEGRATION - -# Undo gnulib replacements for the IPA shared library build. -# The gnulib headers are still needed, but gnulib is not linked -# into the IPA lib so replacement apis don't work. -UNDO_GNULIB_CFLAGS = -Drpl_strerror_r=strerror_r - -# Note, we only build the IPA if -fvisibility=hidden is supported in -# the first place. -IPAGENT_CFLAGS = $(INTERNAL_CFLAGS) $(UST_CFLAGS) \ - $(UNDO_GNULIB_CFLAGS) \ - -fPIC -DIN_PROCESS_AGENT \ - -fvisibility=hidden - -IPAGENT_COMPILE = $(ECHO_CXX) $(COMPILE.pre) $(IPAGENT_CFLAGS) $(COMPILE.post) - -# Rules for special cases. - -ax-ipa.o: ax.c - $(IPAGENT_COMPILE) $(WARN_CFLAGS_NO_FORMAT) $< - $(POSTCOMPILE) - -ax.o: ax.c - $(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $< - $(POSTCOMPILE) - -# Rules for objects that go in the in-process agent. - -arch/%-ipa.o: ../arch/%.c - $(IPAGENT_COMPILE) $< - $(POSTCOMPILE) - -gdbsupport/%-ipa.o: ../../gdbsupport/%.c - $(IPAGENT_COMPILE) $< - $(POSTCOMPILE) - -%-ipa.o: %-generated.c - $(IPAGENT_COMPILE) $< - $(POSTCOMPILE) - -%-ipa.o: %.c - $(IPAGENT_COMPILE) $< - $(POSTCOMPILE) - -%-ipa.o: ../%.c - $(IPAGENT_COMPILE) $< - $(POSTCOMPILE) - -# Note: Between two matching pattern rules, GNU Make 3.81 chooses the first one. -# Therefore, this one needs to be before "%.o: %.c" for it to be considered for -# files such as linux-amd64-ipa.o generated from linux-amd64-ipa.c. -# -# Later versions of GNU Make choose the rule with the shortest stem, so it would -# work in any order. - -%-ipa.o: %-ipa.c - $(IPAGENT_COMPILE) $< - $(POSTCOMPILE) - -# Rules for objects that go in the gdbserver binary. - -arch/%.o: ../arch/%.c - $(COMPILE) $< - $(POSTCOMPILE) - -gdbsupport/%.o: ../../gdbsupport/%.c - $(COMPILE) $< - $(POSTCOMPILE) - -%.o: %-generated.c - $(COMPILE) $< - $(POSTCOMPILE) - -%.o: %.c - $(COMPILE) $< - $(POSTCOMPILE) - -nat/%.o: ../nat/%.c - $(COMPILE) $< - $(POSTCOMPILE) - -target/%.o: ../target/%.c - $(COMPILE) $< - $(POSTCOMPILE) - -%.o: ../%.c - $(COMPILE) $< - $(POSTCOMPILE) - -# Rules for register format descriptions. Suffix destination files with -# -generated to identify and clean them easily. - -%-generated.c: ../regformats/%.dat $(regdat_sh) - $(ECHO_REGDAT) $(SHELL) $(regdat_sh) $< $@ - -%-generated.c: ../regformats/arm/%.dat $(regdat_sh) - $(ECHO_REGDAT) $(SHELL) $(regdat_sh) $< $@ - -%-generated.c: ../regformats/rs6000/%.dat $(regdat_sh) - $(ECHO_REGDAT) $(SHELL) $(regdat_sh) $< $@ - -# -# Dependency tracking. -# - -ifeq ($(DEPMODE),depmode=gcc3) -# Note that we put the dependencies into a .Tpo file, then move them -# into place if the compile succeeds. We need this because gcc does -# not atomically write the dependency output file. -override COMPILE.post = -c -o $@ -MT $@ -MMD -MP \ - -MF $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo -override POSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo \ - $(@D)/$(DEPDIR)/$(basename $(@F)).Po -else -override COMPILE.pre = source='$<' object='$@' libtool=no \ - DEPDIR=$(DEPDIR) $(DEPMODE) $(depcomp) \ - $(CXX) -x c++ $(CXX_DIALECT) -# depcomp handles atomicity for us, so we don't need a postcompile -# step. -override POSTCOMPILE = -endif - -# A list of all the objects we might care about in this build, for -# dependency tracking. -all_object_files = $(OBS) $(GDBREPLAY_OBS) $(IPA_OBJS) - -# Ensure that generated files are created early. Use order-only -# dependencies if available. They require GNU make 3.80 or newer, -# and the .VARIABLES variable was introduced at the same time. -ifdef .VARIABLES -$(all_object_files): | $(generated_files) -else -$(all_object_files) : $(generated_files) -endif - -# All the .deps files to include. -all_deps_files = $(foreach dep,$(patsubst %.o,%.Po,$(all_object_files)),\ - $(dir $(dep))/$(DEPDIR)/$(notdir $(dep))) - -# Dependencies. --include $(all_deps_files) - -# Disable implicit make rules. -include $(srcdir)/../disable-implicit-rules.mk - -# Do not delete intermediate files (e.g. *-generated.c). -.SECONDARY: - -# This is the end of "Makefile.in". diff --git a/gdb/gdbserver/README b/gdb/gdbserver/README deleted file mode 100644 index 52a876b24e8..00000000000 --- a/gdb/gdbserver/README +++ /dev/null @@ -1,152 +0,0 @@ - README for GDBserver & GDBreplay - by Stu Grossman and Fred Fish - -Introduction: - -This is GDBserver, a remote server for Un*x-like systems. It can be used to -control the execution of a program on a target system from a GDB on a different -host. GDB and GDBserver communicate using the standard remote serial protocol -implemented in remote.c, and various *-stub.c files. They communicate via -either a serial line or a TCP connection. - -For more information about GDBserver, see the GDB manual. - -Usage (server (target) side): - -First, you need to have a copy of the program you want to debug put onto -the target system. The program can be stripped to save space if needed, as -GDBserver doesn't care about symbols. All symbol handling is taken care of by -the GDB running on the host system. - -To use the server, you log on to the target system, and run the `gdbserver' -program. You must tell it (a) how to communicate with GDB, (b) the name of -your program, and (c) its arguments. The general syntax is: - - target> gdbserver COMM PROGRAM [ARGS ...] - -For example, using a serial port, you might say: - - target> gdbserver /dev/com1 emacs foo.txt - -This tells GDBserver to debug emacs with an argument of foo.txt, and to -communicate with GDB via /dev/com1. GDBserver now waits patiently for the -host GDB to communicate with it. - -To use a TCP connection, you could say: - - target> gdbserver host:2345 emacs foo.txt - -This says pretty much the same thing as the last example, except that we are -going to communicate with the host GDB via TCP. The `host:2345' argument means -that we are expecting to see a TCP connection from `host' to local TCP port -2345. (Currently, the `host' part is ignored.) You can choose any number you -want for the port number as long as it does not conflict with any existing TCP -ports on the target system. This same port number must be used in the host -GDBs `target remote' command, which will be described shortly. Note that if -you chose a port number that conflicts with another service, GDBserver will -print an error message and exit. - -On some targets, GDBserver can also attach to running programs. This is -accomplished via the --attach argument. The syntax is: - - target> gdbserver --attach COMM PID - -PID is the process ID of a currently running process. It isn't necessary -to point GDBserver at a binary for the running process. - -Usage (host side): - -You need an unstripped copy of the target program on your host system, since -GDB needs to examine it's symbol tables and such. Start up GDB as you normally -would, with the target program as the first argument. (You may need to use the ---baud option if the serial line is running at anything except 9600 baud.) -Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET-PROG'. After that, the only -new command you need to know about is `target remote'. It's argument is either -a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT -descriptor. For example: - - (gdb) target remote /dev/ttyb - -communicates with the server via serial line /dev/ttyb, and: - - (gdb) target remote the-target:2345 - -communicates via a TCP connection to port 2345 on host `the-target', where -you previously started up GDBserver with the same port number. Note that for -TCP connections, you must start up GDBserver prior to using the `target remote' -command, otherwise you may get an error that looks something like -`Connection refused'. - -Building GDBserver: - -The supported targets as of November 2006 are: - arm-*-linux* - bfin-*-uclinux - bfin-*-linux-uclibc - crisv32-*-linux* - cris-*-linux* - i[34567]86-*-cygwin* - i[34567]86-*-linux* - i[34567]86-*-mingw* - ia64-*-linux* - m32r*-*-linux* - m68*-*-linux* - m68*-*-uclinux* - mips*64*-*-linux* - mips*-*-linux* - powerpc[64]-*-linux* - s390[x]-*-linux* - sh-*-linux* - spu*-*-* - x86_64-*-linux* - -Configuring GDBserver you should specify the same machine for host and -target (which are the machine that GDBserver is going to run on. This -is not the same as the machine that GDB is going to run on; building -GDBserver automatically as part of building a whole tree of tools does -not currently work if cross-compilation is involved (we don't get the -right CC in the Makefile, to start with)). - -Building GDBserver for your target is very straightforward. If you build -GDB natively on a target which GDBserver supports, it will be built -automatically when you build GDB. You can also build just GDBserver: - - % mkdir obj - % cd obj - % path-to-gdbserver-sources/configure - % make - -If you prefer to cross-compile to your target, then you can also build -GDBserver that way. In a Bourne shell, for example: - - % export CC=your-cross-compiler - % path-to-gdbserver-sources/configure your-target-name - % make - -Using GDBreplay: - -A special hacked down version of GDBserver can be used to replay remote -debug log files created by GDB. Before using the GDB "target" command to -initiate a remote debug session, use "set remotelogfile " to tell -GDB that you want to make a recording of the serial or tcp session. Note -that when replaying the session, GDB communicates with GDBreplay via tcp, -regardless of whether the original session was via a serial link or tcp. - -Once you are done with the remote debug session, start GDBreplay and -tell it the name of the log file and the host and port number that GDB -should connect to (typically the same as the host running GDB): - - $ gdbreplay logfile host:port - -Then start GDB (preferably in a different screen or window) and use the -"target" command to connect to GDBreplay: - - (gdb) target remote host:port - -Repeat the same sequence of user commands to GDB that you gave in the -original debug session. GDB should not be able to tell that it is talking -to GDBreplay rather than a real target, all other things being equal. Note -that GDBreplay echos the command lines to stderr, as well as the contents of -the packets it sends and receives. The last command echoed by GDBreplay is -the next command that needs to be typed to GDB to continue the session in -sync with the original session. diff --git a/gdb/gdbserver/acinclude.m4 b/gdb/gdbserver/acinclude.m4 deleted file mode 100644 index eba3a131315..00000000000 --- a/gdb/gdbserver/acinclude.m4 +++ /dev/null @@ -1,58 +0,0 @@ -dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE. -m4_include(../../bfd/bfd.m4) - -m4_include(../acx_configure_dir.m4) - -# This gets AM_GDB_WARNINGS. -m4_include(../warning.m4) - -dnl This gets autoconf bugfixes -m4_include(../../config/override.m4) - -dnl For ACX_PKGVERSION and ACX_BUGURL. -m4_include(../../config/acx.m4) - -m4_include(../../config/depstand.m4) -m4_include(../../config/lead-dot.m4) - -dnl Needed for common.m4 -dnl For AC_LIB_HAVE_LINKFLAGS. -m4_include(../../config/lib-ld.m4) -m4_include(../../config/lib-prefix.m4) -m4_include(../../config/lib-link.m4) -dnl codeset.m4 is needed for common.m4, but not for -dnl anything else in gdbserver. -m4_include(../../config/codeset.m4) -m4_include(../../gdbsupport/common.m4) - -dnl For libiberty_INIT. -m4_include(../libiberty.m4) - -dnl For GDB_AC_PTRACE. -m4_include(../ptrace.m4) - -m4_include(../ax_cxx_compile_stdcxx.m4) - -dnl For GDB_AC_SELFTEST. -m4_include(../selftest.m4) - -m4_include([../../config/ax_pthread.m4]) - -dnl Check for existence of a type $1 in libthread_db.h -dnl Based on BFD_HAVE_SYS_PROCFS_TYPE in bfd/bfd.m4. - -AC_DEFUN([GDBSERVER_HAVE_THREAD_DB_TYPE], -[AC_MSG_CHECKING([for $1 in thread_db.h]) - AC_CACHE_VAL(gdbserver_cv_have_thread_db_type_$1, - [AC_TRY_COMPILE([ -#include ], - [$1 avar], - gdbserver_cv_have_thread_db_type_$1=yes, - gdbserver_cv_have_thread_db_type_$1=no - )]) - if test $gdbserver_cv_have_thread_db_type_$1 = yes; then - AC_DEFINE([HAVE_]translit($1, [a-z], [A-Z]), 1, - [Define if has $1.]) - fi - AC_MSG_RESULT($gdbserver_cv_have_thread_db_type_$1) -]) diff --git a/gdb/gdbserver/aclocal.m4 b/gdb/gdbserver/aclocal.m4 deleted file mode 100644 index 110b416e615..00000000000 --- a/gdb/gdbserver/aclocal.m4 +++ /dev/null @@ -1,202 +0,0 @@ -# generated automatically by aclocal 1.15.1 -*- Autoconf -*- - -# Copyright (C) 1996-2017 Free Software Foundation, Inc. - -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to -# '$srcdir', '$srcdir/..', or '$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is '.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ([2.52])dnl - m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST([install_sh])]) - -# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- -# From Jim Meyering - -# Copyright (C) 1996-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MAINTAINER_MODE([DEFAULT-MODE]) -# ---------------------------------- -# Control maintainer-specific portions of Makefiles. -# Default is to disable them, unless 'enable' is passed literally. -# For symmetry, 'disable' may be passed as well. Anyway, the user -# can override the default with the --enable/--disable switch. -AC_DEFUN([AM_MAINTAINER_MODE], -[m4_case(m4_default([$1], [disable]), - [enable], [m4_define([am_maintainer_other], [disable])], - [disable], [m4_define([am_maintainer_other], [enable])], - [m4_define([am_maintainer_other], [enable]) - m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) -AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) - dnl maintainer-mode's default is 'disable' unless 'enable' is passed - AC_ARG_ENABLE([maintainer-mode], - [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], - am_maintainer_other[ make rules and dependencies not useful - (and sometimes confusing) to the casual installer])], - [USE_MAINTAINER_MODE=$enableval], - [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) - AC_MSG_RESULT([$USE_MAINTAINER_MODE]) - AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) - MAINT=$MAINTAINER_MODE_TRUE - AC_SUBST([MAINT])dnl -] -) - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor 'install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in "make install-strip", and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# -------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -m4_include([acinclude.m4]) diff --git a/gdb/gdbserver/ax.c b/gdb/gdbserver/ax.c deleted file mode 100644 index 213db410a07..00000000000 --- a/gdb/gdbserver/ax.c +++ /dev/null @@ -1,1376 +0,0 @@ -/* Agent expression code for remote server. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "ax.h" -#include "gdbsupport/format.h" -#include "tracepoint.h" -#include "gdbsupport/rsp-low.h" - -static void ax_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2); - -#ifdef IN_PROCESS_AGENT -int debug_agent = 0; -#endif - -static void -ax_vdebug (const char *fmt, ...) -{ - char buf[1024]; - va_list ap; - - va_start (ap, fmt); - vsprintf (buf, fmt, ap); -#ifdef IN_PROCESS_AGENT - fprintf (stderr, PROG "/ax: %s\n", buf); -#else - debug_printf (PROG "/ax: %s\n", buf); -#endif - va_end (ap); -} - -#define ax_debug_1(level, fmt, args...) \ - do { \ - if (level <= debug_threads) \ - ax_vdebug ((fmt), ##args); \ - } while (0) - -#define ax_debug(FMT, args...) \ - ax_debug_1 (1, FMT, ##args) - -/* This enum must exactly match what is documented in - gdb/doc/agentexpr.texi, including all the numerical values. */ - -enum gdb_agent_op - { -#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) \ - gdb_agent_op_ ## NAME = VALUE, -#include "gdbsupport/ax.def" -#undef DEFOP - gdb_agent_op_last - }; - -static const char *gdb_agent_op_names [gdb_agent_op_last] = - { - "?undef?" -#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , # NAME -#include "gdbsupport/ax.def" -#undef DEFOP - }; - -#ifndef IN_PROCESS_AGENT -static const unsigned char gdb_agent_op_sizes [gdb_agent_op_last] = - { - 0 -#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , SIZE -#include "gdbsupport/ax.def" -#undef DEFOP - }; -#endif - -/* A wrapper for gdb_agent_op_names that does some bounds-checking. */ - -static const char * -gdb_agent_op_name (int op) -{ - if (op < 0 || op >= gdb_agent_op_last || gdb_agent_op_names[op] == NULL) - return "?undef?"; - return gdb_agent_op_names[op]; -} - -#ifndef IN_PROCESS_AGENT - -/* The packet form of an agent expression consists of an 'X', number - of bytes in expression, a comma, and then the bytes. */ - -struct agent_expr * -gdb_parse_agent_expr (const char **actparm) -{ - const char *act = *actparm; - ULONGEST xlen; - struct agent_expr *aexpr; - - ++act; /* skip the X */ - act = unpack_varlen_hex (act, &xlen); - ++act; /* skip a comma */ - aexpr = XNEW (struct agent_expr); - aexpr->length = xlen; - aexpr->bytes = (unsigned char *) xmalloc (xlen); - hex2bin (act, aexpr->bytes, xlen); - *actparm = act + (xlen * 2); - return aexpr; -} - -void -gdb_free_agent_expr (struct agent_expr *aexpr) -{ - if (aexpr != NULL) - { - free (aexpr->bytes); - free (aexpr); - } -} - -/* Convert the bytes of an agent expression back into hex digits, so - they can be printed or uploaded. This allocates the buffer, - callers should free when they are done with it. */ - -char * -gdb_unparse_agent_expr (struct agent_expr *aexpr) -{ - char *rslt; - - rslt = (char *) xmalloc (2 * aexpr->length + 1); - bin2hex (aexpr->bytes, rslt, aexpr->length); - return rslt; -} - -/* Bytecode compilation. */ - -CORE_ADDR current_insn_ptr; - -int emit_error; - -struct bytecode_address -{ - int pc; - CORE_ADDR address; - int goto_pc; - /* Offset and size of field to be modified in the goto block. */ - int from_offset, from_size; - struct bytecode_address *next; -} *bytecode_address_table; - -void -emit_prologue (void) -{ - target_emit_ops ()->emit_prologue (); -} - -void -emit_epilogue (void) -{ - target_emit_ops ()->emit_epilogue (); -} - -static void -emit_add (void) -{ - target_emit_ops ()->emit_add (); -} - -static void -emit_sub (void) -{ - target_emit_ops ()->emit_sub (); -} - -static void -emit_mul (void) -{ - target_emit_ops ()->emit_mul (); -} - -static void -emit_lsh (void) -{ - target_emit_ops ()->emit_lsh (); -} - -static void -emit_rsh_signed (void) -{ - target_emit_ops ()->emit_rsh_signed (); -} - -static void -emit_rsh_unsigned (void) -{ - target_emit_ops ()->emit_rsh_unsigned (); -} - -static void -emit_ext (int arg) -{ - target_emit_ops ()->emit_ext (arg); -} - -static void -emit_log_not (void) -{ - target_emit_ops ()->emit_log_not (); -} - -static void -emit_bit_and (void) -{ - target_emit_ops ()->emit_bit_and (); -} - -static void -emit_bit_or (void) -{ - target_emit_ops ()->emit_bit_or (); -} - -static void -emit_bit_xor (void) -{ - target_emit_ops ()->emit_bit_xor (); -} - -static void -emit_bit_not (void) -{ - target_emit_ops ()->emit_bit_not (); -} - -static void -emit_equal (void) -{ - target_emit_ops ()->emit_equal (); -} - -static void -emit_less_signed (void) -{ - target_emit_ops ()->emit_less_signed (); -} - -static void -emit_less_unsigned (void) -{ - target_emit_ops ()->emit_less_unsigned (); -} - -static void -emit_ref (int size) -{ - target_emit_ops ()->emit_ref (size); -} - -static void -emit_if_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_if_goto (offset_p, size_p); -} - -static void -emit_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_goto (offset_p, size_p); -} - -static void -write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) -{ - target_emit_ops ()->write_goto_address (from, to, size); -} - -static void -emit_const (LONGEST num) -{ - target_emit_ops ()->emit_const (num); -} - -static void -emit_reg (int reg) -{ - target_emit_ops ()->emit_reg (reg); -} - -static void -emit_pop (void) -{ - target_emit_ops ()->emit_pop (); -} - -static void -emit_stack_flush (void) -{ - target_emit_ops ()->emit_stack_flush (); -} - -static void -emit_zero_ext (int arg) -{ - target_emit_ops ()->emit_zero_ext (arg); -} - -static void -emit_swap (void) -{ - target_emit_ops ()->emit_swap (); -} - -static void -emit_stack_adjust (int n) -{ - target_emit_ops ()->emit_stack_adjust (n); -} - -/* FN's prototype is `LONGEST(*fn)(int)'. */ - -static void -emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - target_emit_ops ()->emit_int_call_1 (fn, arg1); -} - -/* FN's prototype is `void(*fn)(int,LONGEST)'. */ - -static void -emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - target_emit_ops ()->emit_void_call_2 (fn, arg1); -} - -static void -emit_eq_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_eq_goto (offset_p, size_p); -} - -static void -emit_ne_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_ne_goto (offset_p, size_p); -} - -static void -emit_lt_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_lt_goto (offset_p, size_p); -} - -static void -emit_ge_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_ge_goto (offset_p, size_p); -} - -static void -emit_gt_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_gt_goto (offset_p, size_p); -} - -static void -emit_le_goto (int *offset_p, int *size_p) -{ - target_emit_ops ()->emit_le_goto (offset_p, size_p); -} - -/* Scan an agent expression for any evidence that the given PC is the - target of a jump bytecode in the expression. */ - -static int -is_goto_target (struct agent_expr *aexpr, int pc) -{ - int i; - unsigned char op; - - for (i = 0; i < aexpr->length; i += 1 + gdb_agent_op_sizes[op]) - { - op = aexpr->bytes[i]; - - if (op == gdb_agent_op_goto || op == gdb_agent_op_if_goto) - { - int target = (aexpr->bytes[i + 1] << 8) + aexpr->bytes[i + 2]; - if (target == pc) - return 1; - } - } - - return 0; -} - -/* Given an agent expression, turn it into native code. */ - -enum eval_result_type -compile_bytecodes (struct agent_expr *aexpr) -{ - int pc = 0; - int done = 0; - unsigned char op, next_op; - int arg; - /* This is only used to build 64-bit value for constants. */ - ULONGEST top; - struct bytecode_address *aentry, *aentry2; - -#define UNHANDLED \ - do \ - { \ - ax_debug ("Cannot compile op 0x%x\n", op); \ - return expr_eval_unhandled_opcode; \ - } while (0) - - if (aexpr->length == 0) - { - ax_debug ("empty agent expression\n"); - return expr_eval_empty_expression; - } - - bytecode_address_table = NULL; - - while (!done) - { - op = aexpr->bytes[pc]; - - ax_debug ("About to compile op 0x%x, pc=%d\n", op, pc); - - /* Record the compiled-code address of the bytecode, for use by - jump instructions. */ - aentry = XNEW (struct bytecode_address); - aentry->pc = pc; - aentry->address = current_insn_ptr; - aentry->goto_pc = -1; - aentry->from_offset = aentry->from_size = 0; - aentry->next = bytecode_address_table; - bytecode_address_table = aentry; - - ++pc; - - emit_error = 0; - - switch (op) - { - case gdb_agent_op_add: - emit_add (); - break; - - case gdb_agent_op_sub: - emit_sub (); - break; - - case gdb_agent_op_mul: - emit_mul (); - break; - - case gdb_agent_op_div_signed: - UNHANDLED; - break; - - case gdb_agent_op_div_unsigned: - UNHANDLED; - break; - - case gdb_agent_op_rem_signed: - UNHANDLED; - break; - - case gdb_agent_op_rem_unsigned: - UNHANDLED; - break; - - case gdb_agent_op_lsh: - emit_lsh (); - break; - - case gdb_agent_op_rsh_signed: - emit_rsh_signed (); - break; - - case gdb_agent_op_rsh_unsigned: - emit_rsh_unsigned (); - break; - - case gdb_agent_op_trace: - UNHANDLED; - break; - - case gdb_agent_op_trace_quick: - UNHANDLED; - break; - - case gdb_agent_op_log_not: - emit_log_not (); - break; - - case gdb_agent_op_bit_and: - emit_bit_and (); - break; - - case gdb_agent_op_bit_or: - emit_bit_or (); - break; - - case gdb_agent_op_bit_xor: - emit_bit_xor (); - break; - - case gdb_agent_op_bit_not: - emit_bit_not (); - break; - - case gdb_agent_op_equal: - next_op = aexpr->bytes[pc]; - if (next_op == gdb_agent_op_if_goto - && !is_goto_target (aexpr, pc) - && target_emit_ops ()->emit_eq_goto) - { - ax_debug ("Combining equal & if_goto"); - pc += 1; - aentry->pc = pc; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_eq_goto (&(aentry->from_offset), &(aentry->from_size)); - } - else if (next_op == gdb_agent_op_log_not - && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) - && !is_goto_target (aexpr, pc + 1) - && target_emit_ops ()->emit_ne_goto) - { - ax_debug ("Combining equal & log_not & if_goto"); - pc += 2; - aentry->pc = pc; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_ne_goto (&(aentry->from_offset), &(aentry->from_size)); - } - else - emit_equal (); - break; - - case gdb_agent_op_less_signed: - next_op = aexpr->bytes[pc]; - if (next_op == gdb_agent_op_if_goto - && !is_goto_target (aexpr, pc)) - { - ax_debug ("Combining less_signed & if_goto"); - pc += 1; - aentry->pc = pc; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_lt_goto (&(aentry->from_offset), &(aentry->from_size)); - } - else if (next_op == gdb_agent_op_log_not - && !is_goto_target (aexpr, pc) - && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) - && !is_goto_target (aexpr, pc + 1)) - { - ax_debug ("Combining less_signed & log_not & if_goto"); - pc += 2; - aentry->pc = pc; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_ge_goto (&(aentry->from_offset), &(aentry->from_size)); - } - else - emit_less_signed (); - break; - - case gdb_agent_op_less_unsigned: - emit_less_unsigned (); - break; - - case gdb_agent_op_ext: - arg = aexpr->bytes[pc++]; - if (arg < (sizeof (LONGEST) * 8)) - emit_ext (arg); - break; - - case gdb_agent_op_ref8: - emit_ref (1); - break; - - case gdb_agent_op_ref16: - emit_ref (2); - break; - - case gdb_agent_op_ref32: - emit_ref (4); - break; - - case gdb_agent_op_ref64: - emit_ref (8); - break; - - case gdb_agent_op_if_goto: - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_if_goto (&(aentry->from_offset), &(aentry->from_size)); - break; - - case gdb_agent_op_goto: - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_goto (&(aentry->from_offset), &(aentry->from_size)); - break; - - case gdb_agent_op_const8: - emit_stack_flush (); - top = aexpr->bytes[pc++]; - emit_const (top); - break; - - case gdb_agent_op_const16: - emit_stack_flush (); - top = aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - emit_const (top); - break; - - case gdb_agent_op_const32: - emit_stack_flush (); - top = aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - emit_const (top); - break; - - case gdb_agent_op_const64: - emit_stack_flush (); - top = aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - emit_const (top); - break; - - case gdb_agent_op_reg: - emit_stack_flush (); - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - emit_reg (arg); - break; - - case gdb_agent_op_end: - ax_debug ("At end of expression\n"); - - /* Assume there is one stack element left, and that it is - cached in "top" where emit_epilogue can get to it. */ - emit_stack_adjust (1); - - done = 1; - break; - - case gdb_agent_op_dup: - /* In our design, dup is equivalent to stack flushing. */ - emit_stack_flush (); - break; - - case gdb_agent_op_pop: - emit_pop (); - break; - - case gdb_agent_op_zero_ext: - arg = aexpr->bytes[pc++]; - if (arg < (sizeof (LONGEST) * 8)) - emit_zero_ext (arg); - break; - - case gdb_agent_op_swap: - next_op = aexpr->bytes[pc]; - /* Detect greater-than comparison sequences. */ - if (next_op == gdb_agent_op_less_signed - && !is_goto_target (aexpr, pc) - && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) - && !is_goto_target (aexpr, pc + 1)) - { - ax_debug ("Combining swap & less_signed & if_goto"); - pc += 2; - aentry->pc = pc; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_gt_goto (&(aentry->from_offset), &(aentry->from_size)); - } - else if (next_op == gdb_agent_op_less_signed - && !is_goto_target (aexpr, pc) - && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not) - && !is_goto_target (aexpr, pc + 1) - && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto) - && !is_goto_target (aexpr, pc + 2)) - { - ax_debug ("Combining swap & less_signed & log_not & if_goto"); - pc += 3; - aentry->pc = pc; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - aentry->goto_pc = arg; - emit_le_goto (&(aentry->from_offset), &(aentry->from_size)); - } - else - emit_swap (); - break; - - case gdb_agent_op_getv: - emit_stack_flush (); - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - emit_int_call_1 (get_get_tsv_func_addr (), - arg); - break; - - case gdb_agent_op_setv: - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - emit_void_call_2 (get_set_tsv_func_addr (), - arg); - break; - - case gdb_agent_op_tracev: - UNHANDLED; - break; - - /* GDB never (currently) generates any of these ops. */ - case gdb_agent_op_float: - case gdb_agent_op_ref_float: - case gdb_agent_op_ref_double: - case gdb_agent_op_ref_long_double: - case gdb_agent_op_l_to_d: - case gdb_agent_op_d_to_l: - case gdb_agent_op_trace16: - UNHANDLED; - break; - - default: - ax_debug ("Agent expression op 0x%x not recognized\n", op); - /* Don't struggle on, things will just get worse. */ - return expr_eval_unrecognized_opcode; - } - - /* This catches errors that occur in target-specific code - emission. */ - if (emit_error) - { - ax_debug ("Error %d while emitting code for %s\n", - emit_error, gdb_agent_op_name (op)); - return expr_eval_unhandled_opcode; - } - - ax_debug ("Op %s compiled\n", gdb_agent_op_name (op)); - } - - /* Now fill in real addresses as goto destinations. */ - for (aentry = bytecode_address_table; aentry; aentry = aentry->next) - { - int written = 0; - - if (aentry->goto_pc < 0) - continue; - - /* Find the location that we are going to, and call back into - target-specific code to write the actual address or - displacement. */ - for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next) - { - if (aentry2->pc == aentry->goto_pc) - { - ax_debug ("Want to jump from %s to %s\n", - paddress (aentry->address), - paddress (aentry2->address)); - write_goto_address (aentry->address + aentry->from_offset, - aentry2->address, aentry->from_size); - written = 1; - break; - } - } - - /* Error out if we didn't find a destination. */ - if (!written) - { - ax_debug ("Destination of goto %d not found\n", - aentry->goto_pc); - return expr_eval_invalid_goto; - } - } - - return expr_eval_no_error; -} - -#endif - -/* Make printf-type calls using arguments supplied from the host. We - need to parse the format string ourselves, and call the formatting - function with one argument at a time, partly because there is no - safe portable way to construct a varargs call, and partly to serve - as a security barrier against bad format strings that might get - in. */ - -static void -ax_printf (CORE_ADDR fn, CORE_ADDR chan, const char *format, - int nargs, ULONGEST *args) -{ - const char *f = format; - int i; - const char *current_substring; - int nargs_wanted; - - ax_debug ("Printf of \"%s\" with %d args", format, nargs); - - format_pieces fpieces (&f); - - nargs_wanted = 0; - for (auto &&piece : fpieces) - if (piece.argclass != literal_piece) - ++nargs_wanted; - - if (nargs != nargs_wanted) - error (_("Wrong number of arguments for specified format-string")); - - i = 0; - for (auto &&piece : fpieces) - { - current_substring = piece.string; - ax_debug ("current substring is '%s', class is %d", - current_substring, piece.argclass); - switch (piece.argclass) - { - case string_arg: - { - gdb_byte *str; - CORE_ADDR tem; - int j; - - tem = args[i]; - if (tem == 0) - { - printf (current_substring, "(null)"); - break; - } - - /* This is a %s argument. Find the length of the string. */ - for (j = 0;; j++) - { - gdb_byte c; - - read_inferior_memory (tem + j, &c, 1); - if (c == 0) - break; - } - - /* Copy the string contents into a string inside GDB. */ - str = (gdb_byte *) alloca (j + 1); - if (j != 0) - read_inferior_memory (tem, str, j); - str[j] = 0; - - printf (current_substring, (char *) str); - } - break; - - case long_long_arg: -#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) - { - long long val = args[i]; - - printf (current_substring, val); - break; - } -#else - error (_("long long not supported in agent printf")); -#endif - case int_arg: - { - int val = args[i]; - - printf (current_substring, val); - break; - } - - case long_arg: - { - long val = args[i]; - - printf (current_substring, val); - break; - } - - case size_t_arg: - { - size_t val = args[i]; - - printf (current_substring, val); - break; - } - - case literal_piece: - /* Print a portion of the format string that has no - directives. Note that this will not include any - ordinary %-specs, but it might include "%%". That is - why we use printf_filtered and not puts_filtered here. - Also, we pass a dummy argument because some platforms - have modified GCC to include -Wformat-security by - default, which will warn here if there is no - argument. */ - printf (current_substring, 0); - break; - - default: - error (_("Format directive in '%s' not supported in agent printf"), - current_substring); - } - - /* Maybe advance to the next argument. */ - if (piece.argclass != literal_piece) - ++i; - } - - fflush (stdout); -} - -/* The agent expression evaluator, as specified by the GDB docs. It - returns 0 if everything went OK, and a nonzero error code - otherwise. */ - -enum eval_result_type -gdb_eval_agent_expr (struct eval_agent_expr_context *ctx, - struct agent_expr *aexpr, - ULONGEST *rslt) -{ - int pc = 0; -#define STACK_MAX 100 - ULONGEST stack[STACK_MAX], top; - int sp = 0; - unsigned char op; - int arg; - - /* This union is a convenient way to convert representations. For - now, assume a standard architecture where the hardware integer - types have 8, 16, 32, 64 bit types. A more robust solution would - be to import stdint.h from gnulib. */ - union - { - union - { - unsigned char bytes[1]; - unsigned char val; - } u8; - union - { - unsigned char bytes[2]; - unsigned short val; - } u16; - union - { - unsigned char bytes[4]; - unsigned int val; - } u32; - union - { - unsigned char bytes[8]; - ULONGEST val; - } u64; - } cnv; - - if (aexpr->length == 0) - { - ax_debug ("empty agent expression"); - return expr_eval_empty_expression; - } - - /* Cache the stack top in its own variable. Much of the time we can - operate on this variable, rather than dinking with the stack. It - needs to be copied to the stack when sp changes. */ - top = 0; - - while (1) - { - op = aexpr->bytes[pc++]; - - ax_debug ("About to interpret byte 0x%x", op); - - switch (op) - { - case gdb_agent_op_add: - top += stack[--sp]; - break; - - case gdb_agent_op_sub: - top = stack[--sp] - top; - break; - - case gdb_agent_op_mul: - top *= stack[--sp]; - break; - - case gdb_agent_op_div_signed: - if (top == 0) - { - ax_debug ("Attempted to divide by zero"); - return expr_eval_divide_by_zero; - } - top = ((LONGEST) stack[--sp]) / ((LONGEST) top); - break; - - case gdb_agent_op_div_unsigned: - if (top == 0) - { - ax_debug ("Attempted to divide by zero"); - return expr_eval_divide_by_zero; - } - top = stack[--sp] / top; - break; - - case gdb_agent_op_rem_signed: - if (top == 0) - { - ax_debug ("Attempted to divide by zero"); - return expr_eval_divide_by_zero; - } - top = ((LONGEST) stack[--sp]) % ((LONGEST) top); - break; - - case gdb_agent_op_rem_unsigned: - if (top == 0) - { - ax_debug ("Attempted to divide by zero"); - return expr_eval_divide_by_zero; - } - top = stack[--sp] % top; - break; - - case gdb_agent_op_lsh: - top = stack[--sp] << top; - break; - - case gdb_agent_op_rsh_signed: - top = ((LONGEST) stack[--sp]) >> top; - break; - - case gdb_agent_op_rsh_unsigned: - top = stack[--sp] >> top; - break; - - case gdb_agent_op_trace: - agent_mem_read (ctx, NULL, (CORE_ADDR) stack[--sp], - (ULONGEST) top); - if (--sp >= 0) - top = stack[sp]; - break; - - case gdb_agent_op_trace_quick: - arg = aexpr->bytes[pc++]; - agent_mem_read (ctx, NULL, (CORE_ADDR) top, (ULONGEST) arg); - break; - - case gdb_agent_op_log_not: - top = !top; - break; - - case gdb_agent_op_bit_and: - top &= stack[--sp]; - break; - - case gdb_agent_op_bit_or: - top |= stack[--sp]; - break; - - case gdb_agent_op_bit_xor: - top ^= stack[--sp]; - break; - - case gdb_agent_op_bit_not: - top = ~top; - break; - - case gdb_agent_op_equal: - top = (stack[--sp] == top); - break; - - case gdb_agent_op_less_signed: - top = (((LONGEST) stack[--sp]) < ((LONGEST) top)); - break; - - case gdb_agent_op_less_unsigned: - top = (stack[--sp] < top); - break; - - case gdb_agent_op_ext: - arg = aexpr->bytes[pc++]; - if (arg < (sizeof (LONGEST) * 8)) - { - LONGEST mask = 1 << (arg - 1); - top &= ((LONGEST) 1 << arg) - 1; - top = (top ^ mask) - mask; - } - break; - - case gdb_agent_op_ref8: - agent_mem_read (ctx, cnv.u8.bytes, (CORE_ADDR) top, 1); - top = cnv.u8.val; - break; - - case gdb_agent_op_ref16: - agent_mem_read (ctx, cnv.u16.bytes, (CORE_ADDR) top, 2); - top = cnv.u16.val; - break; - - case gdb_agent_op_ref32: - agent_mem_read (ctx, cnv.u32.bytes, (CORE_ADDR) top, 4); - top = cnv.u32.val; - break; - - case gdb_agent_op_ref64: - agent_mem_read (ctx, cnv.u64.bytes, (CORE_ADDR) top, 8); - top = cnv.u64.val; - break; - - case gdb_agent_op_if_goto: - if (top) - pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]); - else - pc += 2; - if (--sp >= 0) - top = stack[sp]; - break; - - case gdb_agent_op_goto: - pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]); - break; - - case gdb_agent_op_const8: - /* Flush the cached stack top. */ - stack[sp++] = top; - top = aexpr->bytes[pc++]; - break; - - case gdb_agent_op_const16: - /* Flush the cached stack top. */ - stack[sp++] = top; - top = aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - break; - - case gdb_agent_op_const32: - /* Flush the cached stack top. */ - stack[sp++] = top; - top = aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - break; - - case gdb_agent_op_const64: - /* Flush the cached stack top. */ - stack[sp++] = top; - top = aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - top = (top << 8) + aexpr->bytes[pc++]; - break; - - case gdb_agent_op_reg: - /* Flush the cached stack top. */ - stack[sp++] = top; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - { - int regnum = arg; - struct regcache *regcache = ctx->regcache; - - switch (register_size (regcache->tdesc, regnum)) - { - case 8: - collect_register (regcache, regnum, cnv.u64.bytes); - top = cnv.u64.val; - break; - case 4: - collect_register (regcache, regnum, cnv.u32.bytes); - top = cnv.u32.val; - break; - case 2: - collect_register (regcache, regnum, cnv.u16.bytes); - top = cnv.u16.val; - break; - case 1: - collect_register (regcache, regnum, cnv.u8.bytes); - top = cnv.u8.val; - break; - default: - internal_error (__FILE__, __LINE__, - "unhandled register size"); - } - } - break; - - case gdb_agent_op_end: - ax_debug ("At end of expression, sp=%d, stack top cache=0x%s", - sp, pulongest (top)); - if (rslt) - { - if (sp <= 0) - { - /* This should be an error */ - ax_debug ("Stack is empty, nothing to return"); - return expr_eval_empty_stack; - } - *rslt = top; - } - return expr_eval_no_error; - - case gdb_agent_op_dup: - stack[sp++] = top; - break; - - case gdb_agent_op_pop: - if (--sp >= 0) - top = stack[sp]; - break; - - case gdb_agent_op_pick: - arg = aexpr->bytes[pc++]; - stack[sp] = top; - top = stack[sp - arg]; - ++sp; - break; - - case gdb_agent_op_rot: - { - ULONGEST tem = stack[sp - 1]; - - stack[sp - 1] = stack[sp - 2]; - stack[sp - 2] = top; - top = tem; - } - break; - - case gdb_agent_op_zero_ext: - arg = aexpr->bytes[pc++]; - if (arg < (sizeof (LONGEST) * 8)) - top &= ((LONGEST) 1 << arg) - 1; - break; - - case gdb_agent_op_swap: - /* Interchange top two stack elements, making sure top gets - copied back onto stack. */ - stack[sp] = top; - top = stack[sp - 1]; - stack[sp - 1] = stack[sp]; - break; - - case gdb_agent_op_getv: - /* Flush the cached stack top. */ - stack[sp++] = top; - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - top = agent_get_trace_state_variable_value (arg); - break; - - case gdb_agent_op_setv: - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - agent_set_trace_state_variable_value (arg, top); - /* Note that we leave the value on the stack, for the - benefit of later/enclosing expressions. */ - break; - - case gdb_agent_op_tracev: - arg = aexpr->bytes[pc++]; - arg = (arg << 8) + aexpr->bytes[pc++]; - agent_tsv_read (ctx, arg); - break; - - case gdb_agent_op_tracenz: - agent_mem_read_string (ctx, NULL, (CORE_ADDR) stack[--sp], - (ULONGEST) top); - if (--sp >= 0) - top = stack[sp]; - break; - - case gdb_agent_op_printf: - { - int nargs, slen, i; - CORE_ADDR fn = 0, chan = 0; - /* Can't have more args than the entire size of the stack. */ - ULONGEST args[STACK_MAX]; - char *format; - - nargs = aexpr->bytes[pc++]; - slen = aexpr->bytes[pc++]; - slen = (slen << 8) + aexpr->bytes[pc++]; - format = (char *) &(aexpr->bytes[pc]); - pc += slen; - /* Pop function and channel. */ - fn = top; - if (--sp >= 0) - top = stack[sp]; - chan = top; - if (--sp >= 0) - top = stack[sp]; - /* Pop arguments into a dedicated array. */ - for (i = 0; i < nargs; ++i) - { - args[i] = top; - if (--sp >= 0) - top = stack[sp]; - } - - /* A bad format string means something is very wrong; give - up immediately. */ - if (format[slen - 1] != '\0') - error (_("Unterminated format string in printf bytecode")); - - ax_printf (fn, chan, format, nargs, args); - } - break; - - /* GDB never (currently) generates any of these ops. */ - case gdb_agent_op_float: - case gdb_agent_op_ref_float: - case gdb_agent_op_ref_double: - case gdb_agent_op_ref_long_double: - case gdb_agent_op_l_to_d: - case gdb_agent_op_d_to_l: - case gdb_agent_op_trace16: - ax_debug ("Agent expression op 0x%x valid, but not handled", - op); - /* If ever GDB generates any of these, we don't have the - option of ignoring. */ - return expr_eval_unhandled_opcode; - - default: - ax_debug ("Agent expression op 0x%x not recognized", op); - /* Don't struggle on, things will just get worse. */ - return expr_eval_unrecognized_opcode; - } - - /* Check for stack badness. */ - if (sp >= (STACK_MAX - 1)) - { - ax_debug ("Expression stack overflow"); - return expr_eval_stack_overflow; - } - - if (sp < 0) - { - ax_debug ("Expression stack underflow"); - return expr_eval_stack_underflow; - } - - ax_debug ("Op %s -> sp=%d, top=0x%s", - gdb_agent_op_name (op), sp, phex_nz (top, 0)); - } -} diff --git a/gdb/gdbserver/ax.h b/gdb/gdbserver/ax.h deleted file mode 100644 index 1fba69e7ad1..00000000000 --- a/gdb/gdbserver/ax.h +++ /dev/null @@ -1,144 +0,0 @@ -/* Data structures and functions associated with agent expressions in GDB. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_AX_H -#define GDBSERVER_AX_H - -#include "regcache.h" - -#ifdef IN_PROCESS_AGENT -#define debug_threads debug_agent -#endif - -struct traceframe; - -/* Enumeration of the different kinds of things that can happen during - agent expression evaluation. */ - -enum eval_result_type - { - expr_eval_no_error, - expr_eval_empty_expression, - expr_eval_empty_stack, - expr_eval_stack_overflow, - expr_eval_stack_underflow, - expr_eval_unhandled_opcode, - expr_eval_unrecognized_opcode, - expr_eval_divide_by_zero, - expr_eval_invalid_goto - }; - -struct agent_expr -{ - int length; - - unsigned char *bytes; -}; - -#ifndef IN_PROCESS_AGENT - -/* The packet form of an agent expression consists of an 'X', number - of bytes in expression, a comma, and then the bytes. */ -struct agent_expr *gdb_parse_agent_expr (const char **actparm); - -/* Release an agent expression. */ -void gdb_free_agent_expr (struct agent_expr *aexpr); - -/* Convert the bytes of an agent expression back into hex digits, so - they can be printed or uploaded. This allocates the buffer, - callers should free when they are done with it. */ -char *gdb_unparse_agent_expr (struct agent_expr *aexpr); -void emit_prologue (void); -void emit_epilogue (void); -enum eval_result_type compile_bytecodes (struct agent_expr *aexpr); -#endif - -/* The context when evaluating agent expression. */ - -struct eval_agent_expr_context -{ - /* The registers when evaluating agent expression. */ - struct regcache *regcache; - /* The traceframe, if any, when evaluating agent expression. */ - struct traceframe *tframe; - /* The tracepoint, if any, when evaluating agent expression. */ - struct tracepoint *tpoint; -}; - -enum eval_result_type - gdb_eval_agent_expr (struct eval_agent_expr_context *ctx, - struct agent_expr *aexpr, - ULONGEST *rslt); - -/* Bytecode compilation function vector. */ - -struct emit_ops -{ - void (*emit_prologue) (void); - void (*emit_epilogue) (void); - void (*emit_add) (void); - void (*emit_sub) (void); - void (*emit_mul) (void); - void (*emit_lsh) (void); - void (*emit_rsh_signed) (void); - void (*emit_rsh_unsigned) (void); - void (*emit_ext) (int arg); - void (*emit_log_not) (void); - void (*emit_bit_and) (void); - void (*emit_bit_or) (void); - void (*emit_bit_xor) (void); - void (*emit_bit_not) (void); - void (*emit_equal) (void); - void (*emit_less_signed) (void); - void (*emit_less_unsigned) (void); - void (*emit_ref) (int size); - void (*emit_if_goto) (int *offset_p, int *size_p); - void (*emit_goto) (int *offset_p, int *size_p); - void (*write_goto_address) (CORE_ADDR from, CORE_ADDR to, int size); - void (*emit_const) (LONGEST num); - void (*emit_call) (CORE_ADDR fn); - void (*emit_reg) (int reg); - void (*emit_pop) (void); - void (*emit_stack_flush) (void); - void (*emit_zero_ext) (int arg); - void (*emit_swap) (void); - void (*emit_stack_adjust) (int n); - - /* Emit code for a generic function that takes one fixed integer - argument and returns a 64-bit int (for instance, tsv getter). */ - void (*emit_int_call_1) (CORE_ADDR fn, int arg1); - - /* Emit code for a generic function that takes one fixed integer - argument and a 64-bit int from the top of the stack, and returns - nothing (for instance, tsv setter). */ - void (*emit_void_call_2) (CORE_ADDR fn, int arg1); - - /* Emit code specialized for common combinations of compare followed - by a goto. */ - void (*emit_eq_goto) (int *offset_p, int *size_p); - void (*emit_ne_goto) (int *offset_p, int *size_p); - void (*emit_lt_goto) (int *offset_p, int *size_p); - void (*emit_le_goto) (int *offset_p, int *size_p); - void (*emit_gt_goto) (int *offset_p, int *size_p); - void (*emit_ge_goto) (int *offset_p, int *size_p); -}; - -extern CORE_ADDR current_insn_ptr; -extern int emit_error; - -#endif /* GDBSERVER_AX_H */ diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in deleted file mode 100644 index da8c313c360..00000000000 --- a/gdb/gdbserver/config.in +++ /dev/null @@ -1,496 +0,0 @@ -/* config.in. Generated from configure.ac by autoheader. */ - -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -#undef CRAY_STACKSEG_END - -/* Define to 1 if std::thread works. */ -#undef CXX_STD_THREAD - -/* Define to 1 if using `alloca.c'. */ -#undef C_ALLOCA - -/* Define if self-testing features should be enabled */ -#undef GDB_SELF_TEST - -/* Define to 1 if you have `alloca', as a function or macro. */ -#undef HAVE_ALLOCA - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -#undef HAVE_ALLOCA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* define if the compiler supports basic C++11 syntax */ -#undef HAVE_CXX11 - -/* Define to 1 if you have the declaration of `ADDR_NO_RANDOMIZE', and to 0 if - you don't. */ -#undef HAVE_DECL_ADDR_NO_RANDOMIZE - -/* Define to 1 if you have the declaration of `asprintf', and to 0 if you - don't. */ -#undef HAVE_DECL_ASPRINTF - -/* Define to 1 if you have the declaration of `basename(char *)', and to 0 if - you don't. */ -#undef HAVE_DECL_BASENAME - -/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */ -#undef HAVE_DECL_FFS - -/* Define to 1 if you have the declaration of `perror', and to 0 if you don't. - */ -#undef HAVE_DECL_PERROR - -/* Define to 1 if you have the declaration of `ptrace', and to 0 if you don't. - */ -#undef HAVE_DECL_PTRACE - -/* Define to 1 if you have the declaration of `snprintf', and to 0 if you - don't. */ -#undef HAVE_DECL_SNPRINTF - -/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. - */ -#undef HAVE_DECL_STRSTR - -/* Define to 1 if you have the declaration of `strtol', and to 0 if you don't. - */ -#undef HAVE_DECL_STRTOL - -/* Define to 1 if you have the declaration of `strtoll', and to 0 if you - don't. */ -#undef HAVE_DECL_STRTOLL - -/* Define to 1 if you have the declaration of `strtoul', and to 0 if you - don't. */ -#undef HAVE_DECL_STRTOUL - -/* Define to 1 if you have the declaration of `strtoull', and to 0 if you - don't. */ -#undef HAVE_DECL_STRTOULL - -/* Define to 1 if you have the declaration of `strverscmp', and to 0 if you - don't. */ -#undef HAVE_DECL_STRVERSCMP - -/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you - don't. */ -#undef HAVE_DECL_VASPRINTF - -/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you - don't. */ -#undef HAVE_DECL_VSNPRINTF - -/* Define to 1 if you have the `dladdr' function. */ -#undef HAVE_DLADDR - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if the system has the type `Elf32_auxv_t'. */ -#undef HAVE_ELF32_AUXV_T - -/* Define to 1 if the system has the type `Elf64_auxv_t'. */ -#undef HAVE_ELF64_AUXV_T - -/* Define if has elf_fpregset_t. */ -#undef HAVE_ELF_FPREGSET_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the `fdwalk' function. */ -#undef HAVE_FDWALK - -/* Define to 1 if you have the `fork' function. */ -#undef HAVE_FORK - -/* Define if has fpregset_t. */ -#undef HAVE_FPREGSET_T - -/* Define to 1 if you have the `getauxval' function. */ -#undef HAVE_GETAUXVAL - -/* Define to 1 if you have the `getpagesize' function. */ -#undef HAVE_GETPAGESIZE - -/* Define to 1 if you have the `getrlimit' function. */ -#undef HAVE_GETRLIMIT - -/* Define to 1 if you have the `getrusage' function. */ -#undef HAVE_GETRUSAGE - -/* Define if has gregset_t. */ -#undef HAVE_GREGSET_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if your system has the kinfo_getfile function. */ -#undef HAVE_KINFO_GETFILE - -/* Define if you have and nl_langinfo(CODESET). */ -#undef HAVE_LANGINFO_CODESET - -/* Define to 1 if you have the `dl' library (-ldl). */ -#undef HAVE_LIBDL - -/* Define if you have the ipt library. */ -#undef HAVE_LIBIPT - -/* Define if the target supports branch tracing. */ -#undef HAVE_LINUX_BTRACE - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_ELF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_PERF_EVENT_H - -/* Define if the target supports register sets. */ -#undef HAVE_LINUX_REGSETS - -/* Define if the target supports PTRACE_PEEKUSR for register access. */ -#undef HAVE_LINUX_USRREGS - -/* Define to 1 if you have the header file. */ -#undef HAVE_LOCALE_H - -/* Define to 1 if the system has the type `long long'. */ -#undef HAVE_LONG_LONG - -/* Define if has lwpid_t. */ -#undef HAVE_LWPID_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have a working `mmap' system call. */ -#undef HAVE_MMAP - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_TCP_H - -/* Define if you support the personality syscall. */ -#undef HAVE_PERSONALITY - -/* Define to 1 if you have the `pipe' function. */ -#undef HAVE_PIPE - -/* Define to 1 if you have the `pipe2' function. */ -#undef HAVE_PIPE2 - -/* Define to 1 if you have the `pread' function. */ -#undef HAVE_PREAD - -/* Define to 1 if you have the `pread64' function. */ -#undef HAVE_PREAD64 - -/* Define if has prfpregset_t. */ -#undef HAVE_PRFPREGSET_T - -/* Define if has prgregset32_t. */ -#undef HAVE_PRGREGSET32_T - -/* Define if has prgregset_t. */ -#undef HAVE_PRGREGSET_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_PROC_SERVICE_H - -/* Define if has psaddr_t. */ -#undef HAVE_PSADDR_T - -/* Have PTHREAD_PRIO_INHERIT. */ -#undef HAVE_PTHREAD_PRIO_INHERIT - -/* Define to 1 if you have the `pthread_setname_np' function. */ -#undef HAVE_PTHREAD_SETNAME_NP - -/* Define to 1 if you have the `pthread_sigmask' function. */ -#undef HAVE_PTHREAD_SIGMASK - -/* Define to 1 if you have the `ptrace64' function. */ -#undef HAVE_PTRACE64 - -/* Define if the target supports PTRACE_GETFPXREGS for extended register - access. */ -#undef HAVE_PTRACE_GETFPXREGS - -/* Define if the target supports PTRACE_GETREGS for register access. */ -#undef HAVE_PTRACE_GETREGS - -/* Define to 1 if you have the header file. */ -#undef HAVE_PTRACE_H - -/* Define to 1 if you have the `pt_insn_event' function. */ -#undef HAVE_PT_INSN_EVENT - -/* Define to 1 if you have the `pwrite' function. */ -#undef HAVE_PWRITE - -/* Define to 1 if you have the `sbrk' function. */ -#undef HAVE_SBRK - -/* Define to 1 if you have the `setns' function. */ -#undef HAVE_SETNS - -/* Define to 1 if you have the `setpgid' function. */ -#undef HAVE_SETPGID - -/* Define to 1 if you have the `setpgrp' function. */ -#undef HAVE_SETPGRP - -/* Define to 1 if you have the `sigaction' function. */ -#undef HAVE_SIGACTION - -/* Define to 1 if you have the `sigaltstack' function. */ -#undef HAVE_SIGALTSTACK - -/* Define to 1 if you have the header file. */ -#undef HAVE_SIGNAL_H - -/* Define to 1 if you have the `sigprocmask' function. */ -#undef HAVE_SIGPROCMASK - -/* Define if sigsetjmp is available. */ -#undef HAVE_SIGSETJMP - -/* Define to 1 if you have the `socketpair' function. */ -#undef HAVE_SOCKETPAIR - -/* Define to 1 if the system has the type `socklen_t'. */ -#undef HAVE_SOCKLEN_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if `enabled' is a member of `struct pt_insn'. */ -#undef HAVE_STRUCT_PT_INSN_ENABLED - -/* Define to 1 if `resynced' is a member of `struct pt_insn'. */ -#undef HAVE_STRUCT_PT_INSN_RESYNCED - -/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_BLKSIZE - -/* Define to 1 if `st_blocks' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_BLOCKS - -/* Define to 1 if `fs_base' is a member of `struct user_regs_struct'. */ -#undef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - -/* Define to 1 if `gs_base' is a member of `struct user_regs_struct'. */ -#undef HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE - -/* Define to 1 if the target supports __sync_*_compare_and_swap */ -#undef HAVE_SYNC_BUILTINS - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_FILE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PROCFS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PTRACE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_REG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_WAIT_H - -/* Define if TD_VERSION is available. */ -#undef HAVE_TD_VERSION - -/* Define to 1 if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_THREAD_DB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define if UST is available */ -#undef HAVE_UST - -/* Define to 1 if you have the `vfork' function. */ -#undef HAVE_VFORK - -/* Define to 1 if you have the header file. */ -#undef HAVE_VFORK_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WAIT_H - -/* Define to 1 if `fork' works. */ -#undef HAVE_WORKING_FORK - -/* Define to 1 if `vfork' works. */ -#undef HAVE_WORKING_VFORK - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Additional package description */ -#undef PKGVERSION - -/* Define to necessary symbol if this constant uses a non-standard name on - your system. */ -#undef PTHREAD_CREATE_JOINABLE - -/* Define to the type of arg 1 for ptrace. */ -#undef PTRACE_TYPE_ARG1 - -/* Define to the type of arg 3 for ptrace. */ -#undef PTRACE_TYPE_ARG3 - -/* Define to the type of arg 4 for ptrace. */ -#undef PTRACE_TYPE_ARG4 - -/* Define to the type of arg 5 for ptrace. */ -#undef PTRACE_TYPE_ARG5 - -/* Define as the return type of ptrace. */ -#undef PTRACE_TYPE_RET - -/* Bug reporting address */ -#undef REPORT_BUGS_TO - -/* The size of `long long', as computed by sizeof. */ -#undef SIZEOF_LONG_LONG - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -#undef STACK_DIRECTION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define if we should use libthread_db directly. */ -#undef USE_LIBTHREAD_DB_DIRECTLY - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif - - -/* Define if we should use libthread_db. */ -#undef USE_THREAD_DB - -/* Define if we should use the Windows API, instead of the POSIX API. On - Windows, we use the Windows API when building for MinGW, but the POSIX API - when building for Cygwin. */ -#undef USE_WIN32API - -/* Define if an XML target description is available. */ -#undef USE_XML - -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to 1 if on MINIX. */ -#undef _MINIX - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -#undef _POSIX_1_SOURCE - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -#undef _POSIX_SOURCE - -/* Define to `int' if does not define. */ -#undef pid_t - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define as `fork' if `vfork' does not work. */ -#undef vfork diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure deleted file mode 100755 index 94f2bedf684..00000000000 --- a/gdb/gdbserver/configure +++ /dev/null @@ -1,12159 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, -$0: including any error possibly output before this -$0: message. Then install a modern shell, or manually run -$0: the script under such a shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= - -ac_unique_file="server.c" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_list= -ac_subst_vars='LTLIBOBJS -LIBOBJS -GNULIB_STDINT_H -extra_libraries -IPA_DEPFILES -srv_xmlfiles -srv_xmlbuiltin -GDBSERVER_LIBS -GDBSERVER_DEPFILES -RDYNAMIC -REPORT_BUGS_TEXI -REPORT_BUGS_TO -PKGVERSION -WERROR_CFLAGS -WARN_CFLAGS -ustinc -ustlibs -LTLIBIPT -LIBIPT -HAVE_LIBIPT -PTHREAD_CFLAGS -PTHREAD_LIBS -PTHREAD_CC -ax_pthread_config -SED -ALLOCA -CCDEPMODE -CONFIG_SRC_SUBDIR -DEPDIR -am__leading_dot -host_noncanonical -target_noncanonical -CXX_DIALECT -HAVE_CXX11 -RANLIB -AR -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -target_os -target_vendor -target_cpu -target -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -INSTALL_STRIP_PROGRAM -STRIP -install_sh -EGREP -GREP -CPP -ac_ct_CXX -CXXFLAGS -CXX -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -MAINT -MAINTAINER_MODE_FALSE -MAINTAINER_MODE_TRUE -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_maintainer_mode -enable_largefile -enable_unit_tests -with_intel_pt -with_gnu_ld -enable_rpath -with_libipt_prefix -with_ust -with_ust_include -with_ust_lib -enable_werror -enable_build_warnings -enable_gdb_build_warnings -with_pkgversion -with_bugurl -with_libthread_db -enable_inprocess_agent -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CXX -CXXFLAGS -CCC -CPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures this package to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] - --target=TARGET configure for building compilers for TARGET [HOST] -_ACEOF -fi - -if test -n "$ac_init_help"; then - - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-maintainer-mode - enable make rules and dependencies not useful (and - sometimes confusing) to the casual installer - --disable-largefile omit support for large files - --enable-unit-tests Enable the inclusion of unit tests when compiling - GDB - --disable-rpath do not hardcode runtime library paths - --enable-werror treat compile warnings as errors - --enable-build-warnings enable build-time compiler warnings if gcc is used - --enable-gdb-build-warnings - enable GDB specific build-time compiler warnings if - gcc is used - --enable-inprocess-agent - inprocess agent - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-intel-pt include Intel Processor Trace support (auto/yes/no) - --with-gnu-ld assume the C compiler uses GNU ld default=no - --with-libipt-prefix[=DIR] search for libipt in DIR/include and DIR/lib - --without-libipt-prefix don't search for libipt in includedir and libdir - --with-ust=PATH Specify prefix directory for the installed UST package - Equivalent to --with-ust-include=PATH/include - plus --with-ust-lib=PATH/lib - --with-ust-include=PATH Specify directory for installed UST include files - --with-ust-lib=PATH Specify the directory for the installed UST library - --with-pkgversion=PKG Use PKG in the version string in place of "GDB" - --with-bugurl=URL Direct users to URL to report a bug - --with-libthread-db=PATH - use given libthread_db directly - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CXX C++ compiler command - CXXFLAGS C++ compiler flags - CPP C preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to the package provider. -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -configure -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -# --------------------------------------------- -# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. -ac_fn_c_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_decl - -# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES -# ---------------------------------------------------- -# Tries to find if the field MEMBER exists in type AGGR, after including -# INCLUDES, setting cache variable VAR accordingly. -ac_fn_c_check_member () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - eval "$4=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_member - -# ac_fn_cxx_try_link LINENO -# ------------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_link - -# ac_fn_cxx_check_func LINENO FUNC VAR -# ------------------------------------ -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_cxx_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_cxx_check_func - -# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES -# -------------------------------------------- -# Tries to find the compile-time value of EXPR in a program that includes -# INCLUDES, setting VAR accordingly. Returns whether the value could be -# computed -ac_fn_c_compute_int () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=0 ac_mid=0 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid; break -else - as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=-1 ac_mid=-1 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=$ac_mid; break -else - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - ac_lo= ac_hi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid -else - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in #(( -?*) eval "$3=\$ac_lo"; ac_retval=0 ;; -'') ac_retval=1 ;; -esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - return 1; - if (($2) < 0) - { - long int i = longval (); - if (i != ($2)) - return 1; - fprintf (f, "%ld", i); - } - else - { - unsigned long int i = ulongval (); - if (i != ($2)) - return 1; - fprintf (f, "%lu", i); - } - /* Do not output a trailing newline, as this causes \r\n confusion - on some platforms. */ - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - echo >>conftest.val; read $3 config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -as_fn_append ac_header_list " stdlib.h" -as_fn_append ac_header_list " unistd.h" -as_fn_append ac_header_list " sys/param.h" -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - -ac_config_headers="$ac_config_headers config.h:config.in" - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 -$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } - # Check whether --enable-maintainer-mode was given. -if test "${enable_maintainer_mode+set}" = set; then : - enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval -else - USE_MAINTAINER_MODE=no -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 -$as_echo "$USE_MAINTAINER_MODE" >&6; } - if test $USE_MAINTAINER_MODE = yes; then - MAINTAINER_MODE_TRUE= - MAINTAINER_MODE_FALSE='#' -else - MAINTAINER_MODE_TRUE='#' - MAINTAINER_MODE_FALSE= -fi - - MAINT=$MAINTAINER_MODE_TRUE - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -else - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - -else - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - - ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = xyes; then : - MINIX=yes -else - MINIX= -fi - - - if test "$MINIX" = yes; then - -$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h - - -$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h - - -$as_echo "#define _MINIX 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if ${ac_cv_safe_to_define___extensions__+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_safe_to_define___extensions__=yes -else - ac_cv_safe_to_define___extensions__=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } - test $ac_cv_safe_to_define___extensions__ = yes && - $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h - - $as_echo "#define _ALL_SOURCE 1" >>confdefs.h - - $as_echo "#define _GNU_SOURCE 1" >>confdefs.h - - $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h - - - -# Check whether --enable-largefile was given. -if test "${enable_largefile+set}" = set; then : - enableval=$enable_largefile; -fi - -if test "$enable_largefile" != no; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 -$as_echo_n "checking for special C compiler options needed for large files... " >&6; } -if ${ac_cv_sys_largefile_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_sys_largefile_CC=no - if test "$GCC" != yes; then - ac_save_CC=$CC - while :; do - # IRIX 6.2 and later do not support large files by default, - # so use the C compiler's -n32 option if that helps. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF - if ac_fn_c_try_compile "$LINENO"; then : - break -fi -rm -f core conftest.err conftest.$ac_objext - CC="$CC -n32" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_largefile_CC=' -n32'; break -fi -rm -f core conftest.err conftest.$ac_objext - break - done - CC=$ac_save_CC - rm -f conftest.$ac_ext - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 -$as_echo "$ac_cv_sys_largefile_CC" >&6; } - if test "$ac_cv_sys_largefile_CC" != no; then - CC=$CC$ac_cv_sys_largefile_CC - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 -$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } -if ${ac_cv_sys_file_offset_bits+:} false; then : - $as_echo_n "(cached) " >&6 -else - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_file_offset_bits=no; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define _FILE_OFFSET_BITS 64 -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_file_offset_bits=64; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cv_sys_file_offset_bits=unknown - break -done -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 -$as_echo "$ac_cv_sys_file_offset_bits" >&6; } -case $ac_cv_sys_file_offset_bits in #( - no | unknown) ;; - *) -cat >>confdefs.h <<_ACEOF -#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits -_ACEOF -;; -esac -rm -rf conftest* - if test $ac_cv_sys_file_offset_bits = unknown; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 -$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } -if ${ac_cv_sys_large_files+:} false; then : - $as_echo_n "(cached) " >&6 -else - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_large_files=no; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define _LARGE_FILES 1 -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_sys_large_files=1; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cv_sys_large_files=unknown - break -done -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 -$as_echo "$ac_cv_sys_large_files" >&6; } -case $ac_cv_sys_large_files in #( - no | unknown) ;; - *) -cat >>confdefs.h <<_ACEOF -#define _LARGE_FILES $ac_cv_sys_large_files -_ACEOF -;; -esac -rm -rf conftest* - fi - - -fi - -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 -$as_echo_n "checking target system type... " >&6; } -if ${ac_cv_target+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$target_alias" = x; then - ac_cv_target=$ac_cv_host -else - ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 -$as_echo "$ac_cv_target" >&6; } -case $ac_cv_target in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; -esac -target=$ac_cv_target -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_target -shift -target_cpu=$1 -target_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -target_os=$* -IFS=$ac_save_IFS -case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac - - -# The aliases save the names the user supplied, while $host etc. -# will get canonicalized. -test -n "$target_alias" && - test "$program_prefix$program_suffix$program_transform_name" = \ - NONENONEs,x,x, && - program_prefix=${target_alias}- - - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_AR" = x; then - AR="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -else - AR="$ac_cv_prog_AR" -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was `s,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` - - -# We require a C++11 compiler. Check if one is available, and if -# necessary, set CXX_DIALECT to some -std=xxx switch. - - ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=true - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - CXX_DIALECT="" - ac_success=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 -$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } -if ${ax_cv_cxx_compile_cxx11+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual void f() {} - }; - - struct Derived : public Base - { - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check single_type; - typedef check> double_type; - typedef check>> triple_type; - typedef check>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template - struct sum; - - template - struct sum - { - static constexpr auto value = N0 + sum::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { func(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - - - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ax_cv_cxx_compile_cxx11=yes -else - ax_cv_cxx_compile_cxx11=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 -$as_echo "$ax_cv_cxx_compile_cxx11" >&6; } - if test x$ax_cv_cxx_compile_cxx11 = xyes; then - ac_success=yes - fi - - if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - switch="-std=gnu++${alternative}" - cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 -$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } -if eval \${$cachevar+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_CXX="$CXX" - CXX="$CXX $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual void f() {} - }; - - struct Derived : public Base - { - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check single_type; - typedef check> double_type; - typedef check>> triple_type; - typedef check>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template - struct sum; - - template - struct sum - { - static constexpr auto value = N0 + sum::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { func(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - - - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - eval $cachevar=yes -else - eval $cachevar=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CXX="$ac_save_CXX" -fi -eval ac_res=\$$cachevar - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXX_DIALECT="$switch" - ac_success=yes - break - fi - done - fi - - if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 -$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } -if eval \${$cachevar+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_CXX="$CXX" - CXX="$CXX $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual void f() {} - }; - - struct Derived : public Base - { - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check single_type; - typedef check> double_type; - typedef check>> triple_type; - typedef check>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template - struct sum; - - template - struct sum - { - static constexpr auto value = N0 + sum::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { func(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - - - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - eval $cachevar=yes -else - eval $cachevar=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CXX="$ac_save_CXX" -fi -eval ac_res=\$$cachevar - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXX_DIALECT="$switch" - ac_success=yes - break - fi - done - if test x$ac_success = xyes; then - break - fi - done - fi - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - if test x$ax_cxx_compile_cxx11_required = xtrue; then - if test x$ac_success = xno; then - as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 - fi - fi - if test x$ac_success = xno; then - HAVE_CXX11=0 - { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 -$as_echo "$as_me: No compiler with C++11 support was found" >&6;} - else - HAVE_CXX11=1 - -$as_echo "#define HAVE_CXX11 1" >>confdefs.h - - fi - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - - -# Set the 'development' global. -. $srcdir/../../bfd/development.sh - - -# Check whether we will enable the inclusion of unit tests when -# compiling GDB. -# -# The default value of this option changes depending whether we're on -# development mode (in which case it's "true") or not (in which case -# it's "false"). -# Check whether --enable-unit-tests was given. -if test "${enable_unit_tests+set}" = set; then : - enableval=$enable_unit_tests; case "${enableval}" in - yes) enable_unittests=true ;; - no) enable_unittests=false ;; - *) as_fn_error $? "bad value ${enableval} for --{enable,disable}-unit-tests option" "$LINENO" 5 ;; -esac -else - enable_unittests=$development -fi - - -if $enable_unittests; then - -$as_echo "#define GDB_SELF_TEST 1" >>confdefs.h - - - srv_selftest_objs="gdbsupport/selftest.o" - -fi - - - case ${build_alias} in - "") build_noncanonical=${build} ;; - *) build_noncanonical=${build_alias} ;; -esac - - case ${host_alias} in - "") host_noncanonical=${build_noncanonical} ;; - *) host_noncanonical=${host_alias} ;; -esac - - case ${target_alias} in - "") target_noncanonical=${host_noncanonical} ;; - *) target_noncanonical=${target_alias} ;; -esac - - - - - - -# Dependency checking. -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depdir" - - - -# Create sub-directories for objects and dependencies. -CONFIG_SRC_SUBDIR="arch gdbsupport nat target" - - -ac_config_commands="$ac_config_commands gdbdepdir" - - -depcc="$CC" am_compiler_list= - -am_depcomp=$ac_aux_dir/depcomp -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CC_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - for depmode in $am_compiler_list; do - if test $depmode = none; then break; fi - - $as_echo "$as_me:$LINENO: trying $depmode" >&5 - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "include sub/conftest.Po" > confmf - - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. - depcmd="depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c" - echo "| $depcmd" | sed -e 's/ */ /g' >&5 - if env $depcmd > conftest.err 2>&1 && - grep sub/conftst6.h sub/conftest.Po >>conftest.err 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po >>conftest.err 2>&1 && - ${MAKE-make} -s -f confmf >>conftest.err 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - $as_echo "$as_me:$LINENO: success" >&5 - break - fi - fi - $as_echo "$as_me:$LINENO: failure, diagnostics are:" >&5 - sed -e 's/^/| /' < conftest.err >&5 - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } -if test x${am_cv_CC_dependencies_compiler_type-none} = xnone -then as_fn_error $? "no usable dependency style found" "$LINENO" 5 -else CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - -fi - - -gnulib_extra_configure_args= -# If large-file support is disabled, make sure gnulib does the same. -if test "$enable_largefile" = no; then -gnulib_extra_configure_args="$gnulib_extra_configure_args --disable-largefile" -fi - -# Configure gnulib. We can't use AC_CONFIG_SUBDIRS as that'd expect -# to find the the source subdir to be configured directly under -# gdbserver/. We need to build gnulib under some other directory not -# "gnulib", to avoid the problem of both GDB and GDBserver wanting to -# build it in the same directory, when building in the source dir. - - in_src="../../gnulib" - in_build="build-gnulib-gdbserver" - in_extra_args="$gnulib_extra_configure_args" - - # Remove --cache-file, --srcdir, and --disable-option-checking arguments - # so they do not pile up. - ac_sub_configure_args= - ac_prev= - eval "set x $ac_configure_args" - shift - for ac_arg - do - if test -n "$ac_prev"; then - ac_prev= - continue - fi - case $ac_arg in - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ - | --c=*) - ;; - --config-cache | -C) - ;; - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - ;; - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - ;; - --disable-option-checking) - ;; - *) - case $ac_arg in - *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_sub_configure_args " '$ac_arg'" ;; - esac - done - - # Always prepend --prefix to ensure using the same prefix - # in subdir configurations. - ac_arg="--prefix=$prefix" - case $ac_arg in - *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" - - # Pass --silent - if test "$silent" = yes; then - ac_sub_configure_args="--silent $ac_sub_configure_args" - fi - - # Always prepend --disable-option-checking to silence warnings, since - # different subdirs can have different --enable and --with options. - ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" - - ac_popdir=`pwd` - ac_dir=$in_build - - ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" - $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 - $as_echo "$ac_msg" >&6 - as_dir="$ac_dir"; as_fn_mkdir_p - - case $srcdir in - [\\/]* | ?:[\\/]* ) - ac_srcdir=$srcdir/$in_src ;; - *) # Relative name. - ac_srcdir=../$srcdir/$in_src ;; - esac - - cd "$ac_dir" - - ac_sub_configure=$ac_srcdir/configure - - # Make the cache file name correct relative to the subdirectory. - case $cache_file in - [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; - *) # Relative name. - ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; - esac - - if test -n "$in_extra_args"; then - # Add the extra args at the end. - ac_sub_configure_args="$ac_sub_configure_args $in_extra_args" - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 -$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} - # The eval makes quoting arguments work. - eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ - --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || - as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 - - cd "$ac_popdir" - - - - in_src="../../libiberty" - in_build="build-libiberty-gdbserver" - in_extra_args= - - # Remove --cache-file, --srcdir, and --disable-option-checking arguments - # so they do not pile up. - ac_sub_configure_args= - ac_prev= - eval "set x $ac_configure_args" - shift - for ac_arg - do - if test -n "$ac_prev"; then - ac_prev= - continue - fi - case $ac_arg in - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ - | --c=*) - ;; - --config-cache | -C) - ;; - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - ;; - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - ;; - --disable-option-checking) - ;; - *) - case $ac_arg in - *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_sub_configure_args " '$ac_arg'" ;; - esac - done - - # Always prepend --prefix to ensure using the same prefix - # in subdir configurations. - ac_arg="--prefix=$prefix" - case $ac_arg in - *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" - - # Pass --silent - if test "$silent" = yes; then - ac_sub_configure_args="--silent $ac_sub_configure_args" - fi - - # Always prepend --disable-option-checking to silence warnings, since - # different subdirs can have different --enable and --with options. - ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" - - ac_popdir=`pwd` - ac_dir=$in_build - - ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" - $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 - $as_echo "$ac_msg" >&6 - as_dir="$ac_dir"; as_fn_mkdir_p - - case $srcdir in - [\\/]* | ?:[\\/]* ) - ac_srcdir=$srcdir/$in_src ;; - *) # Relative name. - ac_srcdir=../$srcdir/$in_src ;; - esac - - cd "$ac_dir" - - ac_sub_configure=$ac_srcdir/configure - - # Make the cache file name correct relative to the subdirectory. - case $cache_file in - [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; - *) # Relative name. - ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; - esac - - if test -n "$in_extra_args"; then - # Add the extra args at the end. - ac_sub_configure_args="$ac_sub_configure_args $in_extra_args" - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 -$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} - # The eval makes quoting arguments work. - eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ - --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || - as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 - - cd "$ac_popdir" - - -for ac_header in termios.h sys/reg.h string.h sys/procfs.h linux/elf.h fcntl.h signal.h sys/file.h sys/ioctl.h netinet/in.h sys/socket.h netdb.h netinet/tcp.h arpa/inet.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define pid_t int -_ACEOF - -fi - -for ac_header in vfork.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" -if test "x$ac_cv_header_vfork_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_VFORK_H 1 -_ACEOF - -fi - -done - -for ac_func in fork vfork -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -if test "x$ac_cv_func_fork" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 -$as_echo_n "checking for working fork... " >&6; } -if ${ac_cv_func_fork_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_fork_works=cross -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ - - /* By Ruediger Kuhlmann. */ - return fork () < 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_fork_works=yes -else - ac_cv_func_fork_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 -$as_echo "$ac_cv_func_fork_works" >&6; } - -else - ac_cv_func_fork_works=$ac_cv_func_fork -fi -if test "x$ac_cv_func_fork_works" = xcross; then - case $host in - *-*-amigaos* | *-*-msdosdjgpp*) - # Override, as these systems have only a dummy fork() stub - ac_cv_func_fork_works=no - ;; - *) - ac_cv_func_fork_works=yes - ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} -fi -ac_cv_func_vfork_works=$ac_cv_func_vfork -if test "x$ac_cv_func_vfork" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 -$as_echo_n "checking for working vfork... " >&6; } -if ${ac_cv_func_vfork_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_vfork_works=cross -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Thanks to Paul Eggert for this test. */ -$ac_includes_default -#include -#ifdef HAVE_VFORK_H -# include -#endif -/* On some sparc systems, changes by the child to local and incoming - argument registers are propagated back to the parent. The compiler - is told about this with #include , but some compilers - (e.g. gcc -O) don't grok . Test for this by using a - static variable whose address is put into a register that is - clobbered by the vfork. */ -static void -#ifdef __cplusplus -sparc_address_test (int arg) -# else -sparc_address_test (arg) int arg; -#endif -{ - static pid_t child; - if (!child) { - child = vfork (); - if (child < 0) { - perror ("vfork"); - _exit(2); - } - if (!child) { - arg = getpid(); - write(-1, "", 0); - _exit (arg); - } - } -} - -int -main () -{ - pid_t parent = getpid (); - pid_t child; - - sparc_address_test (0); - - child = vfork (); - - if (child == 0) { - /* Here is another test for sparc vfork register problems. This - test uses lots of local variables, at least as many local - variables as main has allocated so far including compiler - temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris - 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should - reuse the register of parent for one of the local variables, - since it will think that parent can't possibly be used any more - in this routine. Assigning to the local variable will thus - munge parent in the parent process. */ - pid_t - p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), - p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); - /* Convince the compiler that p..p7 are live; otherwise, it might - use the same hardware register for all 8 local variables. */ - if (p != p1 || p != p2 || p != p3 || p != p4 - || p != p5 || p != p6 || p != p7) - _exit(1); - - /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent - from child file descriptors. If the child closes a descriptor - before it execs or exits, this munges the parent's descriptor - as well. Test for this by closing stdout in the child. */ - _exit(close(fileno(stdout)) != 0); - } else { - int status; - struct stat st; - - while (wait(&status) != child) - ; - return ( - /* Was there some problem with vforking? */ - child < 0 - - /* Did the child fail? (This shouldn't happen.) */ - || status - - /* Did the vfork/compiler bug occur? */ - || parent != getpid() - - /* Did the file descriptor bug occur? */ - || fstat(fileno(stdout), &st) != 0 - ); - } -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_vfork_works=yes -else - ac_cv_func_vfork_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 -$as_echo "$ac_cv_func_vfork_works" >&6; } - -fi; -if test "x$ac_cv_func_fork_works" = xcross; then - ac_cv_func_vfork_works=$ac_cv_func_vfork - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} -fi - -if test "x$ac_cv_func_vfork_works" = xyes; then - -$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h - -else - -$as_echo "#define vfork fork" >>confdefs.h - -fi -if test "x$ac_cv_func_fork_works" = xyes; then - -$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h - -fi - -for ac_func in pread pwrite pread64 -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - -fi - - - - - for ac_header in $ac_header_list -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - - - if test "X$prefix" = "XNONE"; then - acl_final_prefix="$ac_default_prefix" - else - acl_final_prefix="$prefix" - fi - if test "X$exec_prefix" = "XNONE"; then - acl_final_exec_prefix='${prefix}' - else - acl_final_exec_prefix="$exec_prefix" - fi - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" - prefix="$acl_save_prefix" - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 -$as_echo_n "checking for ld used by GCC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | [A-Za-z]:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the path of ld - ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if ${acl_cv_path_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - if "$acl_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then - test "$with_gnu_ld" != no && break - else - test "$with_gnu_ld" != yes && break - fi - fi - done - IFS="$ac_save_ifs" -else - acl_cv_path_LD="$LD" # Let the user override the test with a path. -fi -fi - -LD="$acl_cv_path_LD" -if test -n "$LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if ${acl_cv_prog_gnu_ld+:} false; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU ld's only accept -v. -if $LD -v 2>&1 &5; then - acl_cv_prog_gnu_ld=yes -else - acl_cv_prog_gnu_ld=no -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_prog_gnu_ld" >&5 -$as_echo "$acl_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$acl_cv_prog_gnu_ld - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 -$as_echo_n "checking for shared library run path origin... " >&6; } -if ${acl_cv_rpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - - CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ - ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh - . ./conftest.sh - rm -f ./conftest.sh - acl_cv_rpath=done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 -$as_echo "$acl_cv_rpath" >&6; } - wl="$acl_cv_wl" - libext="$acl_cv_libext" - shlibext="$acl_cv_shlibext" - hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" - hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" - hardcode_direct="$acl_cv_hardcode_direct" - hardcode_minus_L="$acl_cv_hardcode_minus_L" - # Check whether --enable-rpath was given. -if test "${enable_rpath+set}" = set; then : - enableval=$enable_rpath; : -else - enable_rpath=yes -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - - # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works -# for constant arguments. Useless! -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 -$as_echo_n "checking for working alloca.h... " >&6; } -if ${ac_cv_working_alloca_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -char *p = (char *) alloca (2 * sizeof (int)); - if (p) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_working_alloca_h=yes -else - ac_cv_working_alloca_h=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 -$as_echo "$ac_cv_working_alloca_h" >&6; } -if test $ac_cv_working_alloca_h = yes; then - -$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 -$as_echo_n "checking for alloca... " >&6; } -if ${ac_cv_func_alloca_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __GNUC__ -# define alloca __builtin_alloca -#else -# ifdef _MSC_VER -# include -# define alloca _alloca -# else -# ifdef HAVE_ALLOCA_H -# include -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca (size_t); -# endif -# endif -# endif -# endif -#endif - -int -main () -{ -char *p = (char *) alloca (1); - if (p) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_alloca_works=yes -else - ac_cv_func_alloca_works=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 -$as_echo "$ac_cv_func_alloca_works" >&6; } - -if test $ac_cv_func_alloca_works = yes; then - -$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h - -else - # The SVR3 libPW and SVR4 libucb both contain incompatible functions -# that cause trouble. Some versions do not even contain alloca or -# contain a buggy version. If you still want to use their alloca, -# use ar to extract alloca.o from them instead of compiling alloca.c. - -ALLOCA=\${LIBOBJDIR}alloca.$ac_objext - -$as_echo "#define C_ALLOCA 1" >>confdefs.h - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 -$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } -if ${ac_cv_os_cray+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined CRAY && ! defined CRAY2 -webecray -#else -wenotbecray -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "webecray" >/dev/null 2>&1; then : - ac_cv_os_cray=yes -else - ac_cv_os_cray=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 -$as_echo "$ac_cv_os_cray" >&6; } -if test $ac_cv_os_cray = yes; then - for ac_func in _getb67 GETB67 getb67; do - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - -cat >>confdefs.h <<_ACEOF -#define CRAY_STACKSEG_END $ac_func -_ACEOF - - break -fi - - done -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 -$as_echo_n "checking stack direction for C alloca... " >&6; } -if ${ac_cv_c_stack_direction+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_c_stack_direction=0 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -find_stack_direction (int *addr, int depth) -{ - int dir, dummy = 0; - if (! addr) - addr = &dummy; - *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; - dir = depth ? find_stack_direction (addr, depth - 1) : 0; - return dir + dummy; -} - -int -main (int argc, char **argv) -{ - return find_stack_direction (0, argc + !argv + 20) < 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_c_stack_direction=1 -else - ac_cv_c_stack_direction=-1 -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 -$as_echo "$ac_cv_c_stack_direction" >&6; } -cat >>confdefs.h <<_ACEOF -#define STACK_DIRECTION $ac_cv_c_stack_direction -_ACEOF - - -fi - - - WIN32APILIBS= - case ${host} in - *mingw32*) - -$as_echo "#define USE_WIN32API 1" >>confdefs.h - - WIN32APILIBS="-lws2_32" - ;; - esac - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 -$as_echo_n "checking for nl_langinfo and CODESET... " >&6; } -if ${am_cv_langinfo_codeset+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -char* cs = nl_langinfo(CODESET); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - am_cv_langinfo_codeset=yes -else - am_cv_langinfo_codeset=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_langinfo_codeset" >&5 -$as_echo "$am_cv_langinfo_codeset" >&6; } - if test $am_cv_langinfo_codeset = yes; then - -$as_echo "#define HAVE_LANGINFO_CODESET 1" >>confdefs.h - - fi - - - for ac_header in linux/perf_event.h locale.h memory.h signal.h sys/resource.h sys/socket.h sys/un.h sys/wait.h thread_db.h wait.h termios.h dlfcn.h linux/elf.h sys/procfs.h proc_service.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - -for ac_func in getpagesize -do : - ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" -if test "x$ac_cv_func_getpagesize" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETPAGESIZE 1 -_ACEOF - -fi -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 -$as_echo_n "checking for working mmap... " >&6; } -if ${ac_cv_func_mmap_fixed_mapped+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_mmap_fixed_mapped=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -/* malloc might have been renamed as rpl_malloc. */ -#undef malloc - -/* Thanks to Mike Haertel and Jim Avera for this test. - Here is a matrix of mmap possibilities: - mmap private not fixed - mmap private fixed at somewhere currently unmapped - mmap private fixed at somewhere already mapped - mmap shared not fixed - mmap shared fixed at somewhere currently unmapped - mmap shared fixed at somewhere already mapped - For private mappings, we should verify that changes cannot be read() - back from the file, nor mmap's back from the file at a different - address. (There have been systems where private was not correctly - implemented like the infamous i386 svr4.0, and systems where the - VM page cache was not coherent with the file system buffer cache - like early versions of FreeBSD and possibly contemporary NetBSD.) - For shared mappings, we should conversely verify that changes get - propagated back to all the places they're supposed to be. - - Grep wants private fixed already mapped. - The main things grep needs to know about mmap are: - * does it exist and is it safe to write into the mmap'd area - * how to use it (BSD variants) */ - -#include -#include - -#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H -char *malloc (); -#endif - -/* This mess was copied from the GNU getpagesize.h. */ -#ifndef HAVE_GETPAGESIZE -# ifdef _SC_PAGESIZE -# define getpagesize() sysconf(_SC_PAGESIZE) -# else /* no _SC_PAGESIZE */ -# ifdef HAVE_SYS_PARAM_H -# include -# ifdef EXEC_PAGESIZE -# define getpagesize() EXEC_PAGESIZE -# else /* no EXEC_PAGESIZE */ -# ifdef NBPG -# define getpagesize() NBPG * CLSIZE -# ifndef CLSIZE -# define CLSIZE 1 -# endif /* no CLSIZE */ -# else /* no NBPG */ -# ifdef NBPC -# define getpagesize() NBPC -# else /* no NBPC */ -# ifdef PAGESIZE -# define getpagesize() PAGESIZE -# endif /* PAGESIZE */ -# endif /* no NBPC */ -# endif /* no NBPG */ -# endif /* no EXEC_PAGESIZE */ -# else /* no HAVE_SYS_PARAM_H */ -# define getpagesize() 8192 /* punt totally */ -# endif /* no HAVE_SYS_PARAM_H */ -# endif /* no _SC_PAGESIZE */ - -#endif /* no HAVE_GETPAGESIZE */ - -int -main () -{ - char *data, *data2, *data3; - const char *cdata2; - int i, pagesize; - int fd, fd2; - - pagesize = getpagesize (); - - /* First, make a file with some known garbage in it. */ - data = (char *) malloc (pagesize); - if (!data) - return 1; - for (i = 0; i < pagesize; ++i) - *(data + i) = rand (); - umask (0); - fd = creat ("conftest.mmap", 0600); - if (fd < 0) - return 2; - if (write (fd, data, pagesize) != pagesize) - return 3; - close (fd); - - /* Next, check that the tail of a page is zero-filled. File must have - non-zero length, otherwise we risk SIGBUS for entire page. */ - fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); - if (fd2 < 0) - return 4; - cdata2 = ""; - if (write (fd2, cdata2, 1) != 1) - return 5; - data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); - if (data2 == MAP_FAILED) - return 6; - for (i = 0; i < pagesize; ++i) - if (*(data2 + i)) - return 7; - close (fd2); - if (munmap (data2, pagesize)) - return 8; - - /* Next, try to mmap the file at a fixed address which already has - something else allocated at it. If we can, also make sure that - we see the same garbage. */ - fd = open ("conftest.mmap", O_RDWR); - if (fd < 0) - return 9; - if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED, fd, 0L)) - return 10; - for (i = 0; i < pagesize; ++i) - if (*(data + i) != *(data2 + i)) - return 11; - - /* Finally, make sure that changes to the mapped area do not - percolate back to the file as seen by read(). (This is a bug on - some variants of i386 svr4.0.) */ - for (i = 0; i < pagesize; ++i) - *(data2 + i) = *(data2 + i) + 1; - data3 = (char *) malloc (pagesize); - if (!data3) - return 12; - if (read (fd, data3, pagesize) != pagesize) - return 13; - for (i = 0; i < pagesize; ++i) - if (*(data + i) != *(data3 + i)) - return 14; - close (fd); - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_mmap_fixed_mapped=yes -else - ac_cv_func_mmap_fixed_mapped=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 -$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } -if test $ac_cv_func_mmap_fixed_mapped = yes; then - -$as_echo "#define HAVE_MMAP 1" >>confdefs.h - -fi -rm -f conftest.mmap conftest.txt - - for ac_header in vfork.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" -if test "x$ac_cv_header_vfork_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_VFORK_H 1 -_ACEOF - -fi - -done - -for ac_func in fork vfork -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - -if test "x$ac_cv_func_fork" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 -$as_echo_n "checking for working fork... " >&6; } -if ${ac_cv_func_fork_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_fork_works=cross -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ - - /* By Ruediger Kuhlmann. */ - return fork () < 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_fork_works=yes -else - ac_cv_func_fork_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 -$as_echo "$ac_cv_func_fork_works" >&6; } - -else - ac_cv_func_fork_works=$ac_cv_func_fork -fi -if test "x$ac_cv_func_fork_works" = xcross; then - case $host in - *-*-amigaos* | *-*-msdosdjgpp*) - # Override, as these systems have only a dummy fork() stub - ac_cv_func_fork_works=no - ;; - *) - ac_cv_func_fork_works=yes - ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} -fi -ac_cv_func_vfork_works=$ac_cv_func_vfork -if test "x$ac_cv_func_vfork" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 -$as_echo_n "checking for working vfork... " >&6; } -if ${ac_cv_func_vfork_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_vfork_works=cross -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Thanks to Paul Eggert for this test. */ -$ac_includes_default -#include -#ifdef HAVE_VFORK_H -# include -#endif -/* On some sparc systems, changes by the child to local and incoming - argument registers are propagated back to the parent. The compiler - is told about this with #include , but some compilers - (e.g. gcc -O) don't grok . Test for this by using a - static variable whose address is put into a register that is - clobbered by the vfork. */ -static void -#ifdef __cplusplus -sparc_address_test (int arg) -# else -sparc_address_test (arg) int arg; -#endif -{ - static pid_t child; - if (!child) { - child = vfork (); - if (child < 0) { - perror ("vfork"); - _exit(2); - } - if (!child) { - arg = getpid(); - write(-1, "", 0); - _exit (arg); - } - } -} - -int -main () -{ - pid_t parent = getpid (); - pid_t child; - - sparc_address_test (0); - - child = vfork (); - - if (child == 0) { - /* Here is another test for sparc vfork register problems. This - test uses lots of local variables, at least as many local - variables as main has allocated so far including compiler - temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris - 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should - reuse the register of parent for one of the local variables, - since it will think that parent can't possibly be used any more - in this routine. Assigning to the local variable will thus - munge parent in the parent process. */ - pid_t - p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), - p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); - /* Convince the compiler that p..p7 are live; otherwise, it might - use the same hardware register for all 8 local variables. */ - if (p != p1 || p != p2 || p != p3 || p != p4 - || p != p5 || p != p6 || p != p7) - _exit(1); - - /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent - from child file descriptors. If the child closes a descriptor - before it execs or exits, this munges the parent's descriptor - as well. Test for this by closing stdout in the child. */ - _exit(close(fileno(stdout)) != 0); - } else { - int status; - struct stat st; - - while (wait(&status) != child) - ; - return ( - /* Was there some problem with vforking? */ - child < 0 - - /* Did the child fail? (This shouldn't happen.) */ - || status - - /* Did the vfork/compiler bug occur? */ - || parent != getpid() - - /* Did the file descriptor bug occur? */ - || fstat(fileno(stdout), &st) != 0 - ); - } -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_vfork_works=yes -else - ac_cv_func_vfork_works=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 -$as_echo "$ac_cv_func_vfork_works" >&6; } - -fi; -if test "x$ac_cv_func_fork_works" = xcross; then - ac_cv_func_vfork_works=$ac_cv_func_vfork - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} -fi - -if test "x$ac_cv_func_vfork_works" = xyes; then - -$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h - -else - -$as_echo "#define vfork fork" >>confdefs.h - -fi -if test "x$ac_cv_func_fork_works" = xyes; then - -$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h - -fi - - for ac_func in fdwalk getrlimit pipe pipe2 socketpair sigaction \ - ptrace64 sbrk setns sigaltstack sigprocmask \ - setpgid setpgrp getrusage getauxval -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - ac_fn_c_check_decl "$LINENO" "ADDR_NO_RANDOMIZE" "ac_cv_have_decl_ADDR_NO_RANDOMIZE" "#include -" -if test "x$ac_cv_have_decl_ADDR_NO_RANDOMIZE" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_ADDR_NO_RANDOMIZE $ac_have_decl -_ACEOF - - - if test "$cross_compiling" = yes; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - - # if !HAVE_DECL_ADDR_NO_RANDOMIZE - # define ADDR_NO_RANDOMIZE 0x0040000 - # endif - /* Test the flag could be set and stays set. */ - personality (personality (0xffffffff) | ADDR_NO_RANDOMIZE); - if (!(personality (personality (0xffffffff)) & ADDR_NO_RANDOMIZE)) - return 1 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_personality=true -else - have_personality=false -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - - # if !HAVE_DECL_ADDR_NO_RANDOMIZE - # define ADDR_NO_RANDOMIZE 0x0040000 - # endif - /* Test the flag could be set and stays set. */ - personality (personality (0xffffffff) | ADDR_NO_RANDOMIZE); - if (!(personality (personality (0xffffffff)) & ADDR_NO_RANDOMIZE)) - return 1 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - have_personality=true -else - have_personality=false -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - if $have_personality - then - -$as_echo "#define HAVE_PERSONALITY 1" >>confdefs.h - - fi - - ac_fn_c_check_decl "$LINENO" "strstr" "ac_cv_have_decl_strstr" "$ac_includes_default" -if test "x$ac_cv_have_decl_strstr" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRSTR $ac_have_decl -_ACEOF - - - # ----------------------- # - # Checks for structures. # - # ----------------------- # - - ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_BLOCKS 1 -_ACEOF - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 -_ACEOF - - -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing kinfo_getfile" >&5 -$as_echo_n "checking for library containing kinfo_getfile... " >&6; } -if ${ac_cv_search_kinfo_getfile+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char kinfo_getfile (); -int -main () -{ -return kinfo_getfile (); - ; - return 0; -} -_ACEOF -for ac_lib in '' util util-freebsd; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_kinfo_getfile=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_kinfo_getfile+:} false; then : - break -fi -done -if ${ac_cv_search_kinfo_getfile+:} false; then : - -else - ac_cv_search_kinfo_getfile=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_kinfo_getfile" >&5 -$as_echo "$ac_cv_search_kinfo_getfile" >&6; } -ac_res=$ac_cv_search_kinfo_getfile -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -$as_echo "#define HAVE_KINFO_GETFILE 1" >>confdefs.h - -fi - - - # Check for std::thread. This does not work on some platforms, like - # mingw and DJGPP. - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on Tru64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then - ax_pthread_save_CC="$CC" - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - if test "x$PTHREAD_CC" != "x"; then : - CC="$PTHREAD_CC" -fi - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 -$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_join (); -int -main () -{ -return pthread_join (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ax_pthread_ok=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 -$as_echo "$ax_pthread_ok" >&6; } - if test "x$ax_pthread_ok" = "xno"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - CC="$ax_pthread_save_CC" - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 -# (Note: HP C rejects this with "bad form for `-t' option") -# -pthreads: Solaris/gcc (Note: HP C also rejects) -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads and -# -D_REENTRANT too), HP C (must be checked before -lpthread, which -# is present but should not be used directly; and before -mthreads, -# because the compiler interprets this as "-mt" + "-hreads") -# -mthreads: Mingw32/gcc, Lynx/gcc -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case $host_os in - - freebsd*) - - # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) - # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - - ax_pthread_flags="-kthread lthread $ax_pthread_flags" - ;; - - hpux*) - - # From the cc(1) man page: "[-mt] Sets various -D flags to enable - # multi-threading and also sets -lpthread." - - ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" - ;; - - openedition*) - - # IBM z/OS requires a feature-test macro to be defined in order to - # enable POSIX threads at all, so give the user a hint if this is - # not set. (We don't define these ourselves, as they can affect - # other portions of the system API in unpredictable ways.) - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) - AX_PTHREAD_ZOS_MISSING -# endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 -$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} -fi -rm -f conftest* - - ;; - - solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (N.B.: The stubs are missing - # pthread_cleanup_push, or rather a function called by this macro, - # so we could check for that, but who knows whether they'll stub - # that too in a future libc.) So we'll check first for the - # standard Solaris way of linking pthreads (-mt -lpthread). - - ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" - ;; -esac - -# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) - -if test "x$GCC" = "xyes"; then : - ax_pthread_flags="-pthread -pthreads $ax_pthread_flags" -fi - -# The presence of a feature test macro requesting re-entrant function -# definitions is, on some systems, a strong hint that pthreads support is -# correctly enabled - -case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) - ax_pthread_check_macro="_REENTRANT" - ;; - - aix*) - ax_pthread_check_macro="_THREAD_SAFE" - ;; - - *) - ax_pthread_check_macro="--" - ;; -esac -if test "x$ax_pthread_check_macro" = "x--"; then : - ax_pthread_check_cond=0 -else - ax_pthread_check_cond="!defined($ax_pthread_check_macro)" -fi - -# Are we compiling with Clang? - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 -$as_echo_n "checking whether $CC is Clang... " >&6; } -if ${ax_cv_PTHREAD_CLANG+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_PTHREAD_CLANG=no - # Note that Autoconf sets GCC=yes for Clang as well as GCC - if test "x$GCC" = "xyes"; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ -# if defined(__clang__) && defined(__llvm__) - AX_PTHREAD_CC_IS_CLANG -# endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then : - ax_cv_PTHREAD_CLANG=yes -fi -rm -f conftest* - - fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 -$as_echo "$ax_cv_PTHREAD_CLANG" >&6; } -ax_pthread_clang="$ax_cv_PTHREAD_CLANG" - -ax_pthread_clang_warning=no - -# Clang needs special handling, because older versions handle the -pthread -# option in a rather... idiosyncratic way - -if test "x$ax_pthread_clang" = "xyes"; then - - # Clang takes -pthread; it has never supported any other flag - - # (Note 1: This will need to be revisited if a system that Clang - # supports has POSIX threads in a separate library. This tends not - # to be the way of modern systems, but it's conceivable.) - - # (Note 2: On some systems, notably Darwin, -pthread is not needed - # to get POSIX threads support; the API is always present and - # active. We could reasonably leave PTHREAD_CFLAGS empty. But - # -pthread does define _REENTRANT, and while the Darwin headers - # ignore this macro, third-party headers might not.) - - PTHREAD_CFLAGS="-pthread" - PTHREAD_LIBS= - - ax_pthread_ok=yes - - # However, older versions of Clang make a point of warning the user - # that, in an invocation where only linking and no compilation is - # taking place, the -pthread option has no effect ("argument unused - # during compilation"). They expect -pthread to be passed in only - # when source code is being compiled. - # - # Problem is, this is at odds with the way Automake and most other - # C build frameworks function, which is that the same flags used in - # compilation (CFLAGS) are also used in linking. Many systems - # supported by AX_PTHREAD require exactly this for POSIX threads - # support, and in fact it is often not straightforward to specify a - # flag that is used only in the compilation phase and not in - # linking. Such a scenario is extremely rare in practice. - # - # Even though use of the -pthread flag in linking would only print - # a warning, this can be a nuisance for well-run software projects - # that build with -Werror. So if the active version of Clang has - # this misfeature, we search for an option to squash it. - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 -$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } -if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown - # Create an alternate version of $ac_link that compiles and - # links in two steps (.c -> .o, .o -> exe) instead of one - # (.c -> exe), because the warning occurs only in the second - # step - ax_pthread_save_ac_link="$ac_link" - ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' - ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` - ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" - ax_pthread_save_CFLAGS="$CFLAGS" - for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do - if test "x$ax_pthread_try" = "xunknown"; then : - break -fi - CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" - ac_link="$ax_pthread_save_ac_link" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(void){return 0;} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_link="$ax_pthread_2step_ac_link" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(void){return 0;} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - break -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - done - ac_link="$ax_pthread_save_ac_link" - CFLAGS="$ax_pthread_save_CFLAGS" - if test "x$ax_pthread_try" = "x"; then : - ax_pthread_try=no -fi - ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 -$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } - - case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in - no | unknown) ;; - *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; - esac - -fi # $ax_pthread_clang = yes - -if test "x$ax_pthread_ok" = "xno"; then -for ax_pthread_try_flag in $ax_pthread_flags; do - - case $ax_pthread_try_flag in - none) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 -$as_echo_n "checking whether pthreads work without any flags... " >&6; } - ;; - - -mt,pthread) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5 -$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; } - PTHREAD_CFLAGS="-mt" - PTHREAD_LIBS="-lpthread" - ;; - - -*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 -$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } - PTHREAD_CFLAGS="$ax_pthread_try_flag" - ;; - - pthread-config) - # Extract the first word of "pthread-config", so it can be a program name with args. -set dummy pthread-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ax_pthread_config+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ax_pthread_config"; then - ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ax_pthread_config="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" -fi -fi -ax_pthread_config=$ac_cv_prog_ax_pthread_config -if test -n "$ax_pthread_config"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 -$as_echo "$ax_pthread_config" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - if test "x$ax_pthread_config" = "xno"; then : - continue -fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 -$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } - PTHREAD_LIBS="-l$ax_pthread_try_flag" - ;; - esac - - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -# if $ax_pthread_check_cond -# error "$ax_pthread_check_macro must be defined" -# endif - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; } -int -main () -{ -pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */ - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ax_pthread_ok=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 -$as_echo "$ax_pthread_ok" >&6; } - if test "x$ax_pthread_ok" = "xyes"; then : - break -fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$ax_pthread_ok" = "xyes"; then - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 -$as_echo_n "checking for joinable pthread attribute... " >&6; } -if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_PTHREAD_JOINABLE_ATTR=unknown - for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -int attr = $ax_pthread_attr; return attr /* ; */ - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 -$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } - if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ - test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ - test "x$ax_pthread_joinable_attr_defined" != "xyes"; then : - -cat >>confdefs.h <<_ACEOF -#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR -_ACEOF - - ax_pthread_joinable_attr_defined=yes - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 -$as_echo_n "checking whether more special flags are required for pthreads... " >&6; } -if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_PTHREAD_SPECIAL_FLAGS=no - case $host_os in - solaris*) - ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" - ;; - esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 -$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } - if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ - test "x$ax_pthread_special_flags_added" != "xyes"; then : - PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" - ax_pthread_special_flags_added=yes -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 -$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; } -if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -int i = PTHREAD_PRIO_INHERIT; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ax_cv_PTHREAD_PRIO_INHERIT=yes -else - ax_cv_PTHREAD_PRIO_INHERIT=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 -$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } - if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ - test "x$ax_pthread_prio_inherit_defined" != "xyes"; then : - -$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h - - ax_pthread_prio_inherit_defined=yes - -fi - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != "xyes"; then - case $host_os in - aix*) - case "x/$CC" in #( - x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : - #handle absolute path differently from PATH based program lookup - case "x$CC" in #( - x/*) : - if as_fn_executable_p ${CC}_r; then : - PTHREAD_CC="${CC}_r" -fi ;; #( - *) : - for ac_prog in ${CC}_r -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PTHREAD_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$PTHREAD_CC"; then - ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_PTHREAD_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PTHREAD_CC=$ac_cv_prog_PTHREAD_CC -if test -n "$PTHREAD_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 -$as_echo "$PTHREAD_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$PTHREAD_CC" && break -done -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - ;; -esac ;; #( - *) : - ;; -esac - ;; - esac - fi -fi - -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - - - - - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test "x$ax_pthread_ok" = "xyes"; then - threads=yes - : -else - ax_pthread_ok=no - threads=no -fi -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - if test "$threads" = "yes"; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$PTHREAD_CFLAGS $save_CXXFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::thread" >&5 -$as_echo_n "checking for std::thread... " >&6; } -if ${gdb_cv_cxx_std_thread+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - void callback() { } -int -main () -{ -std::thread t(callback); - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - gdb_cv_cxx_std_thread=yes -else - gdb_cv_cxx_std_thread=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_cxx_std_thread" >&5 -$as_echo "$gdb_cv_cxx_std_thread" >&6; } - - # This check must be here, while LIBS includes any necessary - # threading library. - for ac_func in pthread_sigmask pthread_setname_np -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - LIBS="$save_LIBS" - CXXFLAGS="$save_CXXFLAGS" - fi - if test "$gdb_cv_cxx_std_thread" = "yes"; then - -$as_echo "#define CXX_STD_THREAD 1" >>confdefs.h - - fi - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigsetjmp" >&5 -$as_echo_n "checking for sigsetjmp... " >&6; } -if ${gdb_cv_func_sigsetjmp+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - -int -main () -{ -sigjmp_buf env; while (! sigsetjmp (env, 1)) siglongjmp (env, 1); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdb_cv_func_sigsetjmp=yes -else - gdb_cv_func_sigsetjmp=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_sigsetjmp" >&5 -$as_echo "$gdb_cv_func_sigsetjmp" >&6; } - if test "$gdb_cv_func_sigsetjmp" = "yes"; then - -$as_echo "#define HAVE_SIGSETJMP 1" >>confdefs.h - - fi - - -# Check whether --with-intel_pt was given. -if test "${with_intel_pt+set}" = set; then : - withval=$with_intel_pt; -else - with_intel_pt=auto -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use intel pt" >&5 -$as_echo_n "checking whether to use intel pt... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_intel_pt" >&5 -$as_echo "$with_intel_pt" >&6; } - - if test "${with_intel_pt}" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Intel Processor Trace support disabled; some features may be unavailable." >&5 -$as_echo "$as_me: WARNING: Intel Processor Trace support disabled; some features may be unavailable." >&2;} - HAVE_LIBIPT=no - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - #ifndef PERF_ATTR_SIZE_VER5 - # error - #endif - -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - perf_event=yes -else - perf_event=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext - if test "$perf_event" != yes; then - if test "$with_intel_pt" = yes; then - as_fn_error $? "linux/perf_event.h missing or too old" "$LINENO" 5 - else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: linux/perf_event.h missing or too old; some features may be unavailable." >&5 -$as_echo "$as_me: WARNING: linux/perf_event.h missing or too old; some features may be unavailable." >&2;} - fi - fi - - - - - - - - - - use_additional=yes - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - -# Check whether --with-libipt-prefix was given. -if test "${with_libipt_prefix+set}" = set; then : - withval=$with_libipt_prefix; - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - else - additional_includedir="$withval/include" - additional_libdir="$withval/lib" - fi - fi - -fi - - LIBIPT= - LTLIBIPT= - INCIPT= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='ipt ' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIBIPT="${LIBIPT}${LIBIPT:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }$value" - else - : - fi - else - found_dir= - found_la= - found_so= - found_a= - if test $use_additional = yes; then - if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then - found_dir="$additional_libdir" - found_so="$additional_libdir/lib$name.$shlibext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - else - if test -f "$additional_libdir/lib$name.$libext"; then - found_dir="$additional_libdir" - found_a="$additional_libdir/lib$name.$libext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIBIPT; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then - found_dir="$dir" - found_so="$dir/lib$name.$shlibext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - else - if test -f "$dir/lib$name.$libext"; then - found_dir="$dir" - found_a="$dir/lib$name.$libext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then - LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" - else - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - if test "$hardcode_direct" = yes; then - LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" - else - if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then - LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - haveit= - for x in $LDFLAGS $LIBIPT; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIBIPT="${LIBIPT}${LIBIPT:+ }-L$found_dir" - fi - if test "$hardcode_minus_L" != no; then - LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" - else - LIBIPT="${LIBIPT}${LIBIPT:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - LIBIPT="${LIBIPT}${LIBIPT:+ }$found_a" - else - LIBIPT="${LIBIPT}${LIBIPT:+ }-L$found_dir -l$name" - fi - fi - additional_includedir= - case "$found_dir" in - */lib | */lib/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INCIPT; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - INCIPT="${INCIPT}${INCIPT:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - if test -n "$found_la"; then - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - if test "X$additional_libdir" != "X/usr/lib"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/lib"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIBIPT; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LIBIPT="${LIBIPT}${LIBIPT:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIBIPT; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - LIBIPT="${LIBIPT}${LIBIPT:+ }$dep" - LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }$dep" - ;; - esac - done - fi - else - LIBIPT="${LIBIPT}${LIBIPT:+ }-l$name" - LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$hardcode_libdir_separator"; then - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" - done - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBIPT="${LIBIPT}${LIBIPT:+ }$flag" - else - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIBIPT="${LIBIPT}${LIBIPT:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - for found_dir in $ltrpathdirs; do - LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-R$found_dir" - done - fi - - - ac_save_CPPFLAGS="$CPPFLAGS" - - for element in $INCIPT; do - haveit= - for x in $CPPFLAGS; do - - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - eval x=\"$x\" - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" - - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" - fi - done - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libipt" >&5 -$as_echo_n "checking for libipt... " >&6; } -if ${ac_cv_libipt+:} false; then : - $as_echo_n "(cached) " >&6 -else - - ac_save_LIBS="$LIBS" - LIBS="$LIBS $LIBIPT" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include "intel-pt.h" -int -main () -{ -pt_insn_alloc_decoder (0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_libipt=yes -else - ac_cv_libipt=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$ac_save_LIBS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libipt" >&5 -$as_echo "$ac_cv_libipt" >&6; } - if test "$ac_cv_libipt" = yes; then - HAVE_LIBIPT=yes - -$as_echo "#define HAVE_LIBIPT 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libipt" >&5 -$as_echo_n "checking how to link with libipt... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBIPT" >&5 -$as_echo "$LIBIPT" >&6; } - else - HAVE_LIBIPT=no - CPPFLAGS="$ac_save_CPPFLAGS" - LIBIPT= - LTLIBIPT= - fi - - - - - - - if test "$HAVE_LIBIPT" != yes; then - if test "$with_intel_pt" = yes; then - as_fn_error $? "libipt is missing or unusable" "$LINENO" 5 - else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libipt is missing or unusable; some features may be unavailable." >&5 -$as_echo "$as_me: WARNING: libipt is missing or unusable; some features may be unavailable." >&2;} - fi - else - save_LIBS=$LIBS - LIBS="$LIBS $LIBIPT" - for ac_func in pt_insn_event -do : - ac_fn_c_check_func "$LINENO" "pt_insn_event" "ac_cv_func_pt_insn_event" -if test "x$ac_cv_func_pt_insn_event" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_PT_INSN_EVENT 1 -_ACEOF - -fi -done - - ac_fn_c_check_member "$LINENO" "struct pt_insn" "enabled" "ac_cv_member_struct_pt_insn_enabled" "#include -" -if test "x$ac_cv_member_struct_pt_insn_enabled" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_PT_INSN_ENABLED 1 -_ACEOF - - -fi -ac_fn_c_check_member "$LINENO" "struct pt_insn" "resynced" "ac_cv_member_struct_pt_insn_resynced" "#include -" -if test "x$ac_cv_member_struct_pt_insn_resynced" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_PT_INSN_RESYNCED 1 -_ACEOF - - -fi - - LIBS=$save_LIBS - fi - fi - - if test "$ac_cv_header_sys_procfs_h" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gregset_t in sys/procfs.h" >&5 -$as_echo_n "checking for gregset_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_gregset_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -gregset_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_gregset_t=yes -else - bfd_cv_have_sys_procfs_type_gregset_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_gregset_t = yes; then - -$as_echo "#define HAVE_GREGSET_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_gregset_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_gregset_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpregset_t in sys/procfs.h" >&5 -$as_echo_n "checking for fpregset_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_fpregset_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -fpregset_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_fpregset_t=yes -else - bfd_cv_have_sys_procfs_type_fpregset_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_fpregset_t = yes; then - -$as_echo "#define HAVE_FPREGSET_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_fpregset_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_fpregset_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prgregset_t in sys/procfs.h" >&5 -$as_echo_n "checking for prgregset_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_prgregset_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -prgregset_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_prgregset_t=yes -else - bfd_cv_have_sys_procfs_type_prgregset_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_prgregset_t = yes; then - -$as_echo "#define HAVE_PRGREGSET_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_prgregset_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_prgregset_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prfpregset_t in sys/procfs.h" >&5 -$as_echo_n "checking for prfpregset_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_prfpregset_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -prfpregset_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_prfpregset_t=yes -else - bfd_cv_have_sys_procfs_type_prfpregset_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then - -$as_echo "#define HAVE_PRFPREGSET_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_prfpregset_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_prfpregset_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prgregset32_t in sys/procfs.h" >&5 -$as_echo_n "checking for prgregset32_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_prgregset32_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -prgregset32_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_prgregset32_t=yes -else - bfd_cv_have_sys_procfs_type_prgregset32_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_prgregset32_t = yes; then - -$as_echo "#define HAVE_PRGREGSET32_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_prgregset32_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_prgregset32_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lwpid_t in sys/procfs.h" >&5 -$as_echo_n "checking for lwpid_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_lwpid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -lwpid_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_lwpid_t=yes -else - bfd_cv_have_sys_procfs_type_lwpid_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_lwpid_t = yes; then - -$as_echo "#define HAVE_LWPID_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_lwpid_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_lwpid_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for psaddr_t in sys/procfs.h" >&5 -$as_echo_n "checking for psaddr_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_psaddr_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -psaddr_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_psaddr_t=yes -else - bfd_cv_have_sys_procfs_type_psaddr_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_psaddr_t = yes; then - -$as_echo "#define HAVE_PSADDR_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_psaddr_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_psaddr_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for elf_fpregset_t in sys/procfs.h" >&5 -$as_echo_n "checking for elf_fpregset_t in sys/procfs.h... " >&6; } - if ${bfd_cv_have_sys_procfs_type_elf_fpregset_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _SYSCALL32 -/* Needed for new procfs interface on sparc-solaris. */ -#define _STRUCTURED_PROC 1 -#include -int -main () -{ -elf_fpregset_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - bfd_cv_have_sys_procfs_type_elf_fpregset_t=yes -else - bfd_cv_have_sys_procfs_type_elf_fpregset_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_elf_fpregset_t = yes; then - -$as_echo "#define HAVE_ELF_FPREGSET_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_elf_fpregset_t" >&5 -$as_echo "$bfd_cv_have_sys_procfs_type_elf_fpregset_t" >&6; } - - fi - - -# Check the return and argument types of ptrace. - - -for ac_header in sys/ptrace.h ptrace.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -gdb_ptrace_headers=' -#include -#if HAVE_SYS_PTRACE_H -# include -#endif -#if HAVE_UNISTD_H -# include -#endif -' -# There is no point in checking if we don't have a prototype. -ac_fn_c_check_decl "$LINENO" "ptrace" "ac_cv_have_decl_ptrace" "$gdb_ptrace_headers -" -if test "x$ac_cv_have_decl_ptrace" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_PTRACE $ac_have_decl -_ACEOF -if test $ac_have_decl = 1; then : - -else - - : ${gdb_cv_func_ptrace_ret='int'} - : ${gdb_cv_func_ptrace_args='int,int,long,long'} - -fi - -# Check return type. Varargs (used on GNU/Linux) conflict with the -# empty argument list, so check for that explicitly. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of ptrace" >&5 -$as_echo_n "checking return type of ptrace... " >&6; } -if ${gdb_cv_func_ptrace_ret+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$gdb_ptrace_headers -int -main () -{ -extern long ptrace (enum __ptrace_request, ...); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdb_cv_func_ptrace_ret='long' -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$gdb_ptrace_headers -int -main () -{ -extern int ptrace (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdb_cv_func_ptrace_ret='int' -else - gdb_cv_func_ptrace_ret='long' -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_ptrace_ret" >&5 -$as_echo "$gdb_cv_func_ptrace_ret" >&6; } - -cat >>confdefs.h <<_ACEOF -#define PTRACE_TYPE_RET $gdb_cv_func_ptrace_ret -_ACEOF - -# Check argument types. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for ptrace" >&5 -$as_echo_n "checking types of arguments for ptrace... " >&6; } -if ${gdb_cv_func_ptrace_args+:} false; then : - $as_echo_n "(cached) " >&6 -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$gdb_ptrace_headers -int -main () -{ -extern long ptrace (enum __ptrace_request, ...); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdb_cv_func_ptrace_args='enum __ptrace_request,int,long,long' -else - -for gdb_arg1 in 'int' 'long'; do - for gdb_arg2 in 'pid_t' 'int' 'long'; do - for gdb_arg3 in 'int *' 'caddr_t' 'int' 'long' 'void *'; do - for gdb_arg4 in 'int' 'long' 'void *'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$gdb_ptrace_headers -int -main () -{ - -extern $gdb_cv_func_ptrace_ret - ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4"; - break 4; -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - for gdb_arg5 in 'int *' 'int' 'long'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$gdb_ptrace_headers -int -main () -{ - -extern $gdb_cv_func_ptrace_ret - ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4, $gdb_arg5); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4,$gdb_arg5"; - break 5; -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done - done - done - done -done -# Provide a safe default value. -: ${gdb_cv_func_ptrace_args='int,int,long,long'} - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_ptrace_args" >&5 -$as_echo "$gdb_cv_func_ptrace_args" >&6; } -ac_save_IFS=$IFS; IFS=',' -set dummy `echo "$gdb_cv_func_ptrace_args" | sed 's/\*/\*/g'` -IFS=$ac_save_IFS -shift - -cat >>confdefs.h <<_ACEOF -#define PTRACE_TYPE_ARG1 $1 -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define PTRACE_TYPE_ARG3 $3 -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define PTRACE_TYPE_ARG4 $4 -_ACEOF - -if test -n "$5"; then - -cat >>confdefs.h <<_ACEOF -#define PTRACE_TYPE_ARG5 $5 -_ACEOF - -fi - - -# Check for UST -ustlibs="" -ustinc="" - - -# Check whether --with-ust was given. -if test "${with_ust+set}" = set; then : - withval=$with_ust; -fi - - -# Check whether --with-ust_include was given. -if test "${with_ust_include+set}" = set; then : - withval=$with_ust_include; -fi - - -# Check whether --with-ust_lib was given. -if test "${with_ust_lib+set}" = set; then : - withval=$with_ust_lib; -fi - - -case $with_ust in - no) - ustlibs= - ustinc= - ;; - "" | yes) - ustlibs=" -lust " - ustinc="" - ;; - *) - ustlibs="-L$with_ust/lib -lust" - ustinc="-I$with_ust/include " - ;; -esac -if test "x$with_ust_include" != x; then - ustinc="-I$with_ust_include " -fi -if test "x$with_ust_lib" != x; then - ustlibs="-L$with_ust_lib -lust" -fi - -if test "x$with_ust" != "xno"; then - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $ustinc" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ust" >&5 -$as_echo_n "checking for ust... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define CONFIG_UST_GDB_INTEGRATION -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; -$as_echo "#define HAVE_UST 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; ustlibs= ; ustinc= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$saved_CFLAGS" -fi - -# Flags needed for UST - - - - -# Check whether --enable-werror was given. -if test "${enable_werror+set}" = set; then : - enableval=$enable_werror; case "${enableval}" in - yes | y) ERROR_ON_WARNING="yes" ;; - no | n) ERROR_ON_WARNING="no" ;; - *) as_fn_error $? "bad value ${enableval} for --enable-werror" "$LINENO" 5 ;; - esac -fi - - -# Enable -Werror by default when using gcc. Turn it off for releases. -if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" && $development; then - ERROR_ON_WARNING=yes -fi - -WERROR_CFLAGS="" -if test "${ERROR_ON_WARNING}" = yes ; then - WERROR_CFLAGS="-Werror" -fi - -# The options we'll try to enable. -build_warnings="-Wall -Wpointer-arith \ --Wno-unused -Wunused-value -Wunused-variable -Wunused-function \ --Wno-switch -Wno-char-subscripts \ --Wempty-body -Wunused-but-set-parameter -Wunused-but-set-variable \ --Wno-sign-compare -Wno-error=maybe-uninitialized \ --Wno-mismatched-tags \ --Wno-error=deprecated-register \ --Wsuggest-override \ --Wimplicit-fallthrough=3 \ --Wduplicated-cond \ --Wshadow=local \ --Wdeprecated-copy \ --Wdeprecated-copy-dtor \ --Wredundant-move \ --Wmissing-declarations" - -case "${host}" in - *-*-mingw32*) - # Enable -Wno-format by default when using gcc on mingw since many - # GCC versions complain about %I64. - build_warnings="$build_warnings -Wno-format" ;; - *-*-solaris*) - # Solaris 11.4 uses #pragma no_inline that GCC - # doesn't understand. - build_warnings="$build_warnings -Wno-unknown-pragmas" - # Solaris 11 marks vfork deprecated. - build_warnings="$build_warnings -Wno-deprecated-declarations" ;; - *) - # Note that gcc requires -Wformat for -Wformat-nonliteral to work, - # but there's a special case for this below. - build_warnings="$build_warnings -Wformat-nonliteral" ;; -esac - -# Check whether --enable-build-warnings was given. -if test "${enable_build_warnings+set}" = set; then : - enableval=$enable_build_warnings; case "${enableval}" in - yes) ;; - no) build_warnings="-w";; - ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` - build_warnings="${build_warnings} ${t}";; - *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` - build_warnings="${t} ${build_warnings}";; - *) build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;; -esac -if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then - echo "Setting compiler warning flags = $build_warnings" 6>&1 -fi -fi -# Check whether --enable-gdb-build-warnings was given. -if test "${enable_gdb_build_warnings+set}" = set; then : - enableval=$enable_gdb_build_warnings; case "${enableval}" in - yes) ;; - no) build_warnings="-w";; - ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` - build_warnings="${build_warnings} ${t}";; - *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` - build_warnings="${t} ${build_warnings}";; - *) build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;; -esac -if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then - echo "Setting GDB specific compiler warning flags = $build_warnings" 6>&1 -fi -fi - -# The set of warnings supported by a C++ compiler is not the same as -# of the C compiler. -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - -WARN_CFLAGS="" -if test "x${build_warnings}" != x -a "x$GCC" = xyes -then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler warning flags" >&5 -$as_echo_n "checking compiler warning flags... " >&6; } - # Separate out the -Werror flag as some files just cannot be - # compiled with it enabled. - for w in ${build_warnings}; do - # GCC does not complain about -Wno-unknown-warning. Invert - # and test -Wunknown-warning instead. - case $w in - -Wno-*) - wtest=`echo $w | sed 's/-Wno-/-W/g'` ;; - -Wformat-nonliteral) - # gcc requires -Wformat before -Wformat-nonliteral - # will work, so stick them together. - w="-Wformat $w" - wtest="$w" - ;; - *) - wtest=$w ;; - esac - - case $w in - -Werr*) WERROR_CFLAGS=-Werror ;; - *) - # Check whether GCC accepts it. - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror $wtest" - saved_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -Werror $wtest" - if test "x$w" = "x-Wunused-variable"; then - # Check for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38958, - # fixed in GCC 4.9. This test is derived from the gdb - # source code that triggered this bug in GCC. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -struct scoped_restore_base {}; - struct scoped_restore_tmpl : public scoped_restore_base { - ~scoped_restore_tmpl() {} - }; -int -main () -{ -const scoped_restore_base &b = scoped_restore_tmpl(); - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - WARN_CFLAGS="${WARN_CFLAGS} $w" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - WARN_CFLAGS="${WARN_CFLAGS} $w" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - CFLAGS="$saved_CFLAGS" - CXXFLAGS="$saved_CXXFLAGS" - esac - done - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WARN_CFLAGS} ${WERROR_CFLAGS}" >&5 -$as_echo "${WARN_CFLAGS} ${WERROR_CFLAGS}" >&6; } -fi - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -old_LIBS="$LIBS" -LIBS="$LIBS -ldl" -for ac_func in dladdr -do : - ac_fn_c_check_func "$LINENO" "dladdr" "ac_cv_func_dladdr" -if test "x$ac_cv_func_dladdr" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_DLADDR 1 -_ACEOF - -fi -done - -LIBS="$old_LIBS" - - - # Check for presence and size of long long. - ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default" -if test "x$ac_cv_type_long_long" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_LONG_LONG 1 -_ACEOF - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long long) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF - - -fi - - - as_ac_Symbol=`$as_echo "ac_cv_have_decl_basename(char *)" | $as_tr_sh` -ac_fn_c_check_decl "$LINENO" "basename(char *)" "$as_ac_Symbol" "$ac_includes_default" -if eval test \"x\$"$as_ac_Symbol"\" = x"yes"; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_BASENAME $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" "$ac_includes_default" -if test "x$ac_cv_have_decl_ffs" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_FFS $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "asprintf" "ac_cv_have_decl_asprintf" "$ac_includes_default" -if test "x$ac_cv_have_decl_asprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_ASPRINTF $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default" -if test "x$ac_cv_have_decl_vasprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_VASPRINTF $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default" -if test "x$ac_cv_have_decl_snprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SNPRINTF $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" -if test "x$ac_cv_have_decl_vsnprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_VSNPRINTF $ac_have_decl -_ACEOF - - ac_fn_c_check_decl "$LINENO" "strtol" "ac_cv_have_decl_strtol" "$ac_includes_default" -if test "x$ac_cv_have_decl_strtol" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRTOL $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "strtoul" "ac_cv_have_decl_strtoul" "$ac_includes_default" -if test "x$ac_cv_have_decl_strtoul" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRTOUL $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "strtoll" "ac_cv_have_decl_strtoll" "$ac_includes_default" -if test "x$ac_cv_have_decl_strtoll" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRTOLL $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "strtoull" "ac_cv_have_decl_strtoull" "$ac_includes_default" -if test "x$ac_cv_have_decl_strtoull" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRTOULL $ac_have_decl -_ACEOF - - ac_fn_c_check_decl "$LINENO" "strverscmp" "ac_cv_have_decl_strverscmp" "$ac_includes_default" -if test "x$ac_cv_have_decl_strverscmp" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRVERSCMP $ac_have_decl -_ACEOF - - - -ac_fn_c_check_decl "$LINENO" "perror" "ac_cv_have_decl_perror" "$ac_includes_default" -if test "x$ac_cv_have_decl_perror" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_PERROR $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default" -if test "x$ac_cv_have_decl_vasprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_VASPRINTF $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" -if test "x$ac_cv_have_decl_vsnprintf" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_VSNPRINTF $ac_have_decl -_ACEOF - - -# See if supports the %fs_base and %gs_bas amd64 segment registers. -# Older amd64 Linux's don't have the fs_base and gs_base members of -# `struct user_regs_struct'. -ac_fn_c_check_member "$LINENO" "struct user_regs_struct" "fs_base" "ac_cv_member_struct_user_regs_struct_fs_base" "#include -#include -" -if test "x$ac_cv_member_struct_user_regs_struct_fs_base" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE 1 -_ACEOF - - -fi -ac_fn_c_check_member "$LINENO" "struct user_regs_struct" "gs_base" "ac_cv_member_struct_user_regs_struct_gs_base" "#include -#include -" -if test "x$ac_cv_member_struct_user_regs_struct_gs_base" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE 1 -_ACEOF - - -fi - - - -ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include -#include - -" -if test "x$ac_cv_type_socklen_t" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_SOCKLEN_T 1 -_ACEOF - - -fi - - -case "${target}" in - *-android*) - # Starting with NDK version 9, actually includes definitions - # of Elf32_auxv_t and Elf64_auxv_t. But sadly, includes - # which defines some of the ELF types incorrectly, - # leading to conflicts with the defintions from . - # This makes it impossible for us to include both and - # , which means that, in practice, we do not have - # access to Elf32_auxv_t and Elf64_auxv_t on this platform. - # Therefore, do not try to auto-detect availability, as it would - # get it wrong on this platform. - ;; - *) - ac_fn_c_check_type "$LINENO" "Elf32_auxv_t" "ac_cv_type_Elf32_auxv_t" "#include - -" -if test "x$ac_cv_type_Elf32_auxv_t" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_ELF32_AUXV_T 1 -_ACEOF - - -fi -ac_fn_c_check_type "$LINENO" "Elf64_auxv_t" "ac_cv_type_Elf64_auxv_t" "#include - -" -if test "x$ac_cv_type_Elf64_auxv_t" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_ELF64_AUXV_T 1 -_ACEOF - - -fi - -esac - - - -# Check whether --with-pkgversion was given. -if test "${with_pkgversion+set}" = set; then : - withval=$with_pkgversion; case "$withval" in - yes) as_fn_error $? "package version not specified" "$LINENO" 5 ;; - no) PKGVERSION= ;; - *) PKGVERSION="($withval) " ;; - esac -else - PKGVERSION="(GDB) " - -fi - - - - - -# Check whether --with-bugurl was given. -if test "${with_bugurl+set}" = set; then : - withval=$with_bugurl; case "$withval" in - yes) as_fn_error $? "bug URL not specified" "$LINENO" 5 ;; - no) BUGURL= - ;; - *) BUGURL="$withval" - ;; - esac -else - BUGURL="http://www.gnu.org/software/gdb/bugs/" - -fi - - case ${BUGURL} in - "") - REPORT_BUGS_TO= - REPORT_BUGS_TEXI= - ;; - *) - REPORT_BUGS_TO="<$BUGURL>" - REPORT_BUGS_TEXI=@uref{`echo "$BUGURL" | sed 's/@/@@/g'`} - ;; - esac; - - - - -cat >>confdefs.h <<_ACEOF -#define PKGVERSION "$PKGVERSION" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define REPORT_BUGS_TO "$REPORT_BUGS_TO" -_ACEOF - - -# Check for various supplementary target information (beyond the -# triplet) which might affect the choices in configure.srv. -case "${target}" in - i[34567]86-*-linux*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if building for x86-64" >&5 -$as_echo_n "checking if building for x86-64... " >&6; } -if ${gdb_cv_i386_is_x86_64+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $CFLAGS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if __x86_64__ -got it -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "got it" >/dev/null 2>&1; then : - gdb_cv_i386_is_x86_64=yes -else - gdb_cv_i386_is_x86_64=no -fi -rm -f conftest* - - CPPFLAGS="$save_CPPFLAGS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_i386_is_x86_64" >&5 -$as_echo "$gdb_cv_i386_is_x86_64" >&6; } - ;; - - x86_64-*-linux*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if building for x32" >&5 -$as_echo_n "checking if building for x32... " >&6; } -if ${gdb_cv_x86_is_x32+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $CFLAGS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if __x86_64__ && __ILP32__ -got it -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "got it" >/dev/null 2>&1; then : - gdb_cv_x86_is_x32=yes -else - gdb_cv_x86_is_x32=no -fi -rm -f conftest* - - CPPFLAGS="$save_CPPFLAGS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_x86_is_x32" >&5 -$as_echo "$gdb_cv_x86_is_x32" >&6; } - ;; - - m68k-*-*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if building for Coldfire" >&5 -$as_echo_n "checking if building for Coldfire... " >&6; } -if ${gdb_cv_m68k_is_coldfire+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $CFLAGS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef __mcoldfire__ -got it -#endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "got it" >/dev/null 2>&1; then : - gdb_cv_m68k_is_coldfire=yes -else - gdb_cv_m68k_is_coldfire=no -fi -rm -f conftest* - - CPPFLAGS="$save_CPPFLAGS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_m68k_is_coldfire" >&5 -$as_echo "$gdb_cv_m68k_is_coldfire" >&6; } - ;; -esac - -. ${srcdir}/configure.srv - -if test "${srv_mingwce}" = "yes"; then - LIBS="$LIBS -lws2" -elif test "${srv_mingw}" = "yes"; then - # WIN32APILIBS is set by GDB_AC_COMMON. - LIBS="$LIBS $WIN32APILIBS" -elif test "${srv_qnx}" = "yes"; then - LIBS="$LIBS -lsocket" -elif test "${srv_lynxos}" = "yes"; then - LIBS="$LIBS -lnetinet" -fi - -if test "${srv_linux_usrregs}" = "yes"; then - -$as_echo "#define HAVE_LINUX_USRREGS 1" >>confdefs.h - -fi - -if test "${srv_linux_regsets}" = "yes"; then - -$as_echo "#define HAVE_LINUX_REGSETS 1" >>confdefs.h - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTRACE_GETREGS" >&5 -$as_echo_n "checking for PTRACE_GETREGS... " >&6; } - if ${gdbsrv_cv_have_ptrace_getregs+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -PTRACE_GETREGS; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdbsrv_cv_have_ptrace_getregs=yes -else - gdbsrv_cv_have_ptrace_getregs=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_ptrace_getregs" >&5 -$as_echo "$gdbsrv_cv_have_ptrace_getregs" >&6; } - if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then - -$as_echo "#define HAVE_PTRACE_GETREGS 1" >>confdefs.h - - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTRACE_GETFPXREGS" >&5 -$as_echo_n "checking for PTRACE_GETFPXREGS... " >&6; } - if ${gdbsrv_cv_have_ptrace_getfpxregs+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -PTRACE_GETFPXREGS; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdbsrv_cv_have_ptrace_getfpxregs=yes -else - gdbsrv_cv_have_ptrace_getfpxregs=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_ptrace_getfpxregs" >&5 -$as_echo "$gdbsrv_cv_have_ptrace_getfpxregs" >&6; } - if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then - -$as_echo "#define HAVE_PTRACE_GETFPXREGS 1" >>confdefs.h - - fi -fi - -if test "${srv_linux_btrace}" = "yes"; then - -$as_echo "#define HAVE_LINUX_BTRACE 1" >>confdefs.h - -fi - -if test "$bfd_cv_have_sys_procfs_type_lwpid_t" != yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lwpid_t in thread_db.h" >&5 -$as_echo_n "checking for lwpid_t in thread_db.h... " >&6; } - if ${gdbserver_cv_have_thread_db_type_lwpid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main () -{ -lwpid_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdbserver_cv_have_thread_db_type_lwpid_t=yes -else - gdbserver_cv_have_thread_db_type_lwpid_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $gdbserver_cv_have_thread_db_type_lwpid_t = yes; then - -$as_echo "#define HAVE_LWPID_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbserver_cv_have_thread_db_type_lwpid_t" >&5 -$as_echo "$gdbserver_cv_have_thread_db_type_lwpid_t" >&6; } - -fi - -if test "$bfd_cv_have_sys_procfs_type_psaddr_t" != yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for psaddr_t in thread_db.h" >&5 -$as_echo_n "checking for psaddr_t in thread_db.h... " >&6; } - if ${gdbserver_cv_have_thread_db_type_psaddr_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main () -{ -psaddr_t avar - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdbserver_cv_have_thread_db_type_psaddr_t=yes -else - gdbserver_cv_have_thread_db_type_psaddr_t=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $gdbserver_cv_have_thread_db_type_psaddr_t = yes; then - -$as_echo "#define HAVE_PSADDR_T 1" >>confdefs.h - - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbserver_cv_have_thread_db_type_psaddr_t" >&5 -$as_echo "$gdbserver_cv_have_thread_db_type_psaddr_t" >&6; } - -fi - -old_LIBS="$LIBS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDL 1 -_ACEOF - - LIBS="-ldl $LIBS" - -fi - -LIBS="$old_LIBS" - -srv_thread_depfiles= -srv_libs= - -if test "$srv_linux_thread_db" = "yes"; then - if test "$ac_cv_lib_dl_dlopen" = "yes"; then - srv_libs="-ldl" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the dynamic export flag" >&5 -$as_echo_n "checking for the dynamic export flag... " >&6; } - old_LDFLAGS="$LDFLAGS" - # Older GNU ld supports --export-dynamic but --dynamic-list may not be - # supported there. - RDYNAMIC="-Wl,--dynamic-list=${srcdir}/proc-service.list" - LDFLAGS="$LDFLAGS $RDYNAMIC" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - found="-Wl,--dynamic-list" - RDYNAMIC='-Wl,--dynamic-list=$(srcdir)/proc-service.list' -else - RDYNAMIC="-rdynamic" - LDFLAGS="$old_LDFLAGS $RDYNAMIC" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - found="-rdynamic" -else - found="no" - RDYNAMIC="" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - - LDFLAGS="$old_LDFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $found" >&5 -$as_echo "$found" >&6; } - else - srv_libs="-lthread_db" - fi - - srv_thread_depfiles="thread-db.o proc-service.o" - -$as_echo "#define USE_THREAD_DB 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TD_VERSION" >&5 -$as_echo_n "checking for TD_VERSION... " >&6; } -if ${gdbsrv_cv_have_td_version+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -TD_VERSION; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdbsrv_cv_have_td_version=yes -else - gdbsrv_cv_have_td_version=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_td_version" >&5 -$as_echo "$gdbsrv_cv_have_td_version" >&6; } - if test "$gdbsrv_cv_have_td_version" = yes; then - -$as_echo "#define HAVE_TD_VERSION 1" >>confdefs.h - - fi -fi - - -# Check whether --with-libthread-db was given. -if test "${with_libthread_db+set}" = set; then : - withval=$with_libthread_db; srv_libthread_db_path="${withval}" - srv_libs="$srv_libthread_db_path" - -fi - - -if test "$srv_libs" != "" -a "$srv_libs" != "-ldl"; then - -$as_echo "#define USE_LIBTHREAD_DB_DIRECTLY 1" >>confdefs.h - -fi - -if test "$srv_xmlfiles" != ""; then - srv_xmlbuiltin="xml-builtin.o" - -$as_echo "#define USE_XML 1" >>confdefs.h - - - tmp_xmlfiles=$srv_xmlfiles - srv_xmlfiles="" - for f in $tmp_xmlfiles; do - srv_xmlfiles="$srv_xmlfiles \$(XML_DIR)/$f" - done -fi - -GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles $srv_selftest_objs" -GDBSERVER_LIBS="$srv_libs" - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports __sync_*_compare_and_swap" >&5 -$as_echo_n "checking whether the target supports __sync_*_compare_and_swap... " >&6; } -if ${gdbsrv_cv_have_sync_builtins+:} false; then : - $as_echo_n "(cached) " >&6 -else - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gdbsrv_cv_have_sync_builtins=yes -else - gdbsrv_cv_have_sync_builtins=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_sync_builtins" >&5 -$as_echo "$gdbsrv_cv_have_sync_builtins" >&6; } -if test "$gdbsrv_cv_have_sync_builtins" = yes; then - -$as_echo "#define HAVE_SYNC_BUILTINS 1" >>confdefs.h - -fi - -saved_cflags="$CFLAGS" -CFLAGS="$CFLAGS -fvisibility=hidden" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gdbsrv_cv_have_visibility_hidden=yes -else - gdbsrv_cv_have_visibility_hidden=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -CFLAGS="$saved_cflags" - -IPA_DEPFILES="" -extra_libraries="" - -# check whether to enable the inprocess agent -if test "$ipa_obj" != "" \ - -a "$gdbsrv_cv_have_sync_builtins" = yes \ - -a "$gdbsrv_cv_have_visibility_hidden" = yes; then - have_ipa=true -else - have_ipa=false -fi - -# Check whether --enable-inprocess-agent was given. -if test "${enable_inprocess_agent+set}" = set; then : - enableval=$enable_inprocess_agent; case "$enableval" in - yes) want_ipa=true ;; - no) want_ipa=false ;; - *) as_fn_error $? "bad value $enableval for inprocess-agent" "$LINENO" 5 ;; -esac -else - want_ipa=$have_ipa -fi - - -if $want_ipa ; then - if $have_ipa ; then - IPA_DEPFILES="$ipa_obj" - extra_libraries="$extra_libraries libinproctrace.so" - else - as_fn_error $? "inprocess agent not supported for this target" "$LINENO" 5 - fi -fi - - - - - - - - -GNULIB=build-gnulib-gdbserver/import - -GNULIB_STDINT_H= -if test x"$STDINT_H" != x; then - GNULIB_STDINT_H=$GNULIB/$STDINT_H -fi - - -ac_config_files="$ac_config_files Makefile" - - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then - as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to the package provider." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -config.status -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR -ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR CONFIG_SRC_SUBDIR="$CONFIG_SRC_SUBDIR" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;; - "depdir") CONFIG_COMMANDS="$CONFIG_COMMANDS depdir" ;; - "gdbdepdir") CONFIG_COMMANDS="$CONFIG_COMMANDS gdbdepdir" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi - ;; - - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "config.h":H) echo > stamp-h ;; - "depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;; - "gdbdepdir":C) - for subdir in ${CONFIG_SRC_SUBDIR} - do - $SHELL $ac_aux_dir/mkinstalldirs $subdir/$DEPDIR - done ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac deleted file mode 100644 index 03b36dc699a..00000000000 --- a/gdb/gdbserver/configure.ac +++ /dev/null @@ -1,445 +0,0 @@ -dnl Autoconf configure script for GDB server. -dnl Copyright (C) 2000-2020 Free Software Foundation, Inc. -dnl -dnl This file is part of GDB. -dnl -dnl This program is free software; you can redistribute it and/or modify -dnl it under the terms of the GNU General Public License as published by -dnl the Free Software Foundation; either version 3 of the License, or -dnl (at your option) any later version. -dnl -dnl This program is distributed in the hope that it will be useful, -dnl but WITHOUT ANY WARRANTY; without even the implied warranty of -dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -dnl GNU General Public License for more details. -dnl -dnl You should have received a copy of the GNU General Public License -dnl along with this program. If not, see . - -dnl Process this file with autoconf to produce a configure script. - -AC_INIT(server.c) -AC_CONFIG_HEADERS(config.h:config.in, [echo > stamp-h]) - -AM_MAINTAINER_MODE - -AC_PROG_CC -AC_PROG_CXX -AC_GNU_SOURCE -AC_SYS_LARGEFILE -AM_PROG_INSTALL_STRIP - -AC_CANONICAL_SYSTEM - -AC_PROG_INSTALL -AC_CHECK_TOOL(AR, ar) -AC_PROG_RANLIB - -AC_ARG_PROGRAM - -# We require a C++11 compiler. Check if one is available, and if -# necessary, set CXX_DIALECT to some -std=xxx switch. -AX_CXX_COMPILE_STDCXX(11, , mandatory) - -AC_HEADER_STDC - -# Set the 'development' global. -. $srcdir/../../bfd/development.sh - -GDB_AC_SELFTEST([ - srv_selftest_objs="gdbsupport/selftest.o" -]) - -ACX_NONCANONICAL_TARGET -ACX_NONCANONICAL_HOST - -# Dependency checking. -ZW_CREATE_DEPDIR - -# Create sub-directories for objects and dependencies. -CONFIG_SRC_SUBDIR="arch gdbsupport nat target" -AC_SUBST(CONFIG_SRC_SUBDIR) - -AC_CONFIG_COMMANDS([gdbdepdir],[ - for subdir in ${CONFIG_SRC_SUBDIR} - do - $SHELL $ac_aux_dir/mkinstalldirs $subdir/$DEPDIR - done], - [ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR CONFIG_SRC_SUBDIR="$CONFIG_SRC_SUBDIR"]) - -ZW_PROG_COMPILER_DEPENDENCIES([CC]) - -gnulib_extra_configure_args= -# If large-file support is disabled, make sure gnulib does the same. -if test "$enable_largefile" = no; then -gnulib_extra_configure_args="$gnulib_extra_configure_args --disable-largefile" -fi - -# Configure gnulib. We can't use AC_CONFIG_SUBDIRS as that'd expect -# to find the the source subdir to be configured directly under -# gdbserver/. We need to build gnulib under some other directory not -# "gnulib", to avoid the problem of both GDB and GDBserver wanting to -# build it in the same directory, when building in the source dir. -ACX_CONFIGURE_DIR(["../../gnulib"], ["build-gnulib-gdbserver"], - ["$gnulib_extra_configure_args"]) - -ACX_CONFIGURE_DIR(["../../libiberty"], ["build-libiberty-gdbserver"]) - -AC_CHECK_HEADERS(termios.h sys/reg.h string.h dnl - sys/procfs.h linux/elf.h dnl - fcntl.h signal.h sys/file.h dnl - sys/ioctl.h netinet/in.h sys/socket.h netdb.h dnl - netinet/tcp.h arpa/inet.h) -AC_FUNC_FORK -AC_CHECK_FUNCS(pread pwrite pread64) - -GDB_AC_COMMON - -# Check the return and argument types of ptrace. -GDB_AC_PTRACE - -# Check for UST -ustlibs="" -ustinc="" - -AC_ARG_WITH(ust, [ --with-ust=PATH Specify prefix directory for the installed UST package - Equivalent to --with-ust-include=PATH/include - plus --with-ust-lib=PATH/lib]) -AC_ARG_WITH(ust_include, [ --with-ust-include=PATH Specify directory for installed UST include files]) -AC_ARG_WITH(ust_lib, [ --with-ust-lib=PATH Specify the directory for the installed UST library]) - -case $with_ust in - no) - ustlibs= - ustinc= - ;; - "" | yes) - ustlibs=" -lust " - ustinc="" - ;; - *) - ustlibs="-L$with_ust/lib -lust" - ustinc="-I$with_ust/include " - ;; -esac -if test "x$with_ust_include" != x; then - ustinc="-I$with_ust_include " -fi -if test "x$with_ust_lib" != x; then - ustlibs="-L$with_ust_lib -lust" -fi - -if test "x$with_ust" != "xno"; then - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $ustinc" - AC_MSG_CHECKING([for ust]) - AC_TRY_COMPILE([ -#define CONFIG_UST_GDB_INTEGRATION -#include - ],[], - [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_UST, 1, [Define if UST is available])], - [AC_MSG_RESULT([no]); ustlibs= ; ustinc= ]) - CFLAGS="$saved_CFLAGS" -fi - -# Flags needed for UST -AC_SUBST(ustlibs) -AC_SUBST(ustinc) - -AM_GDB_WARNINGS - -dnl dladdr is glibc-specific. It is used by thread-db.c but only for -dnl debugging messages. It lives in -ldl which is handled below so we don't -dnl use AC_CHECK_LIB (or AC_SEARCH_LIBS) here. Instead we just temporarily -dnl augment LIBS. -old_LIBS="$LIBS" -LIBS="$LIBS -ldl" -AC_CHECK_FUNCS(dladdr) -LIBS="$old_LIBS" - -libiberty_INIT - -AC_CHECK_DECLS([perror, vasprintf, vsnprintf]) - -# See if supports the %fs_base and %gs_bas amd64 segment registers. -# Older amd64 Linux's don't have the fs_base and gs_base members of -# `struct user_regs_struct'. -AC_CHECK_MEMBERS([struct user_regs_struct.fs_base, struct user_regs_struct.gs_base], - [], [], [#include -#include ]) - - -AC_CHECK_TYPES(socklen_t, [], [], -[#include -#include -]) - -case "${target}" in - *-android*) - # Starting with NDK version 9, actually includes definitions - # of Elf32_auxv_t and Elf64_auxv_t. But sadly, includes - # which defines some of the ELF types incorrectly, - # leading to conflicts with the defintions from . - # This makes it impossible for us to include both and - # , which means that, in practice, we do not have - # access to Elf32_auxv_t and Elf64_auxv_t on this platform. - # Therefore, do not try to auto-detect availability, as it would - # get it wrong on this platform. - ;; - *) - AC_CHECK_TYPES([Elf32_auxv_t, Elf64_auxv_t], [], [], - #include - ) -esac - -ACX_PKGVERSION([GDB]) -ACX_BUGURL([http://www.gnu.org/software/gdb/bugs/]) -AC_DEFINE_UNQUOTED([PKGVERSION], ["$PKGVERSION"], [Additional package description]) -AC_DEFINE_UNQUOTED([REPORT_BUGS_TO], ["$REPORT_BUGS_TO"], [Bug reporting address]) - -# Check for various supplementary target information (beyond the -# triplet) which might affect the choices in configure.srv. -case "${target}" in -changequote(,)dnl - i[34567]86-*-linux*) -changequote([,])dnl - AC_CACHE_CHECK([if building for x86-64], [gdb_cv_i386_is_x86_64], - [save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $CFLAGS" - AC_EGREP_CPP([got it], [ -#if __x86_64__ -got it -#endif - ], [gdb_cv_i386_is_x86_64=yes], - [gdb_cv_i386_is_x86_64=no]) - CPPFLAGS="$save_CPPFLAGS"]) - ;; - - x86_64-*-linux*) - AC_CACHE_CHECK([if building for x32], [gdb_cv_x86_is_x32], - [save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $CFLAGS" - AC_EGREP_CPP([got it], [ -#if __x86_64__ && __ILP32__ -got it -#endif - ], [gdb_cv_x86_is_x32=yes], - [gdb_cv_x86_is_x32=no]) - CPPFLAGS="$save_CPPFLAGS"]) - ;; - - m68k-*-*) - AC_CACHE_CHECK([if building for Coldfire], [gdb_cv_m68k_is_coldfire], - [save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $CFLAGS" - AC_EGREP_CPP([got it], [ -#ifdef __mcoldfire__ -got it -#endif - ], [gdb_cv_m68k_is_coldfire=yes], - [gdb_cv_m68k_is_coldfire=no]) - CPPFLAGS="$save_CPPFLAGS"]) - ;; -esac - -. ${srcdir}/configure.srv - -if test "${srv_mingwce}" = "yes"; then - LIBS="$LIBS -lws2" -elif test "${srv_mingw}" = "yes"; then - # WIN32APILIBS is set by GDB_AC_COMMON. - LIBS="$LIBS $WIN32APILIBS" -elif test "${srv_qnx}" = "yes"; then - LIBS="$LIBS -lsocket" -elif test "${srv_lynxos}" = "yes"; then - LIBS="$LIBS -lnetinet" -fi - -if test "${srv_linux_usrregs}" = "yes"; then - AC_DEFINE(HAVE_LINUX_USRREGS, 1, - [Define if the target supports PTRACE_PEEKUSR for register ] - [access.]) -fi - -if test "${srv_linux_regsets}" = "yes"; then - AC_DEFINE(HAVE_LINUX_REGSETS, 1, - [Define if the target supports register sets.]) - - AC_MSG_CHECKING(for PTRACE_GETREGS) - AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getregs, - [AC_TRY_COMPILE([#include ], - [PTRACE_GETREGS;], - [gdbsrv_cv_have_ptrace_getregs=yes], - [gdbsrv_cv_have_ptrace_getregs=no])]) - AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getregs) - if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then - AC_DEFINE(HAVE_PTRACE_GETREGS, 1, - [Define if the target supports PTRACE_GETREGS for register ] - [access.]) - fi - - AC_MSG_CHECKING(for PTRACE_GETFPXREGS) - AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getfpxregs, - [AC_TRY_COMPILE([#include ], - [PTRACE_GETFPXREGS;], - [gdbsrv_cv_have_ptrace_getfpxregs=yes], - [gdbsrv_cv_have_ptrace_getfpxregs=no])]) - AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getfpxregs) - if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then - AC_DEFINE(HAVE_PTRACE_GETFPXREGS, 1, - [Define if the target supports PTRACE_GETFPXREGS for extended ] - [register access.]) - fi -fi - -if test "${srv_linux_btrace}" = "yes"; then - AC_DEFINE(HAVE_LINUX_BTRACE, 1, - [Define if the target supports branch tracing.]) -fi - -dnl Some systems (e.g., Android) have lwpid_t defined in libthread_db.h. -if test "$bfd_cv_have_sys_procfs_type_lwpid_t" != yes; then - GDBSERVER_HAVE_THREAD_DB_TYPE(lwpid_t) -fi - -dnl Some systems (e.g., Android) have psaddr_t defined in libthread_db.h. -if test "$bfd_cv_have_sys_procfs_type_psaddr_t" != yes; then - GDBSERVER_HAVE_THREAD_DB_TYPE(psaddr_t) -fi - -dnl Check for libdl, but do not add it to LIBS as only gdbserver -dnl needs it (and gdbreplay doesn't). -old_LIBS="$LIBS" -AC_CHECK_LIB(dl, dlopen) -LIBS="$old_LIBS" - -srv_thread_depfiles= -srv_libs= - -if test "$srv_linux_thread_db" = "yes"; then - if test "$ac_cv_lib_dl_dlopen" = "yes"; then - srv_libs="-ldl" - AC_MSG_CHECKING(for the dynamic export flag) - old_LDFLAGS="$LDFLAGS" - # Older GNU ld supports --export-dynamic but --dynamic-list may not be - # supported there. - RDYNAMIC="-Wl,--dynamic-list=${srcdir}/proc-service.list" - LDFLAGS="$LDFLAGS $RDYNAMIC" - AC_TRY_LINK([], [], - [found="-Wl,--dynamic-list" - RDYNAMIC='-Wl,--dynamic-list=$(srcdir)/proc-service.list'], - [RDYNAMIC="-rdynamic" - LDFLAGS="$old_LDFLAGS $RDYNAMIC" - AC_TRY_LINK([], [], - [found="-rdynamic"], - [found="no" - RDYNAMIC=""])]) - AC_SUBST(RDYNAMIC) - LDFLAGS="$old_LDFLAGS" - AC_MSG_RESULT($found) - else - srv_libs="-lthread_db" - fi - - srv_thread_depfiles="thread-db.o proc-service.o" - AC_DEFINE(USE_THREAD_DB, 1, [Define if we should use libthread_db.]) - AC_CACHE_CHECK([for TD_VERSION], gdbsrv_cv_have_td_version, - [AC_TRY_COMPILE([#include ], [TD_VERSION;], - [gdbsrv_cv_have_td_version=yes], - [gdbsrv_cv_have_td_version=no])]) - if test "$gdbsrv_cv_have_td_version" = yes; then - AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.]) - fi -fi - -AC_ARG_WITH(libthread-db, -AS_HELP_STRING([--with-libthread-db=PATH], [use given libthread_db directly]), -[srv_libthread_db_path="${withval}" - srv_libs="$srv_libthread_db_path" -]) - -if test "$srv_libs" != "" -a "$srv_libs" != "-ldl"; then - AC_DEFINE(USE_LIBTHREAD_DB_DIRECTLY, 1, [Define if we should use libthread_db directly.]) -fi - -if test "$srv_xmlfiles" != ""; then - srv_xmlbuiltin="xml-builtin.o" - AC_DEFINE(USE_XML, 1, [Define if an XML target description is available.]) - - tmp_xmlfiles=$srv_xmlfiles - srv_xmlfiles="" - for f in $tmp_xmlfiles; do - srv_xmlfiles="$srv_xmlfiles \$(XML_DIR)/$f" - done -fi - -GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles $srv_selftest_objs" -GDBSERVER_LIBS="$srv_libs" - -dnl Check whether the target supports __sync_*_compare_and_swap. -AC_CACHE_CHECK([whether the target supports __sync_*_compare_and_swap], - gdbsrv_cv_have_sync_builtins, [ -AC_TRY_LINK([], [int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1);], - gdbsrv_cv_have_sync_builtins=yes, - gdbsrv_cv_have_sync_builtins=no)]) -if test "$gdbsrv_cv_have_sync_builtins" = yes; then - AC_DEFINE(HAVE_SYNC_BUILTINS, 1, - [Define to 1 if the target supports __sync_*_compare_and_swap]) -fi - -dnl Check for -fvisibility=hidden support in the compiler. -saved_cflags="$CFLAGS" -CFLAGS="$CFLAGS -fvisibility=hidden" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], - [gdbsrv_cv_have_visibility_hidden=yes], - [gdbsrv_cv_have_visibility_hidden=no]) -CFLAGS="$saved_cflags" - -IPA_DEPFILES="" -extra_libraries="" - -# check whether to enable the inprocess agent -if test "$ipa_obj" != "" \ - -a "$gdbsrv_cv_have_sync_builtins" = yes \ - -a "$gdbsrv_cv_have_visibility_hidden" = yes; then - have_ipa=true -else - have_ipa=false -fi - -AC_ARG_ENABLE(inprocess-agent, -AS_HELP_STRING([--enable-inprocess-agent], [inprocess agent]), -[case "$enableval" in - yes) want_ipa=true ;; - no) want_ipa=false ;; - *) AC_MSG_ERROR([bad value $enableval for inprocess-agent]) ;; -esac], -[want_ipa=$have_ipa]) - -if $want_ipa ; then - if $have_ipa ; then - IPA_DEPFILES="$ipa_obj" - extra_libraries="$extra_libraries libinproctrace.so" - else - AC_MSG_ERROR([inprocess agent not supported for this target]) - fi -fi - -AC_SUBST(GDBSERVER_DEPFILES) -AC_SUBST(GDBSERVER_LIBS) -AC_SUBST(srv_xmlbuiltin) -AC_SUBST(srv_xmlfiles) -AC_SUBST(IPA_DEPFILES) -AC_SUBST(extra_libraries) - -GNULIB=build-gnulib-gdbserver/import - -GNULIB_STDINT_H= -if test x"$STDINT_H" != x; then - GNULIB_STDINT_H=$GNULIB/$STDINT_H -fi -AC_SUBST(GNULIB_STDINT_H) - -AC_CONFIG_FILES([Makefile]) - -AC_OUTPUT diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv deleted file mode 100644 index dba0733f1d7..00000000000 --- a/gdb/gdbserver/configure.srv +++ /dev/null @@ -1,402 +0,0 @@ -# Mappings from configuration triplets to gdbserver build options. -# This is invoked from the autoconf-generated configure script, to -# produce the appropriate Makefile substitutions. - -# This file sets the following shell variables: -# srv_regobj The register protocol appropriate for this target. -# srv_tgtobj Any other target-specific modules appropriate -# for this target. -# srv_hostio_err The object implementing the hostio_last_error -# target method. -# srv_xmlfiles All XML files which should be available for -# gdbserver in this configuration. -# ipa_obj Any other target-specific modules appropriate -# for this target's in-process agent. -# -# In addition, on GNU/Linux the following shell variables will be set: -# srv_linux_regsets Set to "yes" if ptrace(PTRACE_GETREGS) and friends -# may be available on this platform; unset otherwise. -# They will only be used if defines -# PTRACE_GETREGS. -# srv_linux_usrregs Set to "yes" if we can get at registers via -# PTRACE_PEEKUSR / PTRACE_POKEUSR. - -# Default hostio_last_error implementation -srv_hostio_err_objs="hostio-errno.o" - -ipa_ppc_linux_regobj="powerpc-32l-ipa.o powerpc-altivec32l-ipa.o powerpc-vsx32l-ipa.o powerpc-isa205-32l-ipa.o powerpc-isa205-altivec32l-ipa.o powerpc-isa205-vsx32l-ipa.o powerpc-isa205-ppr-dscr-vsx32l-ipa.o powerpc-isa207-vsx32l-ipa.o powerpc-isa207-htm-vsx32l-ipa.o powerpc-e500l-ipa.o powerpc-64l-ipa.o powerpc-altivec64l-ipa.o powerpc-vsx64l-ipa.o powerpc-isa205-64l-ipa.o powerpc-isa205-altivec64l-ipa.o powerpc-isa205-vsx64l-ipa.o powerpc-isa205-ppr-dscr-vsx64l-ipa.o powerpc-isa207-vsx64l-ipa.o powerpc-isa207-htm-vsx64l-ipa.o" - -# Linux object files. This is so we don't have to repeat -# these files over and over again. -srv_linux_obj="linux-low.o nat/linux-osdata.o nat/linux-procfs.o nat/linux-ptrace.o nat/linux-waitpid.o nat/linux-personality.o nat/linux-namespaces.o fork-child.o nat/fork-inferior.o" - -# Input is taken from the "${target}" variable. - -case "${target}" in - aarch64*-*-linux*) srv_tgtobj="linux-aarch64-low.o" - srv_tgtobj="$srv_tgtobj nat/aarch64-linux-hw-point.o" - srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" - srv_tgtobj="$srv_tgtobj linux-aarch32-tdesc.o" - srv_tgtobj="${srv_tgtobj} arch/aarch32.o" - srv_tgtobj="${srv_tgtobj} arch/arm.o" - srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o" - srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o" - srv_tgtobj="$srv_tgtobj arch/aarch64.o" - srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o" - srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o" - srv_tgtobj="${srv_tgtobj} $srv_linux_obj" - srv_linux_regsets=yes - srv_linux_thread_db=yes - ipa_obj="linux-aarch64-ipa.o" - ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o" - ipa_obj="${ipa_obj} arch/aarch64-ipa.o" - ;; - arm*-*-linux*) srv_tgtobj="$srv_linux_obj linux-arm-low.o" - srv_tgtobj="$srv_tgtobj linux-arm-tdesc.o" - srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" - srv_tgtobj="$srv_tgtobj linux-aarch32-tdesc.o" - srv_tgtobj="${srv_tgtobj} arch/aarch32.o" - srv_tgtobj="${srv_tgtobj} arch/arm.o" - srv_tgtobj="${srv_tgtobj} arch/arm-linux.o" - srv_tgtobj="${srv_tgtobj} arch/arm-get-next-pcs.o" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - arm*-*-mingw32ce*) srv_regobj=reg-arm.o - srv_tgtobj="win32-low.o win32-arm-low.o" - srv_tgtobj="${srv_tgtobj} wincecompat.o" - # hostio_last_error implementation is in win32-low.c - srv_hostio_err_objs="" - srv_mingw=yes - srv_mingwce=yes - ;; - bfin-*-*linux*) srv_regobj=reg-bfin.o - srv_tgtobj="$srv_linux_obj linux-bfin-low.o" - srv_linux_usrregs=yes - srv_linux_thread_db=yes - ;; - crisv32-*-linux*) srv_regobj=reg-crisv32.o - srv_tgtobj="$srv_linux_obj linux-crisv32-low.o" - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - cris-*-linux*) srv_regobj=reg-cris.o - srv_tgtobj="$srv_linux_obj linux-cris-low.o" - srv_linux_usrregs=yes - srv_linux_thread_db=yes - ;; - i[34567]86-*-cygwin*) srv_regobj="" - srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o" - srv_tgtobj="${srv_tgtobj} win32-i386-low.o" - srv_tgtobj="${srv_tgtobj} arch/i386.o" - ;; - i[34567]86-*-linux*) srv_tgtobj="${srv_tgtobj} arch/i386.o" - srv_tgtobj="${srv_tgtobj} $srv_linux_obj" - srv_tgtobj="${srv_tgtobj} linux-x86-low.o x86-low.o" - srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o i387-fp.o" - srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o" - srv_tgtobj="${srv_tgtobj} nat/linux-btrace.o" - srv_tgtobj="${srv_tgtobj} nat/x86-linux.o" - srv_tgtobj="${srv_tgtobj} nat/x86-linux-dregs.o" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - srv_linux_btrace=yes - ipa_obj="linux-i386-ipa.o linux-x86-tdesc-ipa.o" - ipa_obj="${ipa_obj} arch/i386-ipa.o" - ;; - i[34567]86-*-lynxos*) srv_regobj="" - srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o" - srv_tgtobj="${srv_tgtobj} nat/fork-inferior.o" - srv_tgtobj="${srv_tgtobj} arch/i386.o" - srv_lynxos=yes - ;; - i[34567]86-*-mingw32ce*) - srv_regobj="" - srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o" - srv_tgtobj="${srv_tgtobj} win32-i386-low.o" - srv_tgtobj="${srv_tgtobj} arch/i386.o" - srv_tgtobj="${srv_tgtobj} wincecompat.o" - # hostio_last_error implementation is in win32-low.c - srv_hostio_err_objs="" - srv_mingw=yes - srv_mingwce=yes - ;; - i[34567]86-*-mingw*) srv_regobj="" - srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o" - srv_tgtobj="${srv_tgtobj} win32-i386-low.o" - srv_tgtobj="${srv_tgtobj} arch/i386.o" - srv_mingw=yes - ;; - i[34567]86-*-nto*) srv_regobj="" - srv_tgtobj="nto-low.o nto-x86-low.o arch/i386.o" - srv_qnx="yes" - ;; - ia64-*-linux*) srv_regobj=reg-ia64.o - srv_tgtobj="$srv_linux_obj linux-ia64-low.o" - srv_linux_usrregs=yes - ;; - m32r*-*-linux*) srv_regobj=reg-m32r.o - srv_tgtobj="$srv_linux_obj linux-m32r-low.o" - srv_linux_usrregs=yes - srv_linux_thread_db=yes - ;; - m68*-*-linux*) if test "$gdb_cv_m68k_is_coldfire" = yes; then - srv_regobj=reg-cf.o - else - srv_regobj=reg-m68k.o - fi - srv_tgtobj="$srv_linux_obj linux-m68k-low.o" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - m68*-*-uclinux*) if test "$gdb_cv_m68k_is_coldfire" = yes; then - srv_regobj=reg-cf.o - else - srv_regobj=reg-m68k.o - fi - srv_tgtobj="$srv_linux_obj linux-m68k-low.o" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - mips*-*-linux*) srv_regobj="mips-linux.o" - srv_regobj="${srv_regobj} mips-dsp-linux.o" - srv_regobj="${srv_regobj} mips64-linux.o" - srv_regobj="${srv_regobj} mips64-dsp-linux.o" - srv_tgtobj="$srv_linux_obj linux-mips-low.o" - srv_tgtobj="${srv_tgtobj} nat/mips-linux-watch.o" - srv_xmlfiles="mips-linux.xml" - srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml" - srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml" - srv_xmlfiles="${srv_xmlfiles} mips-cp0.xml" - srv_xmlfiles="${srv_xmlfiles} mips-fpu.xml" - srv_xmlfiles="${srv_xmlfiles} mips-dsp.xml" - srv_xmlfiles="${srv_xmlfiles} mips64-linux.xml" - srv_xmlfiles="${srv_xmlfiles} mips64-dsp-linux.xml" - srv_xmlfiles="${srv_xmlfiles} mips64-cpu.xml" - srv_xmlfiles="${srv_xmlfiles} mips64-cp0.xml" - srv_xmlfiles="${srv_xmlfiles} mips64-fpu.xml" - srv_xmlfiles="${srv_xmlfiles} mips64-dsp.xml" - srv_linux_regsets=yes - srv_linux_usrregs=yes - srv_linux_thread_db=yes - ;; - nios2*-*-linux*) srv_regobj="nios2-linux.o" - srv_tgtobj="$srv_linux_obj linux-nios2-low.o" - srv_xmlfiles="nios2-linux.xml" - srv_xmlfiles="${srv_xmlfiles} nios2-cpu.xml" - srv_linux_regsets=yes - srv_linux_usrregs=yes - srv_linux_thread_db=yes - ;; - powerpc*-*-linux*) srv_regobj="powerpc-32l.o" - srv_regobj="${srv_regobj} powerpc-altivec32l.o" - srv_regobj="${srv_regobj} powerpc-vsx32l.o" - srv_regobj="${srv_regobj} powerpc-isa205-32l.o" - srv_regobj="${srv_regobj} powerpc-isa205-altivec32l.o" - srv_regobj="${srv_regobj} powerpc-isa205-vsx32l.o" - srv_regobj="${srv_regobj} powerpc-isa205-ppr-dscr-vsx32l.o" - srv_regobj="${srv_regobj} powerpc-isa207-vsx32l.o" - srv_regobj="${srv_regobj} powerpc-isa207-htm-vsx32l.o" - srv_regobj="${srv_regobj} powerpc-e500l.o" - srv_regobj="${srv_regobj} powerpc-64l.o" - srv_regobj="${srv_regobj} powerpc-altivec64l.o" - srv_regobj="${srv_regobj} powerpc-vsx64l.o" - srv_regobj="${srv_regobj} powerpc-isa205-64l.o" - srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o" - srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o" - srv_regobj="${srv_regobj} powerpc-isa205-ppr-dscr-vsx64l.o" - srv_regobj="${srv_regobj} powerpc-isa207-vsx64l.o" - srv_regobj="${srv_regobj} powerpc-isa207-htm-vsx64l.o" - srv_tgtobj="$srv_linux_obj linux-ppc-low.o" - srv_tgtobj="${srv_tgtobj} nat/ppc-linux.o" - srv_tgtobj="${srv_tgtobj} arch/ppc-linux-common.o" - srv_xmlfiles="rs6000/powerpc-32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-altivec32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-vsx32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-vsx32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-htm-vsx32l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-altivec.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-vsx.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-linux.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu-isa205.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-dscr.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-ppr.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-tar.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-ebb.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-linux-pmu.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-spr.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-core.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-fpu.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-altivec.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-vsx.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-ppr.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-dscr.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-tar.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-e500l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-altivec64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-vsx64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-vsx64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-htm-vsx64l.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power64-core.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power64-linux.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power64-htm-core.xml" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - ipa_obj="${ipa_ppc_linux_regobj} linux-ppc-ipa.o" - ;; - powerpc-*-lynxos*) srv_regobj="powerpc-32.o" - srv_tgtobj="lynx-low.o lynx-ppc-low.o" - srv_xmlfiles="rs6000/powerpc-32.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml" - srv_lynxos=yes - ;; - s390*-*-linux*) srv_regobj="s390-linux32.o" - srv_regobj="${srv_regobj} s390-linux32v1.o" - srv_regobj="${srv_regobj} s390-linux32v2.o" - srv_regobj="${srv_regobj} s390-linux64.o" - srv_regobj="${srv_regobj} s390-linux64v1.o" - srv_regobj="${srv_regobj} s390-linux64v2.o" - srv_regobj="${srv_regobj} s390-te-linux64.o" - srv_regobj="${srv_regobj} s390-vx-linux64.o" - srv_regobj="${srv_regobj} s390-tevx-linux64.o" - srv_regobj="${srv_regobj} s390-gs-linux64.o" - srv_regobj="${srv_regobj} s390x-linux64.o" - srv_regobj="${srv_regobj} s390x-linux64v1.o" - srv_regobj="${srv_regobj} s390x-linux64v2.o" - srv_regobj="${srv_regobj} s390x-te-linux64.o" - srv_regobj="${srv_regobj} s390x-vx-linux64.o" - srv_regobj="${srv_regobj} s390x-tevx-linux64.o" - srv_regobj="${srv_regobj} s390x-gs-linux64.o" - srv_tgtobj="$srv_linux_obj linux-s390-low.o" - srv_xmlfiles="s390-linux32.xml" - srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml" - srv_xmlfiles="${srv_xmlfiles} s390-linux32v2.xml" - srv_xmlfiles="${srv_xmlfiles} s390-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390-linux64v1.xml" - srv_xmlfiles="${srv_xmlfiles} s390-linux64v2.xml" - srv_xmlfiles="${srv_xmlfiles} s390-te-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390-vx-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390-tevx-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390-gs-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-linux64v1.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-linux64v2.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-te-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-vx-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-tevx-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-gs-linux64.xml" - srv_xmlfiles="${srv_xmlfiles} s390-core32.xml" - srv_xmlfiles="${srv_xmlfiles} s390-core64.xml" - srv_xmlfiles="${srv_xmlfiles} s390x-core64.xml" - srv_xmlfiles="${srv_xmlfiles} s390-acr.xml" - srv_xmlfiles="${srv_xmlfiles} s390-fpr.xml" - srv_xmlfiles="${srv_xmlfiles} s390-tdb.xml" - srv_xmlfiles="${srv_xmlfiles} s390-vx.xml" - srv_xmlfiles="${srv_xmlfiles} s390-gs.xml" - srv_xmlfiles="${srv_xmlfiles} s390-gsbc.xml" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - ipa_obj="linux-s390-ipa.o" - ipa_obj="${ipa_obj} s390-linux32-ipa.o" - ipa_obj="${ipa_obj} s390-linux32v1-ipa.o" - ipa_obj="${ipa_obj} s390-linux32v2-ipa.o" - ipa_obj="${ipa_obj} s390-linux64-ipa.o" - ipa_obj="${ipa_obj} s390-linux64v1-ipa.o" - ipa_obj="${ipa_obj} s390-linux64v2-ipa.o" - ipa_obj="${ipa_obj} s390-vx-linux64-ipa.o" - ipa_obj="${ipa_obj} s390-te-linux64-ipa.o" - ipa_obj="${ipa_obj} s390-tevx-linux64-ipa.o" - ipa_obj="${ipa_obj} s390-gs-linux64-ipa.o" - ipa_obj="${ipa_obj} s390x-linux64-ipa.o" - ipa_obj="${ipa_obj} s390x-linux64v1-ipa.o" - ipa_obj="${ipa_obj} s390x-linux64v2-ipa.o" - ipa_obj="${ipa_obj} s390x-vx-linux64-ipa.o" - ipa_obj="${ipa_obj} s390x-te-linux64-ipa.o" - ipa_obj="${ipa_obj} s390x-tevx-linux64-ipa.o" - ipa_obj="${ipa_obj} s390x-gs-linux64-ipa.o" - ;; - sh*-*-linux*) srv_regobj=reg-sh.o - srv_tgtobj="$srv_linux_obj linux-sh-low.o" - srv_linux_usrregs=yes - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - sparc*-*-linux*) srv_regobj=reg-sparc64.o - srv_tgtobj="$srv_linux_obj linux-sparc-low.o" - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - tic6x-*-uclinux) if $development; then - srv_regobj="tic6x-c64xp-linux.o" - srv_regobj="${srv_regobj} tic6x-c64x-linux.o" - srv_regobj="${srv_regobj} tic6x-c62x-linux.o" - else - srv_regobj="" - fi - srv_tgtobj="$srv_linux_obj linux-tic6x-low.o" - srv_tgtobj="${srv_tgtobj} arch/tic6x.o" - srv_linux_regsets=yes - srv_linux_usrregs=yes - srv_linux_thread_db=yes - ;; - x86_64-*-linux*) srv_tgtobj="$srv_linux_obj linux-x86-low.o x86-low.o" - srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o i387-fp.o" - srv_tgtobj="${srv_tgtobj} arch/i386.o arch/amd64.o" - srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o" - srv_tgtobj="${srv_tgtobj} nat/linux-btrace.o" - srv_tgtobj="${srv_tgtobj} nat/x86-linux.o" - srv_tgtobj="${srv_tgtobj} nat/x86-linux-dregs.o" - srv_tgtobj="${srv_tgtobj} nat/amd64-linux-siginfo.o" - srv_linux_usrregs=yes # This is for i386 progs. - srv_linux_regsets=yes - srv_linux_thread_db=yes - srv_linux_btrace=yes - ipa_obj="linux-amd64-ipa.o linux-x86-tdesc-ipa.o" - ipa_obj="${ipa_obj} arch/amd64-ipa.o" - ;; - x86_64-*-mingw*) srv_regobj="" - srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o" - srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o" - srv_tgtobj="${srv_tgtobj} arch/amd64.o" - srv_mingw=yes - ;; - x86_64-*-cygwin*) srv_regobj="" - srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o" - srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o" - srv_tgtobj="${srv_tgtobj} arch/amd64.o" - ;; - - xtensa*-*-linux*) srv_regobj=reg-xtensa.o - srv_tgtobj="$srv_linux_obj linux-xtensa-low.o" - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - tilegx-*-linux*) srv_regobj=reg-tilegx.o - srv_regobj="${srv_regobj} reg-tilegx32.o" - srv_tgtobj="$srv_linux_obj linux-tile-low.o" - srv_linux_regsets=yes - srv_linux_thread_db=yes - ;; - *) echo "Error: target not supported by gdbserver." - exit 1 - ;; -esac diff --git a/gdb/gdbserver/debug.c b/gdb/gdbserver/debug.c deleted file mode 100644 index 7bb2504570d..00000000000 --- a/gdb/gdbserver/debug.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Debugging routines for the remote server for GDB. - Copyright (C) 2014-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include - -#if !defined (IN_PROCESS_AGENT) -int remote_debug = 0; -#endif - -/* Output file for debugging. Default to standard error. */ -FILE *debug_file = stderr; - -/* See debug.h. */ -int debug_threads; - -/* Include timestamps in debugging output. */ -int debug_timestamp; - -#if !defined (IN_PROCESS_AGENT) - -/* See debug.h. */ - -void -debug_set_output (const char *new_debug_file) -{ - /* Close any existing file and reset to standard error. */ - if (debug_file != stderr) - { - fclose (debug_file); - } - debug_file = stderr; - - /* Catch empty filenames. */ - if (new_debug_file == nullptr || strlen (new_debug_file) == 0) - return; - - FILE *fptr = fopen (new_debug_file, "w"); - - if (fptr == nullptr) - { - debug_printf ("Cannot open %s for writing. %s. Switching to stderr.\n", - new_debug_file, safe_strerror (errno)); - return; - } - - debug_file = fptr; -} - -#endif - -/* Print a debugging message. - If the text begins a new line it is preceded by a timestamp. - We don't get fancy with newline checking, we just check whether the - previous call ended with "\n". */ - -void -debug_vprintf (const char *format, va_list ap) -{ -#if !defined (IN_PROCESS_AGENT) - /* N.B. Not thread safe, and can't be used, as is, with IPA. */ - static int new_line = 1; - - if (debug_timestamp && new_line) - { - using namespace std::chrono; - - steady_clock::time_point now = steady_clock::now (); - seconds s = duration_cast (now.time_since_epoch ()); - microseconds us = duration_cast (now.time_since_epoch ()) - s; - - fprintf (debug_file, "%ld.%06ld ", (long) s.count (), (long) us.count ()); - } -#endif - - vfprintf (debug_file, format, ap); - -#if !defined (IN_PROCESS_AGENT) - if (*format) - new_line = format[strlen (format) - 1] == '\n'; -#endif -} - -/* Flush debugging output. - This is called, for example, when starting an inferior to ensure all debug - output thus far appears before any inferior output. */ - -void -debug_flush (void) -{ - fflush (debug_file); -} - -/* Notify the user that the code is entering FUNCTION_NAME. - FUNCTION_NAME is the name of the calling function, or NULL if unknown. - - This is intended to be called via the debug_enter macro. */ - -void -do_debug_enter (const char *function_name) -{ - if (function_name != NULL) - debug_printf (">>>> entering %s\n", function_name); -} - -/* Notify the user that the code is exiting FUNCTION_NAME. - FUNCTION_NAME is the name of the calling function, or NULL if unknown. - - This is intended to be called via the debug_exit macro. */ - -void -do_debug_exit (const char *function_name) -{ - if (function_name != NULL) - debug_printf ("<<<< exiting %s\n", function_name); -} - -/* See debug.h. */ - -ssize_t -debug_write (const void *buf, size_t nbyte) -{ - int fd = fileno (debug_file); - return write (fd, buf, nbyte); -} diff --git a/gdb/gdbserver/debug.h b/gdb/gdbserver/debug.h deleted file mode 100644 index b026ee734f6..00000000000 --- a/gdb/gdbserver/debug.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Debugging routines for the remote server for GDB. - Copyright (C) 2014-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_DEBUG_H -#define GDBSERVER_DEBUG_H - -#if !defined (IN_PROCESS_AGENT) -extern int remote_debug; - -/* Switch all debug output to DEBUG_FILE. If DEBUG_FILE is nullptr or an - empty string, or if the file cannot be opened, then debug output is sent to - stderr. */ -void debug_set_output (const char *debug_file); -#endif - -extern int using_threads; - -/* Enable miscellaneous debugging output. The name is historical - it - was originally used to debug LinuxThreads support. */ - -extern int debug_threads; - -extern int debug_timestamp; - -void debug_flush (void); -void do_debug_enter (const char *function_name); -void do_debug_exit (const char *function_name); - -/* Async signal safe debug output function that calls write directly. */ -ssize_t debug_write (const void *buf, size_t nbyte); - -/* These macros are for use in major functions that produce a lot of - debugging output. They help identify in the mass of debugging output - when these functions enter and exit. debug_enter is intended to be - called at the start of a function, before any other debugging output. - debug_exit is intended to be called at the end of the same function, - after all debugging output. */ -#ifdef FUNCTION_NAME -#define debug_enter() \ - do { do_debug_enter (FUNCTION_NAME); } while (0) -#define debug_exit() \ - do { do_debug_exit (FUNCTION_NAME); } while (0) -#else -#define debug_enter() \ - do { } while (0) -#define debug_exit() \ - do { } while (0) -#endif - -#endif /* GDBSERVER_DEBUG_H */ diff --git a/gdb/gdbserver/dll.c b/gdb/gdbserver/dll.c deleted file mode 100644 index fdc7becfbee..00000000000 --- a/gdb/gdbserver/dll.c +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2002-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "dll.h" - -#include - -/* An "unspecified" CORE_ADDR, for match_dll. */ -#define UNSPECIFIED_CORE_ADDR (~(CORE_ADDR) 0) - -std::list all_dlls; -int dlls_changed; - -/* Record a newly loaded DLL at BASE_ADDR. */ - -void -loaded_dll (const char *name, CORE_ADDR base_addr) -{ - all_dlls.emplace_back (name != NULL ? name : "", base_addr); - dlls_changed = 1; -} - -/* Record that the DLL with NAME and BASE_ADDR has been unloaded. */ - -void -unloaded_dll (const char *name, CORE_ADDR base_addr) -{ - auto pred = [&] (const dll_info &dll) - { - if (base_addr != UNSPECIFIED_CORE_ADDR - && base_addr == dll.base_addr) - return true; - - if (name != NULL && dll.name == name) - return true; - - return false; - }; - - auto iter = std::find_if (all_dlls.begin (), all_dlls.end (), pred); - - if (iter == all_dlls.end ()) - /* For some inferiors we might get unloaded_dll events without having - a corresponding loaded_dll. In that case, the dll cannot be found - in ALL_DLL, and there is nothing further for us to do. - - This has been observed when running 32bit executables on Windows64 - (i.e. through WOW64, the interface between the 32bits and 64bits - worlds). In that case, the inferior always does some strange - unloading of unnamed dll. */ - return; - else - { - /* DLL has been found so remove the entry and free associated - resources. */ - all_dlls.erase (iter); - dlls_changed = 1; - } -} - -void -clear_dlls (void) -{ - all_dlls.clear (); -} diff --git a/gdb/gdbserver/dll.h b/gdb/gdbserver/dll.h deleted file mode 100644 index 63c1cd44d3b..00000000000 --- a/gdb/gdbserver/dll.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_DLL_H -#define GDBSERVER_DLL_H - -#include - -struct dll_info -{ - dll_info (const std::string &name_, CORE_ADDR base_addr_) - : name (name_), base_addr (base_addr_) - {} - - std::string name; - CORE_ADDR base_addr; -}; - -extern std::list all_dlls; -extern int dlls_changed; - -extern void clear_dlls (void); -extern void loaded_dll (const char *name, CORE_ADDR base_addr); -extern void unloaded_dll (const char *name, CORE_ADDR base_addr); - -#endif /* GDBSERVER_DLL_H */ diff --git a/gdb/gdbserver/event-loop.c b/gdb/gdbserver/event-loop.c deleted file mode 100644 index 8827e8a32eb..00000000000 --- a/gdb/gdbserver/event-loop.c +++ /dev/null @@ -1,567 +0,0 @@ -/* Event loop machinery for the remote server for GDB. - Copyright (C) 1999-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -/* Based on src/gdb/event-loop.c. */ - -#include "server.h" - -#include -#include "gdbsupport/gdb_sys_time.h" - -#ifdef USE_WIN32API -#include -#include -#endif - -#include -#include - -typedef int (event_handler_func) (gdb_fildes_t); - -/* Tell create_file_handler what events we are interested in. */ - -#define GDB_READABLE (1<<1) -#define GDB_WRITABLE (1<<2) -#define GDB_EXCEPTION (1<<3) - -/* Events are queued by on the event_queue and serviced later - on by do_one_event. An event can be, for instance, a file - descriptor becoming ready to be read. Servicing an event simply - means that the procedure PROC will be called. We have 2 queues, - one for file handlers that we listen to in the event loop, and one - for the file handlers+events that are ready. The procedure PROC - associated with each event is always the same (handle_file_event). - Its duty is to invoke the handler associated with the file - descriptor whose state change generated the event, plus doing other - cleanups and such. */ - -struct gdb_event - { - /* Procedure to call to service this event. */ - event_handler_func *proc; - - /* File descriptor that is ready. */ - gdb_fildes_t fd; - }; - -/* Information about each file descriptor we register with the event - loop. */ - -typedef struct file_handler - { - /* File descriptor. */ - gdb_fildes_t fd; - - /* Events we want to monitor. */ - int mask; - - /* Events that have been seen since the last time. */ - int ready_mask; - - /* Procedure to call when fd is ready. */ - handler_func *proc; - - /* Argument to pass to proc. */ - gdb_client_data client_data; - - /* Was an error detected on this fd? */ - int error; - - /* Next registered file descriptor. */ - struct file_handler *next_file; - } -file_handler; - -typedef gdb::unique_xmalloc_ptr gdb_event_up; - -static std::queue> event_queue; - -/* Gdb_notifier is just a list of file descriptors gdb is interested - in. These are the input file descriptor, and the target file - descriptor. Each of the elements in the gdb_notifier list is - basically a description of what kind of events gdb is interested - in, for each fd. */ - -static struct - { - /* Ptr to head of file handler list. */ - file_handler *first_file_handler; - - /* Masks to be used in the next call to select. Bits are set in - response to calls to create_file_handler. */ - fd_set check_masks[3]; - - /* What file descriptors were found ready by select. */ - fd_set ready_masks[3]; - - /* Number of valid bits (highest fd value + 1). (for select) */ - int num_fds; - } -gdb_notifier; - -/* Callbacks are just routines that are executed before waiting for the - next event. In GDB this is struct gdb_timer. We don't need timers - so rather than copy all that complexity in gdbserver, we provide what - we need, but we do so in a way that if/when the day comes that we need - that complexity, it'll be easier to add - replace callbacks with timers - and use a delta of zero (which is all gdb currently uses timers for anyway). - - PROC will be executed before gdbserver goes to sleep to wait for the - next event. */ - -struct callback_event - { - int id; - callback_handler_func *proc; - gdb_client_data data; - struct callback_event *next; - }; - -/* Table of registered callbacks. */ - -static struct - { - struct callback_event *first; - struct callback_event *last; - - /* Id of the last callback created. */ - int num_callbacks; - } -callback_list; - -void -initialize_event_loop (void) -{ -} - -/* Process one event. If an event was processed, 1 is returned - otherwise 0 is returned. Scan the queue from head to tail, - processing therefore the high priority events first, by invoking - the associated event handler procedure. */ - -static int -process_event (void) -{ - /* Let's get rid of the event from the event queue. We need to - do this now because while processing the event, since the - proc function could end up jumping out to the caller of this - function. In that case, we would have on the event queue an - event which has been processed, but not deleted. */ - if (!event_queue.empty ()) - { - gdb_event_up event_ptr = std::move (event_queue.front ()); - event_queue.pop (); - - event_handler_func *proc = event_ptr->proc; - gdb_fildes_t fd = event_ptr->fd; - - /* Now call the procedure associated with the event. */ - if ((*proc) (fd)) - return -1; - return 1; - } - - /* This is the case if there are no event on the event queue. */ - return 0; -} - -/* Append PROC to the callback list. - The result is the "id" of the callback that can be passed back to - delete_callback_event. */ - -int -append_callback_event (callback_handler_func *proc, gdb_client_data data) -{ - struct callback_event *event_ptr = XNEW (struct callback_event); - - event_ptr->id = callback_list.num_callbacks++; - event_ptr->proc = proc; - event_ptr->data = data; - event_ptr->next = NULL; - if (callback_list.first == NULL) - callback_list.first = event_ptr; - if (callback_list.last != NULL) - callback_list.last->next = event_ptr; - callback_list.last = event_ptr; - return event_ptr->id; -} - -/* Delete callback ID. - It is not an error callback ID doesn't exist. */ - -void -delete_callback_event (int id) -{ - struct callback_event **p; - - for (p = &callback_list.first; *p != NULL; p = &(*p)->next) - { - struct callback_event *event_ptr = *p; - - if (event_ptr->id == id) - { - *p = event_ptr->next; - if (event_ptr == callback_list.last) - callback_list.last = NULL; - free (event_ptr); - break; - } - } -} - -/* Run the next callback. - The result is 1 if a callback was called and event processing - should continue, -1 if the callback wants the event loop to exit, - and 0 if there are no more callbacks. */ - -static int -process_callback (void) -{ - struct callback_event *event_ptr; - - event_ptr = callback_list.first; - if (event_ptr != NULL) - { - callback_handler_func *proc = event_ptr->proc; - gdb_client_data data = event_ptr->data; - - /* Remove the event before calling PROC, - more events may get added by PROC. */ - callback_list.first = event_ptr->next; - if (callback_list.first == NULL) - callback_list.last = NULL; - free (event_ptr); - if ((*proc) (data)) - return -1; - return 1; - } - - return 0; -} - -/* Add a file handler/descriptor to the list of descriptors we are - interested in. FD is the file descriptor for the file/stream to be - listened to. MASK is a combination of READABLE, WRITABLE, - EXCEPTION. PROC is the procedure that will be called when an event - occurs for FD. CLIENT_DATA is the argument to pass to PROC. */ - -static void -create_file_handler (gdb_fildes_t fd, int mask, handler_func *proc, - gdb_client_data client_data) -{ - file_handler *file_ptr; - - /* Do we already have a file handler for this file? (We may be - changing its associated procedure). */ - for (file_ptr = gdb_notifier.first_file_handler; - file_ptr != NULL; - file_ptr = file_ptr->next_file) - if (file_ptr->fd == fd) - break; - - /* It is a new file descriptor. Add it to the list. Otherwise, - just change the data associated with it. */ - if (file_ptr == NULL) - { - file_ptr = XNEW (struct file_handler); - file_ptr->fd = fd; - file_ptr->ready_mask = 0; - file_ptr->next_file = gdb_notifier.first_file_handler; - gdb_notifier.first_file_handler = file_ptr; - - if (mask & GDB_READABLE) - FD_SET (fd, &gdb_notifier.check_masks[0]); - else - FD_CLR (fd, &gdb_notifier.check_masks[0]); - - if (mask & GDB_WRITABLE) - FD_SET (fd, &gdb_notifier.check_masks[1]); - else - FD_CLR (fd, &gdb_notifier.check_masks[1]); - - if (mask & GDB_EXCEPTION) - FD_SET (fd, &gdb_notifier.check_masks[2]); - else - FD_CLR (fd, &gdb_notifier.check_masks[2]); - - if (gdb_notifier.num_fds <= fd) - gdb_notifier.num_fds = fd + 1; - } - - file_ptr->proc = proc; - file_ptr->client_data = client_data; - file_ptr->mask = mask; -} - -/* Wrapper function for create_file_handler. */ - -void -add_file_handler (gdb_fildes_t fd, - handler_func *proc, gdb_client_data client_data) -{ - create_file_handler (fd, GDB_READABLE | GDB_EXCEPTION, proc, client_data); -} - -/* Remove the file descriptor FD from the list of monitored fd's: - i.e. we don't care anymore about events on the FD. */ - -void -delete_file_handler (gdb_fildes_t fd) -{ - file_handler *file_ptr, *prev_ptr = NULL; - int i; - - /* Find the entry for the given file. */ - - for (file_ptr = gdb_notifier.first_file_handler; - file_ptr != NULL; - file_ptr = file_ptr->next_file) - if (file_ptr->fd == fd) - break; - - if (file_ptr == NULL) - return; - - if (file_ptr->mask & GDB_READABLE) - FD_CLR (fd, &gdb_notifier.check_masks[0]); - if (file_ptr->mask & GDB_WRITABLE) - FD_CLR (fd, &gdb_notifier.check_masks[1]); - if (file_ptr->mask & GDB_EXCEPTION) - FD_CLR (fd, &gdb_notifier.check_masks[2]); - - /* Find current max fd. */ - - if ((fd + 1) == gdb_notifier.num_fds) - { - gdb_notifier.num_fds--; - for (i = gdb_notifier.num_fds; i; i--) - { - if (FD_ISSET (i - 1, &gdb_notifier.check_masks[0]) - || FD_ISSET (i - 1, &gdb_notifier.check_masks[1]) - || FD_ISSET (i - 1, &gdb_notifier.check_masks[2])) - break; - } - gdb_notifier.num_fds = i; - } - - /* Deactivate the file descriptor, by clearing its mask, so that it - will not fire again. */ - - file_ptr->mask = 0; - - /* Get rid of the file handler in the file handler list. */ - if (file_ptr == gdb_notifier.first_file_handler) - gdb_notifier.first_file_handler = file_ptr->next_file; - else - { - for (prev_ptr = gdb_notifier.first_file_handler; - prev_ptr->next_file != file_ptr; - prev_ptr = prev_ptr->next_file) - ; - prev_ptr->next_file = file_ptr->next_file; - } - free (file_ptr); -} - -/* Handle the given event by calling the procedure associated to the - corresponding file handler. Called by process_event indirectly, - through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the - event in the front of the event queue. */ - -static int -handle_file_event (gdb_fildes_t event_file_desc) -{ - file_handler *file_ptr; - int mask; - - /* Search the file handler list to find one that matches the fd in - the event. */ - for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL; - file_ptr = file_ptr->next_file) - { - if (file_ptr->fd == event_file_desc) - { - /* See if the desired events (mask) match the received - events (ready_mask). */ - - if (file_ptr->ready_mask & GDB_EXCEPTION) - { - warning ("Exception condition detected on fd %s", - pfildes (file_ptr->fd)); - file_ptr->error = 1; - } - else - file_ptr->error = 0; - mask = file_ptr->ready_mask & file_ptr->mask; - - /* Clear the received events for next time around. */ - file_ptr->ready_mask = 0; - - /* If there was a match, then call the handler. */ - if (mask != 0) - { - if ((*file_ptr->proc) (file_ptr->error, - file_ptr->client_data) < 0) - return -1; - } - break; - } - } - - return 0; -} - -/* Create a file event, to be enqueued in the event queue for - processing. The procedure associated to this event is always - handle_file_event, which will in turn invoke the one that was - associated to FD when it was registered with the event loop. */ - -static gdb_event * -create_file_event (gdb_fildes_t fd) -{ - gdb_event *file_event_ptr; - - file_event_ptr = XNEW (gdb_event); - file_event_ptr->proc = handle_file_event; - file_event_ptr->fd = fd; - - return file_event_ptr; -} - -/* Called by do_one_event to wait for new events on the monitored file - descriptors. Queue file events as they are detected by the poll. - If there are no events, this function will block in the call to - select. Return -1 if there are no files descriptors to monitor, - otherwise return 0. */ - -static int -wait_for_event (void) -{ - file_handler *file_ptr; - int num_found = 0; - - /* Make sure all output is done before getting another event. */ - fflush (stdout); - fflush (stderr); - - if (gdb_notifier.num_fds == 0) - return -1; - - gdb_notifier.ready_masks[0] = gdb_notifier.check_masks[0]; - gdb_notifier.ready_masks[1] = gdb_notifier.check_masks[1]; - gdb_notifier.ready_masks[2] = gdb_notifier.check_masks[2]; - num_found = select (gdb_notifier.num_fds, - &gdb_notifier.ready_masks[0], - &gdb_notifier.ready_masks[1], - &gdb_notifier.ready_masks[2], - NULL); - - /* Clear the masks after an error from select. */ - if (num_found == -1) - { - FD_ZERO (&gdb_notifier.ready_masks[0]); - FD_ZERO (&gdb_notifier.ready_masks[1]); - FD_ZERO (&gdb_notifier.ready_masks[2]); -#ifdef EINTR - /* Dont print anything if we got a signal, let gdb handle - it. */ - if (errno != EINTR) - perror_with_name ("select"); -#endif - } - - /* Enqueue all detected file events. */ - - for (file_ptr = gdb_notifier.first_file_handler; - file_ptr != NULL && num_found > 0; - file_ptr = file_ptr->next_file) - { - int mask = 0; - - if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[0])) - mask |= GDB_READABLE; - if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[1])) - mask |= GDB_WRITABLE; - if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[2])) - mask |= GDB_EXCEPTION; - - if (!mask) - continue; - else - num_found--; - - /* Enqueue an event only if this is still a new event for this - fd. */ - - if (file_ptr->ready_mask == 0) - { - gdb_event *file_event_ptr = create_file_event (file_ptr->fd); - - event_queue.emplace (file_event_ptr); - } - file_ptr->ready_mask = mask; - } - - return 0; -} - -/* Start up the event loop. This is the entry point to the event - loop. */ - -void -start_event_loop (void) -{ - /* Loop until there is nothing to do. This is the entry point to - the event loop engine. If nothing is ready at this time, wait - for something to happen (via wait_for_event), then process it. - Return when there are no longer event sources to wait for. */ - - while (1) - { - /* Any events already waiting in the queue? */ - int res = process_event (); - - /* Did the event handler want the event loop to stop? */ - if (res == -1) - return; - - if (res) - continue; - - /* Process any queued callbacks before we go to sleep. */ - res = process_callback (); - - /* Did the callback want the event loop to stop? */ - if (res == -1) - return; - - if (res) - continue; - - /* Wait for a new event. If wait_for_event returns -1, we - should get out because this means that there are no event - sources left. This will make the event loop stop, and the - application exit. */ - - if (wait_for_event () < 0) - return; - } - - /* We are done with the event loop. There are no more event sources - to listen to. So we exit gdbserver. */ -} diff --git a/gdb/gdbserver/event-loop.h b/gdb/gdbserver/event-loop.h deleted file mode 100644 index a49173e867d..00000000000 --- a/gdb/gdbserver/event-loop.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Event loop machinery for the remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_EVENT_LOOP_H -#define GDBSERVER_EVENT_LOOP_H - -typedef void *gdb_client_data; -typedef int (handler_func) (int, gdb_client_data); -typedef int (callback_handler_func) (gdb_client_data); - -extern void delete_file_handler (gdb_fildes_t fd); -extern void add_file_handler (gdb_fildes_t fd, handler_func *proc, - gdb_client_data client_data); -extern int append_callback_event (callback_handler_func *proc, - gdb_client_data client_data); -extern void delete_callback_event (int id); - -extern void start_event_loop (void); -extern void initialize_event_loop (void); - -#endif /* GDBSERVER_EVENT_LOOP_H */ diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c deleted file mode 100644 index 7a71ec0b1ca..00000000000 --- a/gdb/gdbserver/fork-child.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Fork a Unix child process, and set up to debug it, for GDBserver. - Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "gdbsupport/job-control.h" -#include "nat/fork-inferior.h" -#ifdef HAVE_SIGNAL_H -#include -#endif - -#ifdef SIGTTOU -/* A file descriptor for the controlling terminal. */ -static int terminal_fd; - -/* TERMINAL_FD's original foreground group. */ -static pid_t old_foreground_pgrp; - -/* Hand back terminal ownership to the original foreground group. */ - -static void -restore_old_foreground_pgrp (void) -{ - tcsetpgrp (terminal_fd, old_foreground_pgrp); -} -#endif - -/* See nat/fork-inferior.h. */ - -void -prefork_hook (const char *args) -{ - client_state &cs = get_client_state (); - if (debug_threads) - { - debug_printf ("args: %s\n", args); - debug_flush (); - } - -#ifdef SIGTTOU - signal (SIGTTOU, SIG_DFL); - signal (SIGTTIN, SIG_DFL); -#endif - - /* Clear this so the backend doesn't get confused, thinking - CONT_THREAD died, and it needs to resume all threads. */ - cs.cont_thread = null_ptid; -} - -/* See nat/fork-inferior.h. */ - -void -postfork_hook (pid_t pid) -{ -} - -/* See nat/fork-inferior.h. */ - -void -postfork_child_hook () -{ - /* This is set to the result of setpgrp, which if vforked, will be - visible to you in the parent process. It's only used by humans - for debugging. */ - static int debug_setpgrp = 657473; - - debug_setpgrp = gdb_setpgid (); - if (debug_setpgrp == -1) - perror (_("setpgrp failed in child")); -} - -/* See nat/fork-inferior.h. */ - -void -gdb_flush_out_err () -{ - fflush (stdout); - fflush (stderr); -} - -/* See server.h. */ - -void -post_fork_inferior (int pid, const char *program) -{ - client_state &cs = get_client_state (); -#ifdef SIGTTOU - signal (SIGTTOU, SIG_IGN); - signal (SIGTTIN, SIG_IGN); - terminal_fd = fileno (stderr); - old_foreground_pgrp = tcgetpgrp (terminal_fd); - tcsetpgrp (terminal_fd, pid); - atexit (restore_old_foreground_pgrp); -#endif - - startup_inferior (the_target, pid, - START_INFERIOR_TRAPS_EXPECTED, - &cs.last_status, &cs.last_ptid); - current_thread->last_resume_kind = resume_stop; - current_thread->last_status = cs.last_status; - signal_pid = pid; - target_post_create_inferior (); - fprintf (stderr, "Process %s created; pid = %d\n", program, pid); - fflush (stderr); -} diff --git a/gdb/gdbserver/gdb_proc_service.h b/gdb/gdbserver/gdb_proc_service.h deleted file mode 100644 index bf657e76e49..00000000000 --- a/gdb/gdbserver/gdb_proc_service.h +++ /dev/null @@ -1,31 +0,0 @@ -/* replacement for systems that don't have it. - Copyright (C) 2000-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_GDB_PROC_SERVICE_H -#define GDBSERVER_GDB_PROC_SERVICE_H - -#include "gdbsupport/gdb_proc_service.h" - -/* Structure that identifies the target process. */ -struct ps_prochandle -{ - /* We don't need to track anything. All context is served from the - current inferior. */ -}; - -#endif /* GDBSERVER_GDB_PROC_SERVICE_H */ diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c deleted file mode 100644 index 263fb0efeac..00000000000 --- a/gdb/gdbserver/gdbreplay.c +++ /dev/null @@ -1,532 +0,0 @@ -/* Replay a remote debug session logfile for GDB. - Copyright (C) 1996-2020 Free Software Foundation, Inc. - Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver. - - 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 3 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, see . */ - -#include "gdbsupport/common-defs.h" - -#undef PACKAGE -#undef PACKAGE_NAME -#undef PACKAGE_VERSION -#undef PACKAGE_STRING -#undef PACKAGE_TARNAME - -#include -#include "gdbsupport/version.h" - -#if HAVE_SYS_FILE_H -#include -#endif -#if HAVE_SIGNAL_H -#include -#endif -#include -#if HAVE_FCNTL_H -#include -#endif -#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#if HAVE_NETDB_H -#include -#endif -#if HAVE_NETINET_TCP_H -#include -#endif - -#if USE_WIN32API -#include -#endif - -#include "gdbsupport/netstuff.h" -#include "gdbsupport/rsp-low.h" - -#ifndef HAVE_SOCKLEN_T -typedef int socklen_t; -#endif - -/* Sort of a hack... */ -#define EOL (EOF - 1) - -static int remote_desc; - -#ifdef __MINGW32CE__ - -#ifndef COUNTOF -#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0])) -#endif - -#define errno (GetLastError ()) - -char * -strerror (DWORD error) -{ - static char buf[1024]; - WCHAR *msgbuf; - DWORD lasterr = GetLastError (); - DWORD chars = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_ALLOCATE_BUFFER, - NULL, - error, - 0, /* Default language */ - (LPVOID)&msgbuf, - 0, - NULL); - if (chars != 0) - { - /* If there is an \r\n appended, zap it. */ - if (chars >= 2 - && msgbuf[chars - 2] == '\r' - && msgbuf[chars - 1] == '\n') - { - chars -= 2; - msgbuf[chars] = 0; - } - - if (chars > ((COUNTOF (buf)) - 1)) - { - chars = COUNTOF (buf) - 1; - msgbuf [chars] = 0; - } - - wcstombs (buf, msgbuf, chars + 1); - LocalFree (msgbuf); - } - else - sprintf (buf, "unknown win32 error (%ld)", error); - - SetLastError (lasterr); - return buf; -} - -#endif /* __MINGW32CE__ */ - -static void -sync_error (FILE *fp, const char *desc, int expect, int got) -{ - fprintf (stderr, "\n%s\n", desc); - fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n", - ftell (fp), expect, got); - fflush (stderr); - exit (1); -} - -static void -remote_error (const char *desc) -{ - fprintf (stderr, "\n%s\n", desc); - fflush (stderr); - exit (1); -} - -static void -remote_close (void) -{ -#ifdef USE_WIN32API - closesocket (remote_desc); -#else - close (remote_desc); -#endif -} - -/* Open a connection to a remote debugger. - NAME is the filename used for communication. */ - -static void -remote_open (char *name) -{ - char *last_colon = strrchr (name, ':'); - - if (last_colon == NULL) - { - fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name); - fflush (stderr); - exit (1); - } - -#ifdef USE_WIN32API - static int winsock_initialized; -#endif - int tmp; - int tmp_desc; - struct addrinfo hint; - struct addrinfo *ainfo; - - memset (&hint, 0, sizeof (hint)); - /* Assume no prefix will be passed, therefore we should use - AF_UNSPEC. */ - hint.ai_family = AF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - hint.ai_protocol = IPPROTO_TCP; - - parsed_connection_spec parsed = parse_connection_spec (name, &hint); - - if (parsed.port_str.empty ()) - error (_("Missing port on hostname '%s'"), name); - -#ifdef USE_WIN32API - if (!winsock_initialized) - { - WSADATA wsad; - - WSAStartup (MAKEWORD (1, 0), &wsad); - winsock_initialized = 1; - } -#endif - - int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (), - &hint, &ainfo); - - if (r != 0) - { - fprintf (stderr, "%s:%s: cannot resolve name: %s\n", - parsed.host_str.c_str (), parsed.port_str.c_str (), - gai_strerror (r)); - fflush (stderr); - exit (1); - } - - scoped_free_addrinfo free_ainfo (ainfo); - - struct addrinfo *p; - - for (p = ainfo; p != NULL; p = p->ai_next) - { - tmp_desc = socket (p->ai_family, p->ai_socktype, p->ai_protocol); - - if (tmp_desc >= 0) - break; - } - - if (p == NULL) - perror_with_name ("Cannot open socket"); - - /* Allow rapid reuse of this port. */ - tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, - sizeof (tmp)); - - switch (p->ai_family) - { - case AF_INET: - ((struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr = INADDR_ANY; - break; - case AF_INET6: - ((struct sockaddr_in6 *) p->ai_addr)->sin6_addr = in6addr_any; - break; - default: - fprintf (stderr, "Invalid 'ai_family' %d\n", p->ai_family); - exit (1); - } - - if (bind (tmp_desc, p->ai_addr, p->ai_addrlen) != 0) - perror_with_name ("Can't bind address"); - - if (p->ai_socktype == SOCK_DGRAM) - remote_desc = tmp_desc; - else - { - struct sockaddr_storage sockaddr; - socklen_t sockaddrsize = sizeof (sockaddr); - char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT]; - - if (listen (tmp_desc, 1) != 0) - perror_with_name ("Can't listen on socket"); - - remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, - &sockaddrsize); - - if (remote_desc == -1) - perror_with_name ("Accept failed"); - - /* Enable TCP keep alive process. */ - tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, - (char *) &tmp, sizeof (tmp)); - - /* Tell TCP not to delay small packets. This greatly speeds up - interactive response. */ - tmp = 1; - setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, - (char *) &tmp, sizeof (tmp)); - - if (getnameinfo ((struct sockaddr *) &sockaddr, sockaddrsize, - orig_host, sizeof (orig_host), - orig_port, sizeof (orig_port), - NI_NUMERICHOST | NI_NUMERICSERV) == 0) - { - fprintf (stderr, "Remote debugging from host %s, port %s\n", - orig_host, orig_port); - fflush (stderr); - } - -#ifndef USE_WIN32API - close (tmp_desc); /* No longer need this */ - - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then - gdbreplay simply exits when - the remote side dies. */ -#else - closesocket (tmp_desc); /* No longer need this */ -#endif - } - -#if defined(F_SETFL) && defined (FASYNC) - fcntl (remote_desc, F_SETFL, FASYNC); -#endif - - fprintf (stderr, "Replay logfile using %s\n", name); - fflush (stderr); -} - -static int -logchar (FILE *fp) -{ - int ch; - int ch2; - - ch = fgetc (fp); - if (ch != '\r') - { - fputc (ch, stdout); - fflush (stdout); - } - switch (ch) - { - /* Treat \r\n as a newline. */ - case '\r': - ch = fgetc (fp); - if (ch == '\n') - ch = EOL; - else - { - ungetc (ch, fp); - ch = '\r'; - } - fputc (ch == EOL ? '\n' : '\r', stdout); - fflush (stdout); - break; - case '\n': - ch = EOL; - break; - case '\\': - ch = fgetc (fp); - fputc (ch, stdout); - fflush (stdout); - switch (ch) - { - case '\\': - break; - case 'b': - ch = '\b'; - break; - case 'f': - ch = '\f'; - break; - case 'n': - ch = '\n'; - break; - case 'r': - ch = '\r'; - break; - case 't': - ch = '\t'; - break; - case 'v': - ch = '\v'; - break; - case 'x': - ch2 = fgetc (fp); - fputc (ch2, stdout); - fflush (stdout); - ch = fromhex (ch2) << 4; - ch2 = fgetc (fp); - fputc (ch2, stdout); - fflush (stdout); - ch |= fromhex (ch2); - break; - default: - /* Treat any other char as just itself */ - break; - } - default: - break; - } - return (ch); -} - -static int -gdbchar (int desc) -{ - unsigned char fromgdb; - - if (read (desc, &fromgdb, 1) != 1) - return -1; - else - return fromgdb; -} - -/* Accept input from gdb and match with chars from fp (after skipping one - blank) up until a \n is read from fp (which is not matched) */ - -static void -expect (FILE *fp) -{ - int fromlog; - int fromgdb; - - if ((fromlog = logchar (fp)) != ' ') - { - sync_error (fp, "Sync error during gdb read of leading blank", ' ', - fromlog); - } - do - { - fromlog = logchar (fp); - if (fromlog == EOL) - break; - fromgdb = gdbchar (remote_desc); - if (fromgdb < 0) - remote_error ("Error during read from gdb"); - } - while (fromlog == fromgdb); - - if (fromlog != EOL) - { - sync_error (fp, "Sync error during read of gdb packet from log", fromlog, - fromgdb); - } -} - -/* Play data back to gdb from fp (after skipping leading blank) up until a - \n is read from fp (which is discarded and not sent to gdb). */ - -static void -play (FILE *fp) -{ - int fromlog; - char ch; - - if ((fromlog = logchar (fp)) != ' ') - { - sync_error (fp, "Sync error skipping blank during write to gdb", ' ', - fromlog); - } - while ((fromlog = logchar (fp)) != EOL) - { - ch = fromlog; - if (write (remote_desc, &ch, 1) != 1) - remote_error ("Error during write to gdb"); - } -} - -static void -gdbreplay_version (void) -{ - printf ("GNU gdbreplay %s%s\n" - "Copyright (C) 2020 Free Software Foundation, Inc.\n" - "gdbreplay is free software, covered by " - "the GNU General Public License.\n" - "This gdbreplay was configured as \"%s\"\n", - PKGVERSION, version, host_name); -} - -static void -gdbreplay_usage (FILE *stream) -{ - fprintf (stream, "Usage:\tgdbreplay LOGFILE HOST:PORT\n"); - if (REPORT_BUGS_TO[0] && stream == stdout) - fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO); -} - -/* Main function. This is called by the real "main" function, - wrapped in a TRY_CATCH that handles any uncaught exceptions. */ - -static void ATTRIBUTE_NORETURN -captured_main (int argc, char *argv[]) -{ - FILE *fp; - int ch; - - if (argc >= 2 && strcmp (argv[1], "--version") == 0) - { - gdbreplay_version (); - exit (0); - } - if (argc >= 2 && strcmp (argv[1], "--help") == 0) - { - gdbreplay_usage (stdout); - exit (0); - } - - if (argc < 3) - { - gdbreplay_usage (stderr); - exit (1); - } - fp = fopen (argv[1], "r"); - if (fp == NULL) - { - perror_with_name (argv[1]); - } - remote_open (argv[2]); - while ((ch = logchar (fp)) != EOF) - { - switch (ch) - { - case 'w': - /* data sent from gdb to gdbreplay, accept and match it */ - expect (fp); - break; - case 'r': - /* data sent from gdbreplay to gdb, play it */ - play (fp); - break; - case 'c': - /* Command executed by gdb */ - while ((ch = logchar (fp)) != EOL); - break; - } - } - remote_close (); - exit (0); -} - -int -main (int argc, char *argv[]) -{ - try - { - captured_main (argc, argv); - } - catch (const gdb_exception &exception) - { - if (exception.reason == RETURN_ERROR) - { - fflush (stdout); - fprintf (stderr, "%s\n", exception.what ()); - } - - exit (1); - } - - gdb_assert_not_reached ("captured_main should never return"); -} diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h deleted file mode 100644 index 68762517c98..00000000000 --- a/gdb/gdbserver/gdbthread.h +++ /dev/null @@ -1,227 +0,0 @@ -/* Multi-thread control defs for remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_GDBTHREAD_H -#define GDBSERVER_GDBTHREAD_H - -#include "gdbsupport/common-gdbthread.h" -#include "inferiors.h" - -#include - -struct btrace_target_info; -struct regcache; - -struct thread_info -{ - /* The id of this thread. */ - ptid_t id; - - void *target_data; - struct regcache *regcache_data; - - /* The last resume GDB requested on this thread. */ - enum resume_kind last_resume_kind; - - /* The last wait status reported for this thread. */ - struct target_waitstatus last_status; - - /* True if LAST_STATUS hasn't been reported to GDB yet. */ - int status_pending_p; - - /* Given `while-stepping', a thread may be collecting data for more - than one tracepoint simultaneously. E.g.: - - ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs - ff0002 INSN2 - ff0003 INSN3 <-- TP2, collect $regs - ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs - ff0005 INSN5 - - Notice that when instruction INSN5 is reached, the while-stepping - actions of both TP1 and TP3 are still being collected, and that TP2 - had been collected meanwhile. The whole range of ff0001-ff0005 - should be single-stepped, due to at least TP1's while-stepping - action covering the whole range. - - On the other hand, the same tracepoint with a while-stepping action - may be hit by more than one thread simultaneously, hence we can't - keep the current step count in the tracepoint itself. - - This is the head of the list of the states of `while-stepping' - tracepoint actions this thread is now collecting; NULL if empty. - Each item in the list holds the current step of the while-stepping - action. */ - struct wstep_state *while_stepping; - - /* Branch trace target information for this thread. */ - struct btrace_target_info *btrace; -}; - -extern std::list all_threads; - -void remove_thread (struct thread_info *thread); -struct thread_info *add_thread (ptid_t ptid, void *target_data); - -/* Return a pointer to the first thread, or NULL if there isn't one. */ - -struct thread_info *get_first_thread (void); - -struct thread_info *find_thread_ptid (ptid_t ptid); - -/* Find any thread of the PID process. Returns NULL if none is - found. */ -struct thread_info *find_any_thread_of_pid (int pid); - -/* Find the first thread for which FUNC returns true. Return NULL if no thread - satisfying FUNC is found. */ - -template -static thread_info * -find_thread (Func func) -{ - std::list::iterator next, cur = all_threads.begin (); - - while (cur != all_threads.end ()) - { - next = cur; - next++; - - if (func (*cur)) - return *cur; - - cur = next; - } - - return NULL; -} - -/* Like the above, but only consider threads with pid PID. */ - -template -static thread_info * -find_thread (int pid, Func func) -{ - return find_thread ([&] (thread_info *thread) - { - return thread->id.pid () == pid && func (thread); - }); -} - -/* Find the first thread that matches FILTER for which FUNC returns true. - Return NULL if no thread satisfying these conditions is found. */ - -template -static thread_info * -find_thread (ptid_t filter, Func func) -{ - return find_thread ([&] (thread_info *thread) { - return thread->id.matches (filter) && func (thread); - }); -} - -/* Invoke FUNC for each thread. */ - -template -static void -for_each_thread (Func func) -{ - std::list::iterator next, cur = all_threads.begin (); - - while (cur != all_threads.end ()) - { - next = cur; - next++; - func (*cur); - cur = next; - } -} - -/* Like the above, but only consider threads with pid PID. */ - -template -static void -for_each_thread (int pid, Func func) -{ - for_each_thread ([&] (thread_info *thread) - { - if (pid == thread->id.pid ()) - func (thread); - }); -} - -/* Find the a random thread for which FUNC (THREAD) returns true. If - no entry is found then return NULL. */ - -template -static thread_info * -find_thread_in_random (Func func) -{ - int count = 0; - int random_selector; - - /* First count how many interesting entries we have. */ - for_each_thread ([&] (thread_info *thread) { - if (func (thread)) - count++; - }); - - if (count == 0) - return NULL; - - /* Now randomly pick an entry out of those. */ - random_selector = (int) - ((count * (double) rand ()) / (RAND_MAX + 1.0)); - - thread_info *thread = find_thread ([&] (thread_info *thr_arg) { - return func (thr_arg) && (random_selector-- == 0); - }); - - gdb_assert (thread != NULL); - - return thread; -} - -/* Get current thread ID (Linux task ID). */ -#define current_ptid (current_thread->id) - -/* Get the ptid of THREAD. */ - -static inline ptid_t -ptid_of (const thread_info *thread) -{ - return thread->id; -} - -/* Get the pid of THREAD. */ - -static inline int -pid_of (const thread_info *thread) -{ - return thread->id.pid (); -} - -/* Get the lwp of THREAD. */ - -static inline long -lwpid_of (const thread_info *thread) -{ - return thread->id.lwp (); -} - -#endif /* GDBSERVER_GDBTHREAD_H */ diff --git a/gdb/gdbserver/hostio-errno.c b/gdb/gdbserver/hostio-errno.c deleted file mode 100644 index b75e64d212e..00000000000 --- a/gdb/gdbserver/hostio-errno.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Host file transfer support for gdbserver. - Copyright (C) 2007-2020 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 3 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, see . */ - -/* This file implements the hostio_last_error target callback - on top of errno. */ - -#include "server.h" - -#include "hostio.h" - -#include "gdbsupport/fileio.h" - -void -hostio_last_error_from_errno (char *buf) -{ - int error = errno; - int fileio_error = host_to_fileio_error (error); - sprintf (buf, "F-1,%x", fileio_error); -} diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c deleted file mode 100644 index 8af4fbf4087..00000000000 --- a/gdb/gdbserver/hostio.c +++ /dev/null @@ -1,620 +0,0 @@ -/* Host file transfer support for gdbserver. - Copyright (C) 2007-2020 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 3 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, see . */ - -#include "server.h" -#include "gdb/fileio.h" -#include "hostio.h" - -#include -#include -#include -#include -#include -#include "gdbsupport/fileio.h" - -struct fd_list -{ - int fd; - struct fd_list *next; -}; - -static struct fd_list *open_fds; - -static int -safe_fromhex (char a, int *nibble) -{ - if (a >= '0' && a <= '9') - *nibble = a - '0'; - else if (a >= 'a' && a <= 'f') - *nibble = a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - *nibble = a - 'A' + 10; - else - return -1; - - return 0; -} - -/* Filenames are hex encoded, so the maximum we can handle is half the - packet buffer size. Cap to PATH_MAX, if it is shorter. */ -#if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1)) -# define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1) -#else -# define HOSTIO_PATH_MAX PATH_MAX -#endif - -static int -require_filename (char **pp, char *filename) -{ - int count; - char *p; - - p = *pp; - count = 0; - - while (*p && *p != ',') - { - int nib1, nib2; - - /* Don't allow overflow. */ - if (count >= HOSTIO_PATH_MAX - 1) - return -1; - - if (safe_fromhex (p[0], &nib1) - || safe_fromhex (p[1], &nib2)) - return -1; - - filename[count++] = nib1 * 16 + nib2; - p += 2; - } - - filename[count] = '\0'; - *pp = p; - return 0; -} - -static int -require_int (char **pp, int *value) -{ - char *p; - int count, firstdigit; - - p = *pp; - *value = 0; - count = 0; - firstdigit = -1; - - while (*p && *p != ',') - { - int nib; - - if (safe_fromhex (p[0], &nib)) - return -1; - - if (firstdigit == -1) - firstdigit = nib; - - /* Don't allow overflow. */ - if (count >= 8 || (count == 7 && firstdigit >= 0x8)) - return -1; - - *value = *value * 16 + nib; - p++; - count++; - } - - *pp = p; - return 0; -} - -static int -require_data (char *p, int p_len, char **data, int *data_len) -{ - int input_index, output_index, escaped; - - *data = (char *) xmalloc (p_len); - - output_index = 0; - escaped = 0; - for (input_index = 0; input_index < p_len; input_index++) - { - char b = p[input_index]; - - if (escaped) - { - (*data)[output_index++] = b ^ 0x20; - escaped = 0; - } - else if (b == '}') - escaped = 1; - else - (*data)[output_index++] = b; - } - - if (escaped) - { - free (*data); - return -1; - } - - *data_len = output_index; - return 0; -} - -static int -require_comma (char **pp) -{ - if (**pp == ',') - { - (*pp)++; - return 0; - } - else - return -1; -} - -static int -require_end (char *p) -{ - if (*p == '\0') - return 0; - else - return -1; -} - -static int -require_valid_fd (int fd) -{ - struct fd_list *fd_ptr; - - for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next) - if (fd_ptr->fd == fd) - return 0; - - return -1; -} - -/* Fill in own_buf with the last hostio error packet, however it - suitable for the target. */ -static void -hostio_error (char *own_buf) -{ - the_target->hostio_last_error (own_buf); -} - -static void -hostio_packet_error (char *own_buf) -{ - sprintf (own_buf, "F-1,%x", FILEIO_EINVAL); -} - -static void -hostio_reply (char *own_buf, int result) -{ - sprintf (own_buf, "F%x", result); -} - -static int -hostio_reply_with_data (char *own_buf, char *buffer, int len, - int *new_packet_len) -{ - int input_index, output_index, out_maxlen; - - sprintf (own_buf, "F%x;", len); - output_index = strlen (own_buf); - - out_maxlen = PBUFSIZ; - - for (input_index = 0; input_index < len; input_index++) - { - char b = buffer[input_index]; - - if (b == '$' || b == '#' || b == '}' || b == '*') - { - /* These must be escaped. */ - if (output_index + 2 > out_maxlen) - break; - own_buf[output_index++] = '}'; - own_buf[output_index++] = b ^ 0x20; - } - else - { - if (output_index + 1 > out_maxlen) - break; - own_buf[output_index++] = b; - } - } - - *new_packet_len = output_index; - return input_index; -} - -/* Process ID of inferior whose filesystem hostio functions - that take FILENAME arguments will use. Zero means to use - our own filesystem. */ - -static int hostio_fs_pid; - -/* See hostio.h. */ - -void -hostio_handle_new_gdb_connection (void) -{ - hostio_fs_pid = 0; -} - -/* Handle a "vFile:setfs:" packet. */ - -static void -handle_setfs (char *own_buf) -{ - char *p; - int pid; - - /* If the target doesn't have any of the in-filesystem-of methods - then there's no point in GDB sending "vFile:setfs:" packets. We - reply with an empty packet (i.e. we pretend we don't understand - "vFile:setfs:") and that should stop GDB sending any more. */ - if (the_target->multifs_open == NULL - && the_target->multifs_unlink == NULL - && the_target->multifs_readlink == NULL) - { - own_buf[0] = '\0'; - return; - } - - p = own_buf + strlen ("vFile:setfs:"); - - if (require_int (&p, &pid) - || pid < 0 - || require_end (p)) - { - hostio_packet_error (own_buf); - return; - } - - hostio_fs_pid = pid; - - hostio_reply (own_buf, 0); -} - -static void -handle_open (char *own_buf) -{ - char filename[HOSTIO_PATH_MAX]; - char *p; - int fileio_flags, fileio_mode, flags, fd; - mode_t mode; - struct fd_list *new_fd; - - p = own_buf + strlen ("vFile:open:"); - - if (require_filename (&p, filename) - || require_comma (&p) - || require_int (&p, &fileio_flags) - || require_comma (&p) - || require_int (&p, &fileio_mode) - || require_end (p) - || fileio_to_host_openflags (fileio_flags, &flags) - || fileio_to_host_mode (fileio_mode, &mode)) - { - hostio_packet_error (own_buf); - return; - } - - /* We do not need to convert MODE, since the fileio protocol - uses the standard values. */ - if (hostio_fs_pid != 0 && the_target->multifs_open != NULL) - fd = the_target->multifs_open (hostio_fs_pid, filename, - flags, mode); - else - fd = open (filename, flags, mode); - - if (fd == -1) - { - hostio_error (own_buf); - return; - } - - /* Record the new file descriptor. */ - new_fd = XNEW (struct fd_list); - new_fd->fd = fd; - new_fd->next = open_fds; - open_fds = new_fd; - - hostio_reply (own_buf, fd); -} - -static void -handle_pread (char *own_buf, int *new_packet_len) -{ - int fd, ret, len, offset, bytes_sent; - char *p, *data; - static int max_reply_size = -1; - - p = own_buf + strlen ("vFile:pread:"); - - if (require_int (&p, &fd) - || require_comma (&p) - || require_valid_fd (fd) - || require_int (&p, &len) - || require_comma (&p) - || require_int (&p, &offset) - || require_end (p)) - { - hostio_packet_error (own_buf); - return; - } - - /* Do not attempt to read more than the maximum number of bytes - hostio_reply_with_data can fit in a packet. We may still read - too much because of escaping, but this is handled below. */ - if (max_reply_size == -1) - { - sprintf (own_buf, "F%x;", PBUFSIZ); - max_reply_size = PBUFSIZ - strlen (own_buf); - } - if (len > max_reply_size) - len = max_reply_size; - - data = (char *) xmalloc (len); -#ifdef HAVE_PREAD - ret = pread (fd, data, len, offset); -#else - ret = -1; -#endif - /* If we have no pread or it failed for this file, use lseek/read. */ - if (ret == -1) - { - ret = lseek (fd, offset, SEEK_SET); - if (ret != -1) - ret = read (fd, data, len); - } - - if (ret == -1) - { - hostio_error (own_buf); - free (data); - return; - } - - bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len); - - /* If we were using read, and the data did not all fit in the reply, - we would have to back up using lseek here. With pread it does - not matter. But we still have a problem; the return value in the - packet might be wrong, so we must fix it. This time it will - definitely fit. */ - if (bytes_sent < ret) - bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent, - new_packet_len); - - free (data); -} - -static void -handle_pwrite (char *own_buf, int packet_len) -{ - int fd, ret, len, offset; - char *p, *data; - - p = own_buf + strlen ("vFile:pwrite:"); - - if (require_int (&p, &fd) - || require_comma (&p) - || require_valid_fd (fd) - || require_int (&p, &offset) - || require_comma (&p) - || require_data (p, packet_len - (p - own_buf), &data, &len)) - { - hostio_packet_error (own_buf); - return; - } - -#ifdef HAVE_PWRITE - ret = pwrite (fd, data, len, offset); -#else - ret = -1; -#endif - /* If we have no pwrite or it failed for this file, use lseek/write. */ - if (ret == -1) - { - ret = lseek (fd, offset, SEEK_SET); - if (ret != -1) - ret = write (fd, data, len); - } - - if (ret == -1) - { - hostio_error (own_buf); - free (data); - return; - } - - hostio_reply (own_buf, ret); - free (data); -} - -static void -handle_fstat (char *own_buf, int *new_packet_len) -{ - int fd, bytes_sent; - char *p; - struct stat st; - struct fio_stat fst; - - p = own_buf + strlen ("vFile:fstat:"); - - if (require_int (&p, &fd) - || require_valid_fd (fd) - || require_end (p)) - { - hostio_packet_error (own_buf); - return; - } - - if (fstat (fd, &st) == -1) - { - hostio_error (own_buf); - return; - } - - host_to_fileio_stat (&st, &fst); - - bytes_sent = hostio_reply_with_data (own_buf, - (char *) &fst, sizeof (fst), - new_packet_len); - - /* If the response does not fit into a single packet, do not attempt - to return a partial response, but simply fail. */ - if (bytes_sent < sizeof (fst)) - write_enn (own_buf); -} - -static void -handle_close (char *own_buf) -{ - int fd, ret; - char *p; - struct fd_list **open_fd_p, *old_fd; - - p = own_buf + strlen ("vFile:close:"); - - if (require_int (&p, &fd) - || require_valid_fd (fd) - || require_end (p)) - { - hostio_packet_error (own_buf); - return; - } - - ret = close (fd); - - if (ret == -1) - { - hostio_error (own_buf); - return; - } - - open_fd_p = &open_fds; - /* We know that fd is in the list, thanks to require_valid_fd. */ - while ((*open_fd_p)->fd != fd) - open_fd_p = &(*open_fd_p)->next; - - old_fd = *open_fd_p; - *open_fd_p = (*open_fd_p)->next; - free (old_fd); - - hostio_reply (own_buf, ret); -} - -static void -handle_unlink (char *own_buf) -{ - char filename[HOSTIO_PATH_MAX]; - char *p; - int ret; - - p = own_buf + strlen ("vFile:unlink:"); - - if (require_filename (&p, filename) - || require_end (p)) - { - hostio_packet_error (own_buf); - return; - } - - if (hostio_fs_pid != 0 && the_target->multifs_unlink != NULL) - ret = the_target->multifs_unlink (hostio_fs_pid, filename); - else - ret = unlink (filename); - - if (ret == -1) - { - hostio_error (own_buf); - return; - } - - hostio_reply (own_buf, ret); -} - -static void -handle_readlink (char *own_buf, int *new_packet_len) -{ - char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX]; - char *p; - int ret, bytes_sent; - - p = own_buf + strlen ("vFile:readlink:"); - - if (require_filename (&p, filename) - || require_end (p)) - { - hostio_packet_error (own_buf); - return; - } - - if (hostio_fs_pid != 0 && the_target->multifs_readlink != NULL) - ret = the_target->multifs_readlink (hostio_fs_pid, filename, - linkname, - sizeof (linkname) - 1); - else - ret = readlink (filename, linkname, sizeof (linkname) - 1); - - if (ret == -1) - { - hostio_error (own_buf); - return; - } - - bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len); - - /* If the response does not fit into a single packet, do not attempt - to return a partial response, but simply fail. */ - if (bytes_sent < ret) - sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG); -} - -/* Handle all the 'F' file transfer packets. */ - -int -handle_vFile (char *own_buf, int packet_len, int *new_packet_len) -{ - if (startswith (own_buf, "vFile:open:")) - handle_open (own_buf); - else if (startswith (own_buf, "vFile:pread:")) - handle_pread (own_buf, new_packet_len); - else if (startswith (own_buf, "vFile:pwrite:")) - handle_pwrite (own_buf, packet_len); - else if (startswith (own_buf, "vFile:fstat:")) - handle_fstat (own_buf, new_packet_len); - else if (startswith (own_buf, "vFile:close:")) - handle_close (own_buf); - else if (startswith (own_buf, "vFile:unlink:")) - handle_unlink (own_buf); - else if (startswith (own_buf, "vFile:readlink:")) - handle_readlink (own_buf, new_packet_len); - else if (startswith (own_buf, "vFile:setfs:")) - handle_setfs (own_buf); - else - return 0; - - return 1; -} diff --git a/gdb/gdbserver/hostio.h b/gdb/gdbserver/hostio.h deleted file mode 100644 index 4aca65c90d7..00000000000 --- a/gdb/gdbserver/hostio.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Host file transfer support for gdbserver. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_HOSTIO_H -#define GDBSERVER_HOSTIO_H - -/* Per-connection setup. */ -extern void hostio_handle_new_gdb_connection (void); - -/* Functions from hostio.c. */ -extern int handle_vFile (char *, int, int *); - -/* Functions from hostio-errno.c. */ -extern void hostio_last_error_from_errno (char *own_buf); - -#endif /* GDBSERVER_HOSTIO_H */ diff --git a/gdb/gdbserver/i387-fp.c b/gdb/gdbserver/i387-fp.c deleted file mode 100644 index ef7b51303f4..00000000000 --- a/gdb/gdbserver/i387-fp.c +++ /dev/null @@ -1,954 +0,0 @@ -/* i387-specific utility functions, for the remote server for GDB. - Copyright (C) 2000-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "i387-fp.h" -#include "gdbsupport/x86-xstate.h" - -static const int num_mpx_bnd_registers = 4; -static const int num_mpx_cfg_registers = 2; -static const int num_avx512_k_registers = 8; -static const int num_avx512_zmmh_low_registers = 16; -static const int num_avx512_zmmh_high_registers = 16; -static const int num_avx512_ymmh_registers = 16; -static const int num_avx512_xmm_registers = 16; -static const int num_pkeys_registers = 1; - -/* Note: These functions preserve the reserved bits in control registers. - However, gdbserver promptly throws away that information. */ - -/* These structs should have the proper sizes and alignment on both - i386 and x86-64 machines. */ - -struct i387_fsave { - /* All these are only sixteen bits, plus padding, except for fop (which - is only eleven bits), and fooff / fioff (which are 32 bits each). */ - unsigned short fctrl; - unsigned short pad1; - unsigned short fstat; - unsigned short pad2; - unsigned short ftag; - unsigned short pad3; - unsigned int fioff; - unsigned short fiseg; - unsigned short fop; - unsigned int fooff; - unsigned short foseg; - unsigned short pad4; - - /* Space for eight 80-bit FP values. */ - unsigned char st_space[80]; -}; - -struct i387_fxsave { - /* All these are only sixteen bits, plus padding, except for fop (which - is only eleven bits), and fooff / fioff (which are 32 bits each). */ - unsigned short fctrl; - unsigned short fstat; - unsigned short ftag; - unsigned short fop; - unsigned int fioff; - unsigned short fiseg; - unsigned short pad1; - unsigned int fooff; - unsigned short foseg; - unsigned short pad12; - - unsigned int mxcsr; - unsigned int pad3; - - /* Space for eight 80-bit FP values in 128-bit spaces. */ - unsigned char st_space[128]; - - /* Space for eight 128-bit XMM values, or 16 on x86-64. */ - unsigned char xmm_space[256]; -}; - -struct i387_xsave { - /* All these are only sixteen bits, plus padding, except for fop (which - is only eleven bits), and fooff / fioff (which are 32 bits each). */ - unsigned short fctrl; - unsigned short fstat; - unsigned short ftag; - unsigned short fop; - unsigned int fioff; - unsigned short fiseg; - unsigned short pad1; - unsigned int fooff; - unsigned short foseg; - unsigned short pad12; - - unsigned int mxcsr; - unsigned int mxcsr_mask; - - /* Space for eight 80-bit FP values in 128-bit spaces. */ - unsigned char st_space[128]; - - /* Space for eight 128-bit XMM values, or 16 on x86-64. */ - unsigned char xmm_space[256]; - - unsigned char reserved1[48]; - - /* The extended control register 0 (the XFEATURE_ENABLED_MASK - register). */ - unsigned long long xcr0; - - unsigned char reserved2[40]; - - /* The XSTATE_BV bit vector. */ - unsigned long long xstate_bv; - - unsigned char reserved3[56]; - - /* Space for eight upper 128-bit YMM values, or 16 on x86-64. */ - unsigned char ymmh_space[256]; - - unsigned char reserved4[128]; - - /* Space for 4 bound registers values of 128 bits. */ - unsigned char mpx_bnd_space[64]; - - /* Space for 2 MPX configuration registers of 64 bits - plus reserved space. */ - unsigned char mpx_cfg_space[16]; - - unsigned char reserved5[48]; - - /* Space for 8 OpMask register values of 64 bits. */ - unsigned char k_space[64]; - - /* Space for 16 256-bit zmm0-15. */ - unsigned char zmmh_low_space[512]; - - /* Space for 16 512-bit zmm16-31 values. */ - unsigned char zmmh_high_space[1024]; - - /* Space for 1 32-bit PKRU register. The HW XSTATE size for this feature is - actually 64 bits, but WRPKRU/RDPKRU instructions ignore upper 32 bits. */ - unsigned char pkru_space[8]; -}; - -void -i387_cache_to_fsave (struct regcache *regcache, void *buf) -{ - struct i387_fsave *fp = (struct i387_fsave *) buf; - int i; - int st0_regnum = find_regno (regcache->tdesc, "st0"); - unsigned long val2; - - for (i = 0; i < 8; i++) - collect_register (regcache, i + st0_regnum, - ((char *) &fp->st_space[0]) + i * 10); - - fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff"); - fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff"); - - /* This one's 11 bits... */ - val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); - fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); - - /* Some registers are 16-bit. */ - fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); - fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat"); - fp->ftag = regcache_raw_get_unsigned_by_name (regcache, "ftag"); - fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); - fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg"); -} - -void -i387_fsave_to_cache (struct regcache *regcache, const void *buf) -{ - struct i387_fsave *fp = (struct i387_fsave *) buf; - int i; - int st0_regnum = find_regno (regcache->tdesc, "st0"); - unsigned long val; - - for (i = 0; i < 8; i++) - supply_register (regcache, i + st0_regnum, - ((char *) &fp->st_space[0]) + i * 10); - - supply_register_by_name (regcache, "fioff", &fp->fioff); - supply_register_by_name (regcache, "fooff", &fp->fooff); - - /* Some registers are 16-bit. */ - val = fp->fctrl & 0xFFFF; - supply_register_by_name (regcache, "fctrl", &val); - - val = fp->fstat & 0xFFFF; - supply_register_by_name (regcache, "fstat", &val); - - val = fp->ftag & 0xFFFF; - supply_register_by_name (regcache, "ftag", &val); - - val = fp->fiseg & 0xFFFF; - supply_register_by_name (regcache, "fiseg", &val); - - val = fp->foseg & 0xFFFF; - supply_register_by_name (regcache, "foseg", &val); - - /* fop has only 11 valid bits. */ - val = (fp->fop) & 0x7FF; - supply_register_by_name (regcache, "fop", &val); -} - -void -i387_cache_to_fxsave (struct regcache *regcache, void *buf) -{ - struct i387_fxsave *fp = (struct i387_fxsave *) buf; - int i; - int st0_regnum = find_regno (regcache->tdesc, "st0"); - int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); - unsigned long val, val2; - /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ - int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; - - for (i = 0; i < 8; i++) - collect_register (regcache, i + st0_regnum, - ((char *) &fp->st_space[0]) + i * 16); - for (i = 0; i < num_xmm_registers; i++) - collect_register (regcache, i + xmm0_regnum, - ((char *) &fp->xmm_space[0]) + i * 16); - - fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff"); - fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff"); - fp->mxcsr = regcache_raw_get_unsigned_by_name (regcache, "mxcsr"); - - /* This one's 11 bits... */ - val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); - fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); - - /* Some registers are 16-bit. */ - fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); - fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat"); - - /* Convert to the simplifed tag form stored in fxsave data. */ - val = regcache_raw_get_unsigned_by_name (regcache, "ftag"); - val2 = 0; - for (i = 7; i >= 0; i--) - { - int tag = (val >> (i * 2)) & 3; - - if (tag != 3) - val2 |= (1 << i); - } - fp->ftag = val2; - - fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); - fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg"); -} - -void -i387_cache_to_xsave (struct regcache *regcache, void *buf) -{ - struct i387_xsave *fp = (struct i387_xsave *) buf; - int i; - unsigned long val, val2; - unsigned long long xstate_bv = 0; - unsigned long long clear_bv = 0; - char raw[64]; - char *p; - /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ - int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; - - /* The supported bits in `xstat_bv' are 8 bytes. Clear part in - vector registers if its bit in xstat_bv is zero. */ - clear_bv = (~fp->xstate_bv) & x86_xcr0; - - /* Clear part in x87 and vector registers if its bit in xstat_bv is - zero. */ - if (clear_bv) - { - if ((clear_bv & X86_XSTATE_X87)) - { - for (i = 0; i < 8; i++) - memset (((char *) &fp->st_space[0]) + i * 16, 0, 10); - - fp->fioff = 0; - fp->fooff = 0; - fp->fctrl = I387_FCTRL_INIT_VAL; - fp->fstat = 0; - fp->ftag = 0; - fp->fiseg = 0; - fp->foseg = 0; - fp->fop = 0; - } - - if ((clear_bv & X86_XSTATE_SSE)) - for (i = 0; i < num_xmm_registers; i++) - memset (((char *) &fp->xmm_space[0]) + i * 16, 0, 16); - - if ((clear_bv & X86_XSTATE_AVX)) - for (i = 0; i < num_xmm_registers; i++) - memset (((char *) &fp->ymmh_space[0]) + i * 16, 0, 16); - - if ((clear_bv & X86_XSTATE_SSE) && (clear_bv & X86_XSTATE_AVX)) - memset (((char *) &fp->mxcsr), 0, 4); - - if ((clear_bv & X86_XSTATE_BNDREGS)) - for (i = 0; i < num_mpx_bnd_registers; i++) - memset (((char *) &fp->mpx_bnd_space[0]) + i * 16, 0, 16); - - if ((clear_bv & X86_XSTATE_BNDCFG)) - for (i = 0; i < num_mpx_cfg_registers; i++) - memset (((char *) &fp->mpx_cfg_space[0]) + i * 8, 0, 8); - - if ((clear_bv & X86_XSTATE_K)) - for (i = 0; i < num_avx512_k_registers; i++) - memset (((char *) &fp->k_space[0]) + i * 8, 0, 8); - - if ((clear_bv & X86_XSTATE_ZMM_H)) - for (i = 0; i < num_avx512_zmmh_low_registers; i++) - memset (((char *) &fp->zmmh_low_space[0]) + i * 32, 0, 32); - - if ((clear_bv & X86_XSTATE_ZMM)) - { - for (i = 0; i < num_avx512_zmmh_high_registers; i++) - memset (((char *) &fp->zmmh_low_space[0]) + 32 + i * 64, 0, 32); - for (i = 0; i < num_avx512_xmm_registers; i++) - memset (((char *) &fp->zmmh_high_space[0]) + i * 64, 0, 16); - for (i = 0; i < num_avx512_ymmh_registers; i++) - memset (((char *) &fp->zmmh_high_space[0]) + 16 + i * 64, 0, 16); - } - - if ((clear_bv & X86_XSTATE_PKRU)) - for (i = 0; i < num_pkeys_registers; i++) - memset (((char *) &fp->pkru_space[0]) + i * 4, 0, 4); - } - - /* Check if any x87 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_X87)) - { - int st0_regnum = find_regno (regcache->tdesc, "st0"); - - for (i = 0; i < 8; i++) - { - collect_register (regcache, i + st0_regnum, raw); - p = ((char *) &fp->st_space[0]) + i * 16; - if (memcmp (raw, p, 10)) - { - xstate_bv |= X86_XSTATE_X87; - memcpy (p, raw, 10); - } - } - } - - /* Check if any SSE registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_SSE)) - { - int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); - - for (i = 0; i < num_xmm_registers; i++) - { - collect_register (regcache, i + xmm0_regnum, raw); - p = ((char *) &fp->xmm_space[0]) + i * 16; - if (memcmp (raw, p, 16)) - { - xstate_bv |= X86_XSTATE_SSE; - memcpy (p, raw, 16); - } - } - } - - /* Check if any AVX registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_AVX)) - { - int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); - - for (i = 0; i < num_xmm_registers; i++) - { - collect_register (regcache, i + ymm0h_regnum, raw); - p = ((char *) &fp->ymmh_space[0]) + i * 16; - if (memcmp (raw, p, 16)) - { - xstate_bv |= X86_XSTATE_AVX; - memcpy (p, raw, 16); - } - } - } - - /* Check if any bound register has changed. */ - if ((x86_xcr0 & X86_XSTATE_BNDREGS)) - { - int bnd0r_regnum = find_regno (regcache->tdesc, "bnd0raw"); - - for (i = 0; i < num_mpx_bnd_registers; i++) - { - collect_register (regcache, i + bnd0r_regnum, raw); - p = ((char *) &fp->mpx_bnd_space[0]) + i * 16; - if (memcmp (raw, p, 16)) - { - xstate_bv |= X86_XSTATE_BNDREGS; - memcpy (p, raw, 16); - } - } - } - - /* Check if any status register has changed. */ - if ((x86_xcr0 & X86_XSTATE_BNDCFG)) - { - int bndcfg_regnum = find_regno (regcache->tdesc, "bndcfgu"); - - for (i = 0; i < num_mpx_cfg_registers; i++) - { - collect_register (regcache, i + bndcfg_regnum, raw); - p = ((char *) &fp->mpx_cfg_space[0]) + i * 8; - if (memcmp (raw, p, 8)) - { - xstate_bv |= X86_XSTATE_BNDCFG; - memcpy (p, raw, 8); - } - } - } - - /* Check if any K registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_K)) - { - int k0_regnum = find_regno (regcache->tdesc, "k0"); - - for (i = 0; i < num_avx512_k_registers; i++) - { - collect_register (regcache, i + k0_regnum, raw); - p = ((char *) &fp->k_space[0]) + i * 8; - if (memcmp (raw, p, 8) != 0) - { - xstate_bv |= X86_XSTATE_K; - memcpy (p, raw, 8); - } - } - } - - /* Check if any of ZMM0H-ZMM15H registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_ZMM_H)) - { - int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); - - for (i = 0; i < num_avx512_zmmh_low_registers; i++) - { - collect_register (regcache, i + zmm0h_regnum, raw); - p = ((char *) &fp->zmmh_low_space[0]) + i * 32; - if (memcmp (raw, p, 32) != 0) - { - xstate_bv |= X86_XSTATE_ZMM_H; - memcpy (p, raw, 32); - } - } - } - - /* Check if any of ZMM16H-ZMM31H registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_ZMM)) - { - int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); - - for (i = 0; i < num_avx512_zmmh_high_registers; i++) - { - collect_register (regcache, i + zmm16h_regnum, raw); - p = ((char *) &fp->zmmh_high_space[0]) + 32 + i * 64; - if (memcmp (raw, p, 32) != 0) - { - xstate_bv |= X86_XSTATE_ZMM; - memcpy (p, raw, 32); - } - } - } - - /* Check if any XMM_AVX512 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_ZMM)) - { - int xmm_avx512_regnum = find_regno (regcache->tdesc, "xmm16"); - - for (i = 0; i < num_avx512_xmm_registers; i++) - { - collect_register (regcache, i + xmm_avx512_regnum, raw); - p = ((char *) &fp->zmmh_high_space[0]) + i * 64; - if (memcmp (raw, p, 16) != 0) - { - xstate_bv |= X86_XSTATE_ZMM; - memcpy (p, raw, 16); - } - } - } - - /* Check if any YMMH_AVX512 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_ZMM)) - { - int ymmh_avx512_regnum = find_regno (regcache->tdesc, "ymm16h"); - - for (i = 0; i < num_avx512_ymmh_registers; i++) - { - collect_register (regcache, i + ymmh_avx512_regnum, raw); - p = ((char *) &fp->zmmh_high_space[0]) + 16 + i * 64; - if (memcmp (raw, p, 16) != 0) - { - xstate_bv |= X86_XSTATE_ZMM; - memcpy (p, raw, 16); - } - } - } - - /* Check if any PKEYS registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_PKRU)) - { - int pkru_regnum = find_regno (regcache->tdesc, "pkru"); - - for (i = 0; i < num_pkeys_registers; i++) - { - collect_register (regcache, i + pkru_regnum, raw); - p = ((char *) &fp->pkru_space[0]) + i * 4; - if (memcmp (raw, p, 4) != 0) - { - xstate_bv |= X86_XSTATE_PKRU; - memcpy (p, raw, 4); - } - } - } - - if ((x86_xcr0 & X86_XSTATE_SSE) || (x86_xcr0 & X86_XSTATE_AVX)) - { - collect_register_by_name (regcache, "mxcsr", raw); - if (memcmp (raw, &fp->mxcsr, 4) != 0) - { - if (((fp->xstate_bv | xstate_bv) - & (X86_XSTATE_SSE | X86_XSTATE_AVX)) == 0) - xstate_bv |= X86_XSTATE_SSE; - memcpy (&fp->mxcsr, raw, 4); - } - } - - if (x86_xcr0 & X86_XSTATE_X87) - { - collect_register_by_name (regcache, "fioff", raw); - if (memcmp (raw, &fp->fioff, 4) != 0) - { - xstate_bv |= X86_XSTATE_X87; - memcpy (&fp->fioff, raw, 4); - } - - collect_register_by_name (regcache, "fooff", raw); - if (memcmp (raw, &fp->fooff, 4) != 0) - { - xstate_bv |= X86_XSTATE_X87; - memcpy (&fp->fooff, raw, 4); - } - - /* This one's 11 bits... */ - val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); - val2 = (val2 & 0x7FF) | (fp->fop & 0xF800); - if (fp->fop != val2) - { - xstate_bv |= X86_XSTATE_X87; - fp->fop = val2; - } - - /* Some registers are 16-bit. */ - val = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); - if (fp->fctrl != val) - { - xstate_bv |= X86_XSTATE_X87; - fp->fctrl = val; - } - - val = regcache_raw_get_unsigned_by_name (regcache, "fstat"); - if (fp->fstat != val) - { - xstate_bv |= X86_XSTATE_X87; - fp->fstat = val; - } - - /* Convert to the simplifed tag form stored in fxsave data. */ - val = regcache_raw_get_unsigned_by_name (regcache, "ftag"); - val2 = 0; - for (i = 7; i >= 0; i--) - { - int tag = (val >> (i * 2)) & 3; - - if (tag != 3) - val2 |= (1 << i); - } - if (fp->ftag != val2) - { - xstate_bv |= X86_XSTATE_X87; - fp->ftag = val2; - } - - val = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); - if (fp->fiseg != val) - { - xstate_bv |= X86_XSTATE_X87; - fp->fiseg = val; - } - - val = regcache_raw_get_unsigned_by_name (regcache, "foseg"); - if (fp->foseg != val) - { - xstate_bv |= X86_XSTATE_X87; - fp->foseg = val; - } - } - - /* Update the corresponding bits in xstate_bv if any SSE/AVX - registers are changed. */ - fp->xstate_bv |= xstate_bv; -} - -static int -i387_ftag (struct i387_fxsave *fp, int regno) -{ - unsigned char *raw = &fp->st_space[regno * 16]; - unsigned int exponent; - unsigned long fraction[2]; - int integer; - - integer = raw[7] & 0x80; - exponent = (((raw[9] & 0x7f) << 8) | raw[8]); - fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); - fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) - | (raw[5] << 8) | raw[4]); - - if (exponent == 0x7fff) - { - /* Special. */ - return (2); - } - else if (exponent == 0x0000) - { - if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) - { - /* Zero. */ - return (1); - } - else - { - /* Special. */ - return (2); - } - } - else - { - if (integer) - { - /* Valid. */ - return (0); - } - else - { - /* Special. */ - return (2); - } - } -} - -void -i387_fxsave_to_cache (struct regcache *regcache, const void *buf) -{ - struct i387_fxsave *fp = (struct i387_fxsave *) buf; - int i, top; - int st0_regnum = find_regno (regcache->tdesc, "st0"); - int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); - unsigned long val; - /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ - int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; - - for (i = 0; i < 8; i++) - supply_register (regcache, i + st0_regnum, - ((char *) &fp->st_space[0]) + i * 16); - for (i = 0; i < num_xmm_registers; i++) - supply_register (regcache, i + xmm0_regnum, - ((char *) &fp->xmm_space[0]) + i * 16); - - supply_register_by_name (regcache, "fioff", &fp->fioff); - supply_register_by_name (regcache, "fooff", &fp->fooff); - supply_register_by_name (regcache, "mxcsr", &fp->mxcsr); - - /* Some registers are 16-bit. */ - val = fp->fctrl & 0xFFFF; - supply_register_by_name (regcache, "fctrl", &val); - - val = fp->fstat & 0xFFFF; - supply_register_by_name (regcache, "fstat", &val); - - /* Generate the form of ftag data that GDB expects. */ - top = (fp->fstat >> 11) & 0x7; - val = 0; - for (i = 7; i >= 0; i--) - { - int tag; - if (fp->ftag & (1 << i)) - tag = i387_ftag (fp, (i + 8 - top) % 8); - else - tag = 3; - val |= tag << (2 * i); - } - supply_register_by_name (regcache, "ftag", &val); - - val = fp->fiseg & 0xFFFF; - supply_register_by_name (regcache, "fiseg", &val); - - val = fp->foseg & 0xFFFF; - supply_register_by_name (regcache, "foseg", &val); - - val = (fp->fop) & 0x7FF; - supply_register_by_name (regcache, "fop", &val); -} - -void -i387_xsave_to_cache (struct regcache *regcache, const void *buf) -{ - struct i387_xsave *fp = (struct i387_xsave *) buf; - struct i387_fxsave *fxp = (struct i387_fxsave *) buf; - int i, top; - unsigned long val; - unsigned long long clear_bv; - gdb_byte *p; - /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ - int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; - - /* The supported bits in `xstat_bv' are 8 bytes. Clear part in - vector registers if its bit in xstat_bv is zero. */ - clear_bv = (~fp->xstate_bv) & x86_xcr0; - - /* Check if any x87 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_X87) != 0) - { - int st0_regnum = find_regno (regcache->tdesc, "st0"); - - if ((clear_bv & X86_XSTATE_X87) != 0) - { - for (i = 0; i < 8; i++) - supply_register_zeroed (regcache, i + st0_regnum); - } - else - { - p = (gdb_byte *) &fp->st_space[0]; - for (i = 0; i < 8; i++) - supply_register (regcache, i + st0_regnum, p + i * 16); - } - } - - if ((x86_xcr0 & X86_XSTATE_SSE) != 0) - { - int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); - - if ((clear_bv & X86_XSTATE_SSE)) - { - for (i = 0; i < num_xmm_registers; i++) - supply_register_zeroed (regcache, i + xmm0_regnum); - } - else - { - p = (gdb_byte *) &fp->xmm_space[0]; - for (i = 0; i < num_xmm_registers; i++) - supply_register (regcache, i + xmm0_regnum, p + i * 16); - } - } - - if ((x86_xcr0 & X86_XSTATE_AVX) != 0) - { - int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); - - if ((clear_bv & X86_XSTATE_AVX) != 0) - { - for (i = 0; i < num_xmm_registers; i++) - supply_register_zeroed (regcache, i + ymm0h_regnum); - } - else - { - p = (gdb_byte *) &fp->ymmh_space[0]; - for (i = 0; i < num_xmm_registers; i++) - supply_register (regcache, i + ymm0h_regnum, p + i * 16); - } - } - - if ((x86_xcr0 & X86_XSTATE_BNDREGS)) - { - int bnd0r_regnum = find_regno (regcache->tdesc, "bnd0raw"); - - - if ((clear_bv & X86_XSTATE_BNDREGS) != 0) - { - for (i = 0; i < num_mpx_bnd_registers; i++) - supply_register_zeroed (regcache, i + bnd0r_regnum); - } - else - { - p = (gdb_byte *) &fp->mpx_bnd_space[0]; - for (i = 0; i < num_mpx_bnd_registers; i++) - supply_register (regcache, i + bnd0r_regnum, p + i * 16); - } - - } - - if ((x86_xcr0 & X86_XSTATE_BNDCFG)) - { - int bndcfg_regnum = find_regno (regcache->tdesc, "bndcfgu"); - - if ((clear_bv & X86_XSTATE_BNDCFG) != 0) - { - for (i = 0; i < num_mpx_cfg_registers; i++) - supply_register_zeroed (regcache, i + bndcfg_regnum); - } - else - { - p = (gdb_byte *) &fp->mpx_cfg_space[0]; - for (i = 0; i < num_mpx_cfg_registers; i++) - supply_register (regcache, i + bndcfg_regnum, p + i * 8); - } - } - - if ((x86_xcr0 & X86_XSTATE_K) != 0) - { - int k0_regnum = find_regno (regcache->tdesc, "k0"); - - if ((clear_bv & X86_XSTATE_K) != 0) - { - for (i = 0; i < num_avx512_k_registers; i++) - supply_register_zeroed (regcache, i + k0_regnum); - } - else - { - p = (gdb_byte *) &fp->k_space[0]; - for (i = 0; i < num_avx512_k_registers; i++) - supply_register (regcache, i + k0_regnum, p + i * 8); - } - } - - if ((x86_xcr0 & X86_XSTATE_ZMM_H) != 0) - { - int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); - - if ((clear_bv & X86_XSTATE_ZMM_H) != 0) - { - for (i = 0; i < num_avx512_zmmh_low_registers; i++) - supply_register_zeroed (regcache, i + zmm0h_regnum); - } - else - { - p = (gdb_byte *) &fp->zmmh_low_space[0]; - for (i = 0; i < num_avx512_zmmh_low_registers; i++) - supply_register (regcache, i + zmm0h_regnum, p + i * 32); - } - } - - if ((x86_xcr0 & X86_XSTATE_ZMM) != 0) - { - int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); - int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h"); - int xmm16_regnum = find_regno (regcache->tdesc, "xmm16"); - - if ((clear_bv & X86_XSTATE_ZMM) != 0) - { - for (i = 0; i < num_avx512_zmmh_high_registers; i++) - supply_register_zeroed (regcache, i + zmm16h_regnum); - for (i = 0; i < num_avx512_ymmh_registers; i++) - supply_register_zeroed (regcache, i + ymm16h_regnum); - for (i = 0; i < num_avx512_xmm_registers; i++) - supply_register_zeroed (regcache, i + xmm16_regnum); - } - else - { - p = (gdb_byte *) &fp->zmmh_high_space[0]; - for (i = 0; i < num_avx512_zmmh_high_registers; i++) - supply_register (regcache, i + zmm16h_regnum, p + 32 + i * 64); - for (i = 0; i < num_avx512_ymmh_registers; i++) - supply_register (regcache, i + ymm16h_regnum, p + 16 + i * 64); - for (i = 0; i < num_avx512_xmm_registers; i++) - supply_register (regcache, i + xmm16_regnum, p + i * 64); - } - } - - if ((x86_xcr0 & X86_XSTATE_PKRU) != 0) - { - int pkru_regnum = find_regno (regcache->tdesc, "pkru"); - - if ((clear_bv & X86_XSTATE_PKRU) != 0) - { - for (i = 0; i < num_pkeys_registers; i++) - supply_register_zeroed (regcache, i + pkru_regnum); - } - else - { - p = (gdb_byte *) &fp->pkru_space[0]; - for (i = 0; i < num_pkeys_registers; i++) - supply_register (regcache, i + pkru_regnum, p + i * 4); - } - } - - if ((clear_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX)) - == (X86_XSTATE_SSE | X86_XSTATE_AVX)) - { - unsigned int default_mxcsr = I387_MXCSR_INIT_VAL; - supply_register_by_name (regcache, "mxcsr", &default_mxcsr); - } - else - supply_register_by_name (regcache, "mxcsr", &fp->mxcsr); - - if ((clear_bv & X86_XSTATE_X87) != 0) - { - supply_register_by_name_zeroed (regcache, "fioff"); - supply_register_by_name_zeroed (regcache, "fooff"); - - val = I387_FCTRL_INIT_VAL; - supply_register_by_name (regcache, "fctrl", &val); - - supply_register_by_name_zeroed (regcache, "fstat"); - - val = 0xFFFF; - supply_register_by_name (regcache, "ftag", &val); - - supply_register_by_name_zeroed (regcache, "fiseg"); - supply_register_by_name_zeroed (regcache, "foseg"); - supply_register_by_name_zeroed (regcache, "fop"); - } - else - { - supply_register_by_name (regcache, "fioff", &fp->fioff); - supply_register_by_name (regcache, "fooff", &fp->fooff); - - /* Some registers are 16-bit. */ - val = fp->fctrl & 0xFFFF; - supply_register_by_name (regcache, "fctrl", &val); - - val = fp->fstat & 0xFFFF; - supply_register_by_name (regcache, "fstat", &val); - - /* Generate the form of ftag data that GDB expects. */ - top = (fp->fstat >> 11) & 0x7; - val = 0; - for (i = 7; i >= 0; i--) - { - int tag; - if (fp->ftag & (1 << i)) - tag = i387_ftag (fxp, (i + 8 - top) % 8); - else - tag = 3; - val |= tag << (2 * i); - } - supply_register_by_name (regcache, "ftag", &val); - - val = fp->fiseg & 0xFFFF; - supply_register_by_name (regcache, "fiseg", &val); - - val = fp->foseg & 0xFFFF; - supply_register_by_name (regcache, "foseg", &val); - - val = (fp->fop) & 0x7FF; - supply_register_by_name (regcache, "fop", &val); - } -} - -/* Default to SSE. */ -unsigned long long x86_xcr0 = X86_XSTATE_SSE_MASK; diff --git a/gdb/gdbserver/i387-fp.h b/gdb/gdbserver/i387-fp.h deleted file mode 100644 index e4e03e7f227..00000000000 --- a/gdb/gdbserver/i387-fp.h +++ /dev/null @@ -1,33 +0,0 @@ -/* i387-specific utility functions, for the remote server for GDB. - Copyright (C) 2000-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_I387_FP_H -#define GDBSERVER_I387_FP_H - -void i387_cache_to_fsave (struct regcache *regcache, void *buf); -void i387_fsave_to_cache (struct regcache *regcache, const void *buf); - -void i387_cache_to_fxsave (struct regcache *regcache, void *buf); -void i387_fxsave_to_cache (struct regcache *regcache, const void *buf); - -void i387_cache_to_xsave (struct regcache *regcache, void *buf); -void i387_xsave_to_cache (struct regcache *regcache, const void *buf); - -extern unsigned long long x86_xcr0; - -#endif /* GDBSERVER_I387_FP_H */ diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c deleted file mode 100644 index 88adb16eac2..00000000000 --- a/gdb/gdbserver/inferiors.c +++ /dev/null @@ -1,244 +0,0 @@ -/* Inferior process information for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#include "server.h" -#include "gdbsupport/common-inferior.h" -#include "gdbthread.h" -#include "dll.h" - -std::list all_processes; -std::list all_threads; - -struct thread_info *current_thread; - -/* The current working directory used to start the inferior. */ -static const char *current_inferior_cwd = NULL; - -struct thread_info * -add_thread (ptid_t thread_id, void *target_data) -{ - struct thread_info *new_thread = XCNEW (struct thread_info); - - new_thread->id = thread_id; - new_thread->last_resume_kind = resume_continue; - new_thread->last_status.kind = TARGET_WAITKIND_IGNORE; - - all_threads.push_back (new_thread); - - if (current_thread == NULL) - current_thread = new_thread; - - new_thread->target_data = target_data; - - return new_thread; -} - -/* See gdbthread.h. */ - -struct thread_info * -get_first_thread (void) -{ - if (!all_threads.empty ()) - return all_threads.front (); - else - return NULL; -} - -struct thread_info * -find_thread_ptid (ptid_t ptid) -{ - return find_thread ([&] (thread_info *thread) { - return thread->id == ptid; - }); -} - -/* Find a thread associated with the given PROCESS, or NULL if no - such thread exists. */ - -static struct thread_info * -find_thread_process (const struct process_info *const process) -{ - return find_any_thread_of_pid (process->pid); -} - -/* See gdbthread.h. */ - -struct thread_info * -find_any_thread_of_pid (int pid) -{ - return find_thread (pid, [] (thread_info *thread) { - return true; - }); -} - -static void -free_one_thread (thread_info *thread) -{ - free_register_cache (thread_regcache_data (thread)); - free (thread); -} - -void -remove_thread (struct thread_info *thread) -{ - if (thread->btrace != NULL) - target_disable_btrace (thread->btrace); - - discard_queued_stop_replies (ptid_of (thread)); - all_threads.remove (thread); - free_one_thread (thread); - if (current_thread == thread) - current_thread = NULL; -} - -void * -thread_target_data (struct thread_info *thread) -{ - return thread->target_data; -} - -struct regcache * -thread_regcache_data (struct thread_info *thread) -{ - return thread->regcache_data; -} - -void -set_thread_regcache_data (struct thread_info *thread, struct regcache *data) -{ - thread->regcache_data = data; -} - -void -clear_inferiors (void) -{ - for_each_thread (free_one_thread); - all_threads.clear (); - - clear_dlls (); - - current_thread = NULL; -} - -struct process_info * -add_process (int pid, int attached) -{ - process_info *process = new process_info (pid, attached); - - all_processes.push_back (process); - - return process; -} - -/* Remove a process from the common process list and free the memory - allocated for it. - The caller is responsible for freeing private data first. */ - -void -remove_process (struct process_info *process) -{ - clear_symbol_cache (&process->symbol_cache); - free_all_breakpoints (process); - gdb_assert (find_thread_process (process) == NULL); - all_processes.remove (process); - delete process; -} - -process_info * -find_process_pid (int pid) -{ - return find_process ([&] (process_info *process) { - return process->pid == pid; - }); -} - -/* Get the first process in the process list, or NULL if the list is empty. */ - -process_info * -get_first_process (void) -{ - if (!all_processes.empty ()) - return all_processes.front (); - else - return NULL; -} - -/* Return non-zero if there are any inferiors that we have created - (as opposed to attached-to). */ - -int -have_started_inferiors_p (void) -{ - return find_process ([] (process_info *process) { - return !process->attached; - }) != NULL; -} - -/* Return non-zero if there are any inferiors that we have attached to. */ - -int -have_attached_inferiors_p (void) -{ - return find_process ([] (process_info *process) { - return process->attached; - }) != NULL; -} - -struct process_info * -get_thread_process (const struct thread_info *thread) -{ - return find_process_pid (thread->id.pid ()); -} - -struct process_info * -current_process (void) -{ - gdb_assert (current_thread != NULL); - return get_thread_process (current_thread); -} - -/* See gdbsupport/common-gdbthread.h. */ - -void -switch_to_thread (process_stratum_target *ops, ptid_t ptid) -{ - gdb_assert (ptid != minus_one_ptid); - current_thread = find_thread_ptid (ptid); -} - -/* See gdbsupport/common-inferior.h. */ - -const char * -get_inferior_cwd () -{ - return current_inferior_cwd; -} - -/* See gdbsupport/common-inferior.h. */ - -void -set_inferior_cwd (const char *cwd) -{ - xfree ((void *) current_inferior_cwd); - if (cwd != NULL) - current_inferior_cwd = xstrdup (cwd); - else - current_inferior_cwd = NULL; -} diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h deleted file mode 100644 index 4e24b2c7bb2..00000000000 --- a/gdb/gdbserver/inferiors.h +++ /dev/null @@ -1,147 +0,0 @@ -/* Inferior process information for the remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_INFERIORS_H -#define GDBSERVER_INFERIORS_H - -#include "gdbsupport/gdb_vecs.h" -#include - -struct thread_info; -struct regcache; -struct target_desc; -struct sym_cache; -struct breakpoint; -struct raw_breakpoint; -struct fast_tracepoint_jump; -struct process_info_private; - -struct process_info -{ - process_info (int pid_, int attached_) - : pid (pid_), attached (attached_) - {} - - /* This process' pid. */ - int pid; - - /* Nonzero if this child process was attached rather than - spawned. */ - int attached; - - /* True if GDB asked us to detach from this process, but we remained - attached anyway. */ - int gdb_detached = 0; - - /* The symbol cache. */ - struct sym_cache *symbol_cache = NULL; - - /* The list of memory breakpoints. */ - struct breakpoint *breakpoints = NULL; - - /* The list of raw memory breakpoints. */ - struct raw_breakpoint *raw_breakpoints = NULL; - - /* The list of installed fast tracepoints. */ - struct fast_tracepoint_jump *fast_tracepoint_jumps = NULL; - - /* The list of syscalls to report, or just a single element, ANY_SYSCALL, - for unfiltered syscall reporting. */ - std::vector syscalls_to_catch; - - const struct target_desc *tdesc = NULL; - - /* Private target data. */ - struct process_info_private *priv = NULL; -}; - -/* Get the pid of PROC. */ - -static inline int -pid_of (const process_info *proc) -{ - return proc->pid; -} - -/* Return a pointer to the process that corresponds to the current - thread (current_thread). It is an error to call this if there is - no current thread selected. */ - -struct process_info *current_process (void); -struct process_info *get_thread_process (const struct thread_info *); - -extern std::list all_processes; - -/* Invoke FUNC for each process. */ - -template -static void -for_each_process (Func func) -{ - std::list::iterator next, cur = all_processes.begin (); - - while (cur != all_processes.end ()) - { - next = cur; - next++; - func (*cur); - cur = next; - } -} - -/* Find the first process for which FUNC returns true. Return NULL if no - process satisfying FUNC is found. */ - -template -static process_info * -find_process (Func func) -{ - std::list::iterator next, cur = all_processes.begin (); - - while (cur != all_processes.end ()) - { - next = cur; - next++; - - if (func (*cur)) - return *cur; - - cur = next; - } - - return NULL; -} - -extern struct thread_info *current_thread; - -/* Return the first process in the processes list. */ -struct process_info *get_first_process (void); - -struct process_info *add_process (int pid, int attached); -void remove_process (struct process_info *process); -struct process_info *find_process_pid (int pid); -int have_started_inferiors_p (void); -int have_attached_inferiors_p (void); - -void clear_inferiors (void); - -void *thread_target_data (struct thread_info *); -struct regcache *thread_regcache_data (struct thread_info *); -void set_thread_regcache_data (struct thread_info *, struct regcache *); - -#endif /* GDBSERVER_INFERIORS_H */ diff --git a/gdb/gdbserver/linux-aarch32-low.c b/gdb/gdbserver/linux-aarch32-low.c deleted file mode 100644 index c6a70249d3b..00000000000 --- a/gdb/gdbserver/linux-aarch32-low.c +++ /dev/null @@ -1,303 +0,0 @@ -/* Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "arch/arm.h" -#include "arch/arm-linux.h" -#include "linux-low.h" -#include "linux-aarch32-low.h" - -#include -/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h. - On Bionic elf.h and linux/elf.h have conflicting definitions. */ -#ifndef ELFMAG0 -#include -#endif - -/* Correct in either endianness. */ -#define arm_abi_breakpoint 0xef9f0001UL - -/* For new EABI binaries. We recognize it regardless of which ABI - is used for gdbserver, so single threaded debugging should work - OK, but for multi-threaded debugging we only insert the current - ABI's breakpoint instruction. For now at least. */ -#define arm_eabi_breakpoint 0xe7f001f0UL - -#if (defined __ARM_EABI__ || defined __aarch64__) -static const unsigned long arm_breakpoint = arm_eabi_breakpoint; -#else -static const unsigned long arm_breakpoint = arm_abi_breakpoint; -#endif - -#define arm_breakpoint_len 4 -static const unsigned short thumb_breakpoint = 0xde01; -#define thumb_breakpoint_len 2 -static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 }; -#define thumb2_breakpoint_len 4 - -/* Some older versions of GNU/Linux and Android do not define - the following macros. */ -#ifndef NT_ARM_VFP -#define NT_ARM_VFP 0x400 -#endif - -/* Collect GP registers from REGCACHE to buffer BUF. */ - -void -arm_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - uint32_t *regs = (uint32_t *) buf; - uint32_t cpsr = regs[ARM_CPSR_GREGNUM]; - - for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++) - collect_register (regcache, i, ®s[i]); - - collect_register (regcache, ARM_PS_REGNUM, ®s[ARM_CPSR_GREGNUM]); - /* Keep reserved bits bit 20 to bit 23. */ - regs[ARM_CPSR_GREGNUM] = ((regs[ARM_CPSR_GREGNUM] & 0xff0fffff) - | (cpsr & 0x00f00000)); -} - -/* Supply GP registers contents, stored in BUF, to REGCACHE. */ - -void -arm_store_gregset (struct regcache *regcache, const void *buf) -{ - int i; - char zerobuf[8]; - const uint32_t *regs = (const uint32_t *) buf; - uint32_t cpsr = regs[ARM_CPSR_GREGNUM]; - - memset (zerobuf, 0, 8); - for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++) - supply_register (regcache, i, ®s[i]); - - for (; i < ARM_PS_REGNUM; i++) - supply_register (regcache, i, zerobuf); - - /* Clear reserved bits bit 20 to bit 23. */ - cpsr &= 0xff0fffff; - supply_register (regcache, ARM_PS_REGNUM, &cpsr); -} - -/* Collect NUM number of VFP registers from REGCACHE to buffer BUF. */ - -void -arm_fill_vfpregset_num (struct regcache *regcache, void *buf, int num) -{ - int i, base; - - gdb_assert (num == 16 || num == 32); - - base = find_regno (regcache->tdesc, "d0"); - for (i = 0; i < num; i++) - collect_register (regcache, base + i, (char *) buf + i * 8); - - collect_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8); -} - -/* Supply NUM number of VFP registers contents, stored in BUF, to - REGCACHE. */ - -void -arm_store_vfpregset_num (struct regcache *regcache, const void *buf, int num) -{ - int i, base; - - gdb_assert (num == 16 || num == 32); - - base = find_regno (regcache->tdesc, "d0"); - for (i = 0; i < num; i++) - supply_register (regcache, base + i, (char *) buf + i * 8); - - supply_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8); -} - -static void -arm_fill_vfpregset (struct regcache *regcache, void *buf) -{ - arm_fill_vfpregset_num (regcache, buf, 32); -} - -static void -arm_store_vfpregset (struct regcache *regcache, const void *buf) -{ - arm_store_vfpregset_num (regcache, buf, 32); -} - -/* Register sets with using PTRACE_GETREGSET. */ - -static struct regset_info aarch32_regsets[] = { - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, - ARM_CORE_REGS_SIZE + ARM_INT_REGISTER_SIZE, GENERAL_REGS, - arm_fill_gregset, arm_store_gregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_VFP, ARM_VFP3_REGS_SIZE, - EXTENDED_REGS, - arm_fill_vfpregset, arm_store_vfpregset }, - NULL_REGSET -}; - -static struct regsets_info aarch32_regsets_info = - { - aarch32_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -struct regs_info regs_info_aarch32 = - { - NULL, /* regset_bitmap */ - NULL, /* usrregs */ - &aarch32_regsets_info - }; - -/* Returns 1 if the current instruction set is thumb, 0 otherwise. */ - -int -arm_is_thumb_mode (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 1); - unsigned long cpsr; - - collect_register_by_name (regcache, "cpsr", &cpsr); - - if (cpsr & 0x20) - return 1; - else - return 0; -} - -/* Returns 1 if there is a software breakpoint at location. */ - -int -arm_breakpoint_at (CORE_ADDR where) -{ - if (arm_is_thumb_mode ()) - { - /* Thumb mode. */ - unsigned short insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 2); - if (insn == thumb_breakpoint) - return 1; - - if (insn == thumb2_breakpoint[0]) - { - (*the_target->read_memory) (where + 2, (unsigned char *) &insn, 2); - if (insn == thumb2_breakpoint[1]) - return 1; - } - } - else - { - /* ARM mode. */ - unsigned long insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 4); - if (insn == arm_abi_breakpoint) - return 1; - - if (insn == arm_eabi_breakpoint) - return 1; - } - - return 0; -} - -/* Implementation of linux_target_ops method "breakpoint_kind_from_pc". - - Determine the type and size of breakpoint to insert at PCPTR. Uses the - program counter value to determine whether a 16-bit or 32-bit breakpoint - should be used. It returns the breakpoint's kind, and adjusts the program - counter (if necessary) to point to the actual memory location where the - breakpoint should be inserted. */ - -int -arm_breakpoint_kind_from_pc (CORE_ADDR *pcptr) -{ - if (IS_THUMB_ADDR (*pcptr)) - { - gdb_byte buf[2]; - - *pcptr = UNMAKE_THUMB_ADDR (*pcptr); - - /* Check whether we are replacing a thumb2 32-bit instruction. */ - if (target_read_memory (*pcptr, buf, 2) == 0) - { - unsigned short inst1 = 0; - - target_read_memory (*pcptr, (gdb_byte *) &inst1, 2); - if (thumb_insn_size (inst1) == 4) - return ARM_BP_KIND_THUMB2; - } - return ARM_BP_KIND_THUMB; - } - else - return ARM_BP_KIND_ARM; -} - -/* Implementation of the linux_target_ops method "sw_breakpoint_from_kind". */ - -const gdb_byte * -arm_sw_breakpoint_from_kind (int kind , int *size) -{ - *size = arm_breakpoint_len; - /* Define an ARM-mode breakpoint; we only set breakpoints in the C - library, which is most likely to be ARM. If the kernel supports - clone events, we will never insert a breakpoint, so even a Thumb - C library will work; so will mixing EABI/non-EABI gdbserver and - application. */ - switch (kind) - { - case ARM_BP_KIND_THUMB: - *size = thumb_breakpoint_len; - return (gdb_byte *) &thumb_breakpoint; - case ARM_BP_KIND_THUMB2: - *size = thumb2_breakpoint_len; - return (gdb_byte *) &thumb2_breakpoint; - case ARM_BP_KIND_ARM: - *size = arm_breakpoint_len; - return (const gdb_byte *) &arm_breakpoint; - default: - return NULL; - } - return NULL; -} - -/* Implementation of the linux_target_ops method - "breakpoint_kind_from_current_state". */ - -int -arm_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) -{ - if (arm_is_thumb_mode ()) - { - *pcptr = MAKE_THUMB_ADDR (*pcptr); - return arm_breakpoint_kind_from_pc (pcptr); - } - else - { - return arm_breakpoint_kind_from_pc (pcptr); - } -} - -void -initialize_low_arch_aarch32 (void) -{ - initialize_regsets_info (&aarch32_regsets_info); -} diff --git a/gdb/gdbserver/linux-aarch32-low.h b/gdb/gdbserver/linux-aarch32-low.h deleted file mode 100644 index 85eda5cbc8c..00000000000 --- a/gdb/gdbserver/linux-aarch32-low.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_AARCH32_LOW_H -#define GDBSERVER_LINUX_AARCH32_LOW_H - -extern struct regs_info regs_info_aarch32; - -void arm_fill_gregset (struct regcache *regcache, void *buf); -void arm_store_gregset (struct regcache *regcache, const void *buf); -void arm_fill_vfpregset_num (struct regcache *regcache, void *buf, int num); -void arm_store_vfpregset_num (struct regcache *regcache, const void *buf, - int num); - -int arm_breakpoint_kind_from_pc (CORE_ADDR *pcptr); -const gdb_byte *arm_sw_breakpoint_from_kind (int kind , int *size); -int arm_breakpoint_kind_from_current_state (CORE_ADDR *pcptr); -int arm_breakpoint_at (CORE_ADDR where); - -void initialize_low_arch_aarch32 (void); - -void init_registers_arm_with_neon (void); -int arm_is_thumb_mode (void); - -#endif /* GDBSERVER_LINUX_AARCH32_LOW_H */ diff --git a/gdb/gdbserver/linux-aarch32-tdesc.c b/gdb/gdbserver/linux-aarch32-tdesc.c deleted file mode 100644 index b0dffe27e71..00000000000 --- a/gdb/gdbserver/linux-aarch32-tdesc.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (C) 2019-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" - -#include "linux-aarch32-tdesc.h" - -#include "tdesc.h" -#include "arch/aarch32.h" -#include - -static struct target_desc *tdesc_aarch32; - -/* See linux-aarch32-tdesc.h. */ - -const target_desc * -aarch32_linux_read_description () -{ - if (tdesc_aarch32 == nullptr) - { - tdesc_aarch32 = aarch32_create_target_description (); - - static const char *expedite_regs[] = { "r11", "sp", "pc", 0 }; - init_target_desc (tdesc_aarch32, expedite_regs); - } - return tdesc_aarch32; -} - -/* See linux-aarch32-tdesc.h. */ - -bool -is_aarch32_linux_description (const target_desc *tdesc) -{ - gdb_assert (tdesc != nullptr); - return tdesc == tdesc_aarch32; -} diff --git a/gdb/gdbserver/linux-aarch32-tdesc.h b/gdb/gdbserver/linux-aarch32-tdesc.h deleted file mode 100644 index 67d3f696190..00000000000 --- a/gdb/gdbserver/linux-aarch32-tdesc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2019-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_AARCH32_TDESC_H -#define GDBSERVER_LINUX_AARCH32_TDESC_H - -/* Return the AArch32 target description. */ - -const target_desc * aarch32_linux_read_description (); - -/* Return true if TDESC is the AArch32 target description. */ - -bool is_aarch32_linux_description (const target_desc *tdesc); - -#endif /* linux-aarch32-tdesc.h. */ diff --git a/gdb/gdbserver/linux-aarch64-ipa.c b/gdb/gdbserver/linux-aarch64-ipa.c deleted file mode 100644 index 694dfd77dfa..00000000000 --- a/gdb/gdbserver/linux-aarch64-ipa.c +++ /dev/null @@ -1,209 +0,0 @@ -/* GNU/Linux/AArch64 specific low level interface, for the in-process - agent library for GDB. - - Copyright (C) 2015-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include -#include "tracepoint.h" -#include -#ifdef HAVE_GETAUXVAL -#include -#endif -#include "linux-aarch64-tdesc.h" - -/* Each register saved by the jump pad is in a 16 byte cell. */ -#define FT_CR_SIZE 16 - -#define FT_CR_FPCR 0 -#define FT_CR_FPSR 1 -#define FT_CR_CPSR 2 -#define FT_CR_PC 3 -#define FT_CR_SP 4 -#define FT_CR_X0 5 -#define FT_CR_GPR(n) (FT_CR_X0 + (n)) -#define FT_CR_FPR(n) (FT_CR_GPR (31) + (n)) - -/* Mapping between registers collected by the jump pad and GDB's register - array layout used by regcache. - - See linux-aarch64-low.c (aarch64_install_fast_tracepoint_jump_pad) for - more details. */ - -static const int aarch64_ft_collect_regmap[] = { - FT_CR_GPR (0), - FT_CR_GPR (1), - FT_CR_GPR (2), - FT_CR_GPR (3), - FT_CR_GPR (4), - FT_CR_GPR (5), - FT_CR_GPR (6), - FT_CR_GPR (7), - FT_CR_GPR (8), - FT_CR_GPR (9), - FT_CR_GPR (10), - FT_CR_GPR (11), - FT_CR_GPR (12), - FT_CR_GPR (13), - FT_CR_GPR (14), - FT_CR_GPR (15), - FT_CR_GPR (16), - FT_CR_GPR (17), - FT_CR_GPR (18), - FT_CR_GPR (19), - FT_CR_GPR (20), - FT_CR_GPR (21), - FT_CR_GPR (22), - FT_CR_GPR (23), - FT_CR_GPR (24), - FT_CR_GPR (25), - FT_CR_GPR (26), - FT_CR_GPR (27), - FT_CR_GPR (28), - /* FP */ - FT_CR_GPR (29), - /* LR */ - FT_CR_GPR (30), - FT_CR_SP, - FT_CR_PC, - FT_CR_CPSR, - FT_CR_FPR (0), - FT_CR_FPR (1), - FT_CR_FPR (2), - FT_CR_FPR (3), - FT_CR_FPR (4), - FT_CR_FPR (5), - FT_CR_FPR (6), - FT_CR_FPR (7), - FT_CR_FPR (8), - FT_CR_FPR (9), - FT_CR_FPR (10), - FT_CR_FPR (11), - FT_CR_FPR (12), - FT_CR_FPR (13), - FT_CR_FPR (14), - FT_CR_FPR (15), - FT_CR_FPR (16), - FT_CR_FPR (17), - FT_CR_FPR (18), - FT_CR_FPR (19), - FT_CR_FPR (20), - FT_CR_FPR (21), - FT_CR_FPR (22), - FT_CR_FPR (23), - FT_CR_FPR (24), - FT_CR_FPR (25), - FT_CR_FPR (26), - FT_CR_FPR (27), - FT_CR_FPR (28), - FT_CR_FPR (29), - FT_CR_FPR (30), - FT_CR_FPR (31), - FT_CR_FPSR, - FT_CR_FPCR -}; - -#define AARCH64_NUM_FT_COLLECT_GREGS \ - (sizeof (aarch64_ft_collect_regmap) / sizeof(aarch64_ft_collect_regmap[0])) - -/* Fill in REGCACHE with registers saved by the jump pad in BUF. */ - -void -supply_fast_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf) -{ - int i; - - for (i = 0; i < AARCH64_NUM_FT_COLLECT_GREGS; i++) - supply_register (regcache, i, - ((char *) buf) - + (aarch64_ft_collect_regmap[i] * FT_CR_SIZE)); -} - -ULONGEST -get_raw_reg (const unsigned char *raw_regs, int regnum) -{ - if (regnum >= AARCH64_NUM_FT_COLLECT_GREGS) - return 0; - - return *(ULONGEST *) (raw_regs - + aarch64_ft_collect_regmap[regnum] * FT_CR_SIZE); -} - -/* Return target_desc to use for IPA, given the tdesc index passed by - gdbserver. Index is ignored, since we have only one tdesc - at the moment. SVE and pauth not yet supported. */ - -const struct target_desc * -get_ipa_tdesc (int idx) -{ - return aarch64_linux_read_description (0, false); -} - -/* Allocate buffer for the jump pads. The branch instruction has a reach - of +/- 128MiB, and the executable is loaded at 0x400000 (4MiB). - To maximize the area of executable that can use tracepoints, try - allocating at 0x400000 - size initially, decreasing until we hit - a free area. */ - -void * -alloc_jump_pad_buffer (size_t size) -{ - uintptr_t addr; - uintptr_t exec_base = getauxval (AT_PHDR); - int pagesize; - void *res; - - if (exec_base == 0) - exec_base = 0x400000; - - pagesize = sysconf (_SC_PAGE_SIZE); - if (pagesize == -1) - perror_with_name ("sysconf"); - - addr = exec_base - size; - - /* size should already be page-aligned, but this can't hurt. */ - addr &= ~(pagesize - 1); - - /* Search for a free area. If we hit 0, we're out of luck. */ - for (; addr; addr -= pagesize) - { - /* No MAP_FIXED - we don't want to zap someone's mapping. */ - res = mmap ((void *) addr, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* If we got what we wanted, return. */ - if ((uintptr_t) res == addr) - return res; - - /* If we got a mapping, but at a wrong address, undo it. */ - if (res != MAP_FAILED) - munmap (res, size); - } - - return NULL; -} - -void -initialize_low_tracepoint (void) -{ - /* SVE and pauth not yet supported. */ - aarch64_linux_read_description (0, false); -} diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c deleted file mode 100644 index 961fd5b3cc4..00000000000 --- a/gdb/gdbserver/linux-aarch64-low.c +++ /dev/null @@ -1,3098 +0,0 @@ -/* GNU/Linux/AArch64 specific low level interface, for the remote server for - GDB. - - Copyright (C) 2009-2020 Free Software Foundation, Inc. - Contributed by ARM Ltd. - - 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 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "nat/aarch64-linux.h" -#include "nat/aarch64-linux-hw-point.h" -#include "arch/aarch64-insn.h" -#include "linux-aarch32-low.h" -#include "elf/common.h" -#include "ax.h" -#include "tracepoint.h" -#include "debug.h" - -#include -#include -#include "nat/gdb_ptrace.h" -#include -#include -#include -#include - -#include "gdb_proc_service.h" -#include "arch/aarch64.h" -#include "linux-aarch32-tdesc.h" -#include "linux-aarch64-tdesc.h" -#include "nat/aarch64-sve-linux-ptrace.h" -#include "tdesc.h" - -#ifdef HAVE_SYS_REG_H -#include -#endif - -/* Per-process arch-specific data we want to keep. */ - -struct arch_process_info -{ - /* Hardware breakpoint/watchpoint data. - The reason for them to be per-process rather than per-thread is - due to the lack of information in the gdbserver environment; - gdbserver is not told that whether a requested hardware - breakpoint/watchpoint is thread specific or not, so it has to set - each hw bp/wp for every thread in the current process. The - higher level bp/wp management in gdb will resume a thread if a hw - bp/wp trap is not expected for it. Since the hw bp/wp setting is - same for each thread, it is reasonable for the data to live here. - */ - struct aarch64_debug_reg_state debug_reg_state; -}; - -/* Return true if the size of register 0 is 8 byte. */ - -static int -is_64bit_tdesc (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - return register_size (regcache->tdesc, 0) == 8; -} - -/* Return true if the regcache contains the number of SVE registers. */ - -static bool -is_sve_tdesc (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - return tdesc_contains_feature (regcache->tdesc, "org.gnu.gdb.aarch64.sve"); -} - -static void -aarch64_fill_gregset (struct regcache *regcache, void *buf) -{ - struct user_pt_regs *regset = (struct user_pt_regs *) buf; - int i; - - for (i = 0; i < AARCH64_X_REGS_NUM; i++) - collect_register (regcache, AARCH64_X0_REGNUM + i, ®set->regs[i]); - collect_register (regcache, AARCH64_SP_REGNUM, ®set->sp); - collect_register (regcache, AARCH64_PC_REGNUM, ®set->pc); - collect_register (regcache, AARCH64_CPSR_REGNUM, ®set->pstate); -} - -static void -aarch64_store_gregset (struct regcache *regcache, const void *buf) -{ - const struct user_pt_regs *regset = (const struct user_pt_regs *) buf; - int i; - - for (i = 0; i < AARCH64_X_REGS_NUM; i++) - supply_register (regcache, AARCH64_X0_REGNUM + i, ®set->regs[i]); - supply_register (regcache, AARCH64_SP_REGNUM, ®set->sp); - supply_register (regcache, AARCH64_PC_REGNUM, ®set->pc); - supply_register (regcache, AARCH64_CPSR_REGNUM, ®set->pstate); -} - -static void -aarch64_fill_fpregset (struct regcache *regcache, void *buf) -{ - struct user_fpsimd_state *regset = (struct user_fpsimd_state *) buf; - int i; - - for (i = 0; i < AARCH64_V_REGS_NUM; i++) - collect_register (regcache, AARCH64_V0_REGNUM + i, ®set->vregs[i]); - collect_register (regcache, AARCH64_FPSR_REGNUM, ®set->fpsr); - collect_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr); -} - -static void -aarch64_store_fpregset (struct regcache *regcache, const void *buf) -{ - const struct user_fpsimd_state *regset - = (const struct user_fpsimd_state *) buf; - int i; - - for (i = 0; i < AARCH64_V_REGS_NUM; i++) - supply_register (regcache, AARCH64_V0_REGNUM + i, ®set->vregs[i]); - supply_register (regcache, AARCH64_FPSR_REGNUM, ®set->fpsr); - supply_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr); -} - -/* Store the pauth registers to regcache. */ - -static void -aarch64_store_pauthregset (struct regcache *regcache, const void *buf) -{ - uint64_t *pauth_regset = (uint64_t *) buf; - int pauth_base = find_regno (regcache->tdesc, "pauth_dmask"); - - if (pauth_base == 0) - return; - - supply_register (regcache, AARCH64_PAUTH_DMASK_REGNUM (pauth_base), - &pauth_regset[0]); - supply_register (regcache, AARCH64_PAUTH_CMASK_REGNUM (pauth_base), - &pauth_regset[1]); -} - -/* Implementation of linux_target_ops method "get_pc". */ - -static CORE_ADDR -aarch64_get_pc (struct regcache *regcache) -{ - if (register_size (regcache->tdesc, 0) == 8) - return linux_get_pc_64bit (regcache); - else - return linux_get_pc_32bit (regcache); -} - -/* Implementation of linux_target_ops method "set_pc". */ - -static void -aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc) -{ - if (register_size (regcache->tdesc, 0) == 8) - linux_set_pc_64bit (regcache, pc); - else - linux_set_pc_32bit (regcache, pc); -} - -#define aarch64_breakpoint_len 4 - -/* AArch64 BRK software debug mode instruction. - This instruction needs to match gdb/aarch64-tdep.c - (aarch64_default_breakpoint). */ -static const gdb_byte aarch64_breakpoint[] = {0x00, 0x00, 0x20, 0xd4}; - -/* Implementation of linux_target_ops method "breakpoint_at". */ - -static int -aarch64_breakpoint_at (CORE_ADDR where) -{ - if (is_64bit_tdesc ()) - { - gdb_byte insn[aarch64_breakpoint_len]; - - (*the_target->read_memory) (where, (unsigned char *) &insn, - aarch64_breakpoint_len); - if (memcmp (insn, aarch64_breakpoint, aarch64_breakpoint_len) == 0) - return 1; - - return 0; - } - else - return arm_breakpoint_at (where); -} - -static void -aarch64_init_debug_reg_state (struct aarch64_debug_reg_state *state) -{ - int i; - - for (i = 0; i < AARCH64_HBP_MAX_NUM; ++i) - { - state->dr_addr_bp[i] = 0; - state->dr_ctrl_bp[i] = 0; - state->dr_ref_count_bp[i] = 0; - } - - for (i = 0; i < AARCH64_HWP_MAX_NUM; ++i) - { - state->dr_addr_wp[i] = 0; - state->dr_ctrl_wp[i] = 0; - state->dr_ref_count_wp[i] = 0; - } -} - -/* Return the pointer to the debug register state structure in the - current process' arch-specific data area. */ - -struct aarch64_debug_reg_state * -aarch64_get_debug_reg_state (pid_t pid) -{ - struct process_info *proc = find_process_pid (pid); - - return &proc->priv->arch_private->debug_reg_state; -} - -/* Implementation of linux_target_ops method "supports_z_point_type". */ - -static int -aarch64_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - case Z_PACKET_HW_BP: - case Z_PACKET_WRITE_WP: - case Z_PACKET_READ_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - return 0; - } -} - -/* Implementation of linux_target_ops method "insert_point". - - It actually only records the info of the to-be-inserted bp/wp; - the actual insertion will happen when threads are resumed. */ - -static int -aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - int ret; - enum target_hw_bp_type targ_type; - struct aarch64_debug_reg_state *state - = aarch64_get_debug_reg_state (pid_of (current_thread)); - - if (show_debug_regs) - fprintf (stderr, "insert_point on entry (addr=0x%08lx, len=%d)\n", - (unsigned long) addr, len); - - /* Determine the type from the raw breakpoint type. */ - targ_type = raw_bkpt_type_to_target_hw_bp_type (type); - - if (targ_type != hw_execute) - { - if (aarch64_linux_region_ok_for_watchpoint (addr, len)) - ret = aarch64_handle_watchpoint (targ_type, addr, len, - 1 /* is_insert */, state); - else - ret = -1; - } - else - { - if (len == 3) - { - /* LEN is 3 means the breakpoint is set on a 32-bit thumb - instruction. Set it to 2 to correctly encode length bit - mask in hardware/watchpoint control register. */ - len = 2; - } - ret = aarch64_handle_breakpoint (targ_type, addr, len, - 1 /* is_insert */, state); - } - - if (show_debug_regs) - aarch64_show_debug_reg_state (state, "insert_point", addr, len, - targ_type); - - return ret; -} - -/* Implementation of linux_target_ops method "remove_point". - - It actually only records the info of the to-be-removed bp/wp, - the actual removal will be done when threads are resumed. */ - -static int -aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - int ret; - enum target_hw_bp_type targ_type; - struct aarch64_debug_reg_state *state - = aarch64_get_debug_reg_state (pid_of (current_thread)); - - if (show_debug_regs) - fprintf (stderr, "remove_point on entry (addr=0x%08lx, len=%d)\n", - (unsigned long) addr, len); - - /* Determine the type from the raw breakpoint type. */ - targ_type = raw_bkpt_type_to_target_hw_bp_type (type); - - /* Set up state pointers. */ - if (targ_type != hw_execute) - ret = - aarch64_handle_watchpoint (targ_type, addr, len, 0 /* is_insert */, - state); - else - { - if (len == 3) - { - /* LEN is 3 means the breakpoint is set on a 32-bit thumb - instruction. Set it to 2 to correctly encode length bit - mask in hardware/watchpoint control register. */ - len = 2; - } - ret = aarch64_handle_breakpoint (targ_type, addr, len, - 0 /* is_insert */, state); - } - - if (show_debug_regs) - aarch64_show_debug_reg_state (state, "remove_point", addr, len, - targ_type); - - return ret; -} - -/* Implementation of linux_target_ops method "stopped_data_address". */ - -static CORE_ADDR -aarch64_stopped_data_address (void) -{ - siginfo_t siginfo; - int pid, i; - struct aarch64_debug_reg_state *state; - - pid = lwpid_of (current_thread); - - /* Get the siginfo. */ - if (ptrace (PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) - return (CORE_ADDR) 0; - - /* Need to be a hardware breakpoint/watchpoint trap. */ - if (siginfo.si_signo != SIGTRAP - || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) - return (CORE_ADDR) 0; - - /* Check if the address matches any watched address. */ - state = aarch64_get_debug_reg_state (pid_of (current_thread)); - for (i = aarch64_num_wp_regs - 1; i >= 0; --i) - { - const unsigned int offset - = aarch64_watchpoint_offset (state->dr_ctrl_wp[i]); - const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]); - const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr; - const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset; - const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8); - const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i]; - - if (state->dr_ref_count_wp[i] - && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i]) - && addr_trap >= addr_watch_aligned - && addr_trap < addr_watch + len) - { - /* ADDR_TRAP reports the first address of the memory range - accessed by the CPU, regardless of what was the memory - range watched. Thus, a large CPU access that straddles - the ADDR_WATCH..ADDR_WATCH+LEN range may result in an - ADDR_TRAP that is lower than the - ADDR_WATCH..ADDR_WATCH+LEN range. E.g.: - - addr: | 4 | 5 | 6 | 7 | 8 | - |---- range watched ----| - |----------- range accessed ------------| - - In this case, ADDR_TRAP will be 4. - - To match a watchpoint known to GDB core, we must never - report *ADDR_P outside of any ADDR_WATCH..ADDR_WATCH+LEN - range. ADDR_WATCH <= ADDR_TRAP < ADDR_ORIG is a false - positive on kernels older than 4.10. See PR - external/20207. */ - return addr_orig; - } - } - - return (CORE_ADDR) 0; -} - -/* Implementation of linux_target_ops method "stopped_by_watchpoint". */ - -static int -aarch64_stopped_by_watchpoint (void) -{ - if (aarch64_stopped_data_address () != 0) - return 1; - else - return 0; -} - -/* Fetch the thread-local storage pointer for libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - return aarch64_ps_get_thread_area (ph, lwpid, idx, base, - is_64bit_tdesc ()); -} - -/* Implementation of linux_target_ops method "siginfo_fixup". */ - -static int -aarch64_linux_siginfo_fixup (siginfo_t *native, gdb_byte *inf, int direction) -{ - /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ - if (!is_64bit_tdesc ()) - { - if (direction == 0) - aarch64_compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, - native); - else - aarch64_siginfo_from_compat_siginfo (native, - (struct compat_siginfo *) inf); - - return 1; - } - - return 0; -} - -/* Implementation of linux_target_ops method "new_process". */ - -static struct arch_process_info * -aarch64_linux_new_process (void) -{ - struct arch_process_info *info = XCNEW (struct arch_process_info); - - aarch64_init_debug_reg_state (&info->debug_reg_state); - - return info; -} - -/* Implementation of linux_target_ops method "delete_process". */ - -static void -aarch64_linux_delete_process (struct arch_process_info *info) -{ - xfree (info); -} - -/* Implementation of linux_target_ops method "linux_new_fork". */ - -static void -aarch64_linux_new_fork (struct process_info *parent, - struct process_info *child) -{ - /* These are allocated by linux_add_process. */ - gdb_assert (parent->priv != NULL - && parent->priv->arch_private != NULL); - gdb_assert (child->priv != NULL - && child->priv->arch_private != NULL); - - /* Linux kernel before 2.6.33 commit - 72f674d203cd230426437cdcf7dd6f681dad8b0d - will inherit hardware debug registers from parent - on fork/vfork/clone. Newer Linux kernels create such tasks with - zeroed debug registers. - - GDB core assumes the child inherits the watchpoints/hw - breakpoints of the parent, and will remove them all from the - forked off process. Copy the debug registers mirrors into the - new process so that all breakpoints and watchpoints can be - removed together. The debug registers mirror will become zeroed - in the end before detaching the forked off process, thus making - this compatible with older Linux kernels too. */ - - *child->priv->arch_private = *parent->priv->arch_private; -} - -/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h. */ -#define AARCH64_HWCAP_PACA (1 << 30) - -/* Implementation of linux_target_ops method "arch_setup". */ - -static void -aarch64_arch_setup (void) -{ - unsigned int machine; - int is_elf64; - int tid; - - tid = lwpid_of (current_thread); - - is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); - - if (is_elf64) - { - uint64_t vq = aarch64_sve_get_vq (tid); - unsigned long hwcap = linux_get_hwcap (8); - bool pauth_p = hwcap & AARCH64_HWCAP_PACA; - - current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p); - } - else - current_process ()->tdesc = aarch32_linux_read_description (); - - aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread)); -} - -/* Wrapper for aarch64_sve_regs_copy_to_reg_buf. */ - -static void -aarch64_sve_regs_copy_to_regcache (struct regcache *regcache, const void *buf) -{ - return aarch64_sve_regs_copy_to_reg_buf (regcache, buf); -} - -/* Wrapper for aarch64_sve_regs_copy_from_reg_buf. */ - -static void -aarch64_sve_regs_copy_from_regcache (struct regcache *regcache, void *buf) -{ - return aarch64_sve_regs_copy_from_reg_buf (regcache, buf); -} - -static struct regset_info aarch64_regsets[] = -{ - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, - sizeof (struct user_pt_regs), GENERAL_REGS, - aarch64_fill_gregset, aarch64_store_gregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, - sizeof (struct user_fpsimd_state), FP_REGS, - aarch64_fill_fpregset, aarch64_store_fpregset - }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK, - AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS, - NULL, aarch64_store_pauthregset }, - NULL_REGSET -}; - -static struct regsets_info aarch64_regsets_info = - { - aarch64_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct regs_info regs_info_aarch64 = - { - NULL, /* regset_bitmap */ - NULL, /* usrregs */ - &aarch64_regsets_info, - }; - -static struct regset_info aarch64_sve_regsets[] = -{ - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, - sizeof (struct user_pt_regs), GENERAL_REGS, - aarch64_fill_gregset, aarch64_store_gregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_SVE, - SVE_PT_SIZE (AARCH64_MAX_SVE_VQ, SVE_PT_REGS_SVE), EXTENDED_REGS, - aarch64_sve_regs_copy_from_regcache, aarch64_sve_regs_copy_to_regcache - }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK, - AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS, - NULL, aarch64_store_pauthregset }, - NULL_REGSET -}; - -static struct regsets_info aarch64_sve_regsets_info = - { - aarch64_sve_regsets, /* regsets. */ - 0, /* num_regsets. */ - NULL, /* disabled_regsets. */ - }; - -static struct regs_info regs_info_aarch64_sve = - { - NULL, /* regset_bitmap. */ - NULL, /* usrregs. */ - &aarch64_sve_regsets_info, - }; - -/* Implementation of linux_target_ops method "regs_info". */ - -static const struct regs_info * -aarch64_regs_info (void) -{ - if (!is_64bit_tdesc ()) - return ®s_info_aarch32; - - if (is_sve_tdesc ()) - return ®s_info_aarch64_sve; - - return ®s_info_aarch64; -} - -/* Implementation of linux_target_ops method "supports_tracepoints". */ - -static int -aarch64_supports_tracepoints (void) -{ - if (current_thread == NULL) - return 1; - else - { - /* We don't support tracepoints on aarch32 now. */ - return is_64bit_tdesc (); - } -} - -/* Implementation of linux_target_ops method "get_thread_area". */ - -static int -aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp) -{ - struct iovec iovec; - uint64_t reg; - - iovec.iov_base = ® - iovec.iov_len = sizeof (reg); - - if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0) - return -1; - - *addrp = reg; - - return 0; -} - -/* Implementation of linux_target_ops method "get_syscall_trapinfo". */ - -static void -aarch64_get_syscall_trapinfo (struct regcache *regcache, int *sysno) -{ - int use_64bit = register_size (regcache->tdesc, 0) == 8; - - if (use_64bit) - { - long l_sysno; - - collect_register_by_name (regcache, "x8", &l_sysno); - *sysno = (int) l_sysno; - } - else - collect_register_by_name (regcache, "r7", sysno); -} - -/* List of condition codes that we need. */ - -enum aarch64_condition_codes -{ - EQ = 0x0, - NE = 0x1, - LO = 0x3, - GE = 0xa, - LT = 0xb, - GT = 0xc, - LE = 0xd, -}; - -enum aarch64_operand_type -{ - OPERAND_IMMEDIATE, - OPERAND_REGISTER, -}; - -/* Representation of an operand. At this time, it only supports register - and immediate types. */ - -struct aarch64_operand -{ - /* Type of the operand. */ - enum aarch64_operand_type type; - - /* Value of the operand according to the type. */ - union - { - uint32_t imm; - struct aarch64_register reg; - }; -}; - -/* List of registers that we are currently using, we can add more here as - we need to use them. */ - -/* General purpose scratch registers (64 bit). */ -static const struct aarch64_register x0 = { 0, 1 }; -static const struct aarch64_register x1 = { 1, 1 }; -static const struct aarch64_register x2 = { 2, 1 }; -static const struct aarch64_register x3 = { 3, 1 }; -static const struct aarch64_register x4 = { 4, 1 }; - -/* General purpose scratch registers (32 bit). */ -static const struct aarch64_register w0 = { 0, 0 }; -static const struct aarch64_register w2 = { 2, 0 }; - -/* Intra-procedure scratch registers. */ -static const struct aarch64_register ip0 = { 16, 1 }; - -/* Special purpose registers. */ -static const struct aarch64_register fp = { 29, 1 }; -static const struct aarch64_register lr = { 30, 1 }; -static const struct aarch64_register sp = { 31, 1 }; -static const struct aarch64_register xzr = { 31, 1 }; - -/* Dynamically allocate a new register. If we know the register - statically, we should make it a global as above instead of using this - helper function. */ - -static struct aarch64_register -aarch64_register (unsigned num, int is64) -{ - return (struct aarch64_register) { num, is64 }; -} - -/* Helper function to create a register operand, for instructions with - different types of operands. - - For example: - p += emit_mov (p, x0, register_operand (x1)); */ - -static struct aarch64_operand -register_operand (struct aarch64_register reg) -{ - struct aarch64_operand operand; - - operand.type = OPERAND_REGISTER; - operand.reg = reg; - - return operand; -} - -/* Helper function to create an immediate operand, for instructions with - different types of operands. - - For example: - p += emit_mov (p, x0, immediate_operand (12)); */ - -static struct aarch64_operand -immediate_operand (uint32_t imm) -{ - struct aarch64_operand operand; - - operand.type = OPERAND_IMMEDIATE; - operand.imm = imm; - - return operand; -} - -/* Helper function to create an offset memory operand. - - For example: - p += emit_ldr (p, x0, sp, offset_memory_operand (16)); */ - -static struct aarch64_memory_operand -offset_memory_operand (int32_t offset) -{ - return (struct aarch64_memory_operand) { MEMORY_OPERAND_OFFSET, offset }; -} - -/* Helper function to create a pre-index memory operand. - - For example: - p += emit_ldr (p, x0, sp, preindex_memory_operand (16)); */ - -static struct aarch64_memory_operand -preindex_memory_operand (int32_t index) -{ - return (struct aarch64_memory_operand) { MEMORY_OPERAND_PREINDEX, index }; -} - -/* Helper function to create a post-index memory operand. - - For example: - p += emit_ldr (p, x0, sp, postindex_memory_operand (16)); */ - -static struct aarch64_memory_operand -postindex_memory_operand (int32_t index) -{ - return (struct aarch64_memory_operand) { MEMORY_OPERAND_POSTINDEX, index }; -} - -/* System control registers. These special registers can be written and - read with the MRS and MSR instructions. - - - NZCV: Condition flags. GDB refers to this register under the CPSR - name. - - FPSR: Floating-point status register. - - FPCR: Floating-point control registers. - - TPIDR_EL0: Software thread ID register. */ - -enum aarch64_system_control_registers -{ - /* op0 op1 crn crm op2 */ - NZCV = (0x1 << 14) | (0x3 << 11) | (0x4 << 7) | (0x2 << 3) | 0x0, - FPSR = (0x1 << 14) | (0x3 << 11) | (0x4 << 7) | (0x4 << 3) | 0x1, - FPCR = (0x1 << 14) | (0x3 << 11) | (0x4 << 7) | (0x4 << 3) | 0x0, - TPIDR_EL0 = (0x1 << 14) | (0x3 << 11) | (0xd << 7) | (0x0 << 3) | 0x2 -}; - -/* Write a BLR instruction into *BUF. - - BLR rn - - RN is the register to branch to. */ - -static int -emit_blr (uint32_t *buf, struct aarch64_register rn) -{ - return aarch64_emit_insn (buf, BLR | ENCODE (rn.num, 5, 5)); -} - -/* Write a RET instruction into *BUF. - - RET xn - - RN is the register to branch to. */ - -static int -emit_ret (uint32_t *buf, struct aarch64_register rn) -{ - return aarch64_emit_insn (buf, RET | ENCODE (rn.num, 5, 5)); -} - -static int -emit_load_store_pair (uint32_t *buf, enum aarch64_opcodes opcode, - struct aarch64_register rt, - struct aarch64_register rt2, - struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - uint32_t opc; - uint32_t pre_index; - uint32_t write_back; - - if (rt.is64) - opc = ENCODE (2, 2, 30); - else - opc = ENCODE (0, 2, 30); - - switch (operand.type) - { - case MEMORY_OPERAND_OFFSET: - { - pre_index = ENCODE (1, 1, 24); - write_back = ENCODE (0, 1, 23); - break; - } - case MEMORY_OPERAND_POSTINDEX: - { - pre_index = ENCODE (0, 1, 24); - write_back = ENCODE (1, 1, 23); - break; - } - case MEMORY_OPERAND_PREINDEX: - { - pre_index = ENCODE (1, 1, 24); - write_back = ENCODE (1, 1, 23); - break; - } - default: - return 0; - } - - return aarch64_emit_insn (buf, opcode | opc | pre_index | write_back - | ENCODE (operand.index >> 3, 7, 15) - | ENCODE (rt2.num, 5, 10) - | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); -} - -/* Write a STP instruction into *BUF. - - STP rt, rt2, [rn, #offset] - STP rt, rt2, [rn, #index]! - STP rt, rt2, [rn], #index - - RT and RT2 are the registers to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to a - -512 .. 504 range (7 bits << 3). */ - -static int -emit_stp (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rt2, struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - return emit_load_store_pair (buf, STP, rt, rt2, rn, operand); -} - -/* Write a LDP instruction into *BUF. - - LDP rt, rt2, [rn, #offset] - LDP rt, rt2, [rn, #index]! - LDP rt, rt2, [rn], #index - - RT and RT2 are the registers to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to a - -512 .. 504 range (7 bits << 3). */ - -static int -emit_ldp (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rt2, struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - return emit_load_store_pair (buf, LDP, rt, rt2, rn, operand); -} - -/* Write a LDP (SIMD&VFP) instruction using Q registers into *BUF. - - LDP qt, qt2, [rn, #offset] - - RT and RT2 are the Q registers to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to - -1024 .. 1008 range (7 bits << 4). */ - -static int -emit_ldp_q_offset (uint32_t *buf, unsigned rt, unsigned rt2, - struct aarch64_register rn, int32_t offset) -{ - uint32_t opc = ENCODE (2, 2, 30); - uint32_t pre_index = ENCODE (1, 1, 24); - - return aarch64_emit_insn (buf, LDP_SIMD_VFP | opc | pre_index - | ENCODE (offset >> 4, 7, 15) - | ENCODE (rt2, 5, 10) - | ENCODE (rn.num, 5, 5) | ENCODE (rt, 5, 0)); -} - -/* Write a STP (SIMD&VFP) instruction using Q registers into *BUF. - - STP qt, qt2, [rn, #offset] - - RT and RT2 are the Q registers to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to - -1024 .. 1008 range (7 bits << 4). */ - -static int -emit_stp_q_offset (uint32_t *buf, unsigned rt, unsigned rt2, - struct aarch64_register rn, int32_t offset) -{ - uint32_t opc = ENCODE (2, 2, 30); - uint32_t pre_index = ENCODE (1, 1, 24); - - return aarch64_emit_insn (buf, STP_SIMD_VFP | opc | pre_index - | ENCODE (offset >> 4, 7, 15) - | ENCODE (rt2, 5, 10) - | ENCODE (rn.num, 5, 5) | ENCODE (rt, 5, 0)); -} - -/* Write a LDRH instruction into *BUF. - - LDRH wt, [xn, #offset] - LDRH wt, [xn, #index]! - LDRH wt, [xn], #index - - RT is the register to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to - 0 .. 32760 range (12 bits << 3). */ - -static int -emit_ldrh (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - return aarch64_emit_load_store (buf, 1, LDR, rt, rn, operand); -} - -/* Write a LDRB instruction into *BUF. - - LDRB wt, [xn, #offset] - LDRB wt, [xn, #index]! - LDRB wt, [xn], #index - - RT is the register to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to - 0 .. 32760 range (12 bits << 3). */ - -static int -emit_ldrb (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - return aarch64_emit_load_store (buf, 0, LDR, rt, rn, operand); -} - - - -/* Write a STR instruction into *BUF. - - STR rt, [rn, #offset] - STR rt, [rn, #index]! - STR rt, [rn], #index - - RT is the register to store. - RN is the base address register. - OFFSET is the immediate to add to the base address. It is limited to - 0 .. 32760 range (12 bits << 3). */ - -static int -emit_str (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - return aarch64_emit_load_store (buf, rt.is64 ? 3 : 2, STR, rt, rn, operand); -} - -/* Helper function emitting an exclusive load or store instruction. */ - -static int -emit_load_store_exclusive (uint32_t *buf, uint32_t size, - enum aarch64_opcodes opcode, - struct aarch64_register rs, - struct aarch64_register rt, - struct aarch64_register rt2, - struct aarch64_register rn) -{ - return aarch64_emit_insn (buf, opcode | ENCODE (size, 2, 30) - | ENCODE (rs.num, 5, 16) | ENCODE (rt2.num, 5, 10) - | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); -} - -/* Write a LAXR instruction into *BUF. - - LDAXR rt, [xn] - - RT is the destination register. - RN is the base address register. */ - -static int -emit_ldaxr (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn) -{ - return emit_load_store_exclusive (buf, rt.is64 ? 3 : 2, LDAXR, xzr, rt, - xzr, rn); -} - -/* Write a STXR instruction into *BUF. - - STXR ws, rt, [xn] - - RS is the result register, it indicates if the store succeeded or not. - RT is the destination register. - RN is the base address register. */ - -static int -emit_stxr (uint32_t *buf, struct aarch64_register rs, - struct aarch64_register rt, struct aarch64_register rn) -{ - return emit_load_store_exclusive (buf, rt.is64 ? 3 : 2, STXR, rs, rt, - xzr, rn); -} - -/* Write a STLR instruction into *BUF. - - STLR rt, [xn] - - RT is the register to store. - RN is the base address register. */ - -static int -emit_stlr (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn) -{ - return emit_load_store_exclusive (buf, rt.is64 ? 3 : 2, STLR, xzr, rt, - xzr, rn); -} - -/* Helper function for data processing instructions with register sources. */ - -static int -emit_data_processing_reg (uint32_t *buf, uint32_t opcode, - struct aarch64_register rd, - struct aarch64_register rn, - struct aarch64_register rm) -{ - uint32_t size = ENCODE (rd.is64, 1, 31); - - return aarch64_emit_insn (buf, opcode | size | ENCODE (rm.num, 5, 16) - | ENCODE (rn.num, 5, 5) | ENCODE (rd.num, 5, 0)); -} - -/* Helper function for data processing instructions taking either a register - or an immediate. */ - -static int -emit_data_processing (uint32_t *buf, enum aarch64_opcodes opcode, - struct aarch64_register rd, - struct aarch64_register rn, - struct aarch64_operand operand) -{ - uint32_t size = ENCODE (rd.is64, 1, 31); - /* The opcode is different for register and immediate source operands. */ - uint32_t operand_opcode; - - if (operand.type == OPERAND_IMMEDIATE) - { - /* xxx1 000x xxxx xxxx xxxx xxxx xxxx xxxx */ - operand_opcode = ENCODE (8, 4, 25); - - return aarch64_emit_insn (buf, opcode | operand_opcode | size - | ENCODE (operand.imm, 12, 10) - | ENCODE (rn.num, 5, 5) - | ENCODE (rd.num, 5, 0)); - } - else - { - /* xxx0 101x xxxx xxxx xxxx xxxx xxxx xxxx */ - operand_opcode = ENCODE (5, 4, 25); - - return emit_data_processing_reg (buf, opcode | operand_opcode, rd, - rn, operand.reg); - } -} - -/* Write an ADD instruction into *BUF. - - ADD rd, rn, #imm - ADD rd, rn, rm - - This function handles both an immediate and register add. - - RD is the destination register. - RN is the input register. - OPERAND is the source operand, either of type OPERAND_IMMEDIATE or - OPERAND_REGISTER. */ - -static int -emit_add (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_operand operand) -{ - return emit_data_processing (buf, ADD, rd, rn, operand); -} - -/* Write a SUB instruction into *BUF. - - SUB rd, rn, #imm - SUB rd, rn, rm - - This function handles both an immediate and register sub. - - RD is the destination register. - RN is the input register. - IMM is the immediate to substract to RN. */ - -static int -emit_sub (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_operand operand) -{ - return emit_data_processing (buf, SUB, rd, rn, operand); -} - -/* Write a MOV instruction into *BUF. - - MOV rd, #imm - MOV rd, rm - - This function handles both a wide immediate move and a register move, - with the condition that the source register is not xzr. xzr and the - stack pointer share the same encoding and this function only supports - the stack pointer. - - RD is the destination register. - OPERAND is the source operand, either of type OPERAND_IMMEDIATE or - OPERAND_REGISTER. */ - -static int -emit_mov (uint32_t *buf, struct aarch64_register rd, - struct aarch64_operand operand) -{ - if (operand.type == OPERAND_IMMEDIATE) - { - uint32_t size = ENCODE (rd.is64, 1, 31); - /* Do not shift the immediate. */ - uint32_t shift = ENCODE (0, 2, 21); - - return aarch64_emit_insn (buf, MOV | size | shift - | ENCODE (operand.imm, 16, 5) - | ENCODE (rd.num, 5, 0)); - } - else - return emit_add (buf, rd, operand.reg, immediate_operand (0)); -} - -/* Write a MOVK instruction into *BUF. - - MOVK rd, #imm, lsl #shift - - RD is the destination register. - IMM is the immediate. - SHIFT is the logical shift left to apply to IMM. */ - -static int -emit_movk (uint32_t *buf, struct aarch64_register rd, uint32_t imm, - unsigned shift) -{ - uint32_t size = ENCODE (rd.is64, 1, 31); - - return aarch64_emit_insn (buf, MOVK | size | ENCODE (shift, 2, 21) | - ENCODE (imm, 16, 5) | ENCODE (rd.num, 5, 0)); -} - -/* Write instructions into *BUF in order to move ADDR into a register. - ADDR can be a 64-bit value. - - This function will emit a series of MOV and MOVK instructions, such as: - - MOV xd, #(addr) - MOVK xd, #(addr >> 16), lsl #16 - MOVK xd, #(addr >> 32), lsl #32 - MOVK xd, #(addr >> 48), lsl #48 */ - -static int -emit_mov_addr (uint32_t *buf, struct aarch64_register rd, CORE_ADDR addr) -{ - uint32_t *p = buf; - - /* The MOV (wide immediate) instruction clears to top bits of the - register. */ - p += emit_mov (p, rd, immediate_operand (addr & 0xffff)); - - if ((addr >> 16) != 0) - p += emit_movk (p, rd, (addr >> 16) & 0xffff, 1); - else - return p - buf; - - if ((addr >> 32) != 0) - p += emit_movk (p, rd, (addr >> 32) & 0xffff, 2); - else - return p - buf; - - if ((addr >> 48) != 0) - p += emit_movk (p, rd, (addr >> 48) & 0xffff, 3); - - return p - buf; -} - -/* Write a SUBS instruction into *BUF. - - SUBS rd, rn, rm - - This instruction update the condition flags. - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_subs (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_operand operand) -{ - return emit_data_processing (buf, SUBS, rd, rn, operand); -} - -/* Write a CMP instruction into *BUF. - - CMP rn, rm - - This instruction is an alias of SUBS xzr, rn, rm. - - RN and RM are the registers to compare. */ - -static int -emit_cmp (uint32_t *buf, struct aarch64_register rn, - struct aarch64_operand operand) -{ - return emit_subs (buf, xzr, rn, operand); -} - -/* Write a AND instruction into *BUF. - - AND rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_and (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, AND, rd, rn, rm); -} - -/* Write a ORR instruction into *BUF. - - ORR rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_orr (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, ORR, rd, rn, rm); -} - -/* Write a ORN instruction into *BUF. - - ORN rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_orn (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, ORN, rd, rn, rm); -} - -/* Write a EOR instruction into *BUF. - - EOR rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_eor (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, EOR, rd, rn, rm); -} - -/* Write a MVN instruction into *BUF. - - MVN rd, rm - - This is an alias for ORN rd, xzr, rm. - - RD is the destination register. - RM is the source register. */ - -static int -emit_mvn (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rm) -{ - return emit_orn (buf, rd, xzr, rm); -} - -/* Write a LSLV instruction into *BUF. - - LSLV rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_lslv (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, LSLV, rd, rn, rm); -} - -/* Write a LSRV instruction into *BUF. - - LSRV rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_lsrv (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, LSRV, rd, rn, rm); -} - -/* Write a ASRV instruction into *BUF. - - ASRV rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_asrv (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, ASRV, rd, rn, rm); -} - -/* Write a MUL instruction into *BUF. - - MUL rd, rn, rm - - RD is the destination register. - RN and RM are the source registers. */ - -static int -emit_mul (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm) -{ - return emit_data_processing_reg (buf, MUL, rd, rn, rm); -} - -/* Write a MRS instruction into *BUF. The register size is 64-bit. - - MRS xt, system_reg - - RT is the destination register. - SYSTEM_REG is special purpose register to read. */ - -static int -emit_mrs (uint32_t *buf, struct aarch64_register rt, - enum aarch64_system_control_registers system_reg) -{ - return aarch64_emit_insn (buf, MRS | ENCODE (system_reg, 15, 5) - | ENCODE (rt.num, 5, 0)); -} - -/* Write a MSR instruction into *BUF. The register size is 64-bit. - - MSR system_reg, xt - - SYSTEM_REG is special purpose register to write. - RT is the input register. */ - -static int -emit_msr (uint32_t *buf, enum aarch64_system_control_registers system_reg, - struct aarch64_register rt) -{ - return aarch64_emit_insn (buf, MSR | ENCODE (system_reg, 15, 5) - | ENCODE (rt.num, 5, 0)); -} - -/* Write a SEVL instruction into *BUF. - - This is a hint instruction telling the hardware to trigger an event. */ - -static int -emit_sevl (uint32_t *buf) -{ - return aarch64_emit_insn (buf, SEVL); -} - -/* Write a WFE instruction into *BUF. - - This is a hint instruction telling the hardware to wait for an event. */ - -static int -emit_wfe (uint32_t *buf) -{ - return aarch64_emit_insn (buf, WFE); -} - -/* Write a SBFM instruction into *BUF. - - SBFM rd, rn, #immr, #imms - - This instruction moves the bits from #immr to #imms into the - destination, sign extending the result. - - RD is the destination register. - RN is the source register. - IMMR is the bit number to start at (least significant bit). - IMMS is the bit number to stop at (most significant bit). */ - -static int -emit_sbfm (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, uint32_t immr, uint32_t imms) -{ - uint32_t size = ENCODE (rd.is64, 1, 31); - uint32_t n = ENCODE (rd.is64, 1, 22); - - return aarch64_emit_insn (buf, SBFM | size | n | ENCODE (immr, 6, 16) - | ENCODE (imms, 6, 10) | ENCODE (rn.num, 5, 5) - | ENCODE (rd.num, 5, 0)); -} - -/* Write a SBFX instruction into *BUF. - - SBFX rd, rn, #lsb, #width - - This instruction moves #width bits from #lsb into the destination, sign - extending the result. This is an alias for: - - SBFM rd, rn, #lsb, #(lsb + width - 1) - - RD is the destination register. - RN is the source register. - LSB is the bit number to start at (least significant bit). - WIDTH is the number of bits to move. */ - -static int -emit_sbfx (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, uint32_t lsb, uint32_t width) -{ - return emit_sbfm (buf, rd, rn, lsb, lsb + width - 1); -} - -/* Write a UBFM instruction into *BUF. - - UBFM rd, rn, #immr, #imms - - This instruction moves the bits from #immr to #imms into the - destination, extending the result with zeros. - - RD is the destination register. - RN is the source register. - IMMR is the bit number to start at (least significant bit). - IMMS is the bit number to stop at (most significant bit). */ - -static int -emit_ubfm (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, uint32_t immr, uint32_t imms) -{ - uint32_t size = ENCODE (rd.is64, 1, 31); - uint32_t n = ENCODE (rd.is64, 1, 22); - - return aarch64_emit_insn (buf, UBFM | size | n | ENCODE (immr, 6, 16) - | ENCODE (imms, 6, 10) | ENCODE (rn.num, 5, 5) - | ENCODE (rd.num, 5, 0)); -} - -/* Write a UBFX instruction into *BUF. - - UBFX rd, rn, #lsb, #width - - This instruction moves #width bits from #lsb into the destination, - extending the result with zeros. This is an alias for: - - UBFM rd, rn, #lsb, #(lsb + width - 1) - - RD is the destination register. - RN is the source register. - LSB is the bit number to start at (least significant bit). - WIDTH is the number of bits to move. */ - -static int -emit_ubfx (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, uint32_t lsb, uint32_t width) -{ - return emit_ubfm (buf, rd, rn, lsb, lsb + width - 1); -} - -/* Write a CSINC instruction into *BUF. - - CSINC rd, rn, rm, cond - - This instruction conditionally increments rn or rm and places the result - in rd. rn is chosen is the condition is true. - - RD is the destination register. - RN and RM are the source registers. - COND is the encoded condition. */ - -static int -emit_csinc (uint32_t *buf, struct aarch64_register rd, - struct aarch64_register rn, struct aarch64_register rm, - unsigned cond) -{ - uint32_t size = ENCODE (rd.is64, 1, 31); - - return aarch64_emit_insn (buf, CSINC | size | ENCODE (rm.num, 5, 16) - | ENCODE (cond, 4, 12) | ENCODE (rn.num, 5, 5) - | ENCODE (rd.num, 5, 0)); -} - -/* Write a CSET instruction into *BUF. - - CSET rd, cond - - This instruction conditionally write 1 or 0 in the destination register. - 1 is written if the condition is true. This is an alias for: - - CSINC rd, xzr, xzr, !cond - - Note that the condition needs to be inverted. - - RD is the destination register. - RN and RM are the source registers. - COND is the encoded condition. */ - -static int -emit_cset (uint32_t *buf, struct aarch64_register rd, unsigned cond) -{ - /* The least significant bit of the condition needs toggling in order to - invert it. */ - return emit_csinc (buf, rd, xzr, xzr, cond ^ 0x1); -} - -/* Write LEN instructions from BUF into the inferior memory at *TO. - - Note instructions are always little endian on AArch64, unlike data. */ - -static void -append_insns (CORE_ADDR *to, size_t len, const uint32_t *buf) -{ - size_t byte_len = len * sizeof (uint32_t); -#if (__BYTE_ORDER == __BIG_ENDIAN) - uint32_t *le_buf = (uint32_t *) xmalloc (byte_len); - size_t i; - - for (i = 0; i < len; i++) - le_buf[i] = htole32 (buf[i]); - - target_write_memory (*to, (const unsigned char *) le_buf, byte_len); - - xfree (le_buf); -#else - target_write_memory (*to, (const unsigned char *) buf, byte_len); -#endif - - *to += byte_len; -} - -/* Sub-class of struct aarch64_insn_data, store information of - instruction relocation for fast tracepoint. Visitor can - relocate an instruction from BASE.INSN_ADDR to NEW_ADDR and save - the relocated instructions in buffer pointed by INSN_PTR. */ - -struct aarch64_insn_relocation_data -{ - struct aarch64_insn_data base; - - /* The new address the instruction is relocated to. */ - CORE_ADDR new_addr; - /* Pointer to the buffer of relocated instruction(s). */ - uint32_t *insn_ptr; -}; - -/* Implementation of aarch64_insn_visitor method "b". */ - -static void -aarch64_ftrace_insn_reloc_b (const int is_bl, const int32_t offset, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - int64_t new_offset - = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; - - if (can_encode_int32 (new_offset, 28)) - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, is_bl, new_offset); -} - -/* Implementation of aarch64_insn_visitor method "b_cond". */ - -static void -aarch64_ftrace_insn_reloc_b_cond (const unsigned cond, const int32_t offset, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - int64_t new_offset - = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; - - if (can_encode_int32 (new_offset, 21)) - { - insn_reloc->insn_ptr += emit_bcond (insn_reloc->insn_ptr, cond, - new_offset); - } - else if (can_encode_int32 (new_offset, 28)) - { - /* The offset is out of range for a conditional branch - instruction but not for a unconditional branch. We can use - the following instructions instead: - - B.COND TAKEN ; If cond is true, then jump to TAKEN. - B NOT_TAKEN ; Else jump over TAKEN and continue. - TAKEN: - B #(offset - 8) - NOT_TAKEN: - - */ - - insn_reloc->insn_ptr += emit_bcond (insn_reloc->insn_ptr, cond, 8); - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, 8); - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, new_offset - 8); - } -} - -/* Implementation of aarch64_insn_visitor method "cb". */ - -static void -aarch64_ftrace_insn_reloc_cb (const int32_t offset, const int is_cbnz, - const unsigned rn, int is64, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - int64_t new_offset - = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; - - if (can_encode_int32 (new_offset, 21)) - { - insn_reloc->insn_ptr += emit_cb (insn_reloc->insn_ptr, is_cbnz, - aarch64_register (rn, is64), new_offset); - } - else if (can_encode_int32 (new_offset, 28)) - { - /* The offset is out of range for a compare and branch - instruction but not for a unconditional branch. We can use - the following instructions instead: - - CBZ xn, TAKEN ; xn == 0, then jump to TAKEN. - B NOT_TAKEN ; Else jump over TAKEN and continue. - TAKEN: - B #(offset - 8) - NOT_TAKEN: - - */ - insn_reloc->insn_ptr += emit_cb (insn_reloc->insn_ptr, is_cbnz, - aarch64_register (rn, is64), 8); - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, 8); - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, new_offset - 8); - } -} - -/* Implementation of aarch64_insn_visitor method "tb". */ - -static void -aarch64_ftrace_insn_reloc_tb (const int32_t offset, int is_tbnz, - const unsigned rt, unsigned bit, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - int64_t new_offset - = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; - - if (can_encode_int32 (new_offset, 16)) - { - insn_reloc->insn_ptr += emit_tb (insn_reloc->insn_ptr, is_tbnz, bit, - aarch64_register (rt, 1), new_offset); - } - else if (can_encode_int32 (new_offset, 28)) - { - /* The offset is out of range for a test bit and branch - instruction but not for a unconditional branch. We can use - the following instructions instead: - - TBZ xn, #bit, TAKEN ; xn[bit] == 0, then jump to TAKEN. - B NOT_TAKEN ; Else jump over TAKEN and continue. - TAKEN: - B #(offset - 8) - NOT_TAKEN: - - */ - insn_reloc->insn_ptr += emit_tb (insn_reloc->insn_ptr, is_tbnz, bit, - aarch64_register (rt, 1), 8); - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, 8); - insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, - new_offset - 8); - } -} - -/* Implementation of aarch64_insn_visitor method "adr". */ - -static void -aarch64_ftrace_insn_reloc_adr (const int32_t offset, const unsigned rd, - const int is_adrp, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - /* We know exactly the address the ADR{P,} instruction will compute. - We can just write it to the destination register. */ - CORE_ADDR address = data->insn_addr + offset; - - if (is_adrp) - { - /* Clear the lower 12 bits of the offset to get the 4K page. */ - insn_reloc->insn_ptr += emit_mov_addr (insn_reloc->insn_ptr, - aarch64_register (rd, 1), - address & ~0xfff); - } - else - insn_reloc->insn_ptr += emit_mov_addr (insn_reloc->insn_ptr, - aarch64_register (rd, 1), address); -} - -/* Implementation of aarch64_insn_visitor method "ldr_literal". */ - -static void -aarch64_ftrace_insn_reloc_ldr_literal (const int32_t offset, const int is_sw, - const unsigned rt, const int is64, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - CORE_ADDR address = data->insn_addr + offset; - - insn_reloc->insn_ptr += emit_mov_addr (insn_reloc->insn_ptr, - aarch64_register (rt, 1), address); - - /* We know exactly what address to load from, and what register we - can use: - - MOV xd, #(oldloc + offset) - MOVK xd, #((oldloc + offset) >> 16), lsl #16 - ... - - LDR xd, [xd] ; or LDRSW xd, [xd] - - */ - - if (is_sw) - insn_reloc->insn_ptr += emit_ldrsw (insn_reloc->insn_ptr, - aarch64_register (rt, 1), - aarch64_register (rt, 1), - offset_memory_operand (0)); - else - insn_reloc->insn_ptr += emit_ldr (insn_reloc->insn_ptr, - aarch64_register (rt, is64), - aarch64_register (rt, 1), - offset_memory_operand (0)); -} - -/* Implementation of aarch64_insn_visitor method "others". */ - -static void -aarch64_ftrace_insn_reloc_others (const uint32_t insn, - struct aarch64_insn_data *data) -{ - struct aarch64_insn_relocation_data *insn_reloc - = (struct aarch64_insn_relocation_data *) data; - - /* The instruction is not PC relative. Just re-emit it at the new - location. */ - insn_reloc->insn_ptr += aarch64_emit_insn (insn_reloc->insn_ptr, insn); -} - -static const struct aarch64_insn_visitor visitor = -{ - aarch64_ftrace_insn_reloc_b, - aarch64_ftrace_insn_reloc_b_cond, - aarch64_ftrace_insn_reloc_cb, - aarch64_ftrace_insn_reloc_tb, - aarch64_ftrace_insn_reloc_adr, - aarch64_ftrace_insn_reloc_ldr_literal, - aarch64_ftrace_insn_reloc_others, -}; - -/* Implementation of linux_target_ops method - "install_fast_tracepoint_jump_pad". */ - -static int -aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, - CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ - uint32_t buf[256]; - uint32_t *p = buf; - int64_t offset; - int i; - uint32_t insn; - CORE_ADDR buildaddr = *jump_entry; - struct aarch64_insn_relocation_data insn_data; - - /* We need to save the current state on the stack both to restore it - later and to collect register values when the tracepoint is hit. - - The saved registers are pushed in a layout that needs to be in sync - with aarch64_ft_collect_regmap (see linux-aarch64-ipa.c). Later on - the supply_fast_tracepoint_registers function will fill in the - register cache from a pointer to saved registers on the stack we build - here. - - For simplicity, we set the size of each cell on the stack to 16 bytes. - This way one cell can hold any register type, from system registers - to the 128 bit SIMD&FP registers. Furthermore, the stack pointer - has to be 16 bytes aligned anyway. - - Note that the CPSR register does not exist on AArch64. Instead we - can access system bits describing the process state with the - MRS/MSR instructions, namely the condition flags. We save them as - if they are part of a CPSR register because that's how GDB - interprets these system bits. At the moment, only the condition - flags are saved in CPSR (NZCV). - - Stack layout, each cell is 16 bytes (descending): - - High *-------- SIMD&FP registers from 31 down to 0. --------* - | q31 | - . . - . . 32 cells - . . - | q0 | - *---- General purpose registers from 30 down to 0. ----* - | x30 | - . . - . . 31 cells - . . - | x0 | - *------------- Special purpose registers. -------------* - | SP | - | PC | - | CPSR (NZCV) | 5 cells - | FPSR | - | FPCR | <- SP + 16 - *------------- collecting_t object --------------------* - | TPIDR_EL0 | struct tracepoint * | - Low *------------------------------------------------------* - - After this stack is set up, we issue a call to the collector, passing - it the saved registers at (SP + 16). */ - - /* Push SIMD&FP registers on the stack: - - SUB sp, sp, #(32 * 16) - - STP q30, q31, [sp, #(30 * 16)] - ... - STP q0, q1, [sp] - - */ - p += emit_sub (p, sp, sp, immediate_operand (32 * 16)); - for (i = 30; i >= 0; i -= 2) - p += emit_stp_q_offset (p, i, i + 1, sp, i * 16); - - /* Push general purpose registers on the stack. Note that we do not need - to push x31 as it represents the xzr register and not the stack - pointer in a STR instruction. - - SUB sp, sp, #(31 * 16) - - STR x30, [sp, #(30 * 16)] - ... - STR x0, [sp] - - */ - p += emit_sub (p, sp, sp, immediate_operand (31 * 16)); - for (i = 30; i >= 0; i -= 1) - p += emit_str (p, aarch64_register (i, 1), sp, - offset_memory_operand (i * 16)); - - /* Make space for 5 more cells. - - SUB sp, sp, #(5 * 16) - - */ - p += emit_sub (p, sp, sp, immediate_operand (5 * 16)); - - - /* Save SP: - - ADD x4, sp, #((32 + 31 + 5) * 16) - STR x4, [sp, #(4 * 16)] - - */ - p += emit_add (p, x4, sp, immediate_operand ((32 + 31 + 5) * 16)); - p += emit_str (p, x4, sp, offset_memory_operand (4 * 16)); - - /* Save PC (tracepoint address): - - MOV x3, #(tpaddr) - ... - - STR x3, [sp, #(3 * 16)] - - */ - - p += emit_mov_addr (p, x3, tpaddr); - p += emit_str (p, x3, sp, offset_memory_operand (3 * 16)); - - /* Save CPSR (NZCV), FPSR and FPCR: - - MRS x2, nzcv - MRS x1, fpsr - MRS x0, fpcr - - STR x2, [sp, #(2 * 16)] - STR x1, [sp, #(1 * 16)] - STR x0, [sp, #(0 * 16)] - - */ - p += emit_mrs (p, x2, NZCV); - p += emit_mrs (p, x1, FPSR); - p += emit_mrs (p, x0, FPCR); - p += emit_str (p, x2, sp, offset_memory_operand (2 * 16)); - p += emit_str (p, x1, sp, offset_memory_operand (1 * 16)); - p += emit_str (p, x0, sp, offset_memory_operand (0 * 16)); - - /* Push the collecting_t object. It consist of the address of the - tracepoint and an ID for the current thread. We get the latter by - reading the tpidr_el0 system register. It corresponds to the - NT_ARM_TLS register accessible with ptrace. - - MOV x0, #(tpoint) - ... - - MRS x1, tpidr_el0 - - STP x0, x1, [sp, #-16]! - - */ - - p += emit_mov_addr (p, x0, tpoint); - p += emit_mrs (p, x1, TPIDR_EL0); - p += emit_stp (p, x0, x1, sp, preindex_memory_operand (-16)); - - /* Spin-lock: - - The shared memory for the lock is at lockaddr. It will hold zero - if no-one is holding the lock, otherwise it contains the address of - the collecting_t object on the stack of the thread which acquired it. - - At this stage, the stack pointer points to this thread's collecting_t - object. - - We use the following registers: - - x0: Address of the lock. - - x1: Pointer to collecting_t object. - - x2: Scratch register. - - MOV x0, #(lockaddr) - ... - MOV x1, sp - - ; Trigger an event local to this core. So the following WFE - ; instruction is ignored. - SEVL - again: - ; Wait for an event. The event is triggered by either the SEVL - ; or STLR instructions (store release). - WFE - - ; Atomically read at lockaddr. This marks the memory location as - ; exclusive. This instruction also has memory constraints which - ; make sure all previous data reads and writes are done before - ; executing it. - LDAXR x2, [x0] - - ; Try again if another thread holds the lock. - CBNZ x2, again - - ; We can lock it! Write the address of the collecting_t object. - ; This instruction will fail if the memory location is not marked - ; as exclusive anymore. If it succeeds, it will remove the - ; exclusive mark on the memory location. This way, if another - ; thread executes this instruction before us, we will fail and try - ; all over again. - STXR w2, x1, [x0] - CBNZ w2, again - - */ - - p += emit_mov_addr (p, x0, lockaddr); - p += emit_mov (p, x1, register_operand (sp)); - - p += emit_sevl (p); - p += emit_wfe (p); - p += emit_ldaxr (p, x2, x0); - p += emit_cb (p, 1, w2, -2 * 4); - p += emit_stxr (p, w2, x1, x0); - p += emit_cb (p, 1, x2, -4 * 4); - - /* Call collector (struct tracepoint *, unsigned char *): - - MOV x0, #(tpoint) - ... - - ; Saved registers start after the collecting_t object. - ADD x1, sp, #16 - - ; We use an intra-procedure-call scratch register. - MOV ip0, #(collector) - ... - - ; And call back to C! - BLR ip0 - - */ - - p += emit_mov_addr (p, x0, tpoint); - p += emit_add (p, x1, sp, immediate_operand (16)); - - p += emit_mov_addr (p, ip0, collector); - p += emit_blr (p, ip0); - - /* Release the lock. - - MOV x0, #(lockaddr) - ... - - ; This instruction is a normal store with memory ordering - ; constraints. Thanks to this we do not have to put a data - ; barrier instruction to make sure all data read and writes are done - ; before this instruction is executed. Furthermore, this instruction - ; will trigger an event, letting other threads know they can grab - ; the lock. - STLR xzr, [x0] - - */ - p += emit_mov_addr (p, x0, lockaddr); - p += emit_stlr (p, xzr, x0); - - /* Free collecting_t object: - - ADD sp, sp, #16 - - */ - p += emit_add (p, sp, sp, immediate_operand (16)); - - /* Restore CPSR (NZCV), FPSR and FPCR. And free all special purpose - registers from the stack. - - LDR x2, [sp, #(2 * 16)] - LDR x1, [sp, #(1 * 16)] - LDR x0, [sp, #(0 * 16)] - - MSR NZCV, x2 - MSR FPSR, x1 - MSR FPCR, x0 - - ADD sp, sp #(5 * 16) - - */ - p += emit_ldr (p, x2, sp, offset_memory_operand (2 * 16)); - p += emit_ldr (p, x1, sp, offset_memory_operand (1 * 16)); - p += emit_ldr (p, x0, sp, offset_memory_operand (0 * 16)); - p += emit_msr (p, NZCV, x2); - p += emit_msr (p, FPSR, x1); - p += emit_msr (p, FPCR, x0); - - p += emit_add (p, sp, sp, immediate_operand (5 * 16)); - - /* Pop general purpose registers: - - LDR x0, [sp] - ... - LDR x30, [sp, #(30 * 16)] - - ADD sp, sp, #(31 * 16) - - */ - for (i = 0; i <= 30; i += 1) - p += emit_ldr (p, aarch64_register (i, 1), sp, - offset_memory_operand (i * 16)); - p += emit_add (p, sp, sp, immediate_operand (31 * 16)); - - /* Pop SIMD&FP registers: - - LDP q0, q1, [sp] - ... - LDP q30, q31, [sp, #(30 * 16)] - - ADD sp, sp, #(32 * 16) - - */ - for (i = 0; i <= 30; i += 2) - p += emit_ldp_q_offset (p, i, i + 1, sp, i * 16); - p += emit_add (p, sp, sp, immediate_operand (32 * 16)); - - /* Write the code into the inferior memory. */ - append_insns (&buildaddr, p - buf, buf); - - /* Now emit the relocated instruction. */ - *adjusted_insn_addr = buildaddr; - target_read_uint32 (tpaddr, &insn); - - insn_data.base.insn_addr = tpaddr; - insn_data.new_addr = buildaddr; - insn_data.insn_ptr = buf; - - aarch64_relocate_instruction (insn, &visitor, - (struct aarch64_insn_data *) &insn_data); - - /* We may not have been able to relocate the instruction. */ - if (insn_data.insn_ptr == buf) - { - sprintf (err, - "E.Could not relocate instruction from %s to %s.", - core_addr_to_string_nz (tpaddr), - core_addr_to_string_nz (buildaddr)); - return 1; - } - else - append_insns (&buildaddr, insn_data.insn_ptr - buf, buf); - *adjusted_insn_addr_end = buildaddr; - - /* Go back to the start of the buffer. */ - p = buf; - - /* Emit a branch back from the jump pad. */ - offset = (tpaddr + orig_size - buildaddr); - if (!can_encode_int32 (offset, 28)) - { - sprintf (err, - "E.Jump back from jump pad too far from tracepoint " - "(offset 0x%" PRIx64 " cannot be encoded in 28 bits).", - offset); - return 1; - } - - p += emit_b (p, 0, offset); - append_insns (&buildaddr, p - buf, buf); - - /* Give the caller a branch instruction into the jump pad. */ - offset = (*jump_entry - tpaddr); - if (!can_encode_int32 (offset, 28)) - { - sprintf (err, - "E.Jump pad too far from tracepoint " - "(offset 0x%" PRIx64 " cannot be encoded in 28 bits).", - offset); - return 1; - } - - emit_b ((uint32_t *) jjump_pad_insn, 0, offset); - *jjump_pad_insn_size = 4; - - /* Return the end address of our pad. */ - *jump_entry = buildaddr; - - return 0; -} - -/* Helper function writing LEN instructions from START into - current_insn_ptr. */ - -static void -emit_ops_insns (const uint32_t *start, int len) -{ - CORE_ADDR buildaddr = current_insn_ptr; - - if (debug_threads) - debug_printf ("Adding %d instrucions at %s\n", - len, paddress (buildaddr)); - - append_insns (&buildaddr, len, start); - current_insn_ptr = buildaddr; -} - -/* Pop a register from the stack. */ - -static int -emit_pop (uint32_t *buf, struct aarch64_register rt) -{ - return emit_ldr (buf, rt, sp, postindex_memory_operand (1 * 16)); -} - -/* Push a register on the stack. */ - -static int -emit_push (uint32_t *buf, struct aarch64_register rt) -{ - return emit_str (buf, rt, sp, preindex_memory_operand (-1 * 16)); -} - -/* Implementation of emit_ops method "emit_prologue". */ - -static void -aarch64_emit_prologue (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* This function emit a prologue for the following function prototype: - - enum eval_result_type f (unsigned char *regs, - ULONGEST *value); - - The first argument is a buffer of raw registers. The second - argument is the result of - evaluating the expression, which will be set to whatever is on top of - the stack at the end. - - The stack set up by the prologue is as such: - - High *------------------------------------------------------* - | LR | - | FP | <- FP - | x1 (ULONGEST *value) | - | x0 (unsigned char *regs) | - Low *------------------------------------------------------* - - As we are implementing a stack machine, each opcode can expand the - stack so we never know how far we are from the data saved by this - prologue. In order to be able refer to value and regs later, we save - the current stack pointer in the frame pointer. This way, it is not - clobbered when calling C functions. - - Finally, throughout every operation, we are using register x0 as the - top of the stack, and x1 as a scratch register. */ - - p += emit_stp (p, x0, x1, sp, preindex_memory_operand (-2 * 16)); - p += emit_str (p, lr, sp, offset_memory_operand (3 * 8)); - p += emit_str (p, fp, sp, offset_memory_operand (2 * 8)); - - p += emit_add (p, fp, sp, immediate_operand (2 * 8)); - - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_epilogue". */ - -static void -aarch64_emit_epilogue (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* Store the result of the expression (x0) in *value. */ - p += emit_sub (p, x1, fp, immediate_operand (1 * 8)); - p += emit_ldr (p, x1, x1, offset_memory_operand (0)); - p += emit_str (p, x0, x1, offset_memory_operand (0)); - - /* Restore the previous state. */ - p += emit_add (p, sp, fp, immediate_operand (2 * 8)); - p += emit_ldp (p, fp, lr, fp, offset_memory_operand (0)); - - /* Return expr_eval_no_error. */ - p += emit_mov (p, x0, immediate_operand (expr_eval_no_error)); - p += emit_ret (p, lr); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_add". */ - -static void -aarch64_emit_add (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_add (p, x0, x1, register_operand (x0)); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_sub". */ - -static void -aarch64_emit_sub (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_sub (p, x0, x1, register_operand (x0)); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_mul". */ - -static void -aarch64_emit_mul (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_mul (p, x0, x1, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_lsh". */ - -static void -aarch64_emit_lsh (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_lslv (p, x0, x1, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_rsh_signed". */ - -static void -aarch64_emit_rsh_signed (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_asrv (p, x0, x1, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_rsh_unsigned". */ - -static void -aarch64_emit_rsh_unsigned (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_lsrv (p, x0, x1, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_ext". */ - -static void -aarch64_emit_ext (int arg) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_sbfx (p, x0, x0, 0, arg); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_log_not". */ - -static void -aarch64_emit_log_not (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* If the top of the stack is 0, replace it with 1. Else replace it with - 0. */ - - p += emit_cmp (p, x0, immediate_operand (0)); - p += emit_cset (p, x0, EQ); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_bit_and". */ - -static void -aarch64_emit_bit_and (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_and (p, x0, x0, x1); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_bit_or". */ - -static void -aarch64_emit_bit_or (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_orr (p, x0, x0, x1); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_bit_xor". */ - -static void -aarch64_emit_bit_xor (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_eor (p, x0, x0, x1); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_bit_not". */ - -static void -aarch64_emit_bit_not (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_mvn (p, x0, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_equal". */ - -static void -aarch64_emit_equal (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x0, register_operand (x1)); - p += emit_cset (p, x0, EQ); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_less_signed". */ - -static void -aarch64_emit_less_signed (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - p += emit_cset (p, x0, LT); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_less_unsigned". */ - -static void -aarch64_emit_less_unsigned (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - p += emit_cset (p, x0, LO); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_ref". */ - -static void -aarch64_emit_ref (int size) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - switch (size) - { - case 1: - p += emit_ldrb (p, w0, x0, offset_memory_operand (0)); - break; - case 2: - p += emit_ldrh (p, w0, x0, offset_memory_operand (0)); - break; - case 4: - p += emit_ldr (p, w0, x0, offset_memory_operand (0)); - break; - case 8: - p += emit_ldr (p, x0, x0, offset_memory_operand (0)); - break; - default: - /* Unknown size, bail on compilation. */ - emit_error = 1; - break; - } - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_if_goto". */ - -static void -aarch64_emit_if_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* The Z flag is set or cleared here. */ - p += emit_cmp (p, x0, immediate_operand (0)); - /* This instruction must not change the Z flag. */ - p += emit_pop (p, x0); - /* Branch over the next instruction if x0 == 0. */ - p += emit_bcond (p, EQ, 8); - - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_goto". */ - -static void -aarch64_emit_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = 0; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "write_goto_address". */ - -static void -aarch64_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) -{ - uint32_t insn; - - emit_b (&insn, 0, to - from); - append_insns (&from, 1, &insn); -} - -/* Implementation of emit_ops method "emit_const". */ - -static void -aarch64_emit_const (LONGEST num) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_mov_addr (p, x0, num); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_call". */ - -static void -aarch64_emit_call (CORE_ADDR fn) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_mov_addr (p, ip0, fn); - p += emit_blr (p, ip0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_reg". */ - -static void -aarch64_emit_reg (int reg) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* Set x0 to unsigned char *regs. */ - p += emit_sub (p, x0, fp, immediate_operand (2 * 8)); - p += emit_ldr (p, x0, x0, offset_memory_operand (0)); - p += emit_mov (p, x1, immediate_operand (reg)); - - emit_ops_insns (buf, p - buf); - - aarch64_emit_call (get_raw_reg_func_addr ()); -} - -/* Implementation of emit_ops method "emit_pop". */ - -static void -aarch64_emit_pop (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_stack_flush". */ - -static void -aarch64_emit_stack_flush (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_push (p, x0); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_zero_ext". */ - -static void -aarch64_emit_zero_ext (int arg) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_ubfx (p, x0, x0, 0, arg); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_swap". */ - -static void -aarch64_emit_swap (void) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_ldr (p, x1, sp, offset_memory_operand (0 * 16)); - p += emit_str (p, x0, sp, offset_memory_operand (0 * 16)); - p += emit_mov (p, x0, register_operand (x1)); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_stack_adjust". */ - -static void -aarch64_emit_stack_adjust (int n) -{ - /* This is not needed with our design. */ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_add (p, sp, sp, immediate_operand (n * 16)); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_int_call_1". */ - -static void -aarch64_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_mov (p, x0, immediate_operand (arg1)); - - emit_ops_insns (buf, p - buf); - - aarch64_emit_call (fn); -} - -/* Implementation of emit_ops method "emit_void_call_2". */ - -static void -aarch64_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - /* Push x0 on the stack. */ - aarch64_emit_stack_flush (); - - /* Setup arguments for the function call: - - x0: arg1 - x1: top of the stack - - MOV x1, x0 - MOV x0, #arg1 */ - - p += emit_mov (p, x1, register_operand (x0)); - p += emit_mov (p, x0, immediate_operand (arg1)); - - emit_ops_insns (buf, p - buf); - - aarch64_emit_call (fn); - - /* Restore x0. */ - aarch64_emit_pop (); -} - -/* Implementation of emit_ops method "emit_eq_goto". */ - -static void -aarch64_emit_eq_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - /* Branch over the next instruction if x0 != x1. */ - p += emit_bcond (p, NE, 8); - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_ne_goto". */ - -static void -aarch64_emit_ne_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - /* Branch over the next instruction if x0 == x1. */ - p += emit_bcond (p, EQ, 8); - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_lt_goto". */ - -static void -aarch64_emit_lt_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - /* Branch over the next instruction if x0 >= x1. */ - p += emit_bcond (p, GE, 8); - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_le_goto". */ - -static void -aarch64_emit_le_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - /* Branch over the next instruction if x0 > x1. */ - p += emit_bcond (p, GT, 8); - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_gt_goto". */ - -static void -aarch64_emit_gt_goto (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - /* Branch over the next instruction if x0 <= x1. */ - p += emit_bcond (p, LE, 8); - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -/* Implementation of emit_ops method "emit_ge_got". */ - -static void -aarch64_emit_ge_got (int *offset_p, int *size_p) -{ - uint32_t buf[16]; - uint32_t *p = buf; - - p += emit_pop (p, x1); - p += emit_cmp (p, x1, register_operand (x0)); - /* Branch over the next instruction if x0 <= x1. */ - p += emit_bcond (p, LT, 8); - /* The NOP instruction will be patched with an unconditional branch. */ - if (offset_p) - *offset_p = (p - buf) * 4; - if (size_p) - *size_p = 4; - p += emit_nop (p); - - emit_ops_insns (buf, p - buf); -} - -static struct emit_ops aarch64_emit_ops_impl = -{ - aarch64_emit_prologue, - aarch64_emit_epilogue, - aarch64_emit_add, - aarch64_emit_sub, - aarch64_emit_mul, - aarch64_emit_lsh, - aarch64_emit_rsh_signed, - aarch64_emit_rsh_unsigned, - aarch64_emit_ext, - aarch64_emit_log_not, - aarch64_emit_bit_and, - aarch64_emit_bit_or, - aarch64_emit_bit_xor, - aarch64_emit_bit_not, - aarch64_emit_equal, - aarch64_emit_less_signed, - aarch64_emit_less_unsigned, - aarch64_emit_ref, - aarch64_emit_if_goto, - aarch64_emit_goto, - aarch64_write_goto_address, - aarch64_emit_const, - aarch64_emit_call, - aarch64_emit_reg, - aarch64_emit_pop, - aarch64_emit_stack_flush, - aarch64_emit_zero_ext, - aarch64_emit_swap, - aarch64_emit_stack_adjust, - aarch64_emit_int_call_1, - aarch64_emit_void_call_2, - aarch64_emit_eq_goto, - aarch64_emit_ne_goto, - aarch64_emit_lt_goto, - aarch64_emit_le_goto, - aarch64_emit_gt_goto, - aarch64_emit_ge_got, -}; - -/* Implementation of linux_target_ops method "emit_ops". */ - -static struct emit_ops * -aarch64_emit_ops (void) -{ - return &aarch64_emit_ops_impl; -} - -/* Implementation of linux_target_ops method - "get_min_fast_tracepoint_insn_len". */ - -static int -aarch64_get_min_fast_tracepoint_insn_len (void) -{ - return 4; -} - -/* Implementation of linux_target_ops method "supports_range_stepping". */ - -static int -aarch64_supports_range_stepping (void) -{ - return 1; -} - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -aarch64_sw_breakpoint_from_kind (int kind, int *size) -{ - if (is_64bit_tdesc ()) - { - *size = aarch64_breakpoint_len; - return aarch64_breakpoint; - } - else - return arm_sw_breakpoint_from_kind (kind, size); -} - -/* Implementation of linux_target_ops method "breakpoint_kind_from_pc". */ - -static int -aarch64_breakpoint_kind_from_pc (CORE_ADDR *pcptr) -{ - if (is_64bit_tdesc ()) - return aarch64_breakpoint_len; - else - return arm_breakpoint_kind_from_pc (pcptr); -} - -/* Implementation of the linux_target_ops method - "breakpoint_kind_from_current_state". */ - -static int -aarch64_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) -{ - if (is_64bit_tdesc ()) - return aarch64_breakpoint_len; - else - return arm_breakpoint_kind_from_current_state (pcptr); -} - -/* Support for hardware single step. */ - -static int -aarch64_supports_hardware_single_step (void) -{ - return 1; -} - -struct linux_target_ops the_low_target = -{ - aarch64_arch_setup, - aarch64_regs_info, - NULL, /* cannot_fetch_register */ - NULL, /* cannot_store_register */ - NULL, /* fetch_register */ - aarch64_get_pc, - aarch64_set_pc, - aarch64_breakpoint_kind_from_pc, - aarch64_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, /* decr_pc_after_break */ - aarch64_breakpoint_at, - aarch64_supports_z_point_type, - aarch64_insert_point, - aarch64_remove_point, - aarch64_stopped_by_watchpoint, - aarch64_stopped_data_address, - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - aarch64_linux_siginfo_fixup, - aarch64_linux_new_process, - aarch64_linux_delete_process, - aarch64_linux_new_thread, - aarch64_linux_delete_thread, - aarch64_linux_new_fork, - aarch64_linux_prepare_to_resume, - NULL, /* process_qsupported */ - aarch64_supports_tracepoints, - aarch64_get_thread_area, - aarch64_install_fast_tracepoint_jump_pad, - aarch64_emit_ops, - aarch64_get_min_fast_tracepoint_insn_len, - aarch64_supports_range_stepping, - aarch64_breakpoint_kind_from_current_state, - aarch64_supports_hardware_single_step, - aarch64_get_syscall_trapinfo, -}; - -void -initialize_low_arch (void) -{ - initialize_low_arch_aarch32 (); - - initialize_regsets_info (&aarch64_regsets_info); - initialize_regsets_info (&aarch64_sve_regsets_info); -} diff --git a/gdb/gdbserver/linux-aarch64-tdesc.c b/gdb/gdbserver/linux-aarch64-tdesc.c deleted file mode 100644 index 897fbb43bd2..00000000000 --- a/gdb/gdbserver/linux-aarch64-tdesc.c +++ /dev/null @@ -1,60 +0,0 @@ -/* GNU/Linux/aarch64 specific target description, for the remote server - for GDB. - Copyright (C) 2017-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" - -#include "linux-aarch64-tdesc.h" - -#include "tdesc.h" -#include "arch/aarch64.h" -#include "linux-aarch32-low.h" -#include - -/* All possible aarch64 target descriptors. */ -struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/]; - -/* Create the aarch64 target description. */ - -const target_desc * -aarch64_linux_read_description (uint64_t vq, bool pauth_p) -{ - if (vq > AARCH64_MAX_SVE_VQ) - error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq, - AARCH64_MAX_SVE_VQ); - - struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p]; - - if (tdesc == NULL) - { - tdesc = aarch64_create_target_description (vq, pauth_p); - - static const char *expedite_regs_aarch64[] = { "x29", "sp", "pc", NULL }; - static const char *expedite_regs_aarch64_sve[] = { "x29", "sp", "pc", - "vg", NULL }; - - if (vq == 0) - init_target_desc (tdesc, expedite_regs_aarch64); - else - init_target_desc (tdesc, expedite_regs_aarch64_sve); - - tdesc_aarch64_list[vq][pauth_p] = tdesc; - } - - return tdesc; -} diff --git a/gdb/gdbserver/linux-aarch64-tdesc.h b/gdb/gdbserver/linux-aarch64-tdesc.h deleted file mode 100644 index 0165e633d4c..00000000000 --- a/gdb/gdbserver/linux-aarch64-tdesc.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Low level support for aarch64, shared between gdbserver and IPA. - - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_AARCH64_TDESC_H -#define GDBSERVER_LINUX_AARCH64_TDESC_H - -const target_desc * aarch64_linux_read_description (uint64_t vq, bool pauth_p); - -#endif /* GDBSERVER_LINUX_AARCH64_TDESC_H */ diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c deleted file mode 100644 index 53d98f26121..00000000000 --- a/gdb/gdbserver/linux-amd64-ipa.c +++ /dev/null @@ -1,289 +0,0 @@ -/* GNU/Linux/x86-64 specific low level interface, for the in-process - agent library for GDB. - - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include -#include "tracepoint.h" -#include "linux-x86-tdesc.h" -#include "gdbsupport/x86-xstate.h" - -/* Defined in auto-generated file amd64-linux.c. */ -void init_registers_amd64_linux (void); -extern const struct target_desc *tdesc_amd64_linux; - -/* fast tracepoints collect registers. */ - -#define FT_CR_RIP 0 -#define FT_CR_EFLAGS 1 -#define FT_CR_R8 2 -#define FT_CR_R9 3 -#define FT_CR_R10 4 -#define FT_CR_R11 5 -#define FT_CR_R12 6 -#define FT_CR_R13 7 -#define FT_CR_R14 8 -#define FT_CR_R15 9 -#define FT_CR_RAX 10 -#define FT_CR_RBX 11 -#define FT_CR_RCX 12 -#define FT_CR_RDX 13 -#define FT_CR_RSI 14 -#define FT_CR_RDI 15 -#define FT_CR_RBP 16 -#define FT_CR_RSP 17 - -static const int x86_64_ft_collect_regmap[] = { - FT_CR_RAX * 8, FT_CR_RBX * 8, FT_CR_RCX * 8, FT_CR_RDX * 8, - FT_CR_RSI * 8, FT_CR_RDI * 8, FT_CR_RBP * 8, FT_CR_RSP * 8, - FT_CR_R8 * 8, FT_CR_R9 * 8, FT_CR_R10 * 8, FT_CR_R11 * 8, - FT_CR_R12 * 8, FT_CR_R13 * 8, FT_CR_R14 * 8, FT_CR_R15 * 8, - FT_CR_RIP * 8, FT_CR_EFLAGS * 8 -}; - -#define X86_64_NUM_FT_COLLECT_GREGS \ - (sizeof (x86_64_ft_collect_regmap) / sizeof(x86_64_ft_collect_regmap[0])) - -void -supply_fast_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf) -{ - int i; - - for (i = 0; i < X86_64_NUM_FT_COLLECT_GREGS; i++) - supply_register (regcache, i, - ((char *) buf) + x86_64_ft_collect_regmap[i]); -} - -ULONGEST -get_raw_reg (const unsigned char *raw_regs, int regnum) -{ - if (regnum >= X86_64_NUM_FT_COLLECT_GREGS) - return 0; - - return *(ULONGEST *) (raw_regs + x86_64_ft_collect_regmap[regnum]); -} - -#ifdef HAVE_UST - -#include - -/* "struct registers" is the UST object type holding the registers at - the time of the static tracepoint marker call. This doesn't - contain RIP, but we know what it must have been (the marker - address). */ - -#define ST_REGENTRY(REG) \ - { \ - offsetof (struct registers, REG), \ - sizeof (((struct registers *) NULL)->REG) \ - } - -static struct -{ - int offset; - int size; -} x86_64_st_collect_regmap[] = - { - ST_REGENTRY(rax), - ST_REGENTRY(rbx), - ST_REGENTRY(rcx), - ST_REGENTRY(rdx), - ST_REGENTRY(rsi), - ST_REGENTRY(rdi), - ST_REGENTRY(rbp), - ST_REGENTRY(rsp), - ST_REGENTRY(r8), - ST_REGENTRY(r9), - ST_REGENTRY(r10), - ST_REGENTRY(r11), - ST_REGENTRY(r12), - ST_REGENTRY(r13), - ST_REGENTRY(r14), - ST_REGENTRY(r15), - { -1, 0 }, - ST_REGENTRY(rflags), - ST_REGENTRY(cs), - ST_REGENTRY(ss), - }; - -#define X86_64_NUM_ST_COLLECT_GREGS \ - (sizeof (x86_64_st_collect_regmap) / sizeof (x86_64_st_collect_regmap[0])) - -/* GDB's RIP register number. */ -#define AMD64_RIP_REGNUM 16 - -void -supply_static_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf, - CORE_ADDR pc) -{ - int i; - unsigned long newpc = pc; - - supply_register (regcache, AMD64_RIP_REGNUM, &newpc); - - for (i = 0; i < X86_64_NUM_ST_COLLECT_GREGS; i++) - if (x86_64_st_collect_regmap[i].offset != -1) - { - switch (x86_64_st_collect_regmap[i].size) - { - case 8: - supply_register (regcache, i, - ((char *) buf) - + x86_64_st_collect_regmap[i].offset); - break; - case 2: - { - unsigned long reg - = * (short *) (((char *) buf) - + x86_64_st_collect_regmap[i].offset); - reg &= 0xffff; - supply_register (regcache, i, ®); - } - break; - default: - internal_error (__FILE__, __LINE__, - "unhandled register size: %d", - x86_64_st_collect_regmap[i].size); - break; - } - } -} - -#endif /* HAVE_UST */ - -#if !defined __ILP32__ -/* Map the tdesc index to xcr0 mask. */ -static uint64_t idx2mask[X86_TDESC_LAST] = { - X86_XSTATE_X87_MASK, - X86_XSTATE_SSE_MASK, - X86_XSTATE_AVX_MASK, - X86_XSTATE_MPX_MASK, - X86_XSTATE_AVX_MPX_MASK, - X86_XSTATE_AVX_AVX512_MASK, - X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, -}; -#endif - -/* Return target_desc to use for IPA, given the tdesc index passed by - gdbserver. */ - -const struct target_desc * -get_ipa_tdesc (int idx) -{ - if (idx >= X86_TDESC_LAST) - { - internal_error (__FILE__, __LINE__, - "unknown ipa tdesc index: %d", idx); - } - -#if defined __ILP32__ - switch (idx) - { - case X86_TDESC_SSE: - return amd64_linux_read_description (X86_XSTATE_SSE_MASK, true); - case X86_TDESC_AVX: - return amd64_linux_read_description (X86_XSTATE_AVX_MASK, true); - case X86_TDESC_AVX_AVX512: - return amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true); - default: - break; - } -#else - return amd64_linux_read_description (idx2mask[idx], false); -#endif - - internal_error (__FILE__, __LINE__, - "unknown ipa tdesc index: %d", idx); -} - -/* Allocate buffer for the jump pads. The branch instruction has a - reach of +/- 31-bit, and the executable is loaded at low addresses. - - 64-bit: Use MAP_32BIT to allocate in the first 2GB. Shared - libraries, being allocated at the top, are unfortunately out of - luck. - - x32: Since MAP_32BIT is 64-bit only, do the placement manually. - Try allocating at '0x80000000 - SIZE' initially, decreasing until - we hit a free area. This ensures the executable is fully covered, - and is as close as possible to the shared libraries, which are - usually mapped at the top of the first 4GB of the address space. -*/ - -void * -alloc_jump_pad_buffer (size_t size) -{ -#if __ILP32__ - uintptr_t addr; - int pagesize; - - pagesize = sysconf (_SC_PAGE_SIZE); - if (pagesize == -1) - perror_with_name ("sysconf"); - - addr = 0x80000000 - size; - - /* size should already be page-aligned, but this can't hurt. */ - addr &= ~(pagesize - 1); - - /* Search for a free area. If we hit 0, we're out of luck. */ - for (; addr; addr -= pagesize) - { - void *res; - - /* No MAP_FIXED - we don't want to zap someone's mapping. */ - res = mmap ((void *) addr, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* If we got what we wanted, return. */ - if ((uintptr_t) res == addr) - return res; - - /* If we got a mapping, but at a wrong address, undo it. */ - if (res != MAP_FAILED) - munmap (res, size); - } - - return NULL; -#else - void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); - - if (res == MAP_FAILED) - return NULL; - - return res; -#endif -} - -void -initialize_low_tracepoint (void) -{ -#if defined __ILP32__ - amd64_linux_read_description (X86_XSTATE_SSE_MASK, true); - amd64_linux_read_description (X86_XSTATE_AVX_MASK, true); - amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true); -#else - for (auto i = 0; i < X86_TDESC_LAST; i++) - amd64_linux_read_description (idx2mask[i], false); -#endif -} diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c deleted file mode 100644 index 9f046c098bf..00000000000 --- a/gdb/gdbserver/linux-arm-low.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* GNU/Linux/ARM specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "arch/arm.h" -#include "arch/arm-linux.h" -#include "arch/arm-get-next-pcs.h" -#include "linux-aarch32-low.h" -#include "linux-aarch32-tdesc.h" -#include "linux-arm-tdesc.h" - -#include -/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h. - On Bionic elf.h and linux/elf.h have conflicting definitions. */ -#ifndef ELFMAG0 -#include -#endif -#include "nat/gdb_ptrace.h" -#include -#include - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 22 -#endif - -#ifndef PTRACE_GETWMMXREGS -# define PTRACE_GETWMMXREGS 18 -# define PTRACE_SETWMMXREGS 19 -#endif - -#ifndef PTRACE_GETVFPREGS -# define PTRACE_GETVFPREGS 27 -# define PTRACE_SETVFPREGS 28 -#endif - -#ifndef PTRACE_GETHBPREGS -#define PTRACE_GETHBPREGS 29 -#define PTRACE_SETHBPREGS 30 -#endif - -/* Information describing the hardware breakpoint capabilities. */ -static struct -{ - unsigned char arch; - unsigned char max_wp_length; - unsigned char wp_count; - unsigned char bp_count; -} arm_linux_hwbp_cap; - -/* Enum describing the different types of ARM hardware break-/watch-points. */ -typedef enum -{ - arm_hwbp_break = 0, - arm_hwbp_load = 1, - arm_hwbp_store = 2, - arm_hwbp_access = 3 -} arm_hwbp_type; - -/* Type describing an ARM Hardware Breakpoint Control register value. */ -typedef unsigned int arm_hwbp_control_t; - -/* Structure used to keep track of hardware break-/watch-points. */ -struct arm_linux_hw_breakpoint -{ - /* Address to break on, or being watched. */ - unsigned int address; - /* Control register for break-/watch- point. */ - arm_hwbp_control_t control; -}; - -/* Since we cannot dynamically allocate subfields of arch_process_info, - assume a maximum number of supported break-/watchpoints. */ -#define MAX_BPTS 32 -#define MAX_WPTS 32 - -/* Per-process arch-specific data we want to keep. */ -struct arch_process_info -{ - /* Hardware breakpoints for this process. */ - struct arm_linux_hw_breakpoint bpts[MAX_BPTS]; - /* Hardware watchpoints for this process. */ - struct arm_linux_hw_breakpoint wpts[MAX_WPTS]; -}; - -/* Per-thread arch-specific data we want to keep. */ -struct arch_lwp_info -{ - /* Non-zero if our copy differs from what's recorded in the thread. */ - char bpts_changed[MAX_BPTS]; - char wpts_changed[MAX_WPTS]; - /* Cached stopped data address. */ - CORE_ADDR stopped_data_address; -}; - -/* These are in in current kernels. */ -#define HWCAP_VFP 64 -#define HWCAP_IWMMXT 512 -#define HWCAP_NEON 4096 -#define HWCAP_VFPv3 8192 -#define HWCAP_VFPv3D16 16384 - -#ifdef HAVE_SYS_REG_H -#include -#endif - -#define arm_num_regs 26 - -static int arm_regmap[] = { - 0, 4, 8, 12, 16, 20, 24, 28, - 32, 36, 40, 44, 48, 52, 56, 60, - -1, -1, -1, -1, -1, -1, -1, -1, -1, - 64 -}; - -/* Forward declarations needed for get_next_pcs ops. */ -static ULONGEST get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, - int len, - int byte_order); - -static CORE_ADDR get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, - CORE_ADDR val); - -static CORE_ADDR get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self); - -static int get_next_pcs_is_thumb (struct arm_get_next_pcs *self); - -/* get_next_pcs operations. */ -static struct arm_get_next_pcs_ops get_next_pcs_ops = { - get_next_pcs_read_memory_unsigned_integer, - get_next_pcs_syscall_next_pc, - get_next_pcs_addr_bits_remove, - get_next_pcs_is_thumb, - arm_linux_get_next_pcs_fixup, -}; - -static int -arm_cannot_store_register (int regno) -{ - return (regno >= arm_num_regs); -} - -static int -arm_cannot_fetch_register (int regno) -{ - return (regno >= arm_num_regs); -} - -static void -arm_fill_wmmxregset (struct regcache *regcache, void *buf) -{ - if (arm_linux_get_tdesc_fp_type (regcache->tdesc) != ARM_FP_TYPE_IWMMXT) - return; - - for (int i = 0; i < 16; i++) - collect_register (regcache, arm_num_regs + i, (char *) buf + i * 8); - - /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */ - for (int i = 0; i < 6; i++) - collect_register (regcache, arm_num_regs + i + 16, - (char *) buf + 16 * 8 + i * 4); -} - -static void -arm_store_wmmxregset (struct regcache *regcache, const void *buf) -{ - if (arm_linux_get_tdesc_fp_type (regcache->tdesc) != ARM_FP_TYPE_IWMMXT) - return; - - for (int i = 0; i < 16; i++) - supply_register (regcache, arm_num_regs + i, (char *) buf + i * 8); - - /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */ - for (int i = 0; i < 6; i++) - supply_register (regcache, arm_num_regs + i + 16, - (char *) buf + 16 * 8 + i * 4); -} - -static void -arm_fill_vfpregset (struct regcache *regcache, void *buf) -{ - int num; - - if (is_aarch32_linux_description (regcache->tdesc)) - num = 32; - else - { - arm_fp_type fp_type = arm_linux_get_tdesc_fp_type (regcache->tdesc); - - if (fp_type == ARM_FP_TYPE_VFPV3) - num = 32; - else if (fp_type == ARM_FP_TYPE_VFPV2) - num = 16; - else - return; - } - - arm_fill_vfpregset_num (regcache, buf, num); -} - -/* Wrapper of UNMAKE_THUMB_ADDR for get_next_pcs. */ -static CORE_ADDR -get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val) -{ - return UNMAKE_THUMB_ADDR (val); -} - -static void -arm_store_vfpregset (struct regcache *regcache, const void *buf) -{ - int num; - - if (is_aarch32_linux_description (regcache->tdesc)) - num = 32; - else - { - arm_fp_type fp_type = arm_linux_get_tdesc_fp_type (regcache->tdesc); - - if (fp_type == ARM_FP_TYPE_VFPV3) - num = 32; - else if (fp_type == ARM_FP_TYPE_VFPV2) - num = 16; - else - return; - } - - arm_store_vfpregset_num (regcache, buf, num); -} - -/* Wrapper of arm_is_thumb_mode for get_next_pcs. */ -static int -get_next_pcs_is_thumb (struct arm_get_next_pcs *self) -{ - return arm_is_thumb_mode (); -} - -/* Read memory from the inferior. - BYTE_ORDER is ignored and there to keep compatiblity with GDB's - read_memory_unsigned_integer. */ -static ULONGEST -get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, - int len, - int byte_order) -{ - ULONGEST res; - - res = 0; - target_read_memory (memaddr, (unsigned char *) &res, len); - - return res; -} - -/* Fetch the thread-local storage pointer for libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *)*base - idx); - - return PS_OK; -} - - -/* Query Hardware Breakpoint information for the target we are attached to - (using PID as ptrace argument) and set up arm_linux_hwbp_cap. */ -static void -arm_linux_init_hwbp_cap (int pid) -{ - unsigned int val; - - if (ptrace (PTRACE_GETHBPREGS, pid, 0, &val) < 0) - return; - - arm_linux_hwbp_cap.arch = (unsigned char)((val >> 24) & 0xff); - if (arm_linux_hwbp_cap.arch == 0) - return; - - arm_linux_hwbp_cap.max_wp_length = (unsigned char)((val >> 16) & 0xff); - arm_linux_hwbp_cap.wp_count = (unsigned char)((val >> 8) & 0xff); - arm_linux_hwbp_cap.bp_count = (unsigned char)(val & 0xff); - - if (arm_linux_hwbp_cap.wp_count > MAX_WPTS) - internal_error (__FILE__, __LINE__, "Unsupported number of watchpoints"); - if (arm_linux_hwbp_cap.bp_count > MAX_BPTS) - internal_error (__FILE__, __LINE__, "Unsupported number of breakpoints"); -} - -/* How many hardware breakpoints are available? */ -static int -arm_linux_get_hw_breakpoint_count (void) -{ - return arm_linux_hwbp_cap.bp_count; -} - -/* How many hardware watchpoints are available? */ -static int -arm_linux_get_hw_watchpoint_count (void) -{ - return arm_linux_hwbp_cap.wp_count; -} - -/* Maximum length of area watched by hardware watchpoint. */ -static int -arm_linux_get_hw_watchpoint_max_length (void) -{ - return arm_linux_hwbp_cap.max_wp_length; -} - -/* Initialize an ARM hardware break-/watch-point control register value. - BYTE_ADDRESS_SELECT is the mask of bytes to trigger on; HWBP_TYPE is the - type of break-/watch-point; ENABLE indicates whether the point is enabled. - */ -static arm_hwbp_control_t -arm_hwbp_control_initialize (unsigned byte_address_select, - arm_hwbp_type hwbp_type, - int enable) -{ - gdb_assert ((byte_address_select & ~0xffU) == 0); - gdb_assert (hwbp_type != arm_hwbp_break - || ((byte_address_select & 0xfU) != 0)); - - return (byte_address_select << 5) | (hwbp_type << 3) | (3 << 1) | enable; -} - -/* Does the breakpoint control value CONTROL have the enable bit set? */ -static int -arm_hwbp_control_is_enabled (arm_hwbp_control_t control) -{ - return control & 0x1; -} - -/* Is the breakpoint control value CONTROL initialized? */ -static int -arm_hwbp_control_is_initialized (arm_hwbp_control_t control) -{ - return control != 0; -} - -/* Change a breakpoint control word so that it is in the disabled state. */ -static arm_hwbp_control_t -arm_hwbp_control_disable (arm_hwbp_control_t control) -{ - return control & ~0x1; -} - -/* Are two break-/watch-points equal? */ -static int -arm_linux_hw_breakpoint_equal (const struct arm_linux_hw_breakpoint *p1, - const struct arm_linux_hw_breakpoint *p2) -{ - return p1->address == p2->address && p1->control == p2->control; -} - -/* Convert a raw breakpoint type to an enum arm_hwbp_type. */ - -static arm_hwbp_type -raw_bkpt_type_to_arm_hwbp_type (enum raw_bkpt_type raw_type) -{ - switch (raw_type) - { - case raw_bkpt_type_hw: - return arm_hwbp_break; - case raw_bkpt_type_write_wp: - return arm_hwbp_store; - case raw_bkpt_type_read_wp: - return arm_hwbp_load; - case raw_bkpt_type_access_wp: - return arm_hwbp_access; - default: - gdb_assert_not_reached ("unhandled raw type"); - } -} - -/* Initialize the hardware breakpoint structure P for a breakpoint or - watchpoint at ADDR to LEN. The type of watchpoint is given in TYPE. - Returns -1 if TYPE is unsupported, or -2 if the particular combination - of ADDR and LEN cannot be implemented. Otherwise, returns 0 if TYPE - represents a breakpoint and 1 if type represents a watchpoint. */ -static int -arm_linux_hw_point_initialize (enum raw_bkpt_type raw_type, CORE_ADDR addr, - int len, struct arm_linux_hw_breakpoint *p) -{ - arm_hwbp_type hwbp_type; - unsigned mask; - - hwbp_type = raw_bkpt_type_to_arm_hwbp_type (raw_type); - - if (hwbp_type == arm_hwbp_break) - { - /* For breakpoints, the length field encodes the mode. */ - switch (len) - { - case 2: /* 16-bit Thumb mode breakpoint */ - case 3: /* 32-bit Thumb mode breakpoint */ - mask = 0x3; - addr &= ~1; - break; - case 4: /* 32-bit ARM mode breakpoint */ - mask = 0xf; - addr &= ~3; - break; - default: - /* Unsupported. */ - return -2; - } - } - else - { - CORE_ADDR max_wp_length = arm_linux_get_hw_watchpoint_max_length (); - CORE_ADDR aligned_addr; - - /* Can not set watchpoints for zero or negative lengths. */ - if (len <= 0) - return -2; - /* The current ptrace interface can only handle watchpoints that are a - power of 2. */ - if ((len & (len - 1)) != 0) - return -2; - - /* Test that the range [ADDR, ADDR + LEN) fits into the largest address - range covered by a watchpoint. */ - aligned_addr = addr & ~(max_wp_length - 1); - if (aligned_addr + max_wp_length < addr + len) - return -2; - - mask = (1 << len) - 1; - } - - p->address = (unsigned int) addr; - p->control = arm_hwbp_control_initialize (mask, hwbp_type, 1); - - return hwbp_type != arm_hwbp_break; -} - -/* Callback to mark a watch-/breakpoint to be updated in all threads of - the current process. */ - -static void -update_registers_callback (thread_info *thread, int watch, int i) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - /* The actual update is done later just before resuming the lwp, - we just mark that the registers need updating. */ - if (watch) - lwp->arch_private->wpts_changed[i] = 1; - else - lwp->arch_private->bpts_changed[i] = 1; - - /* If the lwp isn't stopped, force it to momentarily pause, so - we can update its breakpoint registers. */ - if (!lwp->stopped) - linux_stop_lwp (lwp); -} - -static int -arm_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - case Z_PACKET_HW_BP: - case Z_PACKET_WRITE_WP: - case Z_PACKET_READ_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - /* Leave the handling of sw breakpoints with the gdb client. */ - return 0; - } -} - -/* Insert hardware break-/watchpoint. */ -static int -arm_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - struct process_info *proc = current_process (); - struct arm_linux_hw_breakpoint p, *pts; - int watch, i, count; - - watch = arm_linux_hw_point_initialize (type, addr, len, &p); - if (watch < 0) - { - /* Unsupported. */ - return watch == -1 ? 1 : -1; - } - - if (watch) - { - count = arm_linux_get_hw_watchpoint_count (); - pts = proc->priv->arch_private->wpts; - } - else - { - count = arm_linux_get_hw_breakpoint_count (); - pts = proc->priv->arch_private->bpts; - } - - for (i = 0; i < count; i++) - if (!arm_hwbp_control_is_enabled (pts[i].control)) - { - pts[i] = p; - - /* Only update the threads of the current process. */ - for_each_thread (current_thread->id.pid (), [&] (thread_info *thread) - { - update_registers_callback (thread, watch, i); - }); - - return 0; - } - - /* We're out of watchpoints. */ - return -1; -} - -/* Remove hardware break-/watchpoint. */ -static int -arm_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - struct process_info *proc = current_process (); - struct arm_linux_hw_breakpoint p, *pts; - int watch, i, count; - - watch = arm_linux_hw_point_initialize (type, addr, len, &p); - if (watch < 0) - { - /* Unsupported. */ - return -1; - } - - if (watch) - { - count = arm_linux_get_hw_watchpoint_count (); - pts = proc->priv->arch_private->wpts; - } - else - { - count = arm_linux_get_hw_breakpoint_count (); - pts = proc->priv->arch_private->bpts; - } - - for (i = 0; i < count; i++) - if (arm_linux_hw_breakpoint_equal (&p, pts + i)) - { - pts[i].control = arm_hwbp_control_disable (pts[i].control); - - /* Only update the threads of the current process. */ - for_each_thread (current_thread->id.pid (), [&] (thread_info *thread) - { - update_registers_callback (thread, watch, i); - }); - - return 0; - } - - /* No watchpoint matched. */ - return -1; -} - -/* Return whether current thread is stopped due to a watchpoint. */ -static int -arm_stopped_by_watchpoint (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - siginfo_t siginfo; - - /* We must be able to set hardware watchpoints. */ - if (arm_linux_get_hw_watchpoint_count () == 0) - return 0; - - /* Retrieve siginfo. */ - errno = 0; - ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), 0, &siginfo); - if (errno != 0) - return 0; - - /* This must be a hardware breakpoint. */ - if (siginfo.si_signo != SIGTRAP - || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) - return 0; - - /* If we are in a positive slot then we're looking at a breakpoint and not - a watchpoint. */ - if (siginfo.si_errno >= 0) - return 0; - - /* Cache stopped data address for use by arm_stopped_data_address. */ - lwp->arch_private->stopped_data_address - = (CORE_ADDR) (uintptr_t) siginfo.si_addr; - - return 1; -} - -/* Return data address that triggered watchpoint. Called only if - arm_stopped_by_watchpoint returned true. */ -static CORE_ADDR -arm_stopped_data_address (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - return lwp->arch_private->stopped_data_address; -} - -/* Called when a new process is created. */ -static struct arch_process_info * -arm_new_process (void) -{ - struct arch_process_info *info = XCNEW (struct arch_process_info); - return info; -} - -/* Called when a process is being deleted. */ - -static void -arm_delete_process (struct arch_process_info *info) -{ - xfree (info); -} - -/* Called when a new thread is detected. */ -static void -arm_new_thread (struct lwp_info *lwp) -{ - struct arch_lwp_info *info = XCNEW (struct arch_lwp_info); - int i; - - for (i = 0; i < MAX_BPTS; i++) - info->bpts_changed[i] = 1; - for (i = 0; i < MAX_WPTS; i++) - info->wpts_changed[i] = 1; - - lwp->arch_private = info; -} - -/* Function to call when a thread is being deleted. */ - -static void -arm_delete_thread (struct arch_lwp_info *arch_lwp) -{ - xfree (arch_lwp); -} - -static void -arm_new_fork (struct process_info *parent, struct process_info *child) -{ - struct arch_process_info *parent_proc_info; - struct arch_process_info *child_proc_info; - struct lwp_info *child_lwp; - struct arch_lwp_info *child_lwp_info; - int i; - - /* These are allocated by linux_add_process. */ - gdb_assert (parent->priv != NULL - && parent->priv->arch_private != NULL); - gdb_assert (child->priv != NULL - && child->priv->arch_private != NULL); - - parent_proc_info = parent->priv->arch_private; - child_proc_info = child->priv->arch_private; - - /* Linux kernel before 2.6.33 commit - 72f674d203cd230426437cdcf7dd6f681dad8b0d - will inherit hardware debug registers from parent - on fork/vfork/clone. Newer Linux kernels create such tasks with - zeroed debug registers. - - GDB core assumes the child inherits the watchpoints/hw - breakpoints of the parent, and will remove them all from the - forked off process. Copy the debug registers mirrors into the - new process so that all breakpoints and watchpoints can be - removed together. The debug registers mirror will become zeroed - in the end before detaching the forked off process, thus making - this compatible with older Linux kernels too. */ - - *child_proc_info = *parent_proc_info; - - /* Mark all the hardware breakpoints and watchpoints as changed to - make sure that the registers will be updated. */ - child_lwp = find_lwp_pid (ptid_t (child->pid)); - child_lwp_info = child_lwp->arch_private; - for (i = 0; i < MAX_BPTS; i++) - child_lwp_info->bpts_changed[i] = 1; - for (i = 0; i < MAX_WPTS; i++) - child_lwp_info->wpts_changed[i] = 1; -} - -/* Called when resuming a thread. - If the debug regs have changed, update the thread's copies. */ -static void -arm_prepare_to_resume (struct lwp_info *lwp) -{ - struct thread_info *thread = get_lwp_thread (lwp); - int pid = lwpid_of (thread); - struct process_info *proc = find_process_pid (pid_of (thread)); - struct arch_process_info *proc_info = proc->priv->arch_private; - struct arch_lwp_info *lwp_info = lwp->arch_private; - int i; - - for (i = 0; i < arm_linux_get_hw_breakpoint_count (); i++) - if (lwp_info->bpts_changed[i]) - { - errno = 0; - - if (arm_hwbp_control_is_enabled (proc_info->bpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, - (PTRACE_TYPE_ARG3) ((i << 1) + 1), - &proc_info->bpts[i].address) < 0) - perror_with_name ("Unexpected error setting breakpoint address"); - - if (arm_hwbp_control_is_initialized (proc_info->bpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, - (PTRACE_TYPE_ARG3) ((i << 1) + 2), - &proc_info->bpts[i].control) < 0) - perror_with_name ("Unexpected error setting breakpoint"); - - lwp_info->bpts_changed[i] = 0; - } - - for (i = 0; i < arm_linux_get_hw_watchpoint_count (); i++) - if (lwp_info->wpts_changed[i]) - { - errno = 0; - - if (arm_hwbp_control_is_enabled (proc_info->wpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, - (PTRACE_TYPE_ARG3) -((i << 1) + 1), - &proc_info->wpts[i].address) < 0) - perror_with_name ("Unexpected error setting watchpoint address"); - - if (arm_hwbp_control_is_initialized (proc_info->wpts[i].control)) - if (ptrace (PTRACE_SETHBPREGS, pid, - (PTRACE_TYPE_ARG3) -((i << 1) + 2), - &proc_info->wpts[i].control) < 0) - perror_with_name ("Unexpected error setting watchpoint"); - - lwp_info->wpts_changed[i] = 0; - } -} - -/* Find the next pc for a sigreturn or rt_sigreturn syscall. In - addition, set IS_THUMB depending on whether we will return to ARM - or Thumb code. - See arm-linux.h for stack layout details. */ -static CORE_ADDR -arm_sigreturn_next_pc (struct regcache *regcache, int svc_number, - int *is_thumb) -{ - unsigned long sp; - unsigned long sp_data; - /* Offset of PC register. */ - int pc_offset = 0; - CORE_ADDR next_pc = 0; - uint32_t cpsr; - - gdb_assert (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn); - - collect_register_by_name (regcache, "sp", &sp); - (*the_target->read_memory) (sp, (unsigned char *) &sp_data, 4); - - pc_offset = arm_linux_sigreturn_next_pc_offset - (sp, sp_data, svc_number, __NR_sigreturn == svc_number ? 1 : 0); - - (*the_target->read_memory) (sp + pc_offset, (unsigned char *) &next_pc, 4); - - /* Set IS_THUMB according the CPSR saved on the stack. */ - (*the_target->read_memory) (sp + pc_offset + 4, (unsigned char *) &cpsr, 4); - *is_thumb = ((cpsr & CPSR_T) != 0); - - return next_pc; -} - -/* When PC is at a syscall instruction, return the PC of the next - instruction to be executed. */ -static CORE_ADDR -get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self) -{ - CORE_ADDR next_pc = 0; - CORE_ADDR pc = regcache_read_pc (self->regcache); - int is_thumb = arm_is_thumb_mode (); - ULONGEST svc_number = 0; - struct regcache *regcache = self->regcache; - - if (is_thumb) - { - collect_register (regcache, 7, &svc_number); - next_pc = pc + 2; - } - else - { - unsigned long this_instr; - unsigned long svc_operand; - - target_read_memory (pc, (unsigned char *) &this_instr, 4); - svc_operand = (0x00ffffff & this_instr); - - if (svc_operand) /* OABI. */ - { - svc_number = svc_operand - 0x900000; - } - else /* EABI. */ - { - collect_register (regcache, 7, &svc_number); - } - - next_pc = pc + 4; - } - - /* This is a sigreturn or sigreturn_rt syscall. */ - if (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn) - { - /* SIGRETURN or RT_SIGRETURN may affect the arm thumb mode, so - update IS_THUMB. */ - next_pc = arm_sigreturn_next_pc (regcache, svc_number, &is_thumb); - } - - /* Addresses for calling Thumb functions have the bit 0 set. */ - if (is_thumb) - next_pc = MAKE_THUMB_ADDR (next_pc); - - return next_pc; -} - -static const struct target_desc * -arm_read_description (void) -{ - unsigned long arm_hwcap = linux_get_hwcap (4); - - if (arm_hwcap & HWCAP_IWMMXT) - return arm_linux_read_description (ARM_FP_TYPE_IWMMXT); - - if (arm_hwcap & HWCAP_VFP) - { - /* Make sure that the kernel supports reading VFP registers. Support was - added in 2.6.30. */ - int pid = lwpid_of (current_thread); - errno = 0; - char *buf = (char *) alloca (ARM_VFP3_REGS_SIZE); - if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0 && errno == EIO) - return arm_linux_read_description (ARM_FP_TYPE_NONE); - - /* NEON implies either no VFP, or VFPv3-D32. We only support - it with VFP. */ - if (arm_hwcap & HWCAP_NEON) - return aarch32_linux_read_description (); - else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) - return arm_linux_read_description (ARM_FP_TYPE_VFPV3); - else - return arm_linux_read_description (ARM_FP_TYPE_VFPV2); - } - - /* The default configuration uses legacy FPA registers, probably - simulated. */ - return arm_linux_read_description (ARM_FP_TYPE_NONE); -} - -static void -arm_arch_setup (void) -{ - int tid = lwpid_of (current_thread); - int gpregs[18]; - struct iovec iov; - - /* Query hardware watchpoint/breakpoint capabilities. */ - arm_linux_init_hwbp_cap (tid); - - current_process ()->tdesc = arm_read_description (); - - iov.iov_base = gpregs; - iov.iov_len = sizeof (gpregs); - - /* Check if PTRACE_GETREGSET works. */ - if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) == 0) - have_ptrace_getregset = 1; - else - have_ptrace_getregset = 0; -} - -/* Fetch the next possible PCs after the current instruction executes. */ - -static std::vector -arm_gdbserver_get_next_pcs (struct regcache *regcache) -{ - struct arm_get_next_pcs next_pcs_ctx; - - arm_get_next_pcs_ctor (&next_pcs_ctx, - &get_next_pcs_ops, - /* Byte order is ignored assumed as host. */ - 0, - 0, - 1, - regcache); - - return arm_get_next_pcs (&next_pcs_ctx); -} - -/* Support for hardware single step. */ - -static int -arm_supports_hardware_single_step (void) -{ - return 0; -} - -/* Implementation of linux_target_ops method "get_syscall_trapinfo". */ - -static void -arm_get_syscall_trapinfo (struct regcache *regcache, int *sysno) -{ - if (arm_is_thumb_mode ()) - collect_register_by_name (regcache, "r7", sysno); - else - { - unsigned long pc; - unsigned long insn; - - collect_register_by_name (regcache, "pc", &pc); - - if ((*the_target->read_memory) (pc - 4, (unsigned char *) &insn, 4)) - *sysno = UNKNOWN_SYSCALL; - else - { - unsigned long svc_operand = (0x00ffffff & insn); - - if (svc_operand) - { - /* OABI */ - *sysno = svc_operand - 0x900000; - } - else - { - /* EABI */ - collect_register_by_name (regcache, "r7", sysno); - } - } - } -} - -/* Register sets without using PTRACE_GETREGSET. */ - -static struct regset_info arm_regsets[] = { - { PTRACE_GETREGS, PTRACE_SETREGS, 0, - ARM_CORE_REGS_SIZE + ARM_INT_REGISTER_SIZE, GENERAL_REGS, - arm_fill_gregset, arm_store_gregset }, - { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 0, IWMMXT_REGS_SIZE, EXTENDED_REGS, - arm_fill_wmmxregset, arm_store_wmmxregset }, - { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 0, ARM_VFP3_REGS_SIZE, EXTENDED_REGS, - arm_fill_vfpregset, arm_store_vfpregset }, - NULL_REGSET -}; - -static struct regsets_info arm_regsets_info = - { - arm_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info arm_usrregs_info = - { - arm_num_regs, - arm_regmap, - }; - -static struct regs_info regs_info_arm = - { - NULL, /* regset_bitmap */ - &arm_usrregs_info, - &arm_regsets_info - }; - -static const struct regs_info * -arm_regs_info (void) -{ - const struct target_desc *tdesc = current_process ()->tdesc; - - if (have_ptrace_getregset == 1 - && (is_aarch32_linux_description (tdesc) - || arm_linux_get_tdesc_fp_type (tdesc) == ARM_FP_TYPE_VFPV3)) - return ®s_info_aarch32; - - return ®s_info_arm; -} - -struct linux_target_ops the_low_target = { - arm_arch_setup, - arm_regs_info, - arm_cannot_fetch_register, - arm_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - arm_breakpoint_kind_from_pc, - arm_sw_breakpoint_from_kind, - arm_gdbserver_get_next_pcs, - 0, - arm_breakpoint_at, - arm_supports_z_point_type, - arm_insert_point, - arm_remove_point, - arm_stopped_by_watchpoint, - arm_stopped_data_address, - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - arm_new_process, - arm_delete_process, - arm_new_thread, - arm_delete_thread, - arm_new_fork, - arm_prepare_to_resume, - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - arm_breakpoint_kind_from_current_state, - arm_supports_hardware_single_step, - arm_get_syscall_trapinfo, -}; - -void -initialize_low_arch (void) -{ - initialize_low_arch_aarch32 (); - initialize_regsets_info (&arm_regsets_info); -} diff --git a/gdb/gdbserver/linux-arm-tdesc.c b/gdb/gdbserver/linux-arm-tdesc.c deleted file mode 100644 index 2c9fac83cd5..00000000000 --- a/gdb/gdbserver/linux-arm-tdesc.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2019-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" - -#include "linux-arm-tdesc.h" - -#include "tdesc.h" -#include "arch/arm.h" -#include - -/* All possible Arm target descriptors. */ -static struct target_desc *tdesc_arm_list[ARM_FP_TYPE_INVALID]; - -/* See linux-arm-tdesc.h. */ - -const target_desc * -arm_linux_read_description (arm_fp_type fp_type) -{ - struct target_desc *tdesc = tdesc_arm_list[fp_type]; - - if (tdesc == nullptr) - { - tdesc = arm_create_target_description (fp_type); - - static const char *expedite_regs[] = { "r11", "sp", "pc", 0 }; - init_target_desc (tdesc, expedite_regs); - - tdesc_arm_list[fp_type] = tdesc; - } - - return tdesc; -} - -/* See linux-arm-tdesc.h. */ - -arm_fp_type -arm_linux_get_tdesc_fp_type (const target_desc *tdesc) -{ - gdb_assert (tdesc != nullptr); - - /* Many of the tdesc_arm_list entries may not have been initialised yet. This - is ok, because tdesc must be one of the initialised ones. */ - for (int i = ARM_FP_TYPE_NONE; i < ARM_FP_TYPE_INVALID; i++) - { - if (tdesc == tdesc_arm_list[i]) - return (arm_fp_type) i; - } - - return ARM_FP_TYPE_INVALID; -} diff --git a/gdb/gdbserver/linux-arm-tdesc.h b/gdb/gdbserver/linux-arm-tdesc.h deleted file mode 100644 index 5e8c6a3be57..00000000000 --- a/gdb/gdbserver/linux-arm-tdesc.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2019-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_ARM_TDESC_H -#define GDBSERVER_LINUX_ARM_TDESC_H - -#include "arch/arm.h" - -/* Return the Arm target description with fp registers FP_TYPE. */ - -const target_desc * arm_linux_read_description (arm_fp_type fp_type); - -/* For a target description TDESC, return its fp type. */ - -arm_fp_type arm_linux_get_tdesc_fp_type (const target_desc *tdesc); - -#endif /* linux-arm-tdesc.h. */ diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c deleted file mode 100644 index 5bfc8868bd9..00000000000 --- a/gdb/gdbserver/linux-bfin-low.c +++ /dev/null @@ -1,159 +0,0 @@ -/* GNU/Linux/BFIN specific low level interface, for the remote server for GDB. - - Copyright (C) 2005-2020 Free Software Foundation, Inc. - - Contributed by Analog Devices, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include - -/* Defined in auto-generated file reg-bfin.c. */ -void init_registers_bfin (void); -extern const struct target_desc *tdesc_bfin; - -static int bfin_regmap[] = -{ - PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, - PT_P0, PT_P1, PT_P2, PT_P3, PT_P4, PT_P5, PT_USP, PT_FP, - PT_I0, PT_I1, PT_I2, PT_I3, PT_M0, PT_M1, PT_M2, PT_M3, - PT_B0, PT_B1, PT_B2, PT_B3, PT_L0, PT_L1, PT_L2, PT_L3, - PT_A0X, PT_A0W, PT_A1X, PT_A1W, PT_ASTAT, PT_RETS, - PT_LC0, PT_LT0, PT_LB0, PT_LC1, PT_LT1, PT_LB1, - -1 /* PT_CYCLES */, -1 /* PT_CYCLES2 */, - -1 /* PT_USP */, PT_SEQSTAT, PT_SYSCFG, PT_PC, PT_RETX, PT_RETN, PT_RETE, - PT_PC, -}; - -#define bfin_num_regs ARRAY_SIZE (bfin_regmap) - -static int -bfin_cannot_store_register (int regno) -{ - return (regno >= bfin_num_regs); -} - -static int -bfin_cannot_fetch_register (int regno) -{ - return (regno >= bfin_num_regs); -} - -#define bfin_breakpoint_len 2 -static const gdb_byte bfin_breakpoint[bfin_breakpoint_len] = {0xa1, 0x00}; - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -bfin_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = bfin_breakpoint_len; - return bfin_breakpoint; -} - -static int -bfin_breakpoint_at (CORE_ADDR where) -{ - unsigned char insn[bfin_breakpoint_len]; - - read_inferior_memory(where, insn, bfin_breakpoint_len); - if (insn[0] == bfin_breakpoint[0] - && insn[1] == bfin_breakpoint[1]) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -static void -bfin_arch_setup (void) -{ - current_process ()->tdesc = tdesc_bfin; -} - -/* Support for hardware single step. */ - -static int -bfin_supports_hardware_single_step (void) -{ - return 1; -} - -static struct usrregs_info bfin_usrregs_info = - { - bfin_num_regs, - bfin_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &bfin_usrregs_info, - }; - -static const struct regs_info * -bfin_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - bfin_arch_setup, - bfin_regs_info, - bfin_cannot_fetch_register, - bfin_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - bfin_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 2, - bfin_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - bfin_supports_hardware_single_step, -}; - - -void -initialize_low_arch (void) -{ - init_registers_bfin (); -} diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c deleted file mode 100644 index 8ea5af92e31..00000000000 --- a/gdb/gdbserver/linux-cris-low.c +++ /dev/null @@ -1,132 +0,0 @@ -/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "nat/gdb_ptrace.h" - -/* Defined in auto-generated file reg-cris.c. */ -void init_registers_cris (void); -extern const struct target_desc *tdesc_cris; - -/* CRISv10 */ -#define cris_num_regs 32 - -/* Locations need to match . */ -static int cris_regmap[] = { - 15*4, 14*4, 13*4, 12*4, - 11*4, 10*4, 9*4, 8*4, - 7*4, 6*4, 5*4, 4*4, - 3*4, 2*4, 23*4, 19*4, - - -1, -1, -1, -1, - -1, 17*4, -1, 16*4, - -1, -1, -1, 18*4, - -1, 17*4, -1, -1 - -}; - -static int -cris_cannot_store_register (int regno) -{ - if (cris_regmap[regno] == -1) - return 1; - - return (regno >= cris_num_regs); -} - -static int -cris_cannot_fetch_register (int regno) -{ - if (cris_regmap[regno] == -1) - return 1; - - return (regno >= cris_num_regs); -} - -static const unsigned short cris_breakpoint = 0xe938; -#define cris_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -cris_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = cris_breakpoint_len; - return (const gdb_byte *) &cris_breakpoint; -} - -static int -cris_breakpoint_at (CORE_ADDR where) -{ - unsigned short insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, - cris_breakpoint_len); - if (insn == cris_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -static void -cris_arch_setup (void) -{ - current_process ()->tdesc = tdesc_cris; -} - -static struct usrregs_info cris_usrregs_info = - { - cris_num_regs, - cris_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &cris_usrregs_info, - }; - -static const struct regs_info * -cris_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - cris_arch_setup, - cris_regs_info, - cris_cannot_fetch_register, - cris_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - cris_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, - cris_breakpoint_at, -}; - -void -initialize_low_arch (void) -{ - init_registers_cris (); -} diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c deleted file mode 100644 index facb5c5c274..00000000000 --- a/gdb/gdbserver/linux-crisv32-low.c +++ /dev/null @@ -1,440 +0,0 @@ -/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "nat/gdb_ptrace.h" - -/* Defined in auto-generated file reg-crisv32.c. */ -void init_registers_crisv32 (void); -extern const struct target_desc *tdesc_crisv32; - -/* CRISv32 */ -#define cris_num_regs 49 - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -/* Note: Ignoring USP (having the stack pointer in two locations causes trouble - without any significant gain). */ - -/* Locations need to match . */ -static int cris_regmap[] = { - 1*4, 2*4, 3*4, 4*4, - 5*4, 6*4, 7*4, 8*4, - 9*4, 10*4, 11*4, 12*4, - 13*4, 14*4, 24*4, 15*4, - - -1, -1, -1, 16*4, - -1, 22*4, 23*4, 17*4, - -1, -1, 21*4, 20*4, - -1, 19*4, -1, 18*4, - - 25*4, - - 26*4, -1, -1, 29*4, - 30*4, 31*4, 32*4, 33*4, - 34*4, 35*4, 36*4, 37*4, - 38*4, 39*4, 40*4, -1 - -}; - -static const unsigned short cris_breakpoint = 0xe938; -#define cris_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -cris_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = cris_breakpoint_len; - return (const gdb_byte *) &cris_breakpoint; -} - -static int -cris_breakpoint_at (CORE_ADDR where) -{ - unsigned short insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, - cris_breakpoint_len); - if (insn == cris_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -static void -cris_write_data_breakpoint (struct regcache *regcache, - int bp, unsigned long start, unsigned long end) -{ - switch (bp) - { - case 0: - supply_register_by_name (regcache, "s3", &start); - supply_register_by_name (regcache, "s4", &end); - break; - case 1: - supply_register_by_name (regcache, "s5", &start); - supply_register_by_name (regcache, "s6", &end); - break; - case 2: - supply_register_by_name (regcache, "s7", &start); - supply_register_by_name (regcache, "s8", &end); - break; - case 3: - supply_register_by_name (regcache, "s9", &start); - supply_register_by_name (regcache, "s10", &end); - break; - case 4: - supply_register_by_name (regcache, "s11", &start); - supply_register_by_name (regcache, "s12", &end); - break; - case 5: - supply_register_by_name (regcache, "s13", &start); - supply_register_by_name (regcache, "s14", &end); - break; - } -} - -static int -cris_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_WRITE_WP: - case Z_PACKET_READ_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - return 0; - } -} - -static int -cris_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - int bp; - unsigned long bp_ctrl; - unsigned long start, end; - unsigned long ccs; - struct regcache *regcache; - - regcache = get_thread_regcache (current_thread, 1); - - /* Read watchpoints are set as access watchpoints, because of GDB's - inability to deal with pure read watchpoints. */ - if (type == raw_bkpt_type_read_wp) - type = raw_bkpt_type_access_wp; - - /* Get the configuration register. */ - collect_register_by_name (regcache, "s0", &bp_ctrl); - - /* The watchpoint allocation scheme is the simplest possible. - For example, if a region is watched for read and - a write watch is requested, a new watchpoint will - be used. Also, if a watch for a region that is already - covered by one or more existing watchpoints, a new - watchpoint will be used. */ - - /* First, find a free data watchpoint. */ - for (bp = 0; bp < 6; bp++) - { - /* Each data watchpoint's control registers occupy 2 bits - (hence the 3), starting at bit 2 for D0 (hence the 2) - with 4 bits between for each watchpoint (yes, the 4). */ - if (!(bp_ctrl & (0x3 << (2 + (bp * 4))))) - break; - } - - if (bp > 5) - { - /* We're out of watchpoints. */ - return -1; - } - - /* Configure the control register first. */ - if (type == raw_bkpt_type_read_wp || type == raw_bkpt_type_access_wp) - { - /* Trigger on read. */ - bp_ctrl |= (1 << (2 + bp * 4)); - } - if (type == raw_bkpt_type_write_wp || type == raw_bkpt_type_access_wp) - { - /* Trigger on write. */ - bp_ctrl |= (2 << (2 + bp * 4)); - } - - /* Setup the configuration register. */ - supply_register_by_name (regcache, "s0", &bp_ctrl); - - /* Setup the range. */ - start = addr; - end = addr + len - 1; - - /* Configure the watchpoint register. */ - cris_write_data_breakpoint (regcache, bp, start, end); - - collect_register_by_name (regcache, "ccs", &ccs); - /* Set the S1 flag to enable watchpoints. */ - ccs |= (1 << 19); - supply_register_by_name (regcache, "ccs", &ccs); - - return 0; -} - -static int -cris_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, int len, - struct raw_breakpoint *bp) -{ - int bp; - unsigned long bp_ctrl; - unsigned long start, end; - struct regcache *regcache; - unsigned long bp_d_regs[12]; - - regcache = get_thread_regcache (current_thread, 1); - - /* Read watchpoints are set as access watchpoints, because of GDB's - inability to deal with pure read watchpoints. */ - if (type == raw_bkpt_type_read_wp) - type = raw_bkpt_type_access_wp; - - /* Get the configuration register. */ - collect_register_by_name (regcache, "s0", &bp_ctrl); - - /* Try to find a watchpoint that is configured for the - specified range, then check that read/write also matches. */ - - /* Ugly pointer arithmetic, since I cannot rely on a - single switch (addr) as there may be several watchpoints with - the same start address for example. */ - - /* Get all range registers to simplify search. */ - collect_register_by_name (regcache, "s3", &bp_d_regs[0]); - collect_register_by_name (regcache, "s4", &bp_d_regs[1]); - collect_register_by_name (regcache, "s5", &bp_d_regs[2]); - collect_register_by_name (regcache, "s6", &bp_d_regs[3]); - collect_register_by_name (regcache, "s7", &bp_d_regs[4]); - collect_register_by_name (regcache, "s8", &bp_d_regs[5]); - collect_register_by_name (regcache, "s9", &bp_d_regs[6]); - collect_register_by_name (regcache, "s10", &bp_d_regs[7]); - collect_register_by_name (regcache, "s11", &bp_d_regs[8]); - collect_register_by_name (regcache, "s12", &bp_d_regs[9]); - collect_register_by_name (regcache, "s13", &bp_d_regs[10]); - collect_register_by_name (regcache, "s14", &bp_d_regs[11]); - - for (bp = 0; bp < 6; bp++) - { - if (bp_d_regs[bp * 2] == addr - && bp_d_regs[bp * 2 + 1] == (addr + len - 1)) { - /* Matching range. */ - int bitpos = 2 + bp * 4; - int rw_bits; - - /* Read/write bits for this BP. */ - rw_bits = (bp_ctrl & (0x3 << bitpos)) >> bitpos; - - if ((type == raw_bkpt_type_read_wp && rw_bits == 0x1) - || (type == raw_bkpt_type_write_wp && rw_bits == 0x2) - || (type == raw_bkpt_type_access_wp && rw_bits == 0x3)) - { - /* Read/write matched. */ - break; - } - } - } - - if (bp > 5) - { - /* No watchpoint matched. */ - return -1; - } - - /* Found a matching watchpoint. Now, deconfigure it by - both disabling read/write in bp_ctrl and zeroing its - start/end addresses. */ - bp_ctrl &= ~(3 << (2 + (bp * 4))); - /* Setup the configuration register. */ - supply_register_by_name (regcache, "s0", &bp_ctrl); - - start = end = 0; - /* Configure the watchpoint register. */ - cris_write_data_breakpoint (regcache, bp, start, end); - - /* Note that we don't clear the S1 flag here. It's done when continuing. */ - return 0; -} - -static int -cris_stopped_by_watchpoint (void) -{ - unsigned long exs; - struct regcache *regcache = get_thread_regcache (current_thread, 1); - - collect_register_by_name (regcache, "exs", &exs); - - return (((exs & 0xff00) >> 8) == 0xc); -} - -static CORE_ADDR -cris_stopped_data_address (void) -{ - unsigned long eda; - struct regcache *regcache = get_thread_regcache (current_thread, 1); - - collect_register_by_name (regcache, "eda", &eda); - - /* FIXME: Possibly adjust to match watched range. */ - return eda; -} - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *) *base - idx); - return PS_OK; -} - -static void -cris_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - - for (i = 0; i < cris_num_regs; i++) - { - if (cris_regmap[i] != -1) - collect_register (regcache, i, ((char *) buf) + cris_regmap[i]); - } -} - -static void -cris_store_gregset (struct regcache *regcache, const void *buf) -{ - int i; - - for (i = 0; i < cris_num_regs; i++) - { - if (cris_regmap[i] != -1) - supply_register (regcache, i, ((char *) buf) + cris_regmap[i]); - } -} - -static void -cris_arch_setup (void) -{ - current_process ()->tdesc = tdesc_crisv32; -} - -/* Support for hardware single step. */ - -static int -cris_supports_hardware_single_step (void) -{ - return 1; -} - -static struct regset_info cris_regsets[] = { - { PTRACE_GETREGS, PTRACE_SETREGS, 0, cris_num_regs * 4, - GENERAL_REGS, cris_fill_gregset, cris_store_gregset }, - NULL_REGSET -}; - - -static struct regsets_info cris_regsets_info = - { - cris_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info cris_usrregs_info = - { - cris_num_regs, - cris_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &cris_usrregs_info, - &cris_regsets_info - }; - -static const struct regs_info * -cris_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - cris_arch_setup, - cris_regs_info, - NULL, - NULL, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - cris_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, - cris_breakpoint_at, - cris_supports_z_point_type, - cris_insert_point, - cris_remove_point, - cris_stopped_by_watchpoint, - cris_stopped_data_address, - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - cris_supports_hardware_single_step, -}; - -void -initialize_low_arch (void) -{ - init_registers_crisv32 (); - - initialize_regsets_info (&cris_regsets_info); -} diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c deleted file mode 100644 index 41f77c8deac..00000000000 --- a/gdb/gdbserver/linux-i386-ipa.c +++ /dev/null @@ -1,294 +0,0 @@ -/* GNU/Linux/x86 specific low level interface, for the in-process - agent library for GDB. - - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include -#include "tracepoint.h" -#include "linux-x86-tdesc.h" -#include "gdbsupport/x86-xstate.h" - -/* GDB register numbers. */ - -enum i386_gdb_regnum -{ - I386_EAX_REGNUM, /* %eax */ - I386_ECX_REGNUM, /* %ecx */ - I386_EDX_REGNUM, /* %edx */ - I386_EBX_REGNUM, /* %ebx */ - I386_ESP_REGNUM, /* %esp */ - I386_EBP_REGNUM, /* %ebp */ - I386_ESI_REGNUM, /* %esi */ - I386_EDI_REGNUM, /* %edi */ - I386_EIP_REGNUM, /* %eip */ - I386_EFLAGS_REGNUM, /* %eflags */ - I386_CS_REGNUM, /* %cs */ - I386_SS_REGNUM, /* %ss */ - I386_DS_REGNUM, /* %ds */ - I386_ES_REGNUM, /* %es */ - I386_FS_REGNUM, /* %fs */ - I386_GS_REGNUM, /* %gs */ - I386_ST0_REGNUM /* %st(0) */ -}; - -#define i386_num_regs 16 - -#define FT_CR_EAX 15 -#define FT_CR_ECX 14 -#define FT_CR_EDX 13 -#define FT_CR_EBX 12 -#define FT_CR_UESP 11 -#define FT_CR_EBP 10 -#define FT_CR_ESI 9 -#define FT_CR_EDI 8 -#define FT_CR_EIP 7 -#define FT_CR_EFL 6 -#define FT_CR_DS 5 -#define FT_CR_ES 4 -#define FT_CR_FS 3 -#define FT_CR_GS 2 -#define FT_CR_SS 1 -#define FT_CR_CS 0 - -/* Mapping between the general-purpose registers in jump tracepoint - format and GDB's register array layout. */ - -static const int i386_ft_collect_regmap[] = -{ - FT_CR_EAX * 4, FT_CR_ECX * 4, FT_CR_EDX * 4, FT_CR_EBX * 4, - FT_CR_UESP * 4, FT_CR_EBP * 4, FT_CR_ESI * 4, FT_CR_EDI * 4, - FT_CR_EIP * 4, FT_CR_EFL * 4, FT_CR_CS * 4, FT_CR_SS * 4, - FT_CR_DS * 4, FT_CR_ES * 4, FT_CR_FS * 4, FT_CR_GS * 4 -}; - -void -supply_fast_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf) -{ - int i; - - for (i = 0; i < i386_num_regs; i++) - { - int regval; - - if (i >= I386_CS_REGNUM && i <= I386_GS_REGNUM) - regval = *(short *) (((char *) buf) + i386_ft_collect_regmap[i]); - else - regval = *(int *) (((char *) buf) + i386_ft_collect_regmap[i]); - - supply_register (regcache, i, ®val); - } -} - -ULONGEST -get_raw_reg (const unsigned char *raw_regs, int regnum) -{ - /* This should maybe be allowed to return an error code, or perhaps - better, have the emit_reg detect this, and emit a constant zero, - or something. */ - - if (regnum > i386_num_regs) - return 0; - else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM) - return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]); - else - return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]); -} - -#ifdef HAVE_UST - -#include - -/* "struct registers" is the UST object type holding the registers at - the time of the static tracepoint marker call. This doesn't - contain EIP, but we know what it must have been (the marker - address). */ - -#define ST_REGENTRY(REG) \ - { \ - offsetof (struct registers, REG), \ - sizeof (((struct registers *) NULL)->REG) \ - } - -static struct -{ - int offset; - int size; -} i386_st_collect_regmap[] = - { - ST_REGENTRY(eax), - ST_REGENTRY(ecx), - ST_REGENTRY(edx), - ST_REGENTRY(ebx), - ST_REGENTRY(esp), - ST_REGENTRY(ebp), - ST_REGENTRY(esi), - ST_REGENTRY(edi), - { -1, 0 }, /* eip */ - ST_REGENTRY(eflags), - ST_REGENTRY(cs), - ST_REGENTRY(ss), - }; - -#define i386_NUM_ST_COLLECT_GREGS \ - (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0])) - -void -supply_static_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf, - CORE_ADDR pc) -{ - int i; - unsigned int newpc = pc; - - supply_register (regcache, I386_EIP_REGNUM, &newpc); - - for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++) - if (i386_st_collect_regmap[i].offset != -1) - { - switch (i386_st_collect_regmap[i].size) - { - case 4: - supply_register (regcache, i, - ((char *) buf) - + i386_st_collect_regmap[i].offset); - break; - case 2: - { - unsigned long reg - = * (short *) (((char *) buf) - + i386_st_collect_regmap[i].offset); - reg &= 0xffff; - supply_register (regcache, i, ®); - } - break; - default: - internal_error (__FILE__, __LINE__, "unhandled register size: %d", - i386_st_collect_regmap[i].size); - } - } -} - -#endif /* HAVE_UST */ - - -/* This is only needed because reg-i386-linux-lib.o references it. We - may use it proper at some point. */ -const char *gdbserver_xmltarget; - -/* Attempt to allocate memory for trampolines in the first 64 KiB of - memory to enable smaller jump patches. */ - -static void -initialize_fast_tracepoint_trampoline_buffer (void) -{ - const CORE_ADDR buffer_end = 64 * 1024; - /* Ensure that the buffer will be at least 1 KiB in size, which is - enough space for over 200 fast tracepoints. */ - const int min_buffer_size = 1024; - char buf[IPA_BUFSIZ]; - CORE_ADDR mmap_min_addr = buffer_end + 1; - ULONGEST buffer_size; - FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r"); - - if (!f) - { - snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s", - safe_strerror (errno)); - set_trampoline_buffer_space (0, 0, buf); - return; - } - - if (fgets (buf, IPA_BUFSIZ, f)) - sscanf (buf, "%llu", &mmap_min_addr); - - fclose (f); - - buffer_size = buffer_end - mmap_min_addr; - - if (buffer_size >= min_buffer_size) - { - if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size, - PROT_READ | PROT_EXEC | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0) - != MAP_FAILED) - set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL); - else - { - snprintf (buf, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s", - safe_strerror (errno)); - set_trampoline_buffer_space (0, 0, buf); - } - } - else - { - snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less", - (int) mmap_min_addr, (int) buffer_end - min_buffer_size); - set_trampoline_buffer_space (0, 0, buf); - } -} - -/* Map the tdesc index to xcr0 mask. */ -static uint64_t idx2mask[X86_TDESC_LAST] = { - X86_XSTATE_X87_MASK, - X86_XSTATE_SSE_MASK, - X86_XSTATE_AVX_MASK, - X86_XSTATE_MPX_MASK, - X86_XSTATE_AVX_MPX_MASK, - X86_XSTATE_AVX_AVX512_MASK, - X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, -}; - -/* Return target_desc to use for IPA, given the tdesc index passed by - gdbserver. */ - -const struct target_desc * -get_ipa_tdesc (int idx) -{ - if (idx >= X86_TDESC_LAST) - { - internal_error (__FILE__, __LINE__, - "unknown ipa tdesc index: %d", idx); - } - return i386_linux_read_description (idx2mask[idx]); -} - -/* Allocate buffer for the jump pads. On i386, we can reach an arbitrary - address with a jump instruction, so just allocate normally. */ - -void * -alloc_jump_pad_buffer (size_t size) -{ - void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - if (res == MAP_FAILED) - return NULL; - - return res; -} - -void -initialize_low_tracepoint (void) -{ - initialize_fast_tracepoint_trampoline_buffer (); - for (auto i = 0; i < X86_TDESC_LAST; i++) - i386_linux_read_description (idx2mask[i]); -} diff --git a/gdb/gdbserver/linux-ia64-low.c b/gdb/gdbserver/linux-ia64-low.c deleted file mode 100644 index 2399e58b366..00000000000 --- a/gdb/gdbserver/linux-ia64-low.c +++ /dev/null @@ -1,360 +0,0 @@ -/* GNU/Linux/IA64 specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -#ifdef HAVE_SYS_REG_H -#include -#endif - -/* Defined in auto-generated file reg-ia64.c. */ -void init_registers_ia64 (void); -extern const struct target_desc *tdesc_ia64; - -#define ia64_num_regs 462 - -#include - -static int ia64_regmap[] = - { - /* general registers */ - -1, /* gr0 not available; i.e, it's always zero */ - PT_R1, - PT_R2, - PT_R3, - PT_R4, - PT_R5, - PT_R6, - PT_R7, - PT_R8, - PT_R9, - PT_R10, - PT_R11, - PT_R12, - PT_R13, - PT_R14, - PT_R15, - PT_R16, - PT_R17, - PT_R18, - PT_R19, - PT_R20, - PT_R21, - PT_R22, - PT_R23, - PT_R24, - PT_R25, - PT_R26, - PT_R27, - PT_R28, - PT_R29, - PT_R30, - PT_R31, - /* gr32 through gr127 not directly available via the ptrace interface */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - /* Floating point registers */ - -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */ - PT_F2, - PT_F3, - PT_F4, - PT_F5, - PT_F6, - PT_F7, - PT_F8, - PT_F9, - PT_F10, - PT_F11, - PT_F12, - PT_F13, - PT_F14, - PT_F15, - PT_F16, - PT_F17, - PT_F18, - PT_F19, - PT_F20, - PT_F21, - PT_F22, - PT_F23, - PT_F24, - PT_F25, - PT_F26, - PT_F27, - PT_F28, - PT_F29, - PT_F30, - PT_F31, - PT_F32, - PT_F33, - PT_F34, - PT_F35, - PT_F36, - PT_F37, - PT_F38, - PT_F39, - PT_F40, - PT_F41, - PT_F42, - PT_F43, - PT_F44, - PT_F45, - PT_F46, - PT_F47, - PT_F48, - PT_F49, - PT_F50, - PT_F51, - PT_F52, - PT_F53, - PT_F54, - PT_F55, - PT_F56, - PT_F57, - PT_F58, - PT_F59, - PT_F60, - PT_F61, - PT_F62, - PT_F63, - PT_F64, - PT_F65, - PT_F66, - PT_F67, - PT_F68, - PT_F69, - PT_F70, - PT_F71, - PT_F72, - PT_F73, - PT_F74, - PT_F75, - PT_F76, - PT_F77, - PT_F78, - PT_F79, - PT_F80, - PT_F81, - PT_F82, - PT_F83, - PT_F84, - PT_F85, - PT_F86, - PT_F87, - PT_F88, - PT_F89, - PT_F90, - PT_F91, - PT_F92, - PT_F93, - PT_F94, - PT_F95, - PT_F96, - PT_F97, - PT_F98, - PT_F99, - PT_F100, - PT_F101, - PT_F102, - PT_F103, - PT_F104, - PT_F105, - PT_F106, - PT_F107, - PT_F108, - PT_F109, - PT_F110, - PT_F111, - PT_F112, - PT_F113, - PT_F114, - PT_F115, - PT_F116, - PT_F117, - PT_F118, - PT_F119, - PT_F120, - PT_F121, - PT_F122, - PT_F123, - PT_F124, - PT_F125, - PT_F126, - PT_F127, - /* predicate registers - we don't fetch these individually */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - /* branch registers */ - PT_B0, - PT_B1, - PT_B2, - PT_B3, - PT_B4, - PT_B5, - PT_B6, - PT_B7, - /* virtual frame pointer and virtual return address pointer */ - -1, -1, - /* other registers */ - PT_PR, - PT_CR_IIP, /* ip */ - PT_CR_IPSR, /* psr */ - PT_CFM, /* cfm */ - /* kernel registers not visible via ptrace interface (?) */ - -1, -1, -1, -1, -1, -1, -1, -1, - /* hole */ - -1, -1, -1, -1, -1, -1, -1, -1, - PT_AR_RSC, - PT_AR_BSP, - PT_AR_BSPSTORE, - PT_AR_RNAT, - -1, - -1, /* Not available: FCR, IA32 floating control register */ - -1, -1, - -1, /* Not available: EFLAG */ - -1, /* Not available: CSD */ - -1, /* Not available: SSD */ - -1, /* Not available: CFLG */ - -1, /* Not available: FSR */ - -1, /* Not available: FIR */ - -1, /* Not available: FDR */ - -1, - PT_AR_CCV, - -1, -1, -1, - PT_AR_UNAT, - -1, -1, -1, - PT_AR_FPSR, - -1, -1, -1, - -1, /* Not available: ITC */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, - PT_AR_PFS, - PT_AR_LC, - PT_AR_EC, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, - }; - -static int -ia64_cannot_store_register (int regno) -{ - return 0; -} - -static int -ia64_cannot_fetch_register (int regno) -{ - return 0; -} - -/* GDB register numbers. */ -#define IA64_GR0_REGNUM 0 -#define IA64_FR0_REGNUM 128 -#define IA64_FR1_REGNUM 129 - -static int -ia64_fetch_register (struct regcache *regcache, int regnum) -{ - /* r0 cannot be fetched but is always zero. */ - if (regnum == IA64_GR0_REGNUM) - { - const gdb_byte zero[8] = { 0 }; - - gdb_assert (sizeof (zero) == register_size (regcache->tdesc, regnum)); - supply_register (regcache, regnum, zero); - return 1; - } - - /* fr0 cannot be fetched but is always zero. */ - if (regnum == IA64_FR0_REGNUM) - { - const gdb_byte f_zero[16] = { 0 }; - - gdb_assert (sizeof (f_zero) == register_size (regcache->tdesc, regnum)); - supply_register (regcache, regnum, f_zero); - return 1; - } - - /* fr1 cannot be fetched but is always one (1.0). */ - if (regnum == IA64_FR1_REGNUM) - { - const gdb_byte f_one[16] = - { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0 }; - - gdb_assert (sizeof (f_one) == register_size (regcache->tdesc, regnum)); - supply_register (regcache, regnum, f_one); - return 1; - } - - return 0; -} - -static struct usrregs_info ia64_usrregs_info = - { - ia64_num_regs, - ia64_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &ia64_usrregs_info - }; - -static const struct regs_info * -ia64_regs_info (void) -{ - return ®s_info; -} - -static void -ia64_arch_setup (void) -{ - current_process ()->tdesc = tdesc_ia64; -} - - -struct linux_target_ops the_low_target = { - ia64_arch_setup, - ia64_regs_info, - ia64_cannot_fetch_register, - ia64_cannot_store_register, - ia64_fetch_register, -}; - -void -initialize_low_arch (void) -{ - init_registers_ia64 (); -} diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c deleted file mode 100644 index 676dea26c63..00000000000 --- a/gdb/gdbserver/linux-low.c +++ /dev/null @@ -1,7492 +0,0 @@ -/* Low level interface to ptrace, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "nat/linux-osdata.h" -#include "gdbsupport/agent.h" -#include "tdesc.h" -#include "gdbsupport/rsp-low.h" -#include "gdbsupport/signals-state-save-restore.h" -#include "nat/linux-nat.h" -#include "nat/linux-waitpid.h" -#include "gdbsupport/gdb_wait.h" -#include "nat/gdb_ptrace.h" -#include "nat/linux-ptrace.h" -#include "nat/linux-procfs.h" -#include "nat/linux-personality.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "gdbsupport/filestuff.h" -#include "tracepoint.h" -#include "hostio.h" -#include -#include "gdbsupport/common-inferior.h" -#include "nat/fork-inferior.h" -#include "gdbsupport/environ.h" -#include "gdbsupport/gdb-sigmask.h" -#include "gdbsupport/scoped_restore.h" -#ifndef ELFMAG0 -/* Don't include here. If it got included by gdb_proc_service.h - then ELFMAG0 will have been defined. If it didn't get included by - gdb_proc_service.h then including it will likely introduce a duplicate - definition of elf_fpregset_t. */ -#include -#endif -#include "nat/linux-namespaces.h" - -#ifdef HAVE_PERSONALITY -# include -# if !HAVE_DECL_ADDR_NO_RANDOMIZE -# define ADDR_NO_RANDOMIZE 0x0040000 -# endif -#endif - -#ifndef O_LARGEFILE -#define O_LARGEFILE 0 -#endif - -#ifndef AT_HWCAP2 -#define AT_HWCAP2 26 -#endif - -/* Some targets did not define these ptrace constants from the start, - so gdbserver defines them locally here. In the future, these may - be removed after they are added to asm/ptrace.h. */ -#if !(defined(PT_TEXT_ADDR) \ - || defined(PT_DATA_ADDR) \ - || defined(PT_TEXT_END_ADDR)) -#if defined(__mcoldfire__) -/* These are still undefined in 3.10 kernels. */ -#define PT_TEXT_ADDR 49*4 -#define PT_DATA_ADDR 50*4 -#define PT_TEXT_END_ADDR 51*4 -/* BFIN already defines these since at least 2.6.32 kernels. */ -#elif defined(BFIN) -#define PT_TEXT_ADDR 220 -#define PT_TEXT_END_ADDR 224 -#define PT_DATA_ADDR 228 -/* These are still undefined in 3.10 kernels. */ -#elif defined(__TMS320C6X__) -#define PT_TEXT_ADDR (0x10000*4) -#define PT_DATA_ADDR (0x10004*4) -#define PT_TEXT_END_ADDR (0x10008*4) -#endif -#endif - -#ifdef HAVE_LINUX_BTRACE -# include "nat/linux-btrace.h" -# include "gdbsupport/btrace-common.h" -#endif - -#ifndef HAVE_ELF32_AUXV_T -/* Copied from glibc's elf.h. */ -typedef struct -{ - uint32_t a_type; /* Entry type */ - union - { - uint32_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf32_auxv_t; -#endif - -#ifndef HAVE_ELF64_AUXV_T -/* Copied from glibc's elf.h. */ -typedef struct -{ - uint64_t a_type; /* Entry type */ - union - { - uint64_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf64_auxv_t; -#endif - -/* Does the current host support PTRACE_GETREGSET? */ -int have_ptrace_getregset = -1; - -/* LWP accessors. */ - -/* See nat/linux-nat.h. */ - -ptid_t -ptid_of_lwp (struct lwp_info *lwp) -{ - return ptid_of (get_lwp_thread (lwp)); -} - -/* See nat/linux-nat.h. */ - -void -lwp_set_arch_private_info (struct lwp_info *lwp, - struct arch_lwp_info *info) -{ - lwp->arch_private = info; -} - -/* See nat/linux-nat.h. */ - -struct arch_lwp_info * -lwp_arch_private_info (struct lwp_info *lwp) -{ - return lwp->arch_private; -} - -/* See nat/linux-nat.h. */ - -int -lwp_is_stopped (struct lwp_info *lwp) -{ - return lwp->stopped; -} - -/* See nat/linux-nat.h. */ - -enum target_stop_reason -lwp_stop_reason (struct lwp_info *lwp) -{ - return lwp->stop_reason; -} - -/* See nat/linux-nat.h. */ - -int -lwp_is_stepping (struct lwp_info *lwp) -{ - return lwp->stepping; -} - -/* A list of all unknown processes which receive stop signals. Some - other process will presumably claim each of these as forked - children momentarily. */ - -struct simple_pid_list -{ - /* The process ID. */ - int pid; - - /* The status as reported by waitpid. */ - int status; - - /* Next in chain. */ - struct simple_pid_list *next; -}; -struct simple_pid_list *stopped_pids; - -/* Trivial list manipulation functions to keep track of a list of new - stopped processes. */ - -static void -add_to_pid_list (struct simple_pid_list **listp, int pid, int status) -{ - struct simple_pid_list *new_pid = XNEW (struct simple_pid_list); - - new_pid->pid = pid; - new_pid->status = status; - new_pid->next = *listp; - *listp = new_pid; -} - -static int -pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp) -{ - struct simple_pid_list **p; - - for (p = listp; *p != NULL; p = &(*p)->next) - if ((*p)->pid == pid) - { - struct simple_pid_list *next = (*p)->next; - - *statusp = (*p)->status; - xfree (*p); - *p = next; - return 1; - } - return 0; -} - -enum stopping_threads_kind - { - /* Not stopping threads presently. */ - NOT_STOPPING_THREADS, - - /* Stopping threads. */ - STOPPING_THREADS, - - /* Stopping and suspending threads. */ - STOPPING_AND_SUSPENDING_THREADS - }; - -/* This is set while stop_all_lwps is in effect. */ -enum stopping_threads_kind stopping_threads = NOT_STOPPING_THREADS; - -/* FIXME make into a target method? */ -int using_threads = 1; - -/* True if we're presently stabilizing threads (moving them out of - jump pads). */ -static int stabilizing_threads; - -static void linux_resume_one_lwp (struct lwp_info *lwp, - int step, int signal, siginfo_t *info); -static void linux_resume (struct thread_resume *resume_info, size_t n); -static void stop_all_lwps (int suspend, struct lwp_info *except); -static void unstop_all_lwps (int unsuspend, struct lwp_info *except); -static void unsuspend_all_lwps (struct lwp_info *except); -static int linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, - int *wstat, int options); -static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); -static struct lwp_info *add_lwp (ptid_t ptid); -static void linux_mourn (struct process_info *process); -static int linux_stopped_by_watchpoint (void); -static void mark_lwp_dead (struct lwp_info *lwp, int wstat); -static int lwp_is_marked_dead (struct lwp_info *lwp); -static void proceed_all_lwps (void); -static int finish_step_over (struct lwp_info *lwp); -static int kill_lwp (unsigned long lwpid, int signo); -static void enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info); -static void complete_ongoing_step_over (void); -static int linux_low_ptrace_options (int attached); -static int check_ptrace_stopped_lwp_gone (struct lwp_info *lp); -static void proceed_one_lwp (thread_info *thread, lwp_info *except); - -/* When the event-loop is doing a step-over, this points at the thread - being stepped. */ -ptid_t step_over_bkpt; - -/* True if the low target can hardware single-step. */ - -static int -can_hardware_single_step (void) -{ - if (the_low_target.supports_hardware_single_step != NULL) - return the_low_target.supports_hardware_single_step (); - else - return 0; -} - -/* True if the low target can software single-step. Such targets - implement the GET_NEXT_PCS callback. */ - -static int -can_software_single_step (void) -{ - return (the_low_target.get_next_pcs != NULL); -} - -/* True if the low target supports memory breakpoints. If so, we'll - have a GET_PC implementation. */ - -static int -supports_breakpoints (void) -{ - return (the_low_target.get_pc != NULL); -} - -/* Returns true if this target can support fast tracepoints. This - does not mean that the in-process agent has been loaded in the - inferior. */ - -static int -supports_fast_tracepoints (void) -{ - return the_low_target.install_fast_tracepoint_jump_pad != NULL; -} - -/* True if LWP is stopped in its stepping range. */ - -static int -lwp_in_step_range (struct lwp_info *lwp) -{ - CORE_ADDR pc = lwp->stop_pc; - - return (pc >= lwp->step_range_start && pc < lwp->step_range_end); -} - -struct pending_signals -{ - int signal; - siginfo_t info; - struct pending_signals *prev; -}; - -/* The read/write ends of the pipe registered as waitable file in the - event loop. */ -static int linux_event_pipe[2] = { -1, -1 }; - -/* True if we're currently in async mode. */ -#define target_is_async_p() (linux_event_pipe[0] != -1) - -static void send_sigstop (struct lwp_info *lwp); -static void wait_for_sigstop (void); - -/* Return non-zero if HEADER is a 64-bit ELF file. */ - -static int -elf_64_header_p (const Elf64_Ehdr *header, unsigned int *machine) -{ - if (header->e_ident[EI_MAG0] == ELFMAG0 - && header->e_ident[EI_MAG1] == ELFMAG1 - && header->e_ident[EI_MAG2] == ELFMAG2 - && header->e_ident[EI_MAG3] == ELFMAG3) - { - *machine = header->e_machine; - return header->e_ident[EI_CLASS] == ELFCLASS64; - - } - *machine = EM_NONE; - return -1; -} - -/* Return non-zero if FILE is a 64-bit ELF file, - zero if the file is not a 64-bit ELF file, - and -1 if the file is not accessible or doesn't exist. */ - -static int -elf_64_file_p (const char *file, unsigned int *machine) -{ - Elf64_Ehdr header; - int fd; - - fd = open (file, O_RDONLY); - if (fd < 0) - return -1; - - if (read (fd, &header, sizeof (header)) != sizeof (header)) - { - close (fd); - return 0; - } - close (fd); - - return elf_64_header_p (&header, machine); -} - -/* Accepts an integer PID; Returns true if the executable PID is - running is a 64-bit ELF file.. */ - -int -linux_pid_exe_is_elf_64_file (int pid, unsigned int *machine) -{ - char file[PATH_MAX]; - - sprintf (file, "/proc/%d/exe", pid); - return elf_64_file_p (file, machine); -} - -static void -delete_lwp (struct lwp_info *lwp) -{ - struct thread_info *thr = get_lwp_thread (lwp); - - if (debug_threads) - debug_printf ("deleting %ld\n", lwpid_of (thr)); - - remove_thread (thr); - - if (the_low_target.delete_thread != NULL) - the_low_target.delete_thread (lwp->arch_private); - else - gdb_assert (lwp->arch_private == NULL); - - free (lwp); -} - -/* Add a process to the common process list, and set its private - data. */ - -static struct process_info * -linux_add_process (int pid, int attached) -{ - struct process_info *proc; - - proc = add_process (pid, attached); - proc->priv = XCNEW (struct process_info_private); - - if (the_low_target.new_process != NULL) - proc->priv->arch_private = the_low_target.new_process (); - - return proc; -} - -static CORE_ADDR get_pc (struct lwp_info *lwp); - -/* Call the target arch_setup function on the current thread. */ - -static void -linux_arch_setup (void) -{ - the_low_target.arch_setup (); -} - -/* Call the target arch_setup function on THREAD. */ - -static void -linux_arch_setup_thread (struct thread_info *thread) -{ - struct thread_info *saved_thread; - - saved_thread = current_thread; - current_thread = thread; - - linux_arch_setup (); - - current_thread = saved_thread; -} - -/* Handle a GNU/Linux extended wait response. If we see a clone, - fork, or vfork event, we need to add the new LWP to our list - (and return 0 so as not to report the trap to higher layers). - If we see an exec event, we will modify ORIG_EVENT_LWP to point - to a new LWP representing the new program. */ - -static int -handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) -{ - client_state &cs = get_client_state (); - struct lwp_info *event_lwp = *orig_event_lwp; - int event = linux_ptrace_get_extended_event (wstat); - struct thread_info *event_thr = get_lwp_thread (event_lwp); - struct lwp_info *new_lwp; - - gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); - - /* All extended events we currently use are mid-syscall. Only - PTRACE_EVENT_STOP is delivered more like a signal-stop, but - you have to be using PTRACE_SEIZE to get that. */ - event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; - - if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) - || (event == PTRACE_EVENT_CLONE)) - { - ptid_t ptid; - unsigned long new_pid; - int ret, status; - - /* Get the pid of the new lwp. */ - ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_thr), (PTRACE_TYPE_ARG3) 0, - &new_pid); - - /* If we haven't already seen the new PID stop, wait for it now. */ - if (!pull_pid_from_list (&stopped_pids, new_pid, &status)) - { - /* The new child has a pending SIGSTOP. We can't affect it until it - hits the SIGSTOP, but we're already attached. */ - - ret = my_waitpid (new_pid, &status, __WALL); - - if (ret == -1) - perror_with_name ("waiting for new child"); - else if (ret != new_pid) - warning ("wait returned unexpected PID %d", ret); - else if (!WIFSTOPPED (status)) - warning ("wait returned unexpected status 0x%x", status); - } - - if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK) - { - struct process_info *parent_proc; - struct process_info *child_proc; - struct lwp_info *child_lwp; - struct thread_info *child_thr; - struct target_desc *tdesc; - - ptid = ptid_t (new_pid, new_pid, 0); - - if (debug_threads) - { - debug_printf ("HEW: Got fork event from LWP %ld, " - "new child is %d\n", - ptid_of (event_thr).lwp (), - ptid.pid ()); - } - - /* Add the new process to the tables and clone the breakpoint - lists of the parent. We need to do this even if the new process - will be detached, since we will need the process object and the - breakpoints to remove any breakpoints from memory when we - detach, and the client side will access registers. */ - child_proc = linux_add_process (new_pid, 0); - gdb_assert (child_proc != NULL); - child_lwp = add_lwp (ptid); - gdb_assert (child_lwp != NULL); - child_lwp->stopped = 1; - child_lwp->must_set_ptrace_flags = 1; - child_lwp->status_pending_p = 0; - child_thr = get_lwp_thread (child_lwp); - child_thr->last_resume_kind = resume_stop; - child_thr->last_status.kind = TARGET_WAITKIND_STOPPED; - - /* If we're suspending all threads, leave this one suspended - too. If the fork/clone parent is stepping over a breakpoint, - all other threads have been suspended already. Leave the - child suspended too. */ - if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS - || event_lwp->bp_reinsert != 0) - { - if (debug_threads) - debug_printf ("HEW: leaving child suspended\n"); - child_lwp->suspended = 1; - } - - parent_proc = get_thread_process (event_thr); - child_proc->attached = parent_proc->attached; - - if (event_lwp->bp_reinsert != 0 - && can_software_single_step () - && event == PTRACE_EVENT_VFORK) - { - /* If we leave single-step breakpoints there, child will - hit it, so uninsert single-step breakpoints from parent - (and child). Once vfork child is done, reinsert - them back to parent. */ - uninsert_single_step_breakpoints (event_thr); - } - - clone_all_breakpoints (child_thr, event_thr); - - tdesc = allocate_target_description (); - copy_target_description (tdesc, parent_proc->tdesc); - child_proc->tdesc = tdesc; - - /* Clone arch-specific process data. */ - if (the_low_target.new_fork != NULL) - the_low_target.new_fork (parent_proc, child_proc); - - /* Save fork info in the parent thread. */ - if (event == PTRACE_EVENT_FORK) - event_lwp->waitstatus.kind = TARGET_WAITKIND_FORKED; - else if (event == PTRACE_EVENT_VFORK) - event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORKED; - - event_lwp->waitstatus.value.related_pid = ptid; - - /* The status_pending field contains bits denoting the - extended event, so when the pending event is handled, - the handler will look at lwp->waitstatus. */ - event_lwp->status_pending_p = 1; - event_lwp->status_pending = wstat; - - /* Link the threads until the parent event is passed on to - higher layers. */ - event_lwp->fork_relative = child_lwp; - child_lwp->fork_relative = event_lwp; - - /* If the parent thread is doing step-over with single-step - breakpoints, the list of single-step breakpoints are cloned - from the parent's. Remove them from the child process. - In case of vfork, we'll reinsert them back once vforked - child is done. */ - if (event_lwp->bp_reinsert != 0 - && can_software_single_step ()) - { - /* The child process is forked and stopped, so it is safe - to access its memory without stopping all other threads - from other processes. */ - delete_single_step_breakpoints (child_thr); - - gdb_assert (has_single_step_breakpoints (event_thr)); - gdb_assert (!has_single_step_breakpoints (child_thr)); - } - - /* Report the event. */ - return 0; - } - - if (debug_threads) - debug_printf ("HEW: Got clone event " - "from LWP %ld, new child is LWP %ld\n", - lwpid_of (event_thr), new_pid); - - ptid = ptid_t (pid_of (event_thr), new_pid, 0); - new_lwp = add_lwp (ptid); - - /* Either we're going to immediately resume the new thread - or leave it stopped. linux_resume_one_lwp is a nop if it - thinks the thread is currently running, so set this first - before calling linux_resume_one_lwp. */ - new_lwp->stopped = 1; - - /* If we're suspending all threads, leave this one suspended - too. If the fork/clone parent is stepping over a breakpoint, - all other threads have been suspended already. Leave the - child suspended too. */ - if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS - || event_lwp->bp_reinsert != 0) - new_lwp->suspended = 1; - - /* Normally we will get the pending SIGSTOP. But in some cases - we might get another signal delivered to the group first. - If we do get another signal, be sure not to lose it. */ - if (WSTOPSIG (status) != SIGSTOP) - { - new_lwp->stop_expected = 1; - new_lwp->status_pending_p = 1; - new_lwp->status_pending = status; - } - else if (cs.report_thread_events) - { - new_lwp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED; - new_lwp->status_pending_p = 1; - new_lwp->status_pending = status; - } - -#ifdef USE_THREAD_DB - thread_db_notice_clone (event_thr, ptid); -#endif - - /* Don't report the event. */ - return 1; - } - else if (event == PTRACE_EVENT_VFORK_DONE) - { - event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE; - - if (event_lwp->bp_reinsert != 0 && can_software_single_step ()) - { - reinsert_single_step_breakpoints (event_thr); - - gdb_assert (has_single_step_breakpoints (event_thr)); - } - - /* Report the event. */ - return 0; - } - else if (event == PTRACE_EVENT_EXEC && cs.report_exec_events) - { - struct process_info *proc; - std::vector syscalls_to_catch; - ptid_t event_ptid; - pid_t event_pid; - - if (debug_threads) - { - debug_printf ("HEW: Got exec event from LWP %ld\n", - lwpid_of (event_thr)); - } - - /* Get the event ptid. */ - event_ptid = ptid_of (event_thr); - event_pid = event_ptid.pid (); - - /* Save the syscall list from the execing process. */ - proc = get_thread_process (event_thr); - syscalls_to_catch = std::move (proc->syscalls_to_catch); - - /* Delete the execing process and all its threads. */ - linux_mourn (proc); - current_thread = NULL; - - /* Create a new process/lwp/thread. */ - proc = linux_add_process (event_pid, 0); - event_lwp = add_lwp (event_ptid); - event_thr = get_lwp_thread (event_lwp); - gdb_assert (current_thread == event_thr); - linux_arch_setup_thread (event_thr); - - /* Set the event status. */ - event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD; - event_lwp->waitstatus.value.execd_pathname - = xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr))); - - /* Mark the exec status as pending. */ - event_lwp->stopped = 1; - event_lwp->status_pending_p = 1; - event_lwp->status_pending = wstat; - event_thr->last_resume_kind = resume_continue; - event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; - - /* Update syscall state in the new lwp, effectively mid-syscall too. */ - event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; - - /* Restore the list to catch. Don't rely on the client, which is free - to avoid sending a new list when the architecture doesn't change. - Also, for ANY_SYSCALL, the architecture doesn't really matter. */ - proc->syscalls_to_catch = std::move (syscalls_to_catch); - - /* Report the event. */ - *orig_event_lwp = event_lwp; - return 0; - } - - internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); -} - -/* Return the PC as read from the regcache of LWP, without any - adjustment. */ - -static CORE_ADDR -get_pc (struct lwp_info *lwp) -{ - struct thread_info *saved_thread; - struct regcache *regcache; - CORE_ADDR pc; - - if (the_low_target.get_pc == NULL) - return 0; - - saved_thread = current_thread; - current_thread = get_lwp_thread (lwp); - - regcache = get_thread_regcache (current_thread, 1); - pc = (*the_low_target.get_pc) (regcache); - - if (debug_threads) - debug_printf ("pc is 0x%lx\n", (long) pc); - - current_thread = saved_thread; - return pc; -} - -/* This function should only be called if LWP got a SYSCALL_SIGTRAP. - Fill *SYSNO with the syscall nr trapped. */ - -static void -get_syscall_trapinfo (struct lwp_info *lwp, int *sysno) -{ - struct thread_info *saved_thread; - struct regcache *regcache; - - if (the_low_target.get_syscall_trapinfo == NULL) - { - /* If we cannot get the syscall trapinfo, report an unknown - system call number. */ - *sysno = UNKNOWN_SYSCALL; - return; - } - - saved_thread = current_thread; - current_thread = get_lwp_thread (lwp); - - regcache = get_thread_regcache (current_thread, 1); - (*the_low_target.get_syscall_trapinfo) (regcache, sysno); - - if (debug_threads) - debug_printf ("get_syscall_trapinfo sysno %d\n", *sysno); - - current_thread = saved_thread; -} - -static int check_stopped_by_watchpoint (struct lwp_info *child); - -/* Called when the LWP stopped for a signal/trap. If it stopped for a - trap check what caused it (breakpoint, watchpoint, trace, etc.), - and save the result in the LWP's stop_reason field. If it stopped - for a breakpoint, decrement the PC if necessary on the lwp's - architecture. Returns true if we now have the LWP's stop PC. */ - -static int -save_stop_reason (struct lwp_info *lwp) -{ - CORE_ADDR pc; - CORE_ADDR sw_breakpoint_pc; - struct thread_info *saved_thread; -#if USE_SIGTRAP_SIGINFO - siginfo_t siginfo; -#endif - - if (the_low_target.get_pc == NULL) - return 0; - - pc = get_pc (lwp); - sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break; - - /* breakpoint_at reads from the current thread. */ - saved_thread = current_thread; - current_thread = get_lwp_thread (lwp); - -#if USE_SIGTRAP_SIGINFO - if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), - (PTRACE_TYPE_ARG3) 0, &siginfo) == 0) - { - if (siginfo.si_signo == SIGTRAP) - { - if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code) - && GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code)) - { - /* The si_code is ambiguous on this arch -- check debug - registers. */ - if (!check_stopped_by_watchpoint (lwp)) - lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; - } - else if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code)) - { - /* If we determine the LWP stopped for a SW breakpoint, - trust it. Particularly don't check watchpoint - registers, because at least on s390, we'd find - stopped-by-watchpoint as long as there's a watchpoint - set. */ - lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; - } - else if (GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code)) - { - /* This can indicate either a hardware breakpoint or - hardware watchpoint. Check debug registers. */ - if (!check_stopped_by_watchpoint (lwp)) - lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; - } - else if (siginfo.si_code == TRAP_TRACE) - { - /* We may have single stepped an instruction that - triggered a watchpoint. In that case, on some - architectures (such as x86), instead of TRAP_HWBKPT, - si_code indicates TRAP_TRACE, and we need to check - the debug registers separately. */ - if (!check_stopped_by_watchpoint (lwp)) - lwp->stop_reason = TARGET_STOPPED_BY_SINGLE_STEP; - } - } - } -#else - /* We may have just stepped a breakpoint instruction. E.g., in - non-stop mode, GDB first tells the thread A to step a range, and - then the user inserts a breakpoint inside the range. In that - case we need to report the breakpoint PC. */ - if ((!lwp->stepping || lwp->stop_pc == sw_breakpoint_pc) - && (*the_low_target.breakpoint_at) (sw_breakpoint_pc)) - lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; - - if (hardware_breakpoint_inserted_here (pc)) - lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; - - if (lwp->stop_reason == TARGET_STOPPED_BY_NO_REASON) - check_stopped_by_watchpoint (lwp); -#endif - - if (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) - { - if (debug_threads) - { - struct thread_info *thr = get_lwp_thread (lwp); - - debug_printf ("CSBB: %s stopped by software breakpoint\n", - target_pid_to_str (ptid_of (thr))); - } - - /* Back up the PC if necessary. */ - if (pc != sw_breakpoint_pc) - { - struct regcache *regcache - = get_thread_regcache (current_thread, 1); - (*the_low_target.set_pc) (regcache, sw_breakpoint_pc); - } - - /* Update this so we record the correct stop PC below. */ - pc = sw_breakpoint_pc; - } - else if (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT) - { - if (debug_threads) - { - struct thread_info *thr = get_lwp_thread (lwp); - - debug_printf ("CSBB: %s stopped by hardware breakpoint\n", - target_pid_to_str (ptid_of (thr))); - } - } - else if (lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT) - { - if (debug_threads) - { - struct thread_info *thr = get_lwp_thread (lwp); - - debug_printf ("CSBB: %s stopped by hardware watchpoint\n", - target_pid_to_str (ptid_of (thr))); - } - } - else if (lwp->stop_reason == TARGET_STOPPED_BY_SINGLE_STEP) - { - if (debug_threads) - { - struct thread_info *thr = get_lwp_thread (lwp); - - debug_printf ("CSBB: %s stopped by trace\n", - target_pid_to_str (ptid_of (thr))); - } - } - - lwp->stop_pc = pc; - current_thread = saved_thread; - return 1; -} - -static struct lwp_info * -add_lwp (ptid_t ptid) -{ - struct lwp_info *lwp; - - lwp = XCNEW (struct lwp_info); - - lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE; - - lwp->thread = add_thread (ptid, lwp); - - if (the_low_target.new_thread != NULL) - the_low_target.new_thread (lwp); - - return lwp; -} - -/* Callback to be used when calling fork_inferior, responsible for - actually initiating the tracing of the inferior. */ - -static void -linux_ptrace_fun () -{ - if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) 0) < 0) - trace_start_error_with_name ("ptrace"); - - if (setpgid (0, 0) < 0) - trace_start_error_with_name ("setpgid"); - - /* If GDBserver is connected to gdb via stdio, redirect the inferior's - stdout to stderr so that inferior i/o doesn't corrupt the connection. - Also, redirect stdin to /dev/null. */ - if (remote_connection_is_stdio ()) - { - if (close (0) < 0) - trace_start_error_with_name ("close"); - if (open ("/dev/null", O_RDONLY) < 0) - trace_start_error_with_name ("open"); - if (dup2 (2, 1) < 0) - trace_start_error_with_name ("dup2"); - if (write (2, "stdin/stdout redirected\n", - sizeof ("stdin/stdout redirected\n") - 1) < 0) - { - /* Errors ignored. */; - } - } -} - -/* Start an inferior process and returns its pid. - PROGRAM is the name of the program to be started, and PROGRAM_ARGS - are its arguments. */ - -static int -linux_create_inferior (const char *program, - const std::vector &program_args) -{ - client_state &cs = get_client_state (); - struct lwp_info *new_lwp; - int pid; - ptid_t ptid; - - { - maybe_disable_address_space_randomization restore_personality - (cs.disable_randomization); - std::string str_program_args = stringify_argv (program_args); - - pid = fork_inferior (program, - str_program_args.c_str (), - get_environ ()->envp (), linux_ptrace_fun, - NULL, NULL, NULL, NULL); - } - - linux_add_process (pid, 0); - - ptid = ptid_t (pid, pid, 0); - new_lwp = add_lwp (ptid); - new_lwp->must_set_ptrace_flags = 1; - - post_fork_inferior (pid, program); - - return pid; -} - -/* Implement the post_create_inferior target_ops method. */ - -static void -linux_post_create_inferior (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - - linux_arch_setup (); - - if (lwp->must_set_ptrace_flags) - { - struct process_info *proc = current_process (); - int options = linux_low_ptrace_options (proc->attached); - - linux_enable_event_reporting (lwpid_of (current_thread), options); - lwp->must_set_ptrace_flags = 0; - } -} - -/* Attach to an inferior process. Returns 0 on success, ERRNO on - error. */ - -int -linux_attach_lwp (ptid_t ptid) -{ - struct lwp_info *new_lwp; - int lwpid = ptid.lwp (); - - if (ptrace (PTRACE_ATTACH, lwpid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0) - != 0) - return errno; - - new_lwp = add_lwp (ptid); - - /* We need to wait for SIGSTOP before being able to make the next - ptrace call on this LWP. */ - new_lwp->must_set_ptrace_flags = 1; - - if (linux_proc_pid_is_stopped (lwpid)) - { - if (debug_threads) - debug_printf ("Attached to a stopped process\n"); - - /* The process is definitely stopped. It is in a job control - stop, unless the kernel predates the TASK_STOPPED / - TASK_TRACED distinction, in which case it might be in a - ptrace stop. Make sure it is in a ptrace stop; from there we - can kill it, signal it, et cetera. - - First make sure there is a pending SIGSTOP. Since we are - already attached, the process can not transition from stopped - to running without a PTRACE_CONT; so we know this signal will - go into the queue. The SIGSTOP generated by PTRACE_ATTACH is - probably already in the queue (unless this kernel is old - enough to use TASK_STOPPED for ptrace stops); but since - SIGSTOP is not an RT signal, it can only be queued once. */ - kill_lwp (lwpid, SIGSTOP); - - /* Finally, resume the stopped process. This will deliver the - SIGSTOP (or a higher priority signal, just like normal - PTRACE_ATTACH), which we'll catch later on. */ - ptrace (PTRACE_CONT, lwpid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); - } - - /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH - brings it to a halt. - - There are several cases to consider here: - - 1) gdbserver has already attached to the process and is being notified - of a new thread that is being created. - In this case we should ignore that SIGSTOP and resume the - process. This is handled below by setting stop_expected = 1, - and the fact that add_thread sets last_resume_kind == - resume_continue. - - 2) This is the first thread (the process thread), and we're attaching - to it via attach_inferior. - In this case we want the process thread to stop. - This is handled by having linux_attach set last_resume_kind == - resume_stop after we return. - - If the pid we are attaching to is also the tgid, we attach to and - stop all the existing threads. Otherwise, we attach to pid and - ignore any other threads in the same group as this pid. - - 3) GDB is connecting to gdbserver and is requesting an enumeration of all - existing threads. - In this case we want the thread to stop. - FIXME: This case is currently not properly handled. - We should wait for the SIGSTOP but don't. Things work apparently - because enough time passes between when we ptrace (ATTACH) and when - gdb makes the next ptrace call on the thread. - - On the other hand, if we are currently trying to stop all threads, we - should treat the new thread as if we had sent it a SIGSTOP. This works - because we are guaranteed that the add_lwp call above added us to the - end of the list, and so the new thread has not yet reached - wait_for_sigstop (but will). */ - new_lwp->stop_expected = 1; - - return 0; -} - -/* Callback for linux_proc_attach_tgid_threads. Attach to PTID if not - already attached. Returns true if a new LWP is found, false - otherwise. */ - -static int -attach_proc_task_lwp_callback (ptid_t ptid) -{ - /* Is this a new thread? */ - if (find_thread_ptid (ptid) == NULL) - { - int lwpid = ptid.lwp (); - int err; - - if (debug_threads) - debug_printf ("Found new lwp %d\n", lwpid); - - err = linux_attach_lwp (ptid); - - /* Be quiet if we simply raced with the thread exiting. EPERM - is returned if the thread's task still exists, and is marked - as exited or zombie, as well as other conditions, so in that - case, confirm the status in /proc/PID/status. */ - if (err == ESRCH - || (err == EPERM && linux_proc_pid_is_gone (lwpid))) - { - if (debug_threads) - { - debug_printf ("Cannot attach to lwp %d: " - "thread is gone (%d: %s)\n", - lwpid, err, safe_strerror (err)); - } - } - else if (err != 0) - { - std::string reason - = linux_ptrace_attach_fail_reason_string (ptid, err); - - warning (_("Cannot attach to lwp %d: %s"), lwpid, reason.c_str ()); - } - - return 1; - } - return 0; -} - -static void async_file_mark (void); - -/* Attach to PID. If PID is the tgid, attach to it and all - of its threads. */ - -static int -linux_attach (unsigned long pid) -{ - struct process_info *proc; - struct thread_info *initial_thread; - ptid_t ptid = ptid_t (pid, pid, 0); - int err; - - proc = linux_add_process (pid, 1); - - /* Attach to PID. We will check for other threads - soon. */ - err = linux_attach_lwp (ptid); - if (err != 0) - { - remove_process (proc); - - std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err); - error ("Cannot attach to process %ld: %s", pid, reason.c_str ()); - } - - /* Don't ignore the initial SIGSTOP if we just attached to this - process. It will be collected by wait shortly. */ - initial_thread = find_thread_ptid (ptid_t (pid, pid, 0)); - initial_thread->last_resume_kind = resume_stop; - - /* We must attach to every LWP. If /proc is mounted, use that to - find them now. On the one hand, the inferior may be using raw - clone instead of using pthreads. On the other hand, even if it - is using pthreads, GDB may not be connected yet (thread_db needs - to do symbol lookups, through qSymbol). Also, thread_db walks - structures in the inferior's address space to find the list of - threads/LWPs, and those structures may well be corrupted. Note - that once thread_db is loaded, we'll still use it to list threads - and associate pthread info with each LWP. */ - linux_proc_attach_tgid_threads (pid, attach_proc_task_lwp_callback); - - /* GDB will shortly read the xml target description for this - process, to figure out the process' architecture. But the target - description is only filled in when the first process/thread in - the thread group reports its initial PTRACE_ATTACH SIGSTOP. Do - that now, otherwise, if GDB is fast enough, it could read the - target description _before_ that initial stop. */ - if (non_stop) - { - struct lwp_info *lwp; - int wstat, lwpid; - ptid_t pid_ptid = ptid_t (pid); - - lwpid = linux_wait_for_event_filtered (pid_ptid, pid_ptid, - &wstat, __WALL); - gdb_assert (lwpid > 0); - - lwp = find_lwp_pid (ptid_t (lwpid)); - - if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGSTOP) - { - lwp->status_pending_p = 1; - lwp->status_pending = wstat; - } - - initial_thread->last_resume_kind = resume_continue; - - async_file_mark (); - - gdb_assert (proc->tdesc != NULL); - } - - return 0; -} - -static int -last_thread_of_process_p (int pid) -{ - bool seen_one = false; - - thread_info *thread = find_thread (pid, [&] (thread_info *thr_arg) - { - if (!seen_one) - { - /* This is the first thread of this process we see. */ - seen_one = true; - return false; - } - else - { - /* This is the second thread of this process we see. */ - return true; - } - }); - - return thread == NULL; -} - -/* Kill LWP. */ - -static void -linux_kill_one_lwp (struct lwp_info *lwp) -{ - struct thread_info *thr = get_lwp_thread (lwp); - int pid = lwpid_of (thr); - - /* PTRACE_KILL is unreliable. After stepping into a signal handler, - there is no signal context, and ptrace(PTRACE_KILL) (or - ptrace(PTRACE_CONT, SIGKILL), pretty much the same) acts like - ptrace(CONT, pid, 0,0) and just resumes the tracee. A better - alternative is to kill with SIGKILL. We only need one SIGKILL - per process, not one for each thread. But since we still support - support debugging programs using raw clone without CLONE_THREAD, - we send one for each thread. For years, we used PTRACE_KILL - only, so we're being a bit paranoid about some old kernels where - PTRACE_KILL might work better (dubious if there are any such, but - that's why it's paranoia), so we try SIGKILL first, PTRACE_KILL - second, and so we're fine everywhere. */ - - errno = 0; - kill_lwp (pid, SIGKILL); - if (debug_threads) - { - int save_errno = errno; - - debug_printf ("LKL: kill_lwp (SIGKILL) %s, 0, 0 (%s)\n", - target_pid_to_str (ptid_of (thr)), - save_errno ? safe_strerror (save_errno) : "OK"); - } - - errno = 0; - ptrace (PTRACE_KILL, pid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); - if (debug_threads) - { - int save_errno = errno; - - debug_printf ("LKL: PTRACE_KILL %s, 0, 0 (%s)\n", - target_pid_to_str (ptid_of (thr)), - save_errno ? safe_strerror (save_errno) : "OK"); - } -} - -/* Kill LWP and wait for it to die. */ - -static void -kill_wait_lwp (struct lwp_info *lwp) -{ - struct thread_info *thr = get_lwp_thread (lwp); - int pid = ptid_of (thr).pid (); - int lwpid = ptid_of (thr).lwp (); - int wstat; - int res; - - if (debug_threads) - debug_printf ("kwl: killing lwp %d, for pid: %d\n", lwpid, pid); - - do - { - linux_kill_one_lwp (lwp); - - /* Make sure it died. Notes: - - - The loop is most likely unnecessary. - - - We don't use linux_wait_for_event as that could delete lwps - while we're iterating over them. We're not interested in - any pending status at this point, only in making sure all - wait status on the kernel side are collected until the - process is reaped. - - - We don't use __WALL here as the __WALL emulation relies on - SIGCHLD, and killing a stopped process doesn't generate - one, nor an exit status. - */ - res = my_waitpid (lwpid, &wstat, 0); - if (res == -1 && errno == ECHILD) - res = my_waitpid (lwpid, &wstat, __WCLONE); - } while (res > 0 && WIFSTOPPED (wstat)); - - /* Even if it was stopped, the child may have already disappeared. - E.g., if it was killed by SIGKILL. */ - if (res < 0 && errno != ECHILD) - perror_with_name ("kill_wait_lwp"); -} - -/* Callback for `for_each_thread'. Kills an lwp of a given process, - except the leader. */ - -static void -kill_one_lwp_callback (thread_info *thread, int pid) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - /* We avoid killing the first thread here, because of a Linux kernel (at - least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before - the children get a chance to be reaped, it will remain a zombie - forever. */ - - if (lwpid_of (thread) == pid) - { - if (debug_threads) - debug_printf ("lkop: is last of process %s\n", - target_pid_to_str (thread->id)); - return; - } - - kill_wait_lwp (lwp); -} - -static int -linux_kill (process_info *process) -{ - int pid = process->pid; - - /* If we're killing a running inferior, make sure it is stopped - first, as PTRACE_KILL will not work otherwise. */ - stop_all_lwps (0, NULL); - - for_each_thread (pid, [&] (thread_info *thread) - { - kill_one_lwp_callback (thread, pid); - }); - - /* See the comment in linux_kill_one_lwp. We did not kill the first - thread in the list, so do so now. */ - lwp_info *lwp = find_lwp_pid (ptid_t (pid)); - - if (lwp == NULL) - { - if (debug_threads) - debug_printf ("lk_1: cannot find lwp for pid: %d\n", - pid); - } - else - kill_wait_lwp (lwp); - - the_target->mourn (process); - - /* Since we presently can only stop all lwps of all processes, we - need to unstop lwps of other processes. */ - unstop_all_lwps (0, NULL); - return 0; -} - -/* Get pending signal of THREAD, for detaching purposes. This is the - signal the thread last stopped for, which we need to deliver to the - thread when detaching, otherwise, it'd be suppressed/lost. */ - -static int -get_detach_signal (struct thread_info *thread) -{ - client_state &cs = get_client_state (); - enum gdb_signal signo = GDB_SIGNAL_0; - int status; - struct lwp_info *lp = get_thread_lwp (thread); - - if (lp->status_pending_p) - status = lp->status_pending; - else - { - /* If the thread had been suspended by gdbserver, and it stopped - cleanly, then it'll have stopped with SIGSTOP. But we don't - want to deliver that SIGSTOP. */ - if (thread->last_status.kind != TARGET_WAITKIND_STOPPED - || thread->last_status.value.sig == GDB_SIGNAL_0) - return 0; - - /* Otherwise, we may need to deliver the signal we - intercepted. */ - status = lp->last_status; - } - - if (!WIFSTOPPED (status)) - { - if (debug_threads) - debug_printf ("GPS: lwp %s hasn't stopped: no pending signal\n", - target_pid_to_str (ptid_of (thread))); - return 0; - } - - /* Extended wait statuses aren't real SIGTRAPs. */ - if (WSTOPSIG (status) == SIGTRAP && linux_is_extended_waitstatus (status)) - { - if (debug_threads) - debug_printf ("GPS: lwp %s had stopped with extended " - "status: no pending signal\n", - target_pid_to_str (ptid_of (thread))); - return 0; - } - - signo = gdb_signal_from_host (WSTOPSIG (status)); - - if (cs.program_signals_p && !cs.program_signals[signo]) - { - if (debug_threads) - debug_printf ("GPS: lwp %s had signal %s, but it is in nopass state\n", - target_pid_to_str (ptid_of (thread)), - gdb_signal_to_string (signo)); - return 0; - } - else if (!cs.program_signals_p - /* If we have no way to know which signals GDB does not - want to have passed to the program, assume - SIGTRAP/SIGINT, which is GDB's default. */ - && (signo == GDB_SIGNAL_TRAP || signo == GDB_SIGNAL_INT)) - { - if (debug_threads) - debug_printf ("GPS: lwp %s had signal %s, " - "but we don't know if we should pass it. " - "Default to not.\n", - target_pid_to_str (ptid_of (thread)), - gdb_signal_to_string (signo)); - return 0; - } - else - { - if (debug_threads) - debug_printf ("GPS: lwp %s has pending signal %s: delivering it.\n", - target_pid_to_str (ptid_of (thread)), - gdb_signal_to_string (signo)); - - return WSTOPSIG (status); - } -} - -/* Detach from LWP. */ - -static void -linux_detach_one_lwp (struct lwp_info *lwp) -{ - struct thread_info *thread = get_lwp_thread (lwp); - int sig; - int lwpid; - - /* If there is a pending SIGSTOP, get rid of it. */ - if (lwp->stop_expected) - { - if (debug_threads) - debug_printf ("Sending SIGCONT to %s\n", - target_pid_to_str (ptid_of (thread))); - - kill_lwp (lwpid_of (thread), SIGCONT); - lwp->stop_expected = 0; - } - - /* Pass on any pending signal for this thread. */ - sig = get_detach_signal (thread); - - /* Preparing to resume may try to write registers, and fail if the - lwp is zombie. If that happens, ignore the error. We'll handle - it below, when detach fails with ESRCH. */ - try - { - /* Flush any pending changes to the process's registers. */ - regcache_invalidate_thread (thread); - - /* Finally, let it resume. */ - if (the_low_target.prepare_to_resume != NULL) - the_low_target.prepare_to_resume (lwp); - } - catch (const gdb_exception_error &ex) - { - if (!check_ptrace_stopped_lwp_gone (lwp)) - throw; - } - - lwpid = lwpid_of (thread); - if (ptrace (PTRACE_DETACH, lwpid, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) (long) sig) < 0) - { - int save_errno = errno; - - /* We know the thread exists, so ESRCH must mean the lwp is - zombie. This can happen if one of the already-detached - threads exits the whole thread group. In that case we're - still attached, and must reap the lwp. */ - if (save_errno == ESRCH) - { - int ret, status; - - ret = my_waitpid (lwpid, &status, __WALL); - if (ret == -1) - { - warning (_("Couldn't reap LWP %d while detaching: %s"), - lwpid, safe_strerror (errno)); - } - else if (!WIFEXITED (status) && !WIFSIGNALED (status)) - { - warning (_("Reaping LWP %d while detaching " - "returned unexpected status 0x%x"), - lwpid, status); - } - } - else - { - error (_("Can't detach %s: %s"), - target_pid_to_str (ptid_of (thread)), - safe_strerror (save_errno)); - } - } - else if (debug_threads) - { - debug_printf ("PTRACE_DETACH (%s, %s, 0) (OK)\n", - target_pid_to_str (ptid_of (thread)), - strsignal (sig)); - } - - delete_lwp (lwp); -} - -/* Callback for for_each_thread. Detaches from non-leader threads of a - given process. */ - -static void -linux_detach_lwp_callback (thread_info *thread) -{ - /* We don't actually detach from the thread group leader just yet. - If the thread group exits, we must reap the zombie clone lwps - before we're able to reap the leader. */ - if (thread->id.pid () == thread->id.lwp ()) - return; - - lwp_info *lwp = get_thread_lwp (thread); - linux_detach_one_lwp (lwp); -} - -static int -linux_detach (process_info *process) -{ - struct lwp_info *main_lwp; - - /* As there's a step over already in progress, let it finish first, - otherwise nesting a stabilize_threads operation on top gets real - messy. */ - complete_ongoing_step_over (); - - /* Stop all threads before detaching. First, ptrace requires that - the thread is stopped to successfully detach. Second, thread_db - may need to uninstall thread event breakpoints from memory, which - only works with a stopped process anyway. */ - stop_all_lwps (0, NULL); - -#ifdef USE_THREAD_DB - thread_db_detach (process); -#endif - - /* Stabilize threads (move out of jump pads). */ - stabilize_threads (); - - /* Detach from the clone lwps first. If the thread group exits just - while we're detaching, we must reap the clone lwps before we're - able to reap the leader. */ - for_each_thread (process->pid, linux_detach_lwp_callback); - - main_lwp = find_lwp_pid (ptid_t (process->pid)); - linux_detach_one_lwp (main_lwp); - - the_target->mourn (process); - - /* Since we presently can only stop all lwps of all processes, we - need to unstop lwps of other processes. */ - unstop_all_lwps (0, NULL); - return 0; -} - -/* Remove all LWPs that belong to process PROC from the lwp list. */ - -static void -linux_mourn (struct process_info *process) -{ - struct process_info_private *priv; - -#ifdef USE_THREAD_DB - thread_db_mourn (process); -#endif - - for_each_thread (process->pid, [] (thread_info *thread) - { - delete_lwp (get_thread_lwp (thread)); - }); - - /* Freeing all private data. */ - priv = process->priv; - if (the_low_target.delete_process != NULL) - the_low_target.delete_process (priv->arch_private); - else - gdb_assert (priv->arch_private == NULL); - free (priv); - process->priv = NULL; - - remove_process (process); -} - -static void -linux_join (int pid) -{ - int status, ret; - - do { - ret = my_waitpid (pid, &status, 0); - if (WIFEXITED (status) || WIFSIGNALED (status)) - break; - } while (ret != -1 || errno != ECHILD); -} - -/* Return nonzero if the given thread is still alive. */ -static int -linux_thread_alive (ptid_t ptid) -{ - struct lwp_info *lwp = find_lwp_pid (ptid); - - /* We assume we always know if a thread exits. If a whole process - exited but we still haven't been able to report it to GDB, we'll - hold on to the last lwp of the dead process. */ - if (lwp != NULL) - return !lwp_is_marked_dead (lwp); - else - return 0; -} - -/* Return 1 if this lwp still has an interesting status pending. If - not (e.g., it had stopped for a breakpoint that is gone), return - false. */ - -static int -thread_still_has_status_pending_p (struct thread_info *thread) -{ - struct lwp_info *lp = get_thread_lwp (thread); - - if (!lp->status_pending_p) - return 0; - - if (thread->last_resume_kind != resume_stop - && (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT - || lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) - { - struct thread_info *saved_thread; - CORE_ADDR pc; - int discard = 0; - - gdb_assert (lp->last_status != 0); - - pc = get_pc (lp); - - saved_thread = current_thread; - current_thread = thread; - - if (pc != lp->stop_pc) - { - if (debug_threads) - debug_printf ("PC of %ld changed\n", - lwpid_of (thread)); - discard = 1; - } - -#if !USE_SIGTRAP_SIGINFO - else if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT - && !(*the_low_target.breakpoint_at) (pc)) - { - if (debug_threads) - debug_printf ("previous SW breakpoint of %ld gone\n", - lwpid_of (thread)); - discard = 1; - } - else if (lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT - && !hardware_breakpoint_inserted_here (pc)) - { - if (debug_threads) - debug_printf ("previous HW breakpoint of %ld gone\n", - lwpid_of (thread)); - discard = 1; - } -#endif - - current_thread = saved_thread; - - if (discard) - { - if (debug_threads) - debug_printf ("discarding pending breakpoint status\n"); - lp->status_pending_p = 0; - return 0; - } - } - - return 1; -} - -/* Returns true if LWP is resumed from the client's perspective. */ - -static int -lwp_resumed (struct lwp_info *lwp) -{ - struct thread_info *thread = get_lwp_thread (lwp); - - if (thread->last_resume_kind != resume_stop) - return 1; - - /* Did gdb send us a `vCont;t', but we haven't reported the - corresponding stop to gdb yet? If so, the thread is still - resumed/running from gdb's perspective. */ - if (thread->last_resume_kind == resume_stop - && thread->last_status.kind == TARGET_WAITKIND_IGNORE) - return 1; - - return 0; -} - -/* Return true if this lwp has an interesting status pending. */ -static bool -status_pending_p_callback (thread_info *thread, ptid_t ptid) -{ - struct lwp_info *lp = get_thread_lwp (thread); - - /* Check if we're only interested in events from a specific process - or a specific LWP. */ - if (!thread->id.matches (ptid)) - return 0; - - if (!lwp_resumed (lp)) - return 0; - - if (lp->status_pending_p - && !thread_still_has_status_pending_p (thread)) - { - linux_resume_one_lwp (lp, lp->stepping, GDB_SIGNAL_0, NULL); - return 0; - } - - return lp->status_pending_p; -} - -struct lwp_info * -find_lwp_pid (ptid_t ptid) -{ - thread_info *thread = find_thread ([&] (thread_info *thr_arg) - { - int lwp = ptid.lwp () != 0 ? ptid.lwp () : ptid.pid (); - return thr_arg->id.lwp () == lwp; - }); - - if (thread == NULL) - return NULL; - - return get_thread_lwp (thread); -} - -/* Return the number of known LWPs in the tgid given by PID. */ - -static int -num_lwps (int pid) -{ - int count = 0; - - for_each_thread (pid, [&] (thread_info *thread) - { - count++; - }); - - return count; -} - -/* See nat/linux-nat.h. */ - -struct lwp_info * -iterate_over_lwps (ptid_t filter, - gdb::function_view callback) -{ - thread_info *thread = find_thread (filter, [&] (thread_info *thr_arg) - { - lwp_info *lwp = get_thread_lwp (thr_arg); - - return callback (lwp); - }); - - if (thread == NULL) - return NULL; - - return get_thread_lwp (thread); -} - -/* Detect zombie thread group leaders, and "exit" them. We can't reap - their exits until all other threads in the group have exited. */ - -static void -check_zombie_leaders (void) -{ - for_each_process ([] (process_info *proc) { - pid_t leader_pid = pid_of (proc); - struct lwp_info *leader_lp; - - leader_lp = find_lwp_pid (ptid_t (leader_pid)); - - if (debug_threads) - debug_printf ("leader_pid=%d, leader_lp!=NULL=%d, " - "num_lwps=%d, zombie=%d\n", - leader_pid, leader_lp!= NULL, num_lwps (leader_pid), - linux_proc_pid_is_zombie (leader_pid)); - - if (leader_lp != NULL && !leader_lp->stopped - /* Check if there are other threads in the group, as we may - have raced with the inferior simply exiting. */ - && !last_thread_of_process_p (leader_pid) - && linux_proc_pid_is_zombie (leader_pid)) - { - /* A leader zombie can mean one of two things: - - - It exited, and there's an exit status pending - available, or only the leader exited (not the whole - program). In the latter case, we can't waitpid the - leader's exit status until all other threads are gone. - - - There are 3 or more threads in the group, and a thread - other than the leader exec'd. On an exec, the Linux - kernel destroys all other threads (except the execing - one) in the thread group, and resets the execing thread's - tid to the tgid. No exit notification is sent for the - execing thread -- from the ptracer's perspective, it - appears as though the execing thread just vanishes. - Until we reap all other threads except the leader and the - execing thread, the leader will be zombie, and the - execing thread will be in `D (disc sleep)'. As soon as - all other threads are reaped, the execing thread changes - it's tid to the tgid, and the previous (zombie) leader - vanishes, giving place to the "new" leader. We could try - distinguishing the exit and exec cases, by waiting once - more, and seeing if something comes out, but it doesn't - sound useful. The previous leader _does_ go away, and - we'll re-add the new one once we see the exec event - (which is just the same as what would happen if the - previous leader did exit voluntarily before some other - thread execs). */ - - if (debug_threads) - debug_printf ("CZL: Thread group leader %d zombie " - "(it exited, or another thread execd).\n", - leader_pid); - - delete_lwp (leader_lp); - } - }); -} - -/* Callback for `find_thread'. Returns the first LWP that is not - stopped. */ - -static bool -not_stopped_callback (thread_info *thread, ptid_t filter) -{ - if (!thread->id.matches (filter)) - return false; - - lwp_info *lwp = get_thread_lwp (thread); - - return !lwp->stopped; -} - -/* Increment LWP's suspend count. */ - -static void -lwp_suspended_inc (struct lwp_info *lwp) -{ - lwp->suspended++; - - if (debug_threads && lwp->suspended > 4) - { - struct thread_info *thread = get_lwp_thread (lwp); - - debug_printf ("LWP %ld has a suspiciously high suspend count," - " suspended=%d\n", lwpid_of (thread), lwp->suspended); - } -} - -/* Decrement LWP's suspend count. */ - -static void -lwp_suspended_decr (struct lwp_info *lwp) -{ - lwp->suspended--; - - if (lwp->suspended < 0) - { - struct thread_info *thread = get_lwp_thread (lwp); - - internal_error (__FILE__, __LINE__, - "unsuspend LWP %ld, suspended=%d\n", lwpid_of (thread), - lwp->suspended); - } -} - -/* This function should only be called if the LWP got a SIGTRAP. - - Handle any tracepoint steps or hits. Return true if a tracepoint - event was handled, 0 otherwise. */ - -static int -handle_tracepoints (struct lwp_info *lwp) -{ - struct thread_info *tinfo = get_lwp_thread (lwp); - int tpoint_related_event = 0; - - gdb_assert (lwp->suspended == 0); - - /* If this tracepoint hit causes a tracing stop, we'll immediately - uninsert tracepoints. To do this, we temporarily pause all - threads, unpatch away, and then unpause threads. We need to make - sure the unpausing doesn't resume LWP too. */ - lwp_suspended_inc (lwp); - - /* And we need to be sure that any all-threads-stopping doesn't try - to move threads out of the jump pads, as it could deadlock the - inferior (LWP could be in the jump pad, maybe even holding the - lock.) */ - - /* Do any necessary step collect actions. */ - tpoint_related_event |= tracepoint_finished_step (tinfo, lwp->stop_pc); - - tpoint_related_event |= handle_tracepoint_bkpts (tinfo, lwp->stop_pc); - - /* See if we just hit a tracepoint and do its main collect - actions. */ - tpoint_related_event |= tracepoint_was_hit (tinfo, lwp->stop_pc); - - lwp_suspended_decr (lwp); - - gdb_assert (lwp->suspended == 0); - gdb_assert (!stabilizing_threads - || (lwp->collecting_fast_tracepoint - != fast_tpoint_collect_result::not_collecting)); - - if (tpoint_related_event) - { - if (debug_threads) - debug_printf ("got a tracepoint event\n"); - return 1; - } - - return 0; -} - -/* Convenience wrapper. Returns information about LWP's fast tracepoint - collection status. */ - -static fast_tpoint_collect_result -linux_fast_tracepoint_collecting (struct lwp_info *lwp, - struct fast_tpoint_collect_status *status) -{ - CORE_ADDR thread_area; - struct thread_info *thread = get_lwp_thread (lwp); - - if (the_low_target.get_thread_area == NULL) - return fast_tpoint_collect_result::not_collecting; - - /* Get the thread area address. This is used to recognize which - thread is which when tracing with the in-process agent library. - We don't read anything from the address, and treat it as opaque; - it's the address itself that we assume is unique per-thread. */ - if ((*the_low_target.get_thread_area) (lwpid_of (thread), &thread_area) == -1) - return fast_tpoint_collect_result::not_collecting; - - return fast_tracepoint_collecting (thread_area, lwp->stop_pc, status); -} - -/* The reason we resume in the caller, is because we want to be able - to pass lwp->status_pending as WSTAT, and we need to clear - status_pending_p before resuming, otherwise, linux_resume_one_lwp - refuses to resume. */ - -static int -maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) -{ - struct thread_info *saved_thread; - - saved_thread = current_thread; - current_thread = get_lwp_thread (lwp); - - if ((wstat == NULL - || (WIFSTOPPED (*wstat) && WSTOPSIG (*wstat) != SIGTRAP)) - && supports_fast_tracepoints () - && agent_loaded_p ()) - { - struct fast_tpoint_collect_status status; - - if (debug_threads) - debug_printf ("Checking whether LWP %ld needs to move out of the " - "jump pad.\n", - lwpid_of (current_thread)); - - fast_tpoint_collect_result r - = linux_fast_tracepoint_collecting (lwp, &status); - - if (wstat == NULL - || (WSTOPSIG (*wstat) != SIGILL - && WSTOPSIG (*wstat) != SIGFPE - && WSTOPSIG (*wstat) != SIGSEGV - && WSTOPSIG (*wstat) != SIGBUS)) - { - lwp->collecting_fast_tracepoint = r; - - if (r != fast_tpoint_collect_result::not_collecting) - { - if (r == fast_tpoint_collect_result::before_insn - && lwp->exit_jump_pad_bkpt == NULL) - { - /* Haven't executed the original instruction yet. - Set breakpoint there, and wait till it's hit, - then single-step until exiting the jump pad. */ - lwp->exit_jump_pad_bkpt - = set_breakpoint_at (status.adjusted_insn_addr, NULL); - } - - if (debug_threads) - debug_printf ("Checking whether LWP %ld needs to move out of " - "the jump pad...it does\n", - lwpid_of (current_thread)); - current_thread = saved_thread; - - return 1; - } - } - else - { - /* If we get a synchronous signal while collecting, *and* - while executing the (relocated) original instruction, - reset the PC to point at the tpoint address, before - reporting to GDB. Otherwise, it's an IPA lib bug: just - report the signal to GDB, and pray for the best. */ - - lwp->collecting_fast_tracepoint - = fast_tpoint_collect_result::not_collecting; - - if (r != fast_tpoint_collect_result::not_collecting - && (status.adjusted_insn_addr <= lwp->stop_pc - && lwp->stop_pc < status.adjusted_insn_addr_end)) - { - siginfo_t info; - struct regcache *regcache; - - /* The si_addr on a few signals references the address - of the faulting instruction. Adjust that as - well. */ - if ((WSTOPSIG (*wstat) == SIGILL - || WSTOPSIG (*wstat) == SIGFPE - || WSTOPSIG (*wstat) == SIGBUS - || WSTOPSIG (*wstat) == SIGSEGV) - && ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), - (PTRACE_TYPE_ARG3) 0, &info) == 0 - /* Final check just to make sure we don't clobber - the siginfo of non-kernel-sent signals. */ - && (uintptr_t) info.si_addr == lwp->stop_pc) - { - info.si_addr = (void *) (uintptr_t) status.tpoint_addr; - ptrace (PTRACE_SETSIGINFO, lwpid_of (current_thread), - (PTRACE_TYPE_ARG3) 0, &info); - } - - regcache = get_thread_regcache (current_thread, 1); - (*the_low_target.set_pc) (regcache, status.tpoint_addr); - lwp->stop_pc = status.tpoint_addr; - - /* Cancel any fast tracepoint lock this thread was - holding. */ - force_unlock_trace_buffer (); - } - - if (lwp->exit_jump_pad_bkpt != NULL) - { - if (debug_threads) - debug_printf ("Cancelling fast exit-jump-pad: removing bkpt. " - "stopping all threads momentarily.\n"); - - stop_all_lwps (1, lwp); - - delete_breakpoint (lwp->exit_jump_pad_bkpt); - lwp->exit_jump_pad_bkpt = NULL; - - unstop_all_lwps (1, lwp); - - gdb_assert (lwp->suspended >= 0); - } - } - } - - if (debug_threads) - debug_printf ("Checking whether LWP %ld needs to move out of the " - "jump pad...no\n", - lwpid_of (current_thread)); - - current_thread = saved_thread; - return 0; -} - -/* Enqueue one signal in the "signals to report later when out of the - jump pad" list. */ - -static void -enqueue_one_deferred_signal (struct lwp_info *lwp, int *wstat) -{ - struct pending_signals *p_sig; - struct thread_info *thread = get_lwp_thread (lwp); - - if (debug_threads) - debug_printf ("Deferring signal %d for LWP %ld.\n", - WSTOPSIG (*wstat), lwpid_of (thread)); - - if (debug_threads) - { - struct pending_signals *sig; - - for (sig = lwp->pending_signals_to_report; - sig != NULL; - sig = sig->prev) - debug_printf (" Already queued %d\n", - sig->signal); - - debug_printf (" (no more currently queued signals)\n"); - } - - /* Don't enqueue non-RT signals if they are already in the deferred - queue. (SIGSTOP being the easiest signal to see ending up here - twice) */ - if (WSTOPSIG (*wstat) < __SIGRTMIN) - { - struct pending_signals *sig; - - for (sig = lwp->pending_signals_to_report; - sig != NULL; - sig = sig->prev) - { - if (sig->signal == WSTOPSIG (*wstat)) - { - if (debug_threads) - debug_printf ("Not requeuing already queued non-RT signal %d" - " for LWP %ld\n", - sig->signal, - lwpid_of (thread)); - return; - } - } - } - - p_sig = XCNEW (struct pending_signals); - p_sig->prev = lwp->pending_signals_to_report; - p_sig->signal = WSTOPSIG (*wstat); - - ptrace (PTRACE_GETSIGINFO, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, - &p_sig->info); - - lwp->pending_signals_to_report = p_sig; -} - -/* Dequeue one signal from the "signals to report later when out of - the jump pad" list. */ - -static int -dequeue_one_deferred_signal (struct lwp_info *lwp, int *wstat) -{ - struct thread_info *thread = get_lwp_thread (lwp); - - if (lwp->pending_signals_to_report != NULL) - { - struct pending_signals **p_sig; - - p_sig = &lwp->pending_signals_to_report; - while ((*p_sig)->prev != NULL) - p_sig = &(*p_sig)->prev; - - *wstat = W_STOPCODE ((*p_sig)->signal); - if ((*p_sig)->info.si_signo != 0) - ptrace (PTRACE_SETSIGINFO, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, - &(*p_sig)->info); - free (*p_sig); - *p_sig = NULL; - - if (debug_threads) - debug_printf ("Reporting deferred signal %d for LWP %ld.\n", - WSTOPSIG (*wstat), lwpid_of (thread)); - - if (debug_threads) - { - struct pending_signals *sig; - - for (sig = lwp->pending_signals_to_report; - sig != NULL; - sig = sig->prev) - debug_printf (" Still queued %d\n", - sig->signal); - - debug_printf (" (no more queued signals)\n"); - } - - return 1; - } - - return 0; -} - -/* Fetch the possibly triggered data watchpoint info and store it in - CHILD. - - On some archs, like x86, that use debug registers to set - watchpoints, it's possible that the way to know which watched - address trapped, is to check the register that is used to select - which address to watch. Problem is, between setting the watchpoint - and reading back which data address trapped, the user may change - the set of watchpoints, and, as a consequence, GDB changes the - debug registers in the inferior. To avoid reading back a stale - stopped-data-address when that happens, we cache in LP the fact - that a watchpoint trapped, and the corresponding data address, as - soon as we see CHILD stop with a SIGTRAP. If GDB changes the debug - registers meanwhile, we have the cached data we can rely on. */ - -static int -check_stopped_by_watchpoint (struct lwp_info *child) -{ - if (the_low_target.stopped_by_watchpoint != NULL) - { - struct thread_info *saved_thread; - - saved_thread = current_thread; - current_thread = get_lwp_thread (child); - - if (the_low_target.stopped_by_watchpoint ()) - { - child->stop_reason = TARGET_STOPPED_BY_WATCHPOINT; - - if (the_low_target.stopped_data_address != NULL) - child->stopped_data_address - = the_low_target.stopped_data_address (); - else - child->stopped_data_address = 0; - } - - current_thread = saved_thread; - } - - return child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT; -} - -/* Return the ptrace options that we want to try to enable. */ - -static int -linux_low_ptrace_options (int attached) -{ - client_state &cs = get_client_state (); - int options = 0; - - if (!attached) - options |= PTRACE_O_EXITKILL; - - if (cs.report_fork_events) - options |= PTRACE_O_TRACEFORK; - - if (cs.report_vfork_events) - options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE); - - if (cs.report_exec_events) - options |= PTRACE_O_TRACEEXEC; - - options |= PTRACE_O_TRACESYSGOOD; - - return options; -} - -/* Do low-level handling of the event, and check if we should go on - and pass it to caller code. Return the affected lwp if we are, or - NULL otherwise. */ - -static struct lwp_info * -linux_low_filter_event (int lwpid, int wstat) -{ - client_state &cs = get_client_state (); - struct lwp_info *child; - struct thread_info *thread; - int have_stop_pc = 0; - - child = find_lwp_pid (ptid_t (lwpid)); - - /* Check for stop events reported by a process we didn't already - know about - anything not already in our LWP list. - - If we're expecting to receive stopped processes after - fork, vfork, and clone events, then we'll just add the - new one to our list and go back to waiting for the event - to be reported - the stopped process might be returned - from waitpid before or after the event is. - - But note the case of a non-leader thread exec'ing after the - leader having exited, and gone from our lists (because - check_zombie_leaders deleted it). The non-leader thread - changes its tid to the tgid. */ - - if (WIFSTOPPED (wstat) && child == NULL && WSTOPSIG (wstat) == SIGTRAP - && linux_ptrace_get_extended_event (wstat) == PTRACE_EVENT_EXEC) - { - ptid_t child_ptid; - - /* A multi-thread exec after we had seen the leader exiting. */ - if (debug_threads) - { - debug_printf ("LLW: Re-adding thread group leader LWP %d" - "after exec.\n", lwpid); - } - - child_ptid = ptid_t (lwpid, lwpid, 0); - child = add_lwp (child_ptid); - child->stopped = 1; - current_thread = child->thread; - } - - /* If we didn't find a process, one of two things presumably happened: - - A process we started and then detached from has exited. Ignore it. - - A process we are controlling has forked and the new child's stop - was reported to us by the kernel. Save its PID. */ - if (child == NULL && WIFSTOPPED (wstat)) - { - add_to_pid_list (&stopped_pids, lwpid, wstat); - return NULL; - } - else if (child == NULL) - return NULL; - - thread = get_lwp_thread (child); - - child->stopped = 1; - - child->last_status = wstat; - - /* Check if the thread has exited. */ - if ((WIFEXITED (wstat) || WIFSIGNALED (wstat))) - { - if (debug_threads) - debug_printf ("LLFE: %d exited.\n", lwpid); - - if (finish_step_over (child)) - { - /* Unsuspend all other LWPs, and set them back running again. */ - unsuspend_all_lwps (child); - } - - /* If there is at least one more LWP, then the exit signal was - not the end of the debugged application and should be - ignored, unless GDB wants to hear about thread exits. */ - if (cs.report_thread_events - || last_thread_of_process_p (pid_of (thread))) - { - /* Since events are serialized to GDB core, and we can't - report this one right now. Leave the status pending for - the next time we're able to report it. */ - mark_lwp_dead (child, wstat); - return child; - } - else - { - delete_lwp (child); - return NULL; - } - } - - gdb_assert (WIFSTOPPED (wstat)); - - if (WIFSTOPPED (wstat)) - { - struct process_info *proc; - - /* Architecture-specific setup after inferior is running. */ - proc = find_process_pid (pid_of (thread)); - if (proc->tdesc == NULL) - { - if (proc->attached) - { - /* This needs to happen after we have attached to the - inferior and it is stopped for the first time, but - before we access any inferior registers. */ - linux_arch_setup_thread (thread); - } - else - { - /* The process is started, but GDBserver will do - architecture-specific setup after the program stops at - the first instruction. */ - child->status_pending_p = 1; - child->status_pending = wstat; - return child; - } - } - } - - if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) - { - struct process_info *proc = find_process_pid (pid_of (thread)); - int options = linux_low_ptrace_options (proc->attached); - - linux_enable_event_reporting (lwpid, options); - child->must_set_ptrace_flags = 0; - } - - /* Always update syscall_state, even if it will be filtered later. */ - if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) - { - child->syscall_state - = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY - ? TARGET_WAITKIND_SYSCALL_RETURN - : TARGET_WAITKIND_SYSCALL_ENTRY); - } - else - { - /* Almost all other ptrace-stops are known to be outside of system - calls, with further exceptions in handle_extended_wait. */ - child->syscall_state = TARGET_WAITKIND_IGNORE; - } - - /* Be careful to not overwrite stop_pc until save_stop_reason is - called. */ - if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP - && linux_is_extended_waitstatus (wstat)) - { - child->stop_pc = get_pc (child); - if (handle_extended_wait (&child, wstat)) - { - /* The event has been handled, so just return without - reporting it. */ - return NULL; - } - } - - if (linux_wstatus_maybe_breakpoint (wstat)) - { - if (save_stop_reason (child)) - have_stop_pc = 1; - } - - if (!have_stop_pc) - child->stop_pc = get_pc (child); - - if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP - && child->stop_expected) - { - if (debug_threads) - debug_printf ("Expected stop.\n"); - child->stop_expected = 0; - - if (thread->last_resume_kind == resume_stop) - { - /* We want to report the stop to the core. Treat the - SIGSTOP as a normal event. */ - if (debug_threads) - debug_printf ("LLW: resume_stop SIGSTOP caught for %s.\n", - target_pid_to_str (ptid_of (thread))); - } - else if (stopping_threads != NOT_STOPPING_THREADS) - { - /* Stopping threads. We don't want this SIGSTOP to end up - pending. */ - if (debug_threads) - debug_printf ("LLW: SIGSTOP caught for %s " - "while stopping threads.\n", - target_pid_to_str (ptid_of (thread))); - return NULL; - } - else - { - /* This is a delayed SIGSTOP. Filter out the event. */ - if (debug_threads) - debug_printf ("LLW: %s %s, 0, 0 (discard delayed SIGSTOP)\n", - child->stepping ? "step" : "continue", - target_pid_to_str (ptid_of (thread))); - - linux_resume_one_lwp (child, child->stepping, 0, NULL); - return NULL; - } - } - - child->status_pending_p = 1; - child->status_pending = wstat; - return child; -} - -/* Return true if THREAD is doing hardware single step. */ - -static int -maybe_hw_step (struct thread_info *thread) -{ - if (can_hardware_single_step ()) - return 1; - else - { - /* GDBserver must insert single-step breakpoint for software - single step. */ - gdb_assert (has_single_step_breakpoints (thread)); - return 0; - } -} - -/* Resume LWPs that are currently stopped without any pending status - to report, but are resumed from the core's perspective. */ - -static void -resume_stopped_resumed_lwps (thread_info *thread) -{ - struct lwp_info *lp = get_thread_lwp (thread); - - if (lp->stopped - && !lp->suspended - && !lp->status_pending_p - && thread->last_status.kind == TARGET_WAITKIND_IGNORE) - { - int step = 0; - - if (thread->last_resume_kind == resume_step) - step = maybe_hw_step (thread); - - if (debug_threads) - debug_printf ("RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n", - target_pid_to_str (ptid_of (thread)), - paddress (lp->stop_pc), - step); - - linux_resume_one_lwp (lp, step, GDB_SIGNAL_0, NULL); - } -} - -/* Wait for an event from child(ren) WAIT_PTID, and return any that - match FILTER_PTID (leaving others pending). The PTIDs can be: - minus_one_ptid, to specify any child; a pid PTID, specifying all - lwps of a thread group; or a PTID representing a single lwp. Store - the stop status through the status pointer WSTAT. OPTIONS is - passed to the waitpid call. Return 0 if no event was found and - OPTIONS contains WNOHANG. Return -1 if no unwaited-for children - was found. Return the PID of the stopped child otherwise. */ - -static int -linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, - int *wstatp, int options) -{ - struct thread_info *event_thread; - struct lwp_info *event_child, *requested_child; - sigset_t block_mask, prev_mask; - - retry: - /* N.B. event_thread points to the thread_info struct that contains - event_child. Keep them in sync. */ - event_thread = NULL; - event_child = NULL; - requested_child = NULL; - - /* Check for a lwp with a pending status. */ - - if (filter_ptid == minus_one_ptid || filter_ptid.is_pid ()) - { - event_thread = find_thread_in_random ([&] (thread_info *thread) - { - return status_pending_p_callback (thread, filter_ptid); - }); - - if (event_thread != NULL) - event_child = get_thread_lwp (event_thread); - if (debug_threads && event_thread) - debug_printf ("Got a pending child %ld\n", lwpid_of (event_thread)); - } - else if (filter_ptid != null_ptid) - { - requested_child = find_lwp_pid (filter_ptid); - - if (stopping_threads == NOT_STOPPING_THREADS - && requested_child->status_pending_p - && (requested_child->collecting_fast_tracepoint - != fast_tpoint_collect_result::not_collecting)) - { - enqueue_one_deferred_signal (requested_child, - &requested_child->status_pending); - requested_child->status_pending_p = 0; - requested_child->status_pending = 0; - linux_resume_one_lwp (requested_child, 0, 0, NULL); - } - - if (requested_child->suspended - && requested_child->status_pending_p) - { - internal_error (__FILE__, __LINE__, - "requesting an event out of a" - " suspended child?"); - } - - if (requested_child->status_pending_p) - { - event_child = requested_child; - event_thread = get_lwp_thread (event_child); - } - } - - if (event_child != NULL) - { - if (debug_threads) - debug_printf ("Got an event from pending child %ld (%04x)\n", - lwpid_of (event_thread), event_child->status_pending); - *wstatp = event_child->status_pending; - event_child->status_pending_p = 0; - event_child->status_pending = 0; - current_thread = event_thread; - return lwpid_of (event_thread); - } - - /* But if we don't find a pending event, we'll have to wait. - - We only enter this loop if no process has a pending wait status. - Thus any action taken in response to a wait status inside this - loop is responding as soon as we detect the status, not after any - pending events. */ - - /* Make sure SIGCHLD is blocked until the sigsuspend below. Block - all signals while here. */ - sigfillset (&block_mask); - gdb_sigmask (SIG_BLOCK, &block_mask, &prev_mask); - - /* Always pull all events out of the kernel. We'll randomly select - an event LWP out of all that have events, to prevent - starvation. */ - while (event_child == NULL) - { - pid_t ret = 0; - - /* Always use -1 and WNOHANG, due to couple of a kernel/ptrace - quirks: - - - If the thread group leader exits while other threads in the - thread group still exist, waitpid(TGID, ...) hangs. That - waitpid won't return an exit status until the other threads - in the group are reaped. - - - When a non-leader thread execs, that thread just vanishes - without reporting an exit (so we'd hang if we waited for it - explicitly in that case). The exec event is reported to - the TGID pid. */ - errno = 0; - ret = my_waitpid (-1, wstatp, options | WNOHANG); - - if (debug_threads) - debug_printf ("LWFE: waitpid(-1, ...) returned %d, %s\n", - ret, errno ? safe_strerror (errno) : "ERRNO-OK"); - - if (ret > 0) - { - if (debug_threads) - { - debug_printf ("LLW: waitpid %ld received %s\n", - (long) ret, status_to_str (*wstatp)); - } - - /* Filter all events. IOW, leave all events pending. We'll - randomly select an event LWP out of all that have events - below. */ - linux_low_filter_event (ret, *wstatp); - /* Retry until nothing comes out of waitpid. A single - SIGCHLD can indicate more than one child stopped. */ - continue; - } - - /* Now that we've pulled all events out of the kernel, resume - LWPs that don't have an interesting event to report. */ - if (stopping_threads == NOT_STOPPING_THREADS) - for_each_thread (resume_stopped_resumed_lwps); - - /* ... and find an LWP with a status to report to the core, if - any. */ - event_thread = find_thread_in_random ([&] (thread_info *thread) - { - return status_pending_p_callback (thread, filter_ptid); - }); - - if (event_thread != NULL) - { - event_child = get_thread_lwp (event_thread); - *wstatp = event_child->status_pending; - event_child->status_pending_p = 0; - event_child->status_pending = 0; - break; - } - - /* Check for zombie thread group leaders. Those can't be reaped - until all other threads in the thread group are. */ - check_zombie_leaders (); - - auto not_stopped = [&] (thread_info *thread) - { - return not_stopped_callback (thread, wait_ptid); - }; - - /* If there are no resumed children left in the set of LWPs we - want to wait for, bail. We can't just block in - waitpid/sigsuspend, because lwps might have been left stopped - in trace-stop state, and we'd be stuck forever waiting for - their status to change (which would only happen if we resumed - them). Even if WNOHANG is set, this return code is preferred - over 0 (below), as it is more detailed. */ - if (find_thread (not_stopped) == NULL) - { - if (debug_threads) - debug_printf ("LLW: exit (no unwaited-for LWP)\n"); - gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); - return -1; - } - - /* No interesting event to report to the caller. */ - if ((options & WNOHANG)) - { - if (debug_threads) - debug_printf ("WNOHANG set, no event found\n"); - - gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); - return 0; - } - - /* Block until we get an event reported with SIGCHLD. */ - if (debug_threads) - debug_printf ("sigsuspend'ing\n"); - - sigsuspend (&prev_mask); - gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); - goto retry; - } - - gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); - - current_thread = event_thread; - - return lwpid_of (event_thread); -} - -/* Wait for an event from child(ren) PTID. PTIDs can be: - minus_one_ptid, to specify any child; a pid PTID, specifying all - lwps of a thread group; or a PTID representing a single lwp. Store - the stop status through the status pointer WSTAT. OPTIONS is - passed to the waitpid call. Return 0 if no event was found and - OPTIONS contains WNOHANG. Return -1 if no unwaited-for children - was found. Return the PID of the stopped child otherwise. */ - -static int -linux_wait_for_event (ptid_t ptid, int *wstatp, int options) -{ - return linux_wait_for_event_filtered (ptid, ptid, wstatp, options); -} - -/* Select one LWP out of those that have events pending. */ - -static void -select_event_lwp (struct lwp_info **orig_lp) -{ - struct thread_info *event_thread = NULL; - - /* In all-stop, give preference to the LWP that is being - single-stepped. There will be at most one, and it's the LWP that - the core is most interested in. If we didn't do this, then we'd - have to handle pending step SIGTRAPs somehow in case the core - later continues the previously-stepped thread, otherwise we'd - report the pending SIGTRAP, and the core, not having stepped the - thread, wouldn't understand what the trap was for, and therefore - would report it to the user as a random signal. */ - if (!non_stop) - { - event_thread = find_thread ([] (thread_info *thread) - { - lwp_info *lp = get_thread_lwp (thread); - - return (thread->last_status.kind == TARGET_WAITKIND_IGNORE - && thread->last_resume_kind == resume_step - && lp->status_pending_p); - }); - - if (event_thread != NULL) - { - if (debug_threads) - debug_printf ("SEL: Select single-step %s\n", - target_pid_to_str (ptid_of (event_thread))); - } - } - if (event_thread == NULL) - { - /* No single-stepping LWP. Select one at random, out of those - which have had events. */ - - event_thread = find_thread_in_random ([&] (thread_info *thread) - { - lwp_info *lp = get_thread_lwp (thread); - - /* Only resumed LWPs that have an event pending. */ - return (thread->last_status.kind == TARGET_WAITKIND_IGNORE - && lp->status_pending_p); - }); - } - - if (event_thread != NULL) - { - struct lwp_info *event_lp = get_thread_lwp (event_thread); - - /* Switch the event LWP. */ - *orig_lp = event_lp; - } -} - -/* Decrement the suspend count of all LWPs, except EXCEPT, if non - NULL. */ - -static void -unsuspend_all_lwps (struct lwp_info *except) -{ - for_each_thread ([&] (thread_info *thread) - { - lwp_info *lwp = get_thread_lwp (thread); - - if (lwp != except) - lwp_suspended_decr (lwp); - }); -} - -static void move_out_of_jump_pad_callback (thread_info *thread); -static bool stuck_in_jump_pad_callback (thread_info *thread); -static bool lwp_running (thread_info *thread); -static ptid_t linux_wait_1 (ptid_t ptid, - struct target_waitstatus *ourstatus, - int target_options); - -/* Stabilize threads (move out of jump pads). - - If a thread is midway collecting a fast tracepoint, we need to - finish the collection and move it out of the jump pad before - reporting the signal. - - This avoids recursion while collecting (when a signal arrives - midway, and the signal handler itself collects), which would trash - the trace buffer. In case the user set a breakpoint in a signal - handler, this avoids the backtrace showing the jump pad, etc.. - Most importantly, there are certain things we can't do safely if - threads are stopped in a jump pad (or in its callee's). For - example: - - - starting a new trace run. A thread still collecting the - previous run, could trash the trace buffer when resumed. The trace - buffer control structures would have been reset but the thread had - no way to tell. The thread could even midway memcpy'ing to the - buffer, which would mean that when resumed, it would clobber the - trace buffer that had been set for a new run. - - - we can't rewrite/reuse the jump pads for new tracepoints - safely. Say you do tstart while a thread is stopped midway while - collecting. When the thread is later resumed, it finishes the - collection, and returns to the jump pad, to execute the original - instruction that was under the tracepoint jump at the time the - older run had been started. If the jump pad had been rewritten - since for something else in the new run, the thread would now - execute the wrong / random instructions. */ - -static void -linux_stabilize_threads (void) -{ - thread_info *thread_stuck = find_thread (stuck_in_jump_pad_callback); - - if (thread_stuck != NULL) - { - if (debug_threads) - debug_printf ("can't stabilize, LWP %ld is stuck in jump pad\n", - lwpid_of (thread_stuck)); - return; - } - - thread_info *saved_thread = current_thread; - - stabilizing_threads = 1; - - /* Kick 'em all. */ - for_each_thread (move_out_of_jump_pad_callback); - - /* Loop until all are stopped out of the jump pads. */ - while (find_thread (lwp_running) != NULL) - { - struct target_waitstatus ourstatus; - struct lwp_info *lwp; - int wstat; - - /* Note that we go through the full wait even loop. While - moving threads out of jump pad, we need to be able to step - over internal breakpoints and such. */ - linux_wait_1 (minus_one_ptid, &ourstatus, 0); - - if (ourstatus.kind == TARGET_WAITKIND_STOPPED) - { - lwp = get_thread_lwp (current_thread); - - /* Lock it. */ - lwp_suspended_inc (lwp); - - if (ourstatus.value.sig != GDB_SIGNAL_0 - || current_thread->last_resume_kind == resume_stop) - { - wstat = W_STOPCODE (gdb_signal_to_host (ourstatus.value.sig)); - enqueue_one_deferred_signal (lwp, &wstat); - } - } - } - - unsuspend_all_lwps (NULL); - - stabilizing_threads = 0; - - current_thread = saved_thread; - - if (debug_threads) - { - thread_stuck = find_thread (stuck_in_jump_pad_callback); - - if (thread_stuck != NULL) - debug_printf ("couldn't stabilize, LWP %ld got stuck in jump pad\n", - lwpid_of (thread_stuck)); - } -} - -/* Convenience function that is called when the kernel reports an - event that is not passed out to GDB. */ - -static ptid_t -ignore_event (struct target_waitstatus *ourstatus) -{ - /* If we got an event, there may still be others, as a single - SIGCHLD can indicate more than one child stopped. This forces - another target_wait call. */ - async_file_mark (); - - ourstatus->kind = TARGET_WAITKIND_IGNORE; - return null_ptid; -} - -/* Convenience function that is called when the kernel reports an exit - event. This decides whether to report the event to GDB as a - process exit event, a thread exit event, or to suppress the - event. */ - -static ptid_t -filter_exit_event (struct lwp_info *event_child, - struct target_waitstatus *ourstatus) -{ - client_state &cs = get_client_state (); - struct thread_info *thread = get_lwp_thread (event_child); - ptid_t ptid = ptid_of (thread); - - if (!last_thread_of_process_p (pid_of (thread))) - { - if (cs.report_thread_events) - ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED; - else - ourstatus->kind = TARGET_WAITKIND_IGNORE; - - delete_lwp (event_child); - } - return ptid; -} - -/* Returns 1 if GDB is interested in any event_child syscalls. */ - -static int -gdb_catching_syscalls_p (struct lwp_info *event_child) -{ - struct thread_info *thread = get_lwp_thread (event_child); - struct process_info *proc = get_thread_process (thread); - - return !proc->syscalls_to_catch.empty (); -} - -/* Returns 1 if GDB is interested in the event_child syscall. - Only to be called when stopped reason is SYSCALL_SIGTRAP. */ - -static int -gdb_catch_this_syscall_p (struct lwp_info *event_child) -{ - int sysno; - struct thread_info *thread = get_lwp_thread (event_child); - struct process_info *proc = get_thread_process (thread); - - if (proc->syscalls_to_catch.empty ()) - return 0; - - if (proc->syscalls_to_catch[0] == ANY_SYSCALL) - return 1; - - get_syscall_trapinfo (event_child, &sysno); - - for (int iter : proc->syscalls_to_catch) - if (iter == sysno) - return 1; - - return 0; -} - -/* Wait for process, returns status. */ - -static ptid_t -linux_wait_1 (ptid_t ptid, - struct target_waitstatus *ourstatus, int target_options) -{ - client_state &cs = get_client_state (); - int w; - struct lwp_info *event_child; - int options; - int pid; - int step_over_finished; - int bp_explains_trap; - int maybe_internal_trap; - int report_to_gdb; - int trace_event; - int in_step_range; - int any_resumed; - - if (debug_threads) - { - debug_enter (); - debug_printf ("linux_wait_1: [%s]\n", target_pid_to_str (ptid)); - } - - /* Translate generic target options into linux options. */ - options = __WALL; - if (target_options & TARGET_WNOHANG) - options |= WNOHANG; - - bp_explains_trap = 0; - trace_event = 0; - in_step_range = 0; - ourstatus->kind = TARGET_WAITKIND_IGNORE; - - auto status_pending_p_any = [&] (thread_info *thread) - { - return status_pending_p_callback (thread, minus_one_ptid); - }; - - auto not_stopped = [&] (thread_info *thread) - { - return not_stopped_callback (thread, minus_one_ptid); - }; - - /* Find a resumed LWP, if any. */ - if (find_thread (status_pending_p_any) != NULL) - any_resumed = 1; - else if (find_thread (not_stopped) != NULL) - any_resumed = 1; - else - any_resumed = 0; - - if (step_over_bkpt == null_ptid) - pid = linux_wait_for_event (ptid, &w, options); - else - { - if (debug_threads) - debug_printf ("step_over_bkpt set [%s], doing a blocking wait\n", - target_pid_to_str (step_over_bkpt)); - pid = linux_wait_for_event (step_over_bkpt, &w, options & ~WNOHANG); - } - - if (pid == 0 || (pid == -1 && !any_resumed)) - { - gdb_assert (target_options & TARGET_WNOHANG); - - if (debug_threads) - { - debug_printf ("linux_wait_1 ret = null_ptid, " - "TARGET_WAITKIND_IGNORE\n"); - debug_exit (); - } - - ourstatus->kind = TARGET_WAITKIND_IGNORE; - return null_ptid; - } - else if (pid == -1) - { - if (debug_threads) - { - debug_printf ("linux_wait_1 ret = null_ptid, " - "TARGET_WAITKIND_NO_RESUMED\n"); - debug_exit (); - } - - ourstatus->kind = TARGET_WAITKIND_NO_RESUMED; - return null_ptid; - } - - event_child = get_thread_lwp (current_thread); - - /* linux_wait_for_event only returns an exit status for the last - child of a process. Report it. */ - if (WIFEXITED (w) || WIFSIGNALED (w)) - { - if (WIFEXITED (w)) - { - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = WEXITSTATUS (w); - - if (debug_threads) - { - debug_printf ("linux_wait_1 ret = %s, exited with " - "retcode %d\n", - target_pid_to_str (ptid_of (current_thread)), - WEXITSTATUS (w)); - debug_exit (); - } - } - else - { - ourstatus->kind = TARGET_WAITKIND_SIGNALLED; - ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (w)); - - if (debug_threads) - { - debug_printf ("linux_wait_1 ret = %s, terminated with " - "signal %d\n", - target_pid_to_str (ptid_of (current_thread)), - WTERMSIG (w)); - debug_exit (); - } - } - - if (ourstatus->kind == TARGET_WAITKIND_EXITED) - return filter_exit_event (event_child, ourstatus); - - return ptid_of (current_thread); - } - - /* If step-over executes a breakpoint instruction, in the case of a - hardware single step it means a gdb/gdbserver breakpoint had been - planted on top of a permanent breakpoint, in the case of a software - single step it may just mean that gdbserver hit the reinsert breakpoint. - The PC has been adjusted by save_stop_reason to point at - the breakpoint address. - So in the case of the hardware single step advance the PC manually - past the breakpoint and in the case of software single step advance only - if it's not the single_step_breakpoint we are hitting. - This avoids that a program would keep trapping a permanent breakpoint - forever. */ - if (step_over_bkpt != null_ptid - && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT - && (event_child->stepping - || !single_step_breakpoint_inserted_here (event_child->stop_pc))) - { - int increment_pc = 0; - int breakpoint_kind = 0; - CORE_ADDR stop_pc = event_child->stop_pc; - - breakpoint_kind = - the_target->breakpoint_kind_from_current_state (&stop_pc); - the_target->sw_breakpoint_from_kind (breakpoint_kind, &increment_pc); - - if (debug_threads) - { - debug_printf ("step-over for %s executed software breakpoint\n", - target_pid_to_str (ptid_of (current_thread))); - } - - if (increment_pc != 0) - { - struct regcache *regcache - = get_thread_regcache (current_thread, 1); - - event_child->stop_pc += increment_pc; - (*the_low_target.set_pc) (regcache, event_child->stop_pc); - - if (!(*the_low_target.breakpoint_at) (event_child->stop_pc)) - event_child->stop_reason = TARGET_STOPPED_BY_NO_REASON; - } - } - - /* If this event was not handled before, and is not a SIGTRAP, we - report it. SIGILL and SIGSEGV are also treated as traps in case - a breakpoint is inserted at the current PC. If this target does - not support internal breakpoints at all, we also report the - SIGTRAP without further processing; it's of no concern to us. */ - maybe_internal_trap - = (supports_breakpoints () - && (WSTOPSIG (w) == SIGTRAP - || ((WSTOPSIG (w) == SIGILL - || WSTOPSIG (w) == SIGSEGV) - && (*the_low_target.breakpoint_at) (event_child->stop_pc)))); - - if (maybe_internal_trap) - { - /* Handle anything that requires bookkeeping before deciding to - report the event or continue waiting. */ - - /* First check if we can explain the SIGTRAP with an internal - breakpoint, or if we should possibly report the event to GDB. - Do this before anything that may remove or insert a - breakpoint. */ - bp_explains_trap = breakpoint_inserted_here (event_child->stop_pc); - - /* We have a SIGTRAP, possibly a step-over dance has just - finished. If so, tweak the state machine accordingly, - reinsert breakpoints and delete any single-step - breakpoints. */ - step_over_finished = finish_step_over (event_child); - - /* Now invoke the callbacks of any internal breakpoints there. */ - check_breakpoints (event_child->stop_pc); - - /* Handle tracepoint data collecting. This may overflow the - trace buffer, and cause a tracing stop, removing - breakpoints. */ - trace_event = handle_tracepoints (event_child); - - if (bp_explains_trap) - { - if (debug_threads) - debug_printf ("Hit a gdbserver breakpoint.\n"); - } - } - else - { - /* We have some other signal, possibly a step-over dance was in - progress, and it should be cancelled too. */ - step_over_finished = finish_step_over (event_child); - } - - /* We have all the data we need. Either report the event to GDB, or - resume threads and keep waiting for more. */ - - /* If we're collecting a fast tracepoint, finish the collection and - move out of the jump pad before delivering a signal. See - linux_stabilize_threads. */ - - if (WIFSTOPPED (w) - && WSTOPSIG (w) != SIGTRAP - && supports_fast_tracepoints () - && agent_loaded_p ()) - { - if (debug_threads) - debug_printf ("Got signal %d for LWP %ld. Check if we need " - "to defer or adjust it.\n", - WSTOPSIG (w), lwpid_of (current_thread)); - - /* Allow debugging the jump pad itself. */ - if (current_thread->last_resume_kind != resume_step - && maybe_move_out_of_jump_pad (event_child, &w)) - { - enqueue_one_deferred_signal (event_child, &w); - - if (debug_threads) - debug_printf ("Signal %d for LWP %ld deferred (in jump pad)\n", - WSTOPSIG (w), lwpid_of (current_thread)); - - linux_resume_one_lwp (event_child, 0, 0, NULL); - - if (debug_threads) - debug_exit (); - return ignore_event (ourstatus); - } - } - - if (event_child->collecting_fast_tracepoint - != fast_tpoint_collect_result::not_collecting) - { - if (debug_threads) - debug_printf ("LWP %ld was trying to move out of the jump pad (%d). " - "Check if we're already there.\n", - lwpid_of (current_thread), - (int) event_child->collecting_fast_tracepoint); - - trace_event = 1; - - event_child->collecting_fast_tracepoint - = linux_fast_tracepoint_collecting (event_child, NULL); - - if (event_child->collecting_fast_tracepoint - != fast_tpoint_collect_result::before_insn) - { - /* No longer need this breakpoint. */ - if (event_child->exit_jump_pad_bkpt != NULL) - { - if (debug_threads) - debug_printf ("No longer need exit-jump-pad bkpt; removing it." - "stopping all threads momentarily.\n"); - - /* Other running threads could hit this breakpoint. - We don't handle moribund locations like GDB does, - instead we always pause all threads when removing - breakpoints, so that any step-over or - decr_pc_after_break adjustment is always taken - care of while the breakpoint is still - inserted. */ - stop_all_lwps (1, event_child); - - delete_breakpoint (event_child->exit_jump_pad_bkpt); - event_child->exit_jump_pad_bkpt = NULL; - - unstop_all_lwps (1, event_child); - - gdb_assert (event_child->suspended >= 0); - } - } - - if (event_child->collecting_fast_tracepoint - == fast_tpoint_collect_result::not_collecting) - { - if (debug_threads) - debug_printf ("fast tracepoint finished " - "collecting successfully.\n"); - - /* We may have a deferred signal to report. */ - if (dequeue_one_deferred_signal (event_child, &w)) - { - if (debug_threads) - debug_printf ("dequeued one signal.\n"); - } - else - { - if (debug_threads) - debug_printf ("no deferred signals.\n"); - - if (stabilizing_threads) - { - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = GDB_SIGNAL_0; - - if (debug_threads) - { - debug_printf ("linux_wait_1 ret = %s, stopped " - "while stabilizing threads\n", - target_pid_to_str (ptid_of (current_thread))); - debug_exit (); - } - - return ptid_of (current_thread); - } - } - } - } - - /* Check whether GDB would be interested in this event. */ - - /* Check if GDB is interested in this syscall. */ - if (WIFSTOPPED (w) - && WSTOPSIG (w) == SYSCALL_SIGTRAP - && !gdb_catch_this_syscall_p (event_child)) - { - if (debug_threads) - { - debug_printf ("Ignored syscall for LWP %ld.\n", - lwpid_of (current_thread)); - } - - linux_resume_one_lwp (event_child, event_child->stepping, - 0, NULL); - - if (debug_threads) - debug_exit (); - return ignore_event (ourstatus); - } - - /* If GDB is not interested in this signal, don't stop other - threads, and don't report it to GDB. Just resume the inferior - right away. We do this for threading-related signals as well as - any that GDB specifically requested we ignore. But never ignore - SIGSTOP if we sent it ourselves, and do not ignore signals when - stepping - they may require special handling to skip the signal - handler. Also never ignore signals that could be caused by a - breakpoint. */ - if (WIFSTOPPED (w) - && current_thread->last_resume_kind != resume_step - && ( -#if defined (USE_THREAD_DB) && !defined (__ANDROID__) - (current_process ()->priv->thread_db != NULL - && (WSTOPSIG (w) == __SIGRTMIN - || WSTOPSIG (w) == __SIGRTMIN + 1)) - || -#endif - (cs.pass_signals[gdb_signal_from_host (WSTOPSIG (w))] - && !(WSTOPSIG (w) == SIGSTOP - && current_thread->last_resume_kind == resume_stop) - && !linux_wstatus_maybe_breakpoint (w)))) - { - siginfo_t info, *info_p; - - if (debug_threads) - debug_printf ("Ignored signal %d for LWP %ld.\n", - WSTOPSIG (w), lwpid_of (current_thread)); - - if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), - (PTRACE_TYPE_ARG3) 0, &info) == 0) - info_p = &info; - else - info_p = NULL; - - if (step_over_finished) - { - /* We cancelled this thread's step-over above. We still - need to unsuspend all other LWPs, and set them back - running again while the signal handler runs. */ - unsuspend_all_lwps (event_child); - - /* Enqueue the pending signal info so that proceed_all_lwps - doesn't lose it. */ - enqueue_pending_signal (event_child, WSTOPSIG (w), info_p); - - proceed_all_lwps (); - } - else - { - linux_resume_one_lwp (event_child, event_child->stepping, - WSTOPSIG (w), info_p); - } - - if (debug_threads) - debug_exit (); - - return ignore_event (ourstatus); - } - - /* Note that all addresses are always "out of the step range" when - there's no range to begin with. */ - in_step_range = lwp_in_step_range (event_child); - - /* If GDB wanted this thread to single step, and the thread is out - of the step range, we always want to report the SIGTRAP, and let - GDB handle it. Watchpoints should always be reported. So should - signals we can't explain. A SIGTRAP we can't explain could be a - GDB breakpoint --- we may or not support Z0 breakpoints. If we - do, we're be able to handle GDB breakpoints on top of internal - breakpoints, by handling the internal breakpoint and still - reporting the event to GDB. If we don't, we're out of luck, GDB - won't see the breakpoint hit. If we see a single-step event but - the thread should be continuing, don't pass the trap to gdb. - That indicates that we had previously finished a single-step but - left the single-step pending -- see - complete_ongoing_step_over. */ - report_to_gdb = (!maybe_internal_trap - || (current_thread->last_resume_kind == resume_step - && !in_step_range) - || event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT - || (!in_step_range - && !bp_explains_trap - && !trace_event - && !step_over_finished - && !(current_thread->last_resume_kind == resume_continue - && event_child->stop_reason == TARGET_STOPPED_BY_SINGLE_STEP)) - || (gdb_breakpoint_here (event_child->stop_pc) - && gdb_condition_true_at_breakpoint (event_child->stop_pc) - && gdb_no_commands_at_breakpoint (event_child->stop_pc)) - || event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE); - - run_breakpoint_commands (event_child->stop_pc); - - /* We found no reason GDB would want us to stop. We either hit one - of our own breakpoints, or finished an internal step GDB - shouldn't know about. */ - if (!report_to_gdb) - { - if (debug_threads) - { - if (bp_explains_trap) - debug_printf ("Hit a gdbserver breakpoint.\n"); - if (step_over_finished) - debug_printf ("Step-over finished.\n"); - if (trace_event) - debug_printf ("Tracepoint event.\n"); - if (lwp_in_step_range (event_child)) - debug_printf ("Range stepping pc 0x%s [0x%s, 0x%s).\n", - paddress (event_child->stop_pc), - paddress (event_child->step_range_start), - paddress (event_child->step_range_end)); - } - - /* We're not reporting this breakpoint to GDB, so apply the - decr_pc_after_break adjustment to the inferior's regcache - ourselves. */ - - if (the_low_target.set_pc != NULL) - { - struct regcache *regcache - = get_thread_regcache (current_thread, 1); - (*the_low_target.set_pc) (regcache, event_child->stop_pc); - } - - if (step_over_finished) - { - /* If we have finished stepping over a breakpoint, we've - stopped and suspended all LWPs momentarily except the - stepping one. This is where we resume them all again. - We're going to keep waiting, so use proceed, which - handles stepping over the next breakpoint. */ - unsuspend_all_lwps (event_child); - } - else - { - /* Remove the single-step breakpoints if any. Note that - there isn't single-step breakpoint if we finished stepping - over. */ - if (can_software_single_step () - && has_single_step_breakpoints (current_thread)) - { - stop_all_lwps (0, event_child); - delete_single_step_breakpoints (current_thread); - unstop_all_lwps (0, event_child); - } - } - - if (debug_threads) - debug_printf ("proceeding all threads.\n"); - proceed_all_lwps (); - - if (debug_threads) - debug_exit (); - - return ignore_event (ourstatus); - } - - if (debug_threads) - { - if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) - { - std::string str - = target_waitstatus_to_string (&event_child->waitstatus); - - debug_printf ("LWP %ld: extended event with waitstatus %s\n", - lwpid_of (get_lwp_thread (event_child)), str.c_str ()); - } - if (current_thread->last_resume_kind == resume_step) - { - if (event_child->step_range_start == event_child->step_range_end) - debug_printf ("GDB wanted to single-step, reporting event.\n"); - else if (!lwp_in_step_range (event_child)) - debug_printf ("Out of step range, reporting event.\n"); - } - if (event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT) - debug_printf ("Stopped by watchpoint.\n"); - else if (gdb_breakpoint_here (event_child->stop_pc)) - debug_printf ("Stopped by GDB breakpoint.\n"); - if (debug_threads) - debug_printf ("Hit a non-gdbserver trap event.\n"); - } - - /* Alright, we're going to report a stop. */ - - /* Remove single-step breakpoints. */ - if (can_software_single_step ()) - { - /* Remove single-step breakpoints or not. It it is true, stop all - lwps, so that other threads won't hit the breakpoint in the - staled memory. */ - int remove_single_step_breakpoints_p = 0; - - if (non_stop) - { - remove_single_step_breakpoints_p - = has_single_step_breakpoints (current_thread); - } - else - { - /* In all-stop, a stop reply cancels all previous resume - requests. Delete all single-step breakpoints. */ - - find_thread ([&] (thread_info *thread) { - if (has_single_step_breakpoints (thread)) - { - remove_single_step_breakpoints_p = 1; - return true; - } - - return false; - }); - } - - if (remove_single_step_breakpoints_p) - { - /* If we remove single-step breakpoints from memory, stop all lwps, - so that other threads won't hit the breakpoint in the staled - memory. */ - stop_all_lwps (0, event_child); - - if (non_stop) - { - gdb_assert (has_single_step_breakpoints (current_thread)); - delete_single_step_breakpoints (current_thread); - } - else - { - for_each_thread ([] (thread_info *thread){ - if (has_single_step_breakpoints (thread)) - delete_single_step_breakpoints (thread); - }); - } - - unstop_all_lwps (0, event_child); - } - } - - if (!stabilizing_threads) - { - /* In all-stop, stop all threads. */ - if (!non_stop) - stop_all_lwps (0, NULL); - - if (step_over_finished) - { - if (!non_stop) - { - /* If we were doing a step-over, all other threads but - the stepping one had been paused in start_step_over, - with their suspend counts incremented. We don't want - to do a full unstop/unpause, because we're in - all-stop mode (so we want threads stopped), but we - still need to unsuspend the other threads, to - decrement their `suspended' count back. */ - unsuspend_all_lwps (event_child); - } - else - { - /* If we just finished a step-over, then all threads had - been momentarily paused. In all-stop, that's fine, - we want threads stopped by now anyway. In non-stop, - we need to re-resume threads that GDB wanted to be - running. */ - unstop_all_lwps (1, event_child); - } - } - - /* If we're not waiting for a specific LWP, choose an event LWP - from among those that have had events. Giving equal priority - to all LWPs that have had events helps prevent - starvation. */ - if (ptid == minus_one_ptid) - { - event_child->status_pending_p = 1; - event_child->status_pending = w; - - select_event_lwp (&event_child); - - /* current_thread and event_child must stay in sync. */ - current_thread = get_lwp_thread (event_child); - - event_child->status_pending_p = 0; - w = event_child->status_pending; - } - - - /* Stabilize threads (move out of jump pads). */ - if (!non_stop) - stabilize_threads (); - } - else - { - /* If we just finished a step-over, then all threads had been - momentarily paused. In all-stop, that's fine, we want - threads stopped by now anyway. In non-stop, we need to - re-resume threads that GDB wanted to be running. */ - if (step_over_finished) - unstop_all_lwps (1, event_child); - } - - if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) - { - /* If the reported event is an exit, fork, vfork or exec, let - GDB know. */ - - /* Break the unreported fork relationship chain. */ - if (event_child->waitstatus.kind == TARGET_WAITKIND_FORKED - || event_child->waitstatus.kind == TARGET_WAITKIND_VFORKED) - { - event_child->fork_relative->fork_relative = NULL; - event_child->fork_relative = NULL; - } - - *ourstatus = event_child->waitstatus; - /* Clear the event lwp's waitstatus since we handled it already. */ - event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE; - } - else - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - /* Now that we've selected our final event LWP, un-adjust its PC if - it was a software breakpoint, and the client doesn't know we can - adjust the breakpoint ourselves. */ - if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT - && !cs.swbreak_feature) - { - int decr_pc = the_low_target.decr_pc_after_break; - - if (decr_pc != 0) - { - struct regcache *regcache - = get_thread_regcache (current_thread, 1); - (*the_low_target.set_pc) (regcache, event_child->stop_pc + decr_pc); - } - } - - if (WSTOPSIG (w) == SYSCALL_SIGTRAP) - { - get_syscall_trapinfo (event_child, - &ourstatus->value.syscall_number); - ourstatus->kind = event_child->syscall_state; - } - else if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) == SIGSTOP) - { - /* A thread that has been requested to stop by GDB with vCont;t, - and it stopped cleanly, so report as SIG0. The use of - SIGSTOP is an implementation detail. */ - ourstatus->value.sig = GDB_SIGNAL_0; - } - else if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) != SIGSTOP) - { - /* A thread that has been requested to stop by GDB with vCont;t, - but, it stopped for other reasons. */ - ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w)); - } - else if (ourstatus->kind == TARGET_WAITKIND_STOPPED) - { - ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w)); - } - - gdb_assert (step_over_bkpt == null_ptid); - - if (debug_threads) - { - debug_printf ("linux_wait_1 ret = %s, %d, %d\n", - target_pid_to_str (ptid_of (current_thread)), - ourstatus->kind, ourstatus->value.sig); - debug_exit (); - } - - if (ourstatus->kind == TARGET_WAITKIND_EXITED) - return filter_exit_event (event_child, ourstatus); - - return ptid_of (current_thread); -} - -/* Get rid of any pending event in the pipe. */ -static void -async_file_flush (void) -{ - int ret; - char buf; - - do - ret = read (linux_event_pipe[0], &buf, 1); - while (ret >= 0 || (ret == -1 && errno == EINTR)); -} - -/* Put something in the pipe, so the event loop wakes up. */ -static void -async_file_mark (void) -{ - int ret; - - async_file_flush (); - - do - ret = write (linux_event_pipe[1], "+", 1); - while (ret == 0 || (ret == -1 && errno == EINTR)); - - /* Ignore EAGAIN. If the pipe is full, the event loop will already - be awakened anyway. */ -} - -static ptid_t -linux_wait (ptid_t ptid, - struct target_waitstatus *ourstatus, int target_options) -{ - ptid_t event_ptid; - - /* Flush the async file first. */ - if (target_is_async_p ()) - async_file_flush (); - - do - { - event_ptid = linux_wait_1 (ptid, ourstatus, target_options); - } - while ((target_options & TARGET_WNOHANG) == 0 - && event_ptid == null_ptid - && ourstatus->kind == TARGET_WAITKIND_IGNORE); - - /* If at least one stop was reported, there may be more. A single - SIGCHLD can signal more than one child stop. */ - if (target_is_async_p () - && (target_options & TARGET_WNOHANG) != 0 - && event_ptid != null_ptid) - async_file_mark (); - - return event_ptid; -} - -/* Send a signal to an LWP. */ - -static int -kill_lwp (unsigned long lwpid, int signo) -{ - int ret; - - errno = 0; - ret = syscall (__NR_tkill, lwpid, signo); - if (errno == ENOSYS) - { - /* If tkill fails, then we are not using nptl threads, a - configuration we no longer support. */ - perror_with_name (("tkill")); - } - return ret; -} - -void -linux_stop_lwp (struct lwp_info *lwp) -{ - send_sigstop (lwp); -} - -static void -send_sigstop (struct lwp_info *lwp) -{ - int pid; - - pid = lwpid_of (get_lwp_thread (lwp)); - - /* If we already have a pending stop signal for this process, don't - send another. */ - if (lwp->stop_expected) - { - if (debug_threads) - debug_printf ("Have pending sigstop for lwp %d\n", pid); - - return; - } - - if (debug_threads) - debug_printf ("Sending sigstop to lwp %d\n", pid); - - lwp->stop_expected = 1; - kill_lwp (pid, SIGSTOP); -} - -static void -send_sigstop (thread_info *thread, lwp_info *except) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - /* Ignore EXCEPT. */ - if (lwp == except) - return; - - if (lwp->stopped) - return; - - send_sigstop (lwp); -} - -/* Increment the suspend count of an LWP, and stop it, if not stopped - yet. */ -static void -suspend_and_send_sigstop (thread_info *thread, lwp_info *except) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - /* Ignore EXCEPT. */ - if (lwp == except) - return; - - lwp_suspended_inc (lwp); - - send_sigstop (thread, except); -} - -static void -mark_lwp_dead (struct lwp_info *lwp, int wstat) -{ - /* Store the exit status for later. */ - lwp->status_pending_p = 1; - lwp->status_pending = wstat; - - /* Store in waitstatus as well, as there's nothing else to process - for this event. */ - if (WIFEXITED (wstat)) - { - lwp->waitstatus.kind = TARGET_WAITKIND_EXITED; - lwp->waitstatus.value.integer = WEXITSTATUS (wstat); - } - else if (WIFSIGNALED (wstat)) - { - lwp->waitstatus.kind = TARGET_WAITKIND_SIGNALLED; - lwp->waitstatus.value.sig = gdb_signal_from_host (WTERMSIG (wstat)); - } - - /* Prevent trying to stop it. */ - lwp->stopped = 1; - - /* No further stops are expected from a dead lwp. */ - lwp->stop_expected = 0; -} - -/* Return true if LWP has exited already, and has a pending exit event - to report to GDB. */ - -static int -lwp_is_marked_dead (struct lwp_info *lwp) -{ - return (lwp->status_pending_p - && (WIFEXITED (lwp->status_pending) - || WIFSIGNALED (lwp->status_pending))); -} - -/* Wait for all children to stop for the SIGSTOPs we just queued. */ - -static void -wait_for_sigstop (void) -{ - struct thread_info *saved_thread; - ptid_t saved_tid; - int wstat; - int ret; - - saved_thread = current_thread; - if (saved_thread != NULL) - saved_tid = saved_thread->id; - else - saved_tid = null_ptid; /* avoid bogus unused warning */ - - if (debug_threads) - debug_printf ("wait_for_sigstop: pulling events\n"); - - /* Passing NULL_PTID as filter indicates we want all events to be - left pending. Eventually this returns when there are no - unwaited-for children left. */ - ret = linux_wait_for_event_filtered (minus_one_ptid, null_ptid, - &wstat, __WALL); - gdb_assert (ret == -1); - - if (saved_thread == NULL || linux_thread_alive (saved_tid)) - current_thread = saved_thread; - else - { - if (debug_threads) - debug_printf ("Previously current thread died.\n"); - - /* We can't change the current inferior behind GDB's back, - otherwise, a subsequent command may apply to the wrong - process. */ - current_thread = NULL; - } -} - -/* Returns true if THREAD is stopped in a jump pad, and we can't - move it out, because we need to report the stop event to GDB. For - example, if the user puts a breakpoint in the jump pad, it's - because she wants to debug it. */ - -static bool -stuck_in_jump_pad_callback (thread_info *thread) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - if (lwp->suspended != 0) - { - internal_error (__FILE__, __LINE__, - "LWP %ld is suspended, suspended=%d\n", - lwpid_of (thread), lwp->suspended); - } - gdb_assert (lwp->stopped); - - /* Allow debugging the jump pad, gdb_collect, etc.. */ - return (supports_fast_tracepoints () - && agent_loaded_p () - && (gdb_breakpoint_here (lwp->stop_pc) - || lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT - || thread->last_resume_kind == resume_step) - && (linux_fast_tracepoint_collecting (lwp, NULL) - != fast_tpoint_collect_result::not_collecting)); -} - -static void -move_out_of_jump_pad_callback (thread_info *thread) -{ - struct thread_info *saved_thread; - struct lwp_info *lwp = get_thread_lwp (thread); - int *wstat; - - if (lwp->suspended != 0) - { - internal_error (__FILE__, __LINE__, - "LWP %ld is suspended, suspended=%d\n", - lwpid_of (thread), lwp->suspended); - } - gdb_assert (lwp->stopped); - - /* For gdb_breakpoint_here. */ - saved_thread = current_thread; - current_thread = thread; - - wstat = lwp->status_pending_p ? &lwp->status_pending : NULL; - - /* Allow debugging the jump pad, gdb_collect, etc. */ - if (!gdb_breakpoint_here (lwp->stop_pc) - && lwp->stop_reason != TARGET_STOPPED_BY_WATCHPOINT - && thread->last_resume_kind != resume_step - && maybe_move_out_of_jump_pad (lwp, wstat)) - { - if (debug_threads) - debug_printf ("LWP %ld needs stabilizing (in jump pad)\n", - lwpid_of (thread)); - - if (wstat) - { - lwp->status_pending_p = 0; - enqueue_one_deferred_signal (lwp, wstat); - - if (debug_threads) - debug_printf ("Signal %d for LWP %ld deferred " - "(in jump pad)\n", - WSTOPSIG (*wstat), lwpid_of (thread)); - } - - linux_resume_one_lwp (lwp, 0, 0, NULL); - } - else - lwp_suspended_inc (lwp); - - current_thread = saved_thread; -} - -static bool -lwp_running (thread_info *thread) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - if (lwp_is_marked_dead (lwp)) - return false; - - return !lwp->stopped; -} - -/* Stop all lwps that aren't stopped yet, except EXCEPT, if not NULL. - If SUSPEND, then also increase the suspend count of every LWP, - except EXCEPT. */ - -static void -stop_all_lwps (int suspend, struct lwp_info *except) -{ - /* Should not be called recursively. */ - gdb_assert (stopping_threads == NOT_STOPPING_THREADS); - - if (debug_threads) - { - debug_enter (); - debug_printf ("stop_all_lwps (%s, except=%s)\n", - suspend ? "stop-and-suspend" : "stop", - except != NULL - ? target_pid_to_str (ptid_of (get_lwp_thread (except))) - : "none"); - } - - stopping_threads = (suspend - ? STOPPING_AND_SUSPENDING_THREADS - : STOPPING_THREADS); - - if (suspend) - for_each_thread ([&] (thread_info *thread) - { - suspend_and_send_sigstop (thread, except); - }); - else - for_each_thread ([&] (thread_info *thread) - { - send_sigstop (thread, except); - }); - - wait_for_sigstop (); - stopping_threads = NOT_STOPPING_THREADS; - - if (debug_threads) - { - debug_printf ("stop_all_lwps done, setting stopping_threads " - "back to !stopping\n"); - debug_exit (); - } -} - -/* Enqueue one signal in the chain of signals which need to be - delivered to this process on next resume. */ - -static void -enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info) -{ - struct pending_signals *p_sig = XNEW (struct pending_signals); - - p_sig->prev = lwp->pending_signals; - p_sig->signal = signal; - if (info == NULL) - memset (&p_sig->info, 0, sizeof (siginfo_t)); - else - memcpy (&p_sig->info, info, sizeof (siginfo_t)); - lwp->pending_signals = p_sig; -} - -/* Install breakpoints for software single stepping. */ - -static void -install_software_single_step_breakpoints (struct lwp_info *lwp) -{ - struct thread_info *thread = get_lwp_thread (lwp); - struct regcache *regcache = get_thread_regcache (thread, 1); - - scoped_restore save_current_thread = make_scoped_restore (¤t_thread); - - current_thread = thread; - std::vector next_pcs = the_low_target.get_next_pcs (regcache); - - for (CORE_ADDR pc : next_pcs) - set_single_step_breakpoint (pc, current_ptid); -} - -/* Single step via hardware or software single step. - Return 1 if hardware single stepping, 0 if software single stepping - or can't single step. */ - -static int -single_step (struct lwp_info* lwp) -{ - int step = 0; - - if (can_hardware_single_step ()) - { - step = 1; - } - else if (can_software_single_step ()) - { - install_software_single_step_breakpoints (lwp); - step = 0; - } - else - { - if (debug_threads) - debug_printf ("stepping is not implemented on this target"); - } - - return step; -} - -/* The signal can be delivered to the inferior if we are not trying to - finish a fast tracepoint collect. Since signal can be delivered in - the step-over, the program may go to signal handler and trap again - after return from the signal handler. We can live with the spurious - double traps. */ - -static int -lwp_signal_can_be_delivered (struct lwp_info *lwp) -{ - return (lwp->collecting_fast_tracepoint - == fast_tpoint_collect_result::not_collecting); -} - -/* Resume execution of LWP. If STEP is nonzero, single-step it. If - SIGNAL is nonzero, give it that signal. */ - -static void -linux_resume_one_lwp_throw (struct lwp_info *lwp, - int step, int signal, siginfo_t *info) -{ - struct thread_info *thread = get_lwp_thread (lwp); - struct thread_info *saved_thread; - int ptrace_request; - struct process_info *proc = get_thread_process (thread); - - /* Note that target description may not be initialised - (proc->tdesc == NULL) at this point because the program hasn't - stopped at the first instruction yet. It means GDBserver skips - the extra traps from the wrapper program (see option --wrapper). - Code in this function that requires register access should be - guarded by proc->tdesc == NULL or something else. */ - - if (lwp->stopped == 0) - return; - - gdb_assert (lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); - - fast_tpoint_collect_result fast_tp_collecting - = lwp->collecting_fast_tracepoint; - - gdb_assert (!stabilizing_threads - || (fast_tp_collecting - != fast_tpoint_collect_result::not_collecting)); - - /* Cancel actions that rely on GDB not changing the PC (e.g., the - user used the "jump" command, or "set $pc = foo"). */ - if (thread->while_stepping != NULL && lwp->stop_pc != get_pc (lwp)) - { - /* Collecting 'while-stepping' actions doesn't make sense - anymore. */ - release_while_stepping_state_list (thread); - } - - /* If we have pending signals or status, and a new signal, enqueue the - signal. Also enqueue the signal if it can't be delivered to the - inferior right now. */ - if (signal != 0 - && (lwp->status_pending_p - || lwp->pending_signals != NULL - || !lwp_signal_can_be_delivered (lwp))) - { - enqueue_pending_signal (lwp, signal, info); - - /* Postpone any pending signal. It was enqueued above. */ - signal = 0; - } - - if (lwp->status_pending_p) - { - if (debug_threads) - debug_printf ("Not resuming lwp %ld (%s, stop %s);" - " has pending status\n", - lwpid_of (thread), step ? "step" : "continue", - lwp->stop_expected ? "expected" : "not expected"); - return; - } - - saved_thread = current_thread; - current_thread = thread; - - /* This bit needs some thinking about. If we get a signal that - we must report while a single-step reinsert is still pending, - we often end up resuming the thread. It might be better to - (ew) allow a stack of pending events; then we could be sure that - the reinsert happened right away and not lose any signals. - - Making this stack would also shrink the window in which breakpoints are - uninserted (see comment in linux_wait_for_lwp) but not enough for - complete correctness, so it won't solve that problem. It may be - worthwhile just to solve this one, however. */ - if (lwp->bp_reinsert != 0) - { - if (debug_threads) - debug_printf (" pending reinsert at 0x%s\n", - paddress (lwp->bp_reinsert)); - - if (can_hardware_single_step ()) - { - if (fast_tp_collecting == fast_tpoint_collect_result::not_collecting) - { - if (step == 0) - warning ("BAD - reinserting but not stepping."); - if (lwp->suspended) - warning ("BAD - reinserting and suspended(%d).", - lwp->suspended); - } - } - - step = maybe_hw_step (thread); - } - - if (fast_tp_collecting == fast_tpoint_collect_result::before_insn) - { - if (debug_threads) - debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad" - " (exit-jump-pad-bkpt)\n", - lwpid_of (thread)); - } - else if (fast_tp_collecting == fast_tpoint_collect_result::at_insn) - { - if (debug_threads) - debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad" - " single-stepping\n", - lwpid_of (thread)); - - if (can_hardware_single_step ()) - step = 1; - else - { - internal_error (__FILE__, __LINE__, - "moving out of jump pad single-stepping" - " not implemented on this target"); - } - } - - /* If we have while-stepping actions in this thread set it stepping. - If we have a signal to deliver, it may or may not be set to - SIG_IGN, we don't know. Assume so, and allow collecting - while-stepping into a signal handler. A possible smart thing to - do would be to set an internal breakpoint at the signal return - address, continue, and carry on catching this while-stepping - action only when that breakpoint is hit. A future - enhancement. */ - if (thread->while_stepping != NULL) - { - if (debug_threads) - debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n", - lwpid_of (thread)); - - step = single_step (lwp); - } - - if (proc->tdesc != NULL && the_low_target.get_pc != NULL) - { - struct regcache *regcache = get_thread_regcache (current_thread, 1); - - lwp->stop_pc = (*the_low_target.get_pc) (regcache); - - if (debug_threads) - { - debug_printf (" %s from pc 0x%lx\n", step ? "step" : "continue", - (long) lwp->stop_pc); - } - } - - /* If we have pending signals, consume one if it can be delivered to - the inferior. */ - if (lwp->pending_signals != NULL && lwp_signal_can_be_delivered (lwp)) - { - struct pending_signals **p_sig; - - p_sig = &lwp->pending_signals; - while ((*p_sig)->prev != NULL) - p_sig = &(*p_sig)->prev; - - signal = (*p_sig)->signal; - if ((*p_sig)->info.si_signo != 0) - ptrace (PTRACE_SETSIGINFO, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, - &(*p_sig)->info); - - free (*p_sig); - *p_sig = NULL; - } - - if (debug_threads) - debug_printf ("Resuming lwp %ld (%s, signal %d, stop %s)\n", - lwpid_of (thread), step ? "step" : "continue", signal, - lwp->stop_expected ? "expected" : "not expected"); - - if (the_low_target.prepare_to_resume != NULL) - the_low_target.prepare_to_resume (lwp); - - regcache_invalidate_thread (thread); - errno = 0; - lwp->stepping = step; - if (step) - ptrace_request = PTRACE_SINGLESTEP; - else if (gdb_catching_syscalls_p (lwp)) - ptrace_request = PTRACE_SYSCALL; - else - ptrace_request = PTRACE_CONT; - ptrace (ptrace_request, - lwpid_of (thread), - (PTRACE_TYPE_ARG3) 0, - /* Coerce to a uintptr_t first to avoid potential gcc warning - of coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_TYPE_ARG4) (uintptr_t) signal); - - current_thread = saved_thread; - if (errno) - perror_with_name ("resuming thread"); - - /* Successfully resumed. Clear state that no longer makes sense, - and mark the LWP as running. Must not do this before resuming - otherwise if that fails other code will be confused. E.g., we'd - later try to stop the LWP and hang forever waiting for a stop - status. Note that we must not throw after this is cleared, - otherwise handle_zombie_lwp_error would get confused. */ - lwp->stopped = 0; - lwp->stop_reason = TARGET_STOPPED_BY_NO_REASON; -} - -/* Called when we try to resume a stopped LWP and that errors out. If - the LWP is no longer in ptrace-stopped state (meaning it's zombie, - or about to become), discard the error, clear any pending status - the LWP may have, and return true (we'll collect the exit status - soon enough). Otherwise, return false. */ - -static int -check_ptrace_stopped_lwp_gone (struct lwp_info *lp) -{ - struct thread_info *thread = get_lwp_thread (lp); - - /* If we get an error after resuming the LWP successfully, we'd - confuse !T state for the LWP being gone. */ - gdb_assert (lp->stopped); - - /* We can't just check whether the LWP is in 'Z (Zombie)' state, - because even if ptrace failed with ESRCH, the tracee may be "not - yet fully dead", but already refusing ptrace requests. In that - case the tracee has 'R (Running)' state for a little bit - (observed in Linux 3.18). See also the note on ESRCH in the - ptrace(2) man page. Instead, check whether the LWP has any state - other than ptrace-stopped. */ - - /* Don't assume anything if /proc/PID/status can't be read. */ - if (linux_proc_pid_is_trace_stopped_nowarn (lwpid_of (thread)) == 0) - { - lp->stop_reason = TARGET_STOPPED_BY_NO_REASON; - lp->status_pending_p = 0; - return 1; - } - return 0; -} - -/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP - disappears while we try to resume it. */ - -static void -linux_resume_one_lwp (struct lwp_info *lwp, - int step, int signal, siginfo_t *info) -{ - try - { - linux_resume_one_lwp_throw (lwp, step, signal, info); - } - catch (const gdb_exception_error &ex) - { - if (!check_ptrace_stopped_lwp_gone (lwp)) - throw; - } -} - -/* This function is called once per thread via for_each_thread. - We look up which resume request applies to THREAD and mark it with a - pointer to the appropriate resume request. - - This algorithm is O(threads * resume elements), but resume elements - is small (and will remain small at least until GDB supports thread - suspension). */ - -static void -linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - for (int ndx = 0; ndx < n; ndx++) - { - ptid_t ptid = resume[ndx].thread; - if (ptid == minus_one_ptid - || ptid == thread->id - /* Handle both 'pPID' and 'pPID.-1' as meaning 'all threads - of PID'. */ - || (ptid.pid () == pid_of (thread) - && (ptid.is_pid () - || ptid.lwp () == -1))) - { - if (resume[ndx].kind == resume_stop - && thread->last_resume_kind == resume_stop) - { - if (debug_threads) - debug_printf ("already %s LWP %ld at GDB's request\n", - (thread->last_status.kind - == TARGET_WAITKIND_STOPPED) - ? "stopped" - : "stopping", - lwpid_of (thread)); - - continue; - } - - /* Ignore (wildcard) resume requests for already-resumed - threads. */ - if (resume[ndx].kind != resume_stop - && thread->last_resume_kind != resume_stop) - { - if (debug_threads) - debug_printf ("already %s LWP %ld at GDB's request\n", - (thread->last_resume_kind - == resume_step) - ? "stepping" - : "continuing", - lwpid_of (thread)); - continue; - } - - /* Don't let wildcard resumes resume fork children that GDB - does not yet know are new fork children. */ - if (lwp->fork_relative != NULL) - { - struct lwp_info *rel = lwp->fork_relative; - - if (rel->status_pending_p - && (rel->waitstatus.kind == TARGET_WAITKIND_FORKED - || rel->waitstatus.kind == TARGET_WAITKIND_VFORKED)) - { - if (debug_threads) - debug_printf ("not resuming LWP %ld: has queued stop reply\n", - lwpid_of (thread)); - continue; - } - } - - /* If the thread has a pending event that has already been - reported to GDBserver core, but GDB has not pulled the - event out of the vStopped queue yet, likewise, ignore the - (wildcard) resume request. */ - if (in_queued_stop_replies (thread->id)) - { - if (debug_threads) - debug_printf ("not resuming LWP %ld: has queued stop reply\n", - lwpid_of (thread)); - continue; - } - - lwp->resume = &resume[ndx]; - thread->last_resume_kind = lwp->resume->kind; - - lwp->step_range_start = lwp->resume->step_range_start; - lwp->step_range_end = lwp->resume->step_range_end; - - /* If we had a deferred signal to report, dequeue one now. - This can happen if LWP gets more than one signal while - trying to get out of a jump pad. */ - if (lwp->stopped - && !lwp->status_pending_p - && dequeue_one_deferred_signal (lwp, &lwp->status_pending)) - { - lwp->status_pending_p = 1; - - if (debug_threads) - debug_printf ("Dequeueing deferred signal %d for LWP %ld, " - "leaving status pending.\n", - WSTOPSIG (lwp->status_pending), - lwpid_of (thread)); - } - - return; - } - } - - /* No resume action for this thread. */ - lwp->resume = NULL; -} - -/* find_thread callback for linux_resume. Return true if this lwp has an - interesting status pending. */ - -static bool -resume_status_pending_p (thread_info *thread) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - /* LWPs which will not be resumed are not interesting, because - we might not wait for them next time through linux_wait. */ - if (lwp->resume == NULL) - return false; - - return thread_still_has_status_pending_p (thread); -} - -/* Return 1 if this lwp that GDB wants running is stopped at an - internal breakpoint that we need to step over. It assumes that any - required STOP_PC adjustment has already been propagated to the - inferior's regcache. */ - -static bool -need_step_over_p (thread_info *thread) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - struct thread_info *saved_thread; - CORE_ADDR pc; - struct process_info *proc = get_thread_process (thread); - - /* GDBserver is skipping the extra traps from the wrapper program, - don't have to do step over. */ - if (proc->tdesc == NULL) - return false; - - /* LWPs which will not be resumed are not interesting, because we - might not wait for them next time through linux_wait. */ - - if (!lwp->stopped) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? Ignoring, not stopped\n", - lwpid_of (thread)); - return false; - } - - if (thread->last_resume_kind == resume_stop) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? Ignoring, should remain" - " stopped\n", - lwpid_of (thread)); - return false; - } - - gdb_assert (lwp->suspended >= 0); - - if (lwp->suspended) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? Ignoring, suspended\n", - lwpid_of (thread)); - return false; - } - - if (lwp->status_pending_p) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? Ignoring, has pending" - " status.\n", - lwpid_of (thread)); - return false; - } - - /* Note: PC, not STOP_PC. Either GDB has adjusted the PC already, - or we have. */ - pc = get_pc (lwp); - - /* If the PC has changed since we stopped, then don't do anything, - and let the breakpoint/tracepoint be hit. This happens if, for - instance, GDB handled the decr_pc_after_break subtraction itself, - GDB is OOL stepping this thread, or the user has issued a "jump" - command, or poked thread's registers herself. */ - if (pc != lwp->stop_pc) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? Cancelling, PC was changed. " - "Old stop_pc was 0x%s, PC is now 0x%s\n", - lwpid_of (thread), - paddress (lwp->stop_pc), paddress (pc)); - return false; - } - - /* On software single step target, resume the inferior with signal - rather than stepping over. */ - if (can_software_single_step () - && lwp->pending_signals != NULL - && lwp_signal_can_be_delivered (lwp)) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? Ignoring, has pending" - " signals.\n", - lwpid_of (thread)); - - return false; - } - - saved_thread = current_thread; - current_thread = thread; - - /* We can only step over breakpoints we know about. */ - if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc)) - { - /* Don't step over a breakpoint that GDB expects to hit - though. If the condition is being evaluated on the target's side - and it evaluate to false, step over this breakpoint as well. */ - if (gdb_breakpoint_here (pc) - && gdb_condition_true_at_breakpoint (pc) - && gdb_no_commands_at_breakpoint (pc)) - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? yes, but found" - " GDB breakpoint at 0x%s; skipping step over\n", - lwpid_of (thread), paddress (pc)); - - current_thread = saved_thread; - return false; - } - else - { - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? yes, " - "found breakpoint at 0x%s\n", - lwpid_of (thread), paddress (pc)); - - /* We've found an lwp that needs stepping over --- return 1 so - that find_thread stops looking. */ - current_thread = saved_thread; - - return true; - } - } - - current_thread = saved_thread; - - if (debug_threads) - debug_printf ("Need step over [LWP %ld]? No, no breakpoint found" - " at 0x%s\n", - lwpid_of (thread), paddress (pc)); - - return false; -} - -/* Start a step-over operation on LWP. When LWP stopped at a - breakpoint, to make progress, we need to remove the breakpoint out - of the way. If we let other threads run while we do that, they may - pass by the breakpoint location and miss hitting it. To avoid - that, a step-over momentarily stops all threads while LWP is - single-stepped by either hardware or software while the breakpoint - is temporarily uninserted from the inferior. When the single-step - finishes, we reinsert the breakpoint, and let all threads that are - supposed to be running, run again. */ - -static int -start_step_over (struct lwp_info *lwp) -{ - struct thread_info *thread = get_lwp_thread (lwp); - struct thread_info *saved_thread; - CORE_ADDR pc; - int step; - - if (debug_threads) - debug_printf ("Starting step-over on LWP %ld. Stopping all threads\n", - lwpid_of (thread)); - - stop_all_lwps (1, lwp); - - if (lwp->suspended != 0) - { - internal_error (__FILE__, __LINE__, - "LWP %ld suspended=%d\n", lwpid_of (thread), - lwp->suspended); - } - - if (debug_threads) - debug_printf ("Done stopping all threads for step-over.\n"); - - /* Note, we should always reach here with an already adjusted PC, - either by GDB (if we're resuming due to GDB's request), or by our - caller, if we just finished handling an internal breakpoint GDB - shouldn't care about. */ - pc = get_pc (lwp); - - saved_thread = current_thread; - current_thread = thread; - - lwp->bp_reinsert = pc; - uninsert_breakpoints_at (pc); - uninsert_fast_tracepoint_jumps_at (pc); - - step = single_step (lwp); - - current_thread = saved_thread; - - linux_resume_one_lwp (lwp, step, 0, NULL); - - /* Require next event from this LWP. */ - step_over_bkpt = thread->id; - return 1; -} - -/* Finish a step-over. Reinsert the breakpoint we had uninserted in - start_step_over, if still there, and delete any single-step - breakpoints we've set, on non hardware single-step targets. */ - -static int -finish_step_over (struct lwp_info *lwp) -{ - if (lwp->bp_reinsert != 0) - { - struct thread_info *saved_thread = current_thread; - - if (debug_threads) - debug_printf ("Finished step over.\n"); - - current_thread = get_lwp_thread (lwp); - - /* Reinsert any breakpoint at LWP->BP_REINSERT. Note that there - may be no breakpoint to reinsert there by now. */ - reinsert_breakpoints_at (lwp->bp_reinsert); - reinsert_fast_tracepoint_jumps_at (lwp->bp_reinsert); - - lwp->bp_reinsert = 0; - - /* Delete any single-step breakpoints. No longer needed. We - don't have to worry about other threads hitting this trap, - and later not being able to explain it, because we were - stepping over a breakpoint, and we hold all threads but - LWP stopped while doing that. */ - if (!can_hardware_single_step ()) - { - gdb_assert (has_single_step_breakpoints (current_thread)); - delete_single_step_breakpoints (current_thread); - } - - step_over_bkpt = null_ptid; - current_thread = saved_thread; - return 1; - } - else - return 0; -} - -/* If there's a step over in progress, wait until all threads stop - (that is, until the stepping thread finishes its step), and - unsuspend all lwps. The stepping thread ends with its status - pending, which is processed later when we get back to processing - events. */ - -static void -complete_ongoing_step_over (void) -{ - if (step_over_bkpt != null_ptid) - { - struct lwp_info *lwp; - int wstat; - int ret; - - if (debug_threads) - debug_printf ("detach: step over in progress, finish it first\n"); - - /* Passing NULL_PTID as filter indicates we want all events to - be left pending. Eventually this returns when there are no - unwaited-for children left. */ - ret = linux_wait_for_event_filtered (minus_one_ptid, null_ptid, - &wstat, __WALL); - gdb_assert (ret == -1); - - lwp = find_lwp_pid (step_over_bkpt); - if (lwp != NULL) - finish_step_over (lwp); - step_over_bkpt = null_ptid; - unsuspend_all_lwps (lwp); - } -} - -/* This function is called once per thread. We check the thread's resume - request, which will tell us whether to resume, step, or leave the thread - stopped; and what signal, if any, it should be sent. - - For threads which we aren't explicitly told otherwise, we preserve - the stepping flag; this is used for stepping over gdbserver-placed - breakpoints. - - If pending_flags was set in any thread, we queue any needed - signals, since we won't actually resume. We already have a pending - event to report, so we don't need to preserve any step requests; - they should be re-issued if necessary. */ - -static void -linux_resume_one_thread (thread_info *thread, bool leave_all_stopped) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - int leave_pending; - - if (lwp->resume == NULL) - return; - - if (lwp->resume->kind == resume_stop) - { - if (debug_threads) - debug_printf ("resume_stop request for LWP %ld\n", lwpid_of (thread)); - - if (!lwp->stopped) - { - if (debug_threads) - debug_printf ("stopping LWP %ld\n", lwpid_of (thread)); - - /* Stop the thread, and wait for the event asynchronously, - through the event loop. */ - send_sigstop (lwp); - } - else - { - if (debug_threads) - debug_printf ("already stopped LWP %ld\n", - lwpid_of (thread)); - - /* The LWP may have been stopped in an internal event that - was not meant to be notified back to GDB (e.g., gdbserver - breakpoint), so we should be reporting a stop event in - this case too. */ - - /* If the thread already has a pending SIGSTOP, this is a - no-op. Otherwise, something later will presumably resume - the thread and this will cause it to cancel any pending - operation, due to last_resume_kind == resume_stop. If - the thread already has a pending status to report, we - will still report it the next time we wait - see - status_pending_p_callback. */ - - /* If we already have a pending signal to report, then - there's no need to queue a SIGSTOP, as this means we're - midway through moving the LWP out of the jumppad, and we - will report the pending signal as soon as that is - finished. */ - if (lwp->pending_signals_to_report == NULL) - send_sigstop (lwp); - } - - /* For stop requests, we're done. */ - lwp->resume = NULL; - thread->last_status.kind = TARGET_WAITKIND_IGNORE; - return; - } - - /* If this thread which is about to be resumed has a pending status, - then don't resume it - we can just report the pending status. - Likewise if it is suspended, because e.g., another thread is - stepping past a breakpoint. Make sure to queue any signals that - would otherwise be sent. In all-stop mode, we do this decision - based on if *any* thread has a pending status. If there's a - thread that needs the step-over-breakpoint dance, then don't - resume any other thread but that particular one. */ - leave_pending = (lwp->suspended - || lwp->status_pending_p - || leave_all_stopped); - - /* If we have a new signal, enqueue the signal. */ - if (lwp->resume->sig != 0) - { - siginfo_t info, *info_p; - - /* If this is the same signal we were previously stopped by, - make sure to queue its siginfo. */ - if (WIFSTOPPED (lwp->last_status) - && WSTOPSIG (lwp->last_status) == lwp->resume->sig - && ptrace (PTRACE_GETSIGINFO, lwpid_of (thread), - (PTRACE_TYPE_ARG3) 0, &info) == 0) - info_p = &info; - else - info_p = NULL; - - enqueue_pending_signal (lwp, lwp->resume->sig, info_p); - } - - if (!leave_pending) - { - if (debug_threads) - debug_printf ("resuming LWP %ld\n", lwpid_of (thread)); - - proceed_one_lwp (thread, NULL); - } - else - { - if (debug_threads) - debug_printf ("leaving LWP %ld stopped\n", lwpid_of (thread)); - } - - thread->last_status.kind = TARGET_WAITKIND_IGNORE; - lwp->resume = NULL; -} - -static void -linux_resume (struct thread_resume *resume_info, size_t n) -{ - struct thread_info *need_step_over = NULL; - - if (debug_threads) - { - debug_enter (); - debug_printf ("linux_resume:\n"); - } - - for_each_thread ([&] (thread_info *thread) - { - linux_set_resume_request (thread, resume_info, n); - }); - - /* If there is a thread which would otherwise be resumed, which has - a pending status, then don't resume any threads - we can just - report the pending status. Make sure to queue any signals that - would otherwise be sent. In non-stop mode, we'll apply this - logic to each thread individually. We consume all pending events - before considering to start a step-over (in all-stop). */ - bool any_pending = false; - if (!non_stop) - any_pending = find_thread (resume_status_pending_p) != NULL; - - /* If there is a thread which would otherwise be resumed, which is - stopped at a breakpoint that needs stepping over, then don't - resume any threads - have it step over the breakpoint with all - other threads stopped, then resume all threads again. Make sure - to queue any signals that would otherwise be delivered or - queued. */ - if (!any_pending && supports_breakpoints ()) - need_step_over = find_thread (need_step_over_p); - - bool leave_all_stopped = (need_step_over != NULL || any_pending); - - if (debug_threads) - { - if (need_step_over != NULL) - debug_printf ("Not resuming all, need step over\n"); - else if (any_pending) - debug_printf ("Not resuming, all-stop and found " - "an LWP with pending status\n"); - else - debug_printf ("Resuming, no pending status or step over needed\n"); - } - - /* Even if we're leaving threads stopped, queue all signals we'd - otherwise deliver. */ - for_each_thread ([&] (thread_info *thread) - { - linux_resume_one_thread (thread, leave_all_stopped); - }); - - if (need_step_over) - start_step_over (get_thread_lwp (need_step_over)); - - if (debug_threads) - { - debug_printf ("linux_resume done\n"); - debug_exit (); - } - - /* We may have events that were pending that can/should be sent to - the client now. Trigger a linux_wait call. */ - if (target_is_async_p ()) - async_file_mark (); -} - -/* This function is called once per thread. We check the thread's - last resume request, which will tell us whether to resume, step, or - leave the thread stopped. Any signal the client requested to be - delivered has already been enqueued at this point. - - If any thread that GDB wants running is stopped at an internal - breakpoint that needs stepping over, we start a step-over operation - on that particular thread, and leave all others stopped. */ - -static void -proceed_one_lwp (thread_info *thread, lwp_info *except) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - int step; - - if (lwp == except) - return; - - if (debug_threads) - debug_printf ("proceed_one_lwp: lwp %ld\n", lwpid_of (thread)); - - if (!lwp->stopped) - { - if (debug_threads) - debug_printf (" LWP %ld already running\n", lwpid_of (thread)); - return; - } - - if (thread->last_resume_kind == resume_stop - && thread->last_status.kind != TARGET_WAITKIND_IGNORE) - { - if (debug_threads) - debug_printf (" client wants LWP to remain %ld stopped\n", - lwpid_of (thread)); - return; - } - - if (lwp->status_pending_p) - { - if (debug_threads) - debug_printf (" LWP %ld has pending status, leaving stopped\n", - lwpid_of (thread)); - return; - } - - gdb_assert (lwp->suspended >= 0); - - if (lwp->suspended) - { - if (debug_threads) - debug_printf (" LWP %ld is suspended\n", lwpid_of (thread)); - return; - } - - if (thread->last_resume_kind == resume_stop - && lwp->pending_signals_to_report == NULL - && (lwp->collecting_fast_tracepoint - == fast_tpoint_collect_result::not_collecting)) - { - /* We haven't reported this LWP as stopped yet (otherwise, the - last_status.kind check above would catch it, and we wouldn't - reach here. This LWP may have been momentarily paused by a - stop_all_lwps call while handling for example, another LWP's - step-over. In that case, the pending expected SIGSTOP signal - that was queued at vCont;t handling time will have already - been consumed by wait_for_sigstop, and so we need to requeue - another one here. Note that if the LWP already has a SIGSTOP - pending, this is a no-op. */ - - if (debug_threads) - debug_printf ("Client wants LWP %ld to stop. " - "Making sure it has a SIGSTOP pending\n", - lwpid_of (thread)); - - send_sigstop (lwp); - } - - if (thread->last_resume_kind == resume_step) - { - if (debug_threads) - debug_printf (" stepping LWP %ld, client wants it stepping\n", - lwpid_of (thread)); - - /* If resume_step is requested by GDB, install single-step - breakpoints when the thread is about to be actually resumed if - the single-step breakpoints weren't removed. */ - if (can_software_single_step () - && !has_single_step_breakpoints (thread)) - install_software_single_step_breakpoints (lwp); - - step = maybe_hw_step (thread); - } - else if (lwp->bp_reinsert != 0) - { - if (debug_threads) - debug_printf (" stepping LWP %ld, reinsert set\n", - lwpid_of (thread)); - - step = maybe_hw_step (thread); - } - else - step = 0; - - linux_resume_one_lwp (lwp, step, 0, NULL); -} - -static void -unsuspend_and_proceed_one_lwp (thread_info *thread, lwp_info *except) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - if (lwp == except) - return; - - lwp_suspended_decr (lwp); - - proceed_one_lwp (thread, except); -} - -/* When we finish a step-over, set threads running again. If there's - another thread that may need a step-over, now's the time to start - it. Eventually, we'll move all threads past their breakpoints. */ - -static void -proceed_all_lwps (void) -{ - struct thread_info *need_step_over; - - /* If there is a thread which would otherwise be resumed, which is - stopped at a breakpoint that needs stepping over, then don't - resume any threads - have it step over the breakpoint with all - other threads stopped, then resume all threads again. */ - - if (supports_breakpoints ()) - { - need_step_over = find_thread (need_step_over_p); - - if (need_step_over != NULL) - { - if (debug_threads) - debug_printf ("proceed_all_lwps: found " - "thread %ld needing a step-over\n", - lwpid_of (need_step_over)); - - start_step_over (get_thread_lwp (need_step_over)); - return; - } - } - - if (debug_threads) - debug_printf ("Proceeding, no step-over needed\n"); - - for_each_thread ([] (thread_info *thread) - { - proceed_one_lwp (thread, NULL); - }); -} - -/* Stopped LWPs that the client wanted to be running, that don't have - pending statuses, are set to run again, except for EXCEPT, if not - NULL. This undoes a stop_all_lwps call. */ - -static void -unstop_all_lwps (int unsuspend, struct lwp_info *except) -{ - if (debug_threads) - { - debug_enter (); - if (except) - debug_printf ("unstopping all lwps, except=(LWP %ld)\n", - lwpid_of (get_lwp_thread (except))); - else - debug_printf ("unstopping all lwps\n"); - } - - if (unsuspend) - for_each_thread ([&] (thread_info *thread) - { - unsuspend_and_proceed_one_lwp (thread, except); - }); - else - for_each_thread ([&] (thread_info *thread) - { - proceed_one_lwp (thread, except); - }); - - if (debug_threads) - { - debug_printf ("unstop_all_lwps done\n"); - debug_exit (); - } -} - - -#ifdef HAVE_LINUX_REGSETS - -#define use_linux_regsets 1 - -/* Returns true if REGSET has been disabled. */ - -static int -regset_disabled (struct regsets_info *info, struct regset_info *regset) -{ - return (info->disabled_regsets != NULL - && info->disabled_regsets[regset - info->regsets]); -} - -/* Disable REGSET. */ - -static void -disable_regset (struct regsets_info *info, struct regset_info *regset) -{ - int dr_offset; - - dr_offset = regset - info->regsets; - if (info->disabled_regsets == NULL) - info->disabled_regsets = (char *) xcalloc (1, info->num_regsets); - info->disabled_regsets[dr_offset] = 1; -} - -static int -regsets_fetch_inferior_registers (struct regsets_info *regsets_info, - struct regcache *regcache) -{ - struct regset_info *regset; - int saw_general_regs = 0; - int pid; - struct iovec iov; - - pid = lwpid_of (current_thread); - for (regset = regsets_info->regsets; regset->size >= 0; regset++) - { - void *buf, *data; - int nt_type, res; - - if (regset->size == 0 || regset_disabled (regsets_info, regset)) - continue; - - buf = xmalloc (regset->size); - - nt_type = regset->nt_type; - if (nt_type) - { - iov.iov_base = buf; - iov.iov_len = regset->size; - data = (void *) &iov; - } - else - data = buf; - -#ifndef __sparc__ - res = ptrace (regset->get_request, pid, - (PTRACE_TYPE_ARG3) (long) nt_type, data); -#else - res = ptrace (regset->get_request, pid, data, nt_type); -#endif - if (res < 0) - { - if (errno == EIO - || (errno == EINVAL && regset->type == OPTIONAL_REGS)) - { - /* If we get EIO on a regset, or an EINVAL and the regset is - optional, do not try it again for this process mode. */ - disable_regset (regsets_info, regset); - } - else if (errno == ENODATA) - { - /* ENODATA may be returned if the regset is currently - not "active". This can happen in normal operation, - so suppress the warning in this case. */ - } - else if (errno == ESRCH) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to read its registers. */ - } - else - { - char s[256]; - sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d", - pid); - perror (s); - } - } - else - { - if (regset->type == GENERAL_REGS) - saw_general_regs = 1; - regset->store_function (regcache, buf); - } - free (buf); - } - if (saw_general_regs) - return 0; - else - return 1; -} - -static int -regsets_store_inferior_registers (struct regsets_info *regsets_info, - struct regcache *regcache) -{ - struct regset_info *regset; - int saw_general_regs = 0; - int pid; - struct iovec iov; - - pid = lwpid_of (current_thread); - for (regset = regsets_info->regsets; regset->size >= 0; regset++) - { - void *buf, *data; - int nt_type, res; - - if (regset->size == 0 || regset_disabled (regsets_info, regset) - || regset->fill_function == NULL) - continue; - - buf = xmalloc (regset->size); - - /* First fill the buffer with the current register set contents, - in case there are any items in the kernel's regset that are - not in gdbserver's regcache. */ - - nt_type = regset->nt_type; - if (nt_type) - { - iov.iov_base = buf; - iov.iov_len = regset->size; - data = (void *) &iov; - } - else - data = buf; - -#ifndef __sparc__ - res = ptrace (regset->get_request, pid, - (PTRACE_TYPE_ARG3) (long) nt_type, data); -#else - res = ptrace (regset->get_request, pid, data, nt_type); -#endif - - if (res == 0) - { - /* Then overlay our cached registers on that. */ - regset->fill_function (regcache, buf); - - /* Only now do we write the register set. */ -#ifndef __sparc__ - res = ptrace (regset->set_request, pid, - (PTRACE_TYPE_ARG3) (long) nt_type, data); -#else - res = ptrace (regset->set_request, pid, data, nt_type); -#endif - } - - if (res < 0) - { - if (errno == EIO - || (errno == EINVAL && regset->type == OPTIONAL_REGS)) - { - /* If we get EIO on a regset, or an EINVAL and the regset is - optional, do not try it again for this process mode. */ - disable_regset (regsets_info, regset); - } - else if (errno == ESRCH) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to change its registers. See also the related - comment in linux_resume_one_lwp. */ - free (buf); - return 0; - } - else - { - perror ("Warning: ptrace(regsets_store_inferior_registers)"); - } - } - else if (regset->type == GENERAL_REGS) - saw_general_regs = 1; - free (buf); - } - if (saw_general_regs) - return 0; - else - return 1; -} - -#else /* !HAVE_LINUX_REGSETS */ - -#define use_linux_regsets 0 -#define regsets_fetch_inferior_registers(regsets_info, regcache) 1 -#define regsets_store_inferior_registers(regsets_info, regcache) 1 - -#endif - -/* Return 1 if register REGNO is supported by one of the regset ptrace - calls or 0 if it has to be transferred individually. */ - -static int -linux_register_in_regsets (const struct regs_info *regs_info, int regno) -{ - unsigned char mask = 1 << (regno % 8); - size_t index = regno / 8; - - return (use_linux_regsets - && (regs_info->regset_bitmap == NULL - || (regs_info->regset_bitmap[index] & mask) != 0)); -} - -#ifdef HAVE_LINUX_USRREGS - -static int -register_addr (const struct usrregs_info *usrregs, int regnum) -{ - int addr; - - if (regnum < 0 || regnum >= usrregs->num_regs) - error ("Invalid register number %d.", regnum); - - addr = usrregs->regmap[regnum]; - - return addr; -} - -/* Fetch one register. */ -static void -fetch_register (const struct usrregs_info *usrregs, - struct regcache *regcache, int regno) -{ - CORE_ADDR regaddr; - int i, size; - char *buf; - int pid; - - if (regno >= usrregs->num_regs) - return; - if ((*the_low_target.cannot_fetch_register) (regno)) - return; - - regaddr = register_addr (usrregs, regno); - if (regaddr == -1) - return; - - size = ((register_size (regcache->tdesc, regno) - + sizeof (PTRACE_XFER_TYPE) - 1) - & -sizeof (PTRACE_XFER_TYPE)); - buf = (char *) alloca (size); - - pid = lwpid_of (current_thread); - for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) - { - errno = 0; - *(PTRACE_XFER_TYPE *) (buf + i) = - ptrace (PTRACE_PEEKUSER, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - of coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_TYPE_ARG3) (uintptr_t) regaddr, (PTRACE_TYPE_ARG4) 0); - regaddr += sizeof (PTRACE_XFER_TYPE); - if (errno != 0) - { - /* Mark register REGNO unavailable. */ - supply_register (regcache, regno, NULL); - return; - } - } - - if (the_low_target.supply_ptrace_register) - the_low_target.supply_ptrace_register (regcache, regno, buf); - else - supply_register (regcache, regno, buf); -} - -/* Store one register. */ -static void -store_register (const struct usrregs_info *usrregs, - struct regcache *regcache, int regno) -{ - CORE_ADDR regaddr; - int i, size; - char *buf; - int pid; - - if (regno >= usrregs->num_regs) - return; - if ((*the_low_target.cannot_store_register) (regno)) - return; - - regaddr = register_addr (usrregs, regno); - if (regaddr == -1) - return; - - size = ((register_size (regcache->tdesc, regno) - + sizeof (PTRACE_XFER_TYPE) - 1) - & -sizeof (PTRACE_XFER_TYPE)); - buf = (char *) alloca (size); - memset (buf, 0, size); - - if (the_low_target.collect_ptrace_register) - the_low_target.collect_ptrace_register (regcache, regno, buf); - else - collect_register (regcache, regno, buf); - - pid = lwpid_of (current_thread); - for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) - { - errno = 0; - ptrace (PTRACE_POKEUSER, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_TYPE_ARG3) (uintptr_t) regaddr, - (PTRACE_TYPE_ARG4) *(PTRACE_XFER_TYPE *) (buf + i)); - if (errno != 0) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to change its registers. See also the related - comment in linux_resume_one_lwp. */ - if (errno == ESRCH) - return; - - if ((*the_low_target.cannot_store_register) (regno) == 0) - error ("writing register %d: %s", regno, safe_strerror (errno)); - } - regaddr += sizeof (PTRACE_XFER_TYPE); - } -} - -/* Fetch all registers, or just one, from the child process. - If REGNO is -1, do this for all registers, skipping any that are - assumed to have been retrieved by regsets_fetch_inferior_registers, - unless ALL is non-zero. - Otherwise, REGNO specifies which register (so we can save time). */ -static void -usr_fetch_inferior_registers (const struct regs_info *regs_info, - struct regcache *regcache, int regno, int all) -{ - struct usrregs_info *usr = regs_info->usrregs; - - if (regno == -1) - { - for (regno = 0; regno < usr->num_regs; regno++) - if (all || !linux_register_in_regsets (regs_info, regno)) - fetch_register (usr, regcache, regno); - } - else - fetch_register (usr, regcache, regno); -} - -/* Store our register values back into the inferior. - If REGNO is -1, do this for all registers, skipping any that are - assumed to have been saved by regsets_store_inferior_registers, - unless ALL is non-zero. - Otherwise, REGNO specifies which register (so we can save time). */ -static void -usr_store_inferior_registers (const struct regs_info *regs_info, - struct regcache *regcache, int regno, int all) -{ - struct usrregs_info *usr = regs_info->usrregs; - - if (regno == -1) - { - for (regno = 0; regno < usr->num_regs; regno++) - if (all || !linux_register_in_regsets (regs_info, regno)) - store_register (usr, regcache, regno); - } - else - store_register (usr, regcache, regno); -} - -#else /* !HAVE_LINUX_USRREGS */ - -#define usr_fetch_inferior_registers(regs_info, regcache, regno, all) do {} while (0) -#define usr_store_inferior_registers(regs_info, regcache, regno, all) do {} while (0) - -#endif - - -static void -linux_fetch_registers (struct regcache *regcache, int regno) -{ - int use_regsets; - int all = 0; - const struct regs_info *regs_info = (*the_low_target.regs_info) (); - - if (regno == -1) - { - if (the_low_target.fetch_register != NULL - && regs_info->usrregs != NULL) - for (regno = 0; regno < regs_info->usrregs->num_regs; regno++) - (*the_low_target.fetch_register) (regcache, regno); - - all = regsets_fetch_inferior_registers (regs_info->regsets_info, regcache); - if (regs_info->usrregs != NULL) - usr_fetch_inferior_registers (regs_info, regcache, -1, all); - } - else - { - if (the_low_target.fetch_register != NULL - && (*the_low_target.fetch_register) (regcache, regno)) - return; - - use_regsets = linux_register_in_regsets (regs_info, regno); - if (use_regsets) - all = regsets_fetch_inferior_registers (regs_info->regsets_info, - regcache); - if ((!use_regsets || all) && regs_info->usrregs != NULL) - usr_fetch_inferior_registers (regs_info, regcache, regno, 1); - } -} - -static void -linux_store_registers (struct regcache *regcache, int regno) -{ - int use_regsets; - int all = 0; - const struct regs_info *regs_info = (*the_low_target.regs_info) (); - - if (regno == -1) - { - all = regsets_store_inferior_registers (regs_info->regsets_info, - regcache); - if (regs_info->usrregs != NULL) - usr_store_inferior_registers (regs_info, regcache, regno, all); - } - else - { - use_regsets = linux_register_in_regsets (regs_info, regno); - if (use_regsets) - all = regsets_store_inferior_registers (regs_info->regsets_info, - regcache); - if ((!use_regsets || all) && regs_info->usrregs != NULL) - usr_store_inferior_registers (regs_info, regcache, regno, 1); - } -} - - -/* Copy LEN bytes from inferior's memory starting at MEMADDR - to debugger memory starting at MYADDR. */ - -static int -linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - int pid = lwpid_of (current_thread); - PTRACE_XFER_TYPE *buffer; - CORE_ADDR addr; - int count; - char filename[64]; - int i; - int ret; - int fd; - - /* Try using /proc. Don't bother for one word. */ - if (len >= 3 * sizeof (long)) - { - int bytes; - - /* We could keep this file open and cache it - possibly one per - thread. That requires some juggling, but is even faster. */ - sprintf (filename, "/proc/%d/mem", pid); - fd = open (filename, O_RDONLY | O_LARGEFILE); - if (fd == -1) - goto no_proc; - - /* If pread64 is available, use it. It's faster if the kernel - supports it (only one syscall), and it's 64-bit safe even on - 32-bit platforms (for instance, SPARC debugging a SPARC64 - application). */ -#ifdef HAVE_PREAD64 - bytes = pread64 (fd, myaddr, len, memaddr); -#else - bytes = -1; - if (lseek (fd, memaddr, SEEK_SET) != -1) - bytes = read (fd, myaddr, len); -#endif - - close (fd); - if (bytes == len) - return 0; - - /* Some data was read, we'll try to get the rest with ptrace. */ - if (bytes > 0) - { - memaddr += bytes; - myaddr += bytes; - len -= bytes; - } - } - - no_proc: - /* Round starting address down to longword boundary. */ - addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); - /* Round ending address up; get number of longwords that makes. */ - count = ((((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) - / sizeof (PTRACE_XFER_TYPE)); - /* Allocate buffer of that many longwords. */ - buffer = XALLOCAVEC (PTRACE_XFER_TYPE, count); - - /* Read all the longwords */ - errno = 0; - for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) - { - /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - buffer[i] = ptrace (PTRACE_PEEKTEXT, pid, - (PTRACE_TYPE_ARG3) (uintptr_t) addr, - (PTRACE_TYPE_ARG4) 0); - if (errno) - break; - } - ret = errno; - - /* Copy appropriate bytes out of the buffer. */ - if (i > 0) - { - i *= sizeof (PTRACE_XFER_TYPE); - i -= memaddr & (sizeof (PTRACE_XFER_TYPE) - 1); - memcpy (myaddr, - (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), - i < len ? i : len); - } - - return ret; -} - -/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's - memory at MEMADDR. On failure (cannot write to the inferior) - returns the value of errno. Always succeeds if LEN is zero. */ - -static int -linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) -{ - int i; - /* Round starting address down to longword boundary. */ - CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); - /* Round ending address up; get number of longwords that makes. */ - int count - = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) - / sizeof (PTRACE_XFER_TYPE); - - /* Allocate buffer of that many longwords. */ - PTRACE_XFER_TYPE *buffer = XALLOCAVEC (PTRACE_XFER_TYPE, count); - - int pid = lwpid_of (current_thread); - - if (len == 0) - { - /* Zero length write always succeeds. */ - return 0; - } - - if (debug_threads) - { - /* Dump up to four bytes. */ - char str[4 * 2 + 1]; - char *p = str; - int dump = len < 4 ? len : 4; - - for (i = 0; i < dump; i++) - { - sprintf (p, "%02x", myaddr[i]); - p += 2; - } - *p = '\0'; - - debug_printf ("Writing %s to 0x%08lx in process %d\n", - str, (long) memaddr, pid); - } - - /* Fill start and end extra bytes of buffer with existing memory data. */ - - errno = 0; - /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - buffer[0] = ptrace (PTRACE_PEEKTEXT, pid, - (PTRACE_TYPE_ARG3) (uintptr_t) addr, - (PTRACE_TYPE_ARG4) 0); - if (errno) - return errno; - - if (count > 1) - { - errno = 0; - buffer[count - 1] - = ptrace (PTRACE_PEEKTEXT, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_TYPE_ARG3) (uintptr_t) (addr + (count - 1) - * sizeof (PTRACE_XFER_TYPE)), - (PTRACE_TYPE_ARG4) 0); - if (errno) - return errno; - } - - /* Copy data to be written over corresponding part of buffer. */ - - memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), - myaddr, len); - - /* Write the entire buffer. */ - - for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) - { - errno = 0; - ptrace (PTRACE_POKETEXT, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_TYPE_ARG3) (uintptr_t) addr, - (PTRACE_TYPE_ARG4) buffer[i]); - if (errno) - return errno; - } - - return 0; -} - -static void -linux_look_up_symbols (void) -{ -#ifdef USE_THREAD_DB - struct process_info *proc = current_process (); - - if (proc->priv->thread_db != NULL) - return; - - thread_db_init (); -#endif -} - -static void -linux_request_interrupt (void) -{ - /* Send a SIGINT to the process group. This acts just like the user - typed a ^C on the controlling terminal. */ - kill (-signal_pid, SIGINT); -} - -/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET - to debugger memory starting at MYADDR. */ - -static int -linux_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len) -{ - char filename[PATH_MAX]; - int fd, n; - int pid = lwpid_of (current_thread); - - xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid); - - fd = open (filename, O_RDONLY); - if (fd < 0) - return -1; - - if (offset != (CORE_ADDR) 0 - && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset) - n = -1; - else - n = read (fd, myaddr, len); - - close (fd); - - return n; -} - -/* These breakpoint and watchpoint related wrapper functions simply - pass on the function call if the target has registered a - corresponding function. */ - -static int -linux_supports_z_point_type (char z_type) -{ - return (the_low_target.supports_z_point_type != NULL - && the_low_target.supports_z_point_type (z_type)); -} - -static int -linux_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - if (type == raw_bkpt_type_sw) - return insert_memory_breakpoint (bp); - else if (the_low_target.insert_point != NULL) - return the_low_target.insert_point (type, addr, size, bp); - else - /* Unsupported (see target.h). */ - return 1; -} - -static int -linux_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - if (type == raw_bkpt_type_sw) - return remove_memory_breakpoint (bp); - else if (the_low_target.remove_point != NULL) - return the_low_target.remove_point (type, addr, size, bp); - else - /* Unsupported (see target.h). */ - return 1; -} - -/* Implement the to_stopped_by_sw_breakpoint target_ops - method. */ - -static int -linux_stopped_by_sw_breakpoint (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - - return (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT); -} - -/* Implement the to_supports_stopped_by_sw_breakpoint target_ops - method. */ - -static int -linux_supports_stopped_by_sw_breakpoint (void) -{ - return USE_SIGTRAP_SIGINFO; -} - -/* Implement the to_stopped_by_hw_breakpoint target_ops - method. */ - -static int -linux_stopped_by_hw_breakpoint (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - - return (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT); -} - -/* Implement the to_supports_stopped_by_hw_breakpoint target_ops - method. */ - -static int -linux_supports_stopped_by_hw_breakpoint (void) -{ - return USE_SIGTRAP_SIGINFO; -} - -/* Implement the supports_hardware_single_step target_ops method. */ - -static int -linux_supports_hardware_single_step (void) -{ - return can_hardware_single_step (); -} - -static int -linux_supports_software_single_step (void) -{ - return can_software_single_step (); -} - -static int -linux_stopped_by_watchpoint (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - - return lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT; -} - -static CORE_ADDR -linux_stopped_data_address (void) -{ - struct lwp_info *lwp = get_thread_lwp (current_thread); - - return lwp->stopped_data_address; -} - -#if defined(__UCLIBC__) && defined(HAS_NOMMU) \ - && defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) \ - && defined(PT_TEXT_END_ADDR) - -/* This is only used for targets that define PT_TEXT_ADDR, - PT_DATA_ADDR and PT_TEXT_END_ADDR. If those are not defined, supposedly - the target has different ways of acquiring this information, like - loadmaps. */ - -/* Under uClinux, programs are loaded at non-zero offsets, which we need - to tell gdb about. */ - -static int -linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p) -{ - unsigned long text, text_end, data; - int pid = lwpid_of (current_thread); - - errno = 0; - - text = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_TEXT_ADDR, - (PTRACE_TYPE_ARG4) 0); - text_end = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_TEXT_END_ADDR, - (PTRACE_TYPE_ARG4) 0); - data = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_DATA_ADDR, - (PTRACE_TYPE_ARG4) 0); - - if (errno == 0) - { - /* Both text and data offsets produced at compile-time (and so - used by gdb) are relative to the beginning of the program, - with the data segment immediately following the text segment. - However, the actual runtime layout in memory may put the data - somewhere else, so when we send gdb a data base-address, we - use the real data base address and subtract the compile-time - data base-address from it (which is just the length of the - text segment). BSS immediately follows data in both - cases. */ - *text_p = text; - *data_p = data - (text_end - text); - - return 1; - } - return 0; -} -#endif - -static int -linux_qxfer_osdata (const char *annex, - unsigned char *readbuf, unsigned const char *writebuf, - CORE_ADDR offset, int len) -{ - return linux_common_xfer_osdata (annex, readbuf, offset, len); -} - -/* Convert a native/host siginfo object, into/from the siginfo in the - layout of the inferiors' architecture. */ - -static void -siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction) -{ - int done = 0; - - if (the_low_target.siginfo_fixup != NULL) - done = the_low_target.siginfo_fixup (siginfo, inf_siginfo, direction); - - /* If there was no callback, or the callback didn't do anything, - then just do a straight memcpy. */ - if (!done) - { - if (direction == 1) - memcpy (siginfo, inf_siginfo, sizeof (siginfo_t)); - else - memcpy (inf_siginfo, siginfo, sizeof (siginfo_t)); - } -} - -static int -linux_xfer_siginfo (const char *annex, unsigned char *readbuf, - unsigned const char *writebuf, CORE_ADDR offset, int len) -{ - int pid; - siginfo_t siginfo; - gdb_byte inf_siginfo[sizeof (siginfo_t)]; - - if (current_thread == NULL) - return -1; - - pid = lwpid_of (current_thread); - - if (debug_threads) - debug_printf ("%s siginfo for lwp %d.\n", - readbuf != NULL ? "Reading" : "Writing", - pid); - - if (offset >= sizeof (siginfo)) - return -1; - - if (ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo) != 0) - return -1; - - /* When GDBSERVER is built as a 64-bit application, ptrace writes into - SIGINFO an object with 64-bit layout. Since debugging a 32-bit - inferior with a 64-bit GDBSERVER should look the same as debugging it - with a 32-bit GDBSERVER, we need to convert it. */ - siginfo_fixup (&siginfo, inf_siginfo, 0); - - if (offset + len > sizeof (siginfo)) - len = sizeof (siginfo) - offset; - - if (readbuf != NULL) - memcpy (readbuf, inf_siginfo + offset, len); - else - { - memcpy (inf_siginfo + offset, writebuf, len); - - /* Convert back to ptrace layout before flushing it out. */ - siginfo_fixup (&siginfo, inf_siginfo, 1); - - if (ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo) != 0) - return -1; - } - - return len; -} - -/* SIGCHLD handler that serves two purposes: In non-stop/async mode, - so we notice when children change state; as the handler for the - sigsuspend in my_waitpid. */ - -static void -sigchld_handler (int signo) -{ - int old_errno = errno; - - if (debug_threads) - { - do - { - /* Use the async signal safe debug function. */ - if (debug_write ("sigchld_handler\n", - sizeof ("sigchld_handler\n") - 1) < 0) - break; /* just ignore */ - } while (0); - } - - if (target_is_async_p ()) - async_file_mark (); /* trigger a linux_wait */ - - errno = old_errno; -} - -static int -linux_supports_non_stop (void) -{ - return 1; -} - -static int -linux_async (int enable) -{ - int previous = target_is_async_p (); - - if (debug_threads) - debug_printf ("linux_async (%d), previous=%d\n", - enable, previous); - - if (previous != enable) - { - sigset_t mask; - sigemptyset (&mask); - sigaddset (&mask, SIGCHLD); - - gdb_sigmask (SIG_BLOCK, &mask, NULL); - - if (enable) - { - if (pipe (linux_event_pipe) == -1) - { - linux_event_pipe[0] = -1; - linux_event_pipe[1] = -1; - gdb_sigmask (SIG_UNBLOCK, &mask, NULL); - - warning ("creating event pipe failed."); - return previous; - } - - fcntl (linux_event_pipe[0], F_SETFL, O_NONBLOCK); - fcntl (linux_event_pipe[1], F_SETFL, O_NONBLOCK); - - /* Register the event loop handler. */ - add_file_handler (linux_event_pipe[0], - handle_target_event, NULL); - - /* Always trigger a linux_wait. */ - async_file_mark (); - } - else - { - delete_file_handler (linux_event_pipe[0]); - - close (linux_event_pipe[0]); - close (linux_event_pipe[1]); - linux_event_pipe[0] = -1; - linux_event_pipe[1] = -1; - } - - gdb_sigmask (SIG_UNBLOCK, &mask, NULL); - } - - return previous; -} - -static int -linux_start_non_stop (int nonstop) -{ - /* Register or unregister from event-loop accordingly. */ - linux_async (nonstop); - - if (target_is_async_p () != (nonstop != 0)) - return -1; - - return 0; -} - -static int -linux_supports_multi_process (void) -{ - return 1; -} - -/* Check if fork events are supported. */ - -static int -linux_supports_fork_events (void) -{ - return linux_supports_tracefork (); -} - -/* Check if vfork events are supported. */ - -static int -linux_supports_vfork_events (void) -{ - return linux_supports_tracefork (); -} - -/* Check if exec events are supported. */ - -static int -linux_supports_exec_events (void) -{ - return linux_supports_traceexec (); -} - -/* Target hook for 'handle_new_gdb_connection'. Causes a reset of the - ptrace flags for all inferiors. This is in case the new GDB connection - doesn't support the same set of events that the previous one did. */ - -static void -linux_handle_new_gdb_connection (void) -{ - /* Request that all the lwps reset their ptrace options. */ - for_each_thread ([] (thread_info *thread) - { - struct lwp_info *lwp = get_thread_lwp (thread); - - if (!lwp->stopped) - { - /* Stop the lwp so we can modify its ptrace options. */ - lwp->must_set_ptrace_flags = 1; - linux_stop_lwp (lwp); - } - else - { - /* Already stopped; go ahead and set the ptrace options. */ - struct process_info *proc = find_process_pid (pid_of (thread)); - int options = linux_low_ptrace_options (proc->attached); - - linux_enable_event_reporting (lwpid_of (thread), options); - lwp->must_set_ptrace_flags = 0; - } - }); -} - -static int -linux_supports_disable_randomization (void) -{ -#ifdef HAVE_PERSONALITY - return 1; -#else - return 0; -#endif -} - -static int -linux_supports_agent (void) -{ - return 1; -} - -static int -linux_supports_range_stepping (void) -{ - if (can_software_single_step ()) - return 1; - if (*the_low_target.supports_range_stepping == NULL) - return 0; - - return (*the_low_target.supports_range_stepping) (); -} - -#if defined PT_GETDSBT || defined PTRACE_GETFDPIC -struct target_loadseg -{ - /* Core address to which the segment is mapped. */ - Elf32_Addr addr; - /* VMA recorded in the program header. */ - Elf32_Addr p_vaddr; - /* Size of this segment in memory. */ - Elf32_Word p_memsz; -}; - -# if defined PT_GETDSBT -struct target_loadmap -{ - /* Protocol version number, must be zero. */ - Elf32_Word version; - /* Pointer to the DSBT table, its size, and the DSBT index. */ - unsigned *dsbt_table; - unsigned dsbt_size, dsbt_index; - /* Number of segments in this map. */ - Elf32_Word nsegs; - /* The actual memory map. */ - struct target_loadseg segs[/*nsegs*/]; -}; -# define LINUX_LOADMAP PT_GETDSBT -# define LINUX_LOADMAP_EXEC PTRACE_GETDSBT_EXEC -# define LINUX_LOADMAP_INTERP PTRACE_GETDSBT_INTERP -# else -struct target_loadmap -{ - /* Protocol version number, must be zero. */ - Elf32_Half version; - /* Number of segments in this map. */ - Elf32_Half nsegs; - /* The actual memory map. */ - struct target_loadseg segs[/*nsegs*/]; -}; -# define LINUX_LOADMAP PTRACE_GETFDPIC -# define LINUX_LOADMAP_EXEC PTRACE_GETFDPIC_EXEC -# define LINUX_LOADMAP_INTERP PTRACE_GETFDPIC_INTERP -# endif - -static int -linux_read_loadmap (const char *annex, CORE_ADDR offset, - unsigned char *myaddr, unsigned int len) -{ - int pid = lwpid_of (current_thread); - int addr = -1; - struct target_loadmap *data = NULL; - unsigned int actual_length, copy_length; - - if (strcmp (annex, "exec") == 0) - addr = (int) LINUX_LOADMAP_EXEC; - else if (strcmp (annex, "interp") == 0) - addr = (int) LINUX_LOADMAP_INTERP; - else - return -1; - - if (ptrace (LINUX_LOADMAP, pid, addr, &data) != 0) - return -1; - - if (data == NULL) - return -1; - - actual_length = sizeof (struct target_loadmap) - + sizeof (struct target_loadseg) * data->nsegs; - - if (offset < 0 || offset > actual_length) - return -1; - - copy_length = actual_length - offset < len ? actual_length - offset : len; - memcpy (myaddr, (char *) data + offset, copy_length); - return copy_length; -} -#else -# define linux_read_loadmap NULL -#endif /* defined PT_GETDSBT || defined PTRACE_GETFDPIC */ - -static void -linux_process_qsupported (char **features, int count) -{ - if (the_low_target.process_qsupported != NULL) - the_low_target.process_qsupported (features, count); -} - -static int -linux_supports_catch_syscall (void) -{ - return (the_low_target.get_syscall_trapinfo != NULL - && linux_supports_tracesysgood ()); -} - -static int -linux_get_ipa_tdesc_idx (void) -{ - if (the_low_target.get_ipa_tdesc_idx == NULL) - return 0; - - return (*the_low_target.get_ipa_tdesc_idx) (); -} - -static int -linux_supports_tracepoints (void) -{ - if (*the_low_target.supports_tracepoints == NULL) - return 0; - - return (*the_low_target.supports_tracepoints) (); -} - -static CORE_ADDR -linux_read_pc (struct regcache *regcache) -{ - if (the_low_target.get_pc == NULL) - return 0; - - return (*the_low_target.get_pc) (regcache); -} - -static void -linux_write_pc (struct regcache *regcache, CORE_ADDR pc) -{ - gdb_assert (the_low_target.set_pc != NULL); - - (*the_low_target.set_pc) (regcache, pc); -} - -static int -linux_thread_stopped (struct thread_info *thread) -{ - return get_thread_lwp (thread)->stopped; -} - -/* This exposes stop-all-threads functionality to other modules. */ - -static void -linux_pause_all (int freeze) -{ - stop_all_lwps (freeze, NULL); -} - -/* This exposes unstop-all-threads functionality to other gdbserver - modules. */ - -static void -linux_unpause_all (int unfreeze) -{ - unstop_all_lwps (unfreeze, NULL); -} - -static int -linux_prepare_to_access_memory (void) -{ - /* Neither ptrace nor /proc/PID/mem allow accessing memory through a - running LWP. */ - if (non_stop) - linux_pause_all (1); - return 0; -} - -static void -linux_done_accessing_memory (void) -{ - /* Neither ptrace nor /proc/PID/mem allow accessing memory through a - running LWP. */ - if (non_stop) - linux_unpause_all (1); -} - -static int -linux_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ - return (*the_low_target.install_fast_tracepoint_jump_pad) - (tpoint, tpaddr, collector, lockaddr, orig_size, - jump_entry, trampoline, trampoline_size, - jjump_pad_insn, jjump_pad_insn_size, - adjusted_insn_addr, adjusted_insn_addr_end, - err); -} - -static struct emit_ops * -linux_emit_ops (void) -{ - if (the_low_target.emit_ops != NULL) - return (*the_low_target.emit_ops) (); - else - return NULL; -} - -static int -linux_get_min_fast_tracepoint_insn_len (void) -{ - return (*the_low_target.get_min_fast_tracepoint_insn_len) (); -} - -/* Extract &phdr and num_phdr in the inferior. Return 0 on success. */ - -static int -get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, - CORE_ADDR *phdr_memaddr, int *num_phdr) -{ - char filename[PATH_MAX]; - int fd; - const int auxv_size = is_elf64 - ? sizeof (Elf64_auxv_t) : sizeof (Elf32_auxv_t); - char buf[sizeof (Elf64_auxv_t)]; /* The larger of the two. */ - - xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid); - - fd = open (filename, O_RDONLY); - if (fd < 0) - return 1; - - *phdr_memaddr = 0; - *num_phdr = 0; - while (read (fd, buf, auxv_size) == auxv_size - && (*phdr_memaddr == 0 || *num_phdr == 0)) - { - if (is_elf64) - { - Elf64_auxv_t *const aux = (Elf64_auxv_t *) buf; - - switch (aux->a_type) - { - case AT_PHDR: - *phdr_memaddr = aux->a_un.a_val; - break; - case AT_PHNUM: - *num_phdr = aux->a_un.a_val; - break; - } - } - else - { - Elf32_auxv_t *const aux = (Elf32_auxv_t *) buf; - - switch (aux->a_type) - { - case AT_PHDR: - *phdr_memaddr = aux->a_un.a_val; - break; - case AT_PHNUM: - *num_phdr = aux->a_un.a_val; - break; - } - } - } - - close (fd); - - if (*phdr_memaddr == 0 || *num_phdr == 0) - { - warning ("Unexpected missing AT_PHDR and/or AT_PHNUM: " - "phdr_memaddr = %ld, phdr_num = %d", - (long) *phdr_memaddr, *num_phdr); - return 2; - } - - return 0; -} - -/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ - -static CORE_ADDR -get_dynamic (const int pid, const int is_elf64) -{ - CORE_ADDR phdr_memaddr, relocation; - int num_phdr, i; - unsigned char *phdr_buf; - const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); - - if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) - return 0; - - gdb_assert (num_phdr < 100); /* Basic sanity check. */ - phdr_buf = (unsigned char *) alloca (num_phdr * phdr_size); - - if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size)) - return 0; - - /* Compute relocation: it is expected to be 0 for "regular" executables, - non-zero for PIE ones. */ - relocation = -1; - for (i = 0; relocation == -1 && i < num_phdr; i++) - if (is_elf64) - { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_PHDR) - relocation = phdr_memaddr - p->p_vaddr; - } - else - { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_PHDR) - relocation = phdr_memaddr - p->p_vaddr; - } - - if (relocation == -1) - { - /* PT_PHDR is optional, but necessary for PIE in general. Fortunately - any real world executables, including PIE executables, have always - PT_PHDR present. PT_PHDR is not present in some shared libraries or - in fpc (Free Pascal 2.4) binaries but neither of those have a need for - or present DT_DEBUG anyway (fpc binaries are statically linked). - - Therefore if there exists DT_DEBUG there is always also PT_PHDR. - - GDB could find RELOCATION also from AT_ENTRY - e_entry. */ - - return 0; - } - - for (i = 0; i < num_phdr; i++) - { - if (is_elf64) - { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; - } - else - { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; - } - } - - return 0; -} - -/* Return &_r_debug in the inferior, or -1 if not present. Return value - can be 0 if the inferior does not yet have the library list initialized. - We look for DT_MIPS_RLD_MAP first. MIPS executables use this instead of - DT_DEBUG, although they sometimes contain an unused DT_DEBUG entry too. */ - -static CORE_ADDR -get_r_debug (const int pid, const int is_elf64) -{ - CORE_ADDR dynamic_memaddr; - const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn); - unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */ - CORE_ADDR map = -1; - - dynamic_memaddr = get_dynamic (pid, is_elf64); - if (dynamic_memaddr == 0) - return map; - - while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0) - { - if (is_elf64) - { - Elf64_Dyn *const dyn = (Elf64_Dyn *) buf; -#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL - union - { - Elf64_Xword map; - unsigned char buf[sizeof (Elf64_Xword)]; - } - rld_map; -#endif -#ifdef DT_MIPS_RLD_MAP - if (dyn->d_tag == DT_MIPS_RLD_MAP) - { - if (linux_read_memory (dyn->d_un.d_val, - rld_map.buf, sizeof (rld_map.buf)) == 0) - return rld_map.map; - else - break; - } -#endif /* DT_MIPS_RLD_MAP */ -#ifdef DT_MIPS_RLD_MAP_REL - if (dyn->d_tag == DT_MIPS_RLD_MAP_REL) - { - if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr, - rld_map.buf, sizeof (rld_map.buf)) == 0) - return rld_map.map; - else - break; - } -#endif /* DT_MIPS_RLD_MAP_REL */ - - if (dyn->d_tag == DT_DEBUG && map == -1) - map = dyn->d_un.d_val; - - if (dyn->d_tag == DT_NULL) - break; - } - else - { - Elf32_Dyn *const dyn = (Elf32_Dyn *) buf; -#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL - union - { - Elf32_Word map; - unsigned char buf[sizeof (Elf32_Word)]; - } - rld_map; -#endif -#ifdef DT_MIPS_RLD_MAP - if (dyn->d_tag == DT_MIPS_RLD_MAP) - { - if (linux_read_memory (dyn->d_un.d_val, - rld_map.buf, sizeof (rld_map.buf)) == 0) - return rld_map.map; - else - break; - } -#endif /* DT_MIPS_RLD_MAP */ -#ifdef DT_MIPS_RLD_MAP_REL - if (dyn->d_tag == DT_MIPS_RLD_MAP_REL) - { - if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr, - rld_map.buf, sizeof (rld_map.buf)) == 0) - return rld_map.map; - else - break; - } -#endif /* DT_MIPS_RLD_MAP_REL */ - - if (dyn->d_tag == DT_DEBUG && map == -1) - map = dyn->d_un.d_val; - - if (dyn->d_tag == DT_NULL) - break; - } - - dynamic_memaddr += dyn_size; - } - - return map; -} - -/* Read one pointer from MEMADDR in the inferior. */ - -static int -read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size) -{ - int ret; - - /* Go through a union so this works on either big or little endian - hosts, when the inferior's pointer size is smaller than the size - of CORE_ADDR. It is assumed the inferior's endianness is the - same of the superior's. */ - union - { - CORE_ADDR core_addr; - unsigned int ui; - unsigned char uc; - } addr; - - ret = linux_read_memory (memaddr, &addr.uc, ptr_size); - if (ret == 0) - { - if (ptr_size == sizeof (CORE_ADDR)) - *ptr = addr.core_addr; - else if (ptr_size == sizeof (unsigned int)) - *ptr = addr.ui; - else - gdb_assert_not_reached ("unhandled pointer size"); - } - return ret; -} - -struct link_map_offsets - { - /* Offset and size of r_debug.r_version. */ - int r_version_offset; - - /* Offset and size of r_debug.r_map. */ - int r_map_offset; - - /* Offset to l_addr field in struct link_map. */ - int l_addr_offset; - - /* Offset to l_name field in struct link_map. */ - int l_name_offset; - - /* Offset to l_ld field in struct link_map. */ - int l_ld_offset; - - /* Offset to l_next field in struct link_map. */ - int l_next_offset; - - /* Offset to l_prev field in struct link_map. */ - int l_prev_offset; - }; - -/* Construct qXfer:libraries-svr4:read reply. */ - -static int -linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, - unsigned const char *writebuf, - CORE_ADDR offset, int len) -{ - struct process_info_private *const priv = current_process ()->priv; - char filename[PATH_MAX]; - int pid, is_elf64; - - static const struct link_map_offsets lmo_32bit_offsets = - { - 0, /* r_version offset. */ - 4, /* r_debug.r_map offset. */ - 0, /* l_addr offset in link_map. */ - 4, /* l_name offset in link_map. */ - 8, /* l_ld offset in link_map. */ - 12, /* l_next offset in link_map. */ - 16 /* l_prev offset in link_map. */ - }; - - static const struct link_map_offsets lmo_64bit_offsets = - { - 0, /* r_version offset. */ - 8, /* r_debug.r_map offset. */ - 0, /* l_addr offset in link_map. */ - 8, /* l_name offset in link_map. */ - 16, /* l_ld offset in link_map. */ - 24, /* l_next offset in link_map. */ - 32 /* l_prev offset in link_map. */ - }; - const struct link_map_offsets *lmo; - unsigned int machine; - int ptr_size; - CORE_ADDR lm_addr = 0, lm_prev = 0; - CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev; - int header_done = 0; - - if (writebuf != NULL) - return -2; - if (readbuf == NULL) - return -1; - - pid = lwpid_of (current_thread); - xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid); - is_elf64 = elf_64_file_p (filename, &machine); - lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; - ptr_size = is_elf64 ? 8 : 4; - - while (annex[0] != '\0') - { - const char *sep; - CORE_ADDR *addrp; - int name_len; - - sep = strchr (annex, '='); - if (sep == NULL) - break; - - name_len = sep - annex; - if (name_len == 5 && startswith (annex, "start")) - addrp = &lm_addr; - else if (name_len == 4 && startswith (annex, "prev")) - addrp = &lm_prev; - else - { - annex = strchr (sep, ';'); - if (annex == NULL) - break; - annex++; - continue; - } - - annex = decode_address_to_semicolon (addrp, sep + 1); - } - - if (lm_addr == 0) - { - int r_version = 0; - - if (priv->r_debug == 0) - priv->r_debug = get_r_debug (pid, is_elf64); - - /* We failed to find DT_DEBUG. Such situation will not change - for this inferior - do not retry it. Report it to GDB as - E01, see for the reasons at the GDB solib-svr4.c side. */ - if (priv->r_debug == (CORE_ADDR) -1) - return -1; - - if (priv->r_debug != 0) - { - if (linux_read_memory (priv->r_debug + lmo->r_version_offset, - (unsigned char *) &r_version, - sizeof (r_version)) != 0 - || r_version != 1) - { - warning ("unexpected r_debug version %d", r_version); - } - else if (read_one_ptr (priv->r_debug + lmo->r_map_offset, - &lm_addr, ptr_size) != 0) - { - warning ("unable to read r_map from 0x%lx", - (long) priv->r_debug + lmo->r_map_offset); - } - } - } - - std::string document = "l_name_offset, - &l_name, ptr_size) == 0 - && read_one_ptr (lm_addr + lmo->l_addr_offset, - &l_addr, ptr_size) == 0 - && read_one_ptr (lm_addr + lmo->l_ld_offset, - &l_ld, ptr_size) == 0 - && read_one_ptr (lm_addr + lmo->l_prev_offset, - &l_prev, ptr_size) == 0 - && read_one_ptr (lm_addr + lmo->l_next_offset, - &l_next, ptr_size) == 0) - { - unsigned char libname[PATH_MAX]; - - if (lm_prev != l_prev) - { - warning ("Corrupted shared library list: 0x%lx != 0x%lx", - (long) lm_prev, (long) l_prev); - break; - } - - /* Ignore the first entry even if it has valid name as the first entry - corresponds to the main executable. The first entry should not be - skipped if the dynamic loader was loaded late by a static executable - (see solib-svr4.c parameter ignore_first). But in such case the main - executable does not have PT_DYNAMIC present and this function already - exited above due to failed get_r_debug. */ - if (lm_prev == 0) - string_appendf (document, " main-lm=\"0x%lx\"", (unsigned long) lm_addr); - else - { - /* Not checking for error because reading may stop before - we've got PATH_MAX worth of characters. */ - libname[0] = '\0'; - linux_read_memory (l_name, libname, sizeof (libname) - 1); - libname[sizeof (libname) - 1] = '\0'; - if (libname[0] != '\0') - { - if (!header_done) - { - /* Terminate `", - (unsigned long) lm_addr, (unsigned long) l_addr, - (unsigned long) l_ld); - } - } - - lm_prev = lm_addr; - lm_addr = l_next; - } - - if (!header_done) - { - /* Empty list; terminate ` document_len) - len = document_len; - - memcpy (readbuf, document.data () + offset, len); - - return len; -} - -#ifdef HAVE_LINUX_BTRACE - -/* See to_disable_btrace target method. */ - -static int -linux_low_disable_btrace (struct btrace_target_info *tinfo) -{ - enum btrace_error err; - - err = linux_disable_btrace (tinfo); - return (err == BTRACE_ERR_NONE ? 0 : -1); -} - -/* Encode an Intel Processor Trace configuration. */ - -static void -linux_low_encode_pt_config (struct buffer *buffer, - const struct btrace_data_pt_config *config) -{ - buffer_grow_str (buffer, "\n"); - - switch (config->cpu.vendor) - { - case CV_INTEL: - buffer_xml_printf (buffer, "\n", - config->cpu.family, config->cpu.model, - config->cpu.stepping); - break; - - default: - break; - } - - buffer_grow_str (buffer, "\n"); -} - -/* Encode a raw buffer. */ - -static void -linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data, - unsigned int size) -{ - if (size == 0) - return; - - /* We use hex encoding - see gdbsupport/rsp-low.h. */ - buffer_grow_str (buffer, "\n"); - - while (size-- > 0) - { - char elem[2]; - - elem[0] = tohex ((*data >> 4) & 0xf); - elem[1] = tohex (*data++ & 0xf); - - buffer_grow (buffer, elem, 2); - } - - buffer_grow_str (buffer, "\n"); -} - -/* See to_read_btrace target method. */ - -static int -linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer, - enum btrace_read_type type) -{ - struct btrace_data btrace; - enum btrace_error err; - - err = linux_read_btrace (&btrace, tinfo, type); - if (err != BTRACE_ERR_NONE) - { - if (err == BTRACE_ERR_OVERFLOW) - buffer_grow_str0 (buffer, "E.Overflow."); - else - buffer_grow_str0 (buffer, "E.Generic Error."); - - return -1; - } - - switch (btrace.format) - { - case BTRACE_FORMAT_NONE: - buffer_grow_str0 (buffer, "E.No Trace."); - return -1; - - case BTRACE_FORMAT_BTS: - buffer_grow_str (buffer, "\n"); - buffer_grow_str (buffer, "\n"); - - for (const btrace_block &block : *btrace.variant.bts.blocks) - buffer_xml_printf (buffer, "\n", - paddress (block.begin), paddress (block.end)); - - buffer_grow_str0 (buffer, "\n"); - break; - - case BTRACE_FORMAT_PT: - buffer_grow_str (buffer, "\n"); - buffer_grow_str (buffer, "\n"); - buffer_grow_str (buffer, "\n"); - - linux_low_encode_pt_config (buffer, &btrace.variant.pt.config); - - linux_low_encode_raw (buffer, btrace.variant.pt.data, - btrace.variant.pt.size); - - buffer_grow_str (buffer, "\n"); - buffer_grow_str0 (buffer, "\n"); - break; - - default: - buffer_grow_str0 (buffer, "E.Unsupported Trace Format."); - return -1; - } - - return 0; -} - -/* See to_btrace_conf target method. */ - -static int -linux_low_btrace_conf (const struct btrace_target_info *tinfo, - struct buffer *buffer) -{ - const struct btrace_config *conf; - - buffer_grow_str (buffer, "\n"); - buffer_grow_str (buffer, "\n"); - - conf = linux_btrace_conf (tinfo); - if (conf != NULL) - { - switch (conf->format) - { - case BTRACE_FORMAT_NONE: - break; - - case BTRACE_FORMAT_BTS: - buffer_xml_printf (buffer, "bts.size); - buffer_xml_printf (buffer, " />\n"); - break; - - case BTRACE_FORMAT_PT: - buffer_xml_printf (buffer, "pt.size); - buffer_xml_printf (buffer, "/>\n"); - break; - } - } - - buffer_grow_str0 (buffer, "\n"); - return 0; -} -#endif /* HAVE_LINUX_BTRACE */ - -/* See nat/linux-nat.h. */ - -ptid_t -current_lwp_ptid (void) -{ - return ptid_of (current_thread); -} - -/* Implementation of the target_ops method "breakpoint_kind_from_pc". */ - -static int -linux_breakpoint_kind_from_pc (CORE_ADDR *pcptr) -{ - if (the_low_target.breakpoint_kind_from_pc != NULL) - return (*the_low_target.breakpoint_kind_from_pc) (pcptr); - else - return default_breakpoint_kind_from_pc (pcptr); -} - -/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -linux_sw_breakpoint_from_kind (int kind, int *size) -{ - gdb_assert (the_low_target.sw_breakpoint_from_kind != NULL); - - return (*the_low_target.sw_breakpoint_from_kind) (kind, size); -} - -/* Implementation of the target_ops method - "breakpoint_kind_from_current_state". */ - -static int -linux_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) -{ - if (the_low_target.breakpoint_kind_from_current_state != NULL) - return (*the_low_target.breakpoint_kind_from_current_state) (pcptr); - else - return linux_breakpoint_kind_from_pc (pcptr); -} - -/* Default implementation of linux_target_ops method "set_pc" for - 32-bit pc register which is literally named "pc". */ - -void -linux_set_pc_32bit (struct regcache *regcache, CORE_ADDR pc) -{ - uint32_t newpc = pc; - - supply_register_by_name (regcache, "pc", &newpc); -} - -/* Default implementation of linux_target_ops method "get_pc" for - 32-bit pc register which is literally named "pc". */ - -CORE_ADDR -linux_get_pc_32bit (struct regcache *regcache) -{ - uint32_t pc; - - collect_register_by_name (regcache, "pc", &pc); - if (debug_threads) - debug_printf ("stop pc is 0x%" PRIx32 "\n", pc); - return pc; -} - -/* Default implementation of linux_target_ops method "set_pc" for - 64-bit pc register which is literally named "pc". */ - -void -linux_set_pc_64bit (struct regcache *regcache, CORE_ADDR pc) -{ - uint64_t newpc = pc; - - supply_register_by_name (regcache, "pc", &newpc); -} - -/* Default implementation of linux_target_ops method "get_pc" for - 64-bit pc register which is literally named "pc". */ - -CORE_ADDR -linux_get_pc_64bit (struct regcache *regcache) -{ - uint64_t pc; - - collect_register_by_name (regcache, "pc", &pc); - if (debug_threads) - debug_printf ("stop pc is 0x%" PRIx64 "\n", pc); - return pc; -} - -/* See linux-low.h. */ - -int -linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp) -{ - gdb_byte *data = (gdb_byte *) alloca (2 * wordsize); - int offset = 0; - - gdb_assert (wordsize == 4 || wordsize == 8); - - while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize) - { - if (wordsize == 4) - { - uint32_t *data_p = (uint32_t *) data; - if (data_p[0] == match) - { - *valp = data_p[1]; - return 1; - } - } - else - { - uint64_t *data_p = (uint64_t *) data; - if (data_p[0] == match) - { - *valp = data_p[1]; - return 1; - } - } - - offset += 2 * wordsize; - } - - return 0; -} - -/* See linux-low.h. */ - -CORE_ADDR -linux_get_hwcap (int wordsize) -{ - CORE_ADDR hwcap = 0; - linux_get_auxv (wordsize, AT_HWCAP, &hwcap); - return hwcap; -} - -/* See linux-low.h. */ - -CORE_ADDR -linux_get_hwcap2 (int wordsize) -{ - CORE_ADDR hwcap2 = 0; - linux_get_auxv (wordsize, AT_HWCAP2, &hwcap2); - return hwcap2; -} - -static process_stratum_target linux_target_ops = { - linux_create_inferior, - linux_post_create_inferior, - linux_attach, - linux_kill, - linux_detach, - linux_mourn, - linux_join, - linux_thread_alive, - linux_resume, - linux_wait, - linux_fetch_registers, - linux_store_registers, - linux_prepare_to_access_memory, - linux_done_accessing_memory, - linux_read_memory, - linux_write_memory, - linux_look_up_symbols, - linux_request_interrupt, - linux_read_auxv, - linux_supports_z_point_type, - linux_insert_point, - linux_remove_point, - linux_stopped_by_sw_breakpoint, - linux_supports_stopped_by_sw_breakpoint, - linux_stopped_by_hw_breakpoint, - linux_supports_stopped_by_hw_breakpoint, - linux_supports_hardware_single_step, - linux_stopped_by_watchpoint, - linux_stopped_data_address, -#if defined(__UCLIBC__) && defined(HAS_NOMMU) \ - && defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) \ - && defined(PT_TEXT_END_ADDR) - linux_read_offsets, -#else - NULL, -#endif -#ifdef USE_THREAD_DB - thread_db_get_tls_address, -#else - NULL, -#endif - hostio_last_error_from_errno, - linux_qxfer_osdata, - linux_xfer_siginfo, - linux_supports_non_stop, - linux_async, - linux_start_non_stop, - linux_supports_multi_process, - linux_supports_fork_events, - linux_supports_vfork_events, - linux_supports_exec_events, - linux_handle_new_gdb_connection, -#ifdef USE_THREAD_DB - thread_db_handle_monitor_command, -#else - NULL, -#endif - linux_common_core_of_thread, - linux_read_loadmap, - linux_process_qsupported, - linux_supports_tracepoints, - linux_read_pc, - linux_write_pc, - linux_thread_stopped, - NULL, - linux_pause_all, - linux_unpause_all, - linux_stabilize_threads, - linux_install_fast_tracepoint_jump_pad, - linux_emit_ops, - linux_supports_disable_randomization, - linux_get_min_fast_tracepoint_insn_len, - linux_qxfer_libraries_svr4, - linux_supports_agent, -#ifdef HAVE_LINUX_BTRACE - linux_enable_btrace, - linux_low_disable_btrace, - linux_low_read_btrace, - linux_low_btrace_conf, -#else - NULL, - NULL, - NULL, - NULL, -#endif - linux_supports_range_stepping, - linux_proc_pid_to_exec_file, - linux_mntns_open_cloexec, - linux_mntns_unlink, - linux_mntns_readlink, - linux_breakpoint_kind_from_pc, - linux_sw_breakpoint_from_kind, - linux_proc_tid_get_name, - linux_breakpoint_kind_from_current_state, - linux_supports_software_single_step, - linux_supports_catch_syscall, - linux_get_ipa_tdesc_idx, -#if USE_THREAD_DB - thread_db_thread_handle, -#else - NULL, -#endif -}; - -#ifdef HAVE_LINUX_REGSETS -void -initialize_regsets_info (struct regsets_info *info) -{ - for (info->num_regsets = 0; - info->regsets[info->num_regsets].size >= 0; - info->num_regsets++) - ; -} -#endif - -void -initialize_low (void) -{ - struct sigaction sigchld_action; - - memset (&sigchld_action, 0, sizeof (sigchld_action)); - set_target_ops (&linux_target_ops); - - linux_ptrace_init_warnings (); - linux_proc_init_warnings (); - - sigchld_action.sa_handler = sigchld_handler; - sigemptyset (&sigchld_action.sa_mask); - sigchld_action.sa_flags = SA_RESTART; - sigaction (SIGCHLD, &sigchld_action, NULL); - - initialize_low_arch (); - - linux_check_ptrace_features (); -} diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h deleted file mode 100644 index e25ddd024dd..00000000000 --- a/gdb/gdbserver/linux-low.h +++ /dev/null @@ -1,456 +0,0 @@ -/* Internal interfaces for the GNU/Linux specific target code for gdbserver. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_LOW_H -#define GDBSERVER_LINUX_LOW_H - -#include "nat/linux-nat.h" -#include "nat/gdb_thread_db.h" -#include - -#include "gdbthread.h" -#include "gdb_proc_service.h" - -/* Included for ptrace type definitions. */ -#include "nat/linux-ptrace.h" -#include "target/waitstatus.h" /* For enum target_stop_reason. */ -#include "tracepoint.h" - -#define PTRACE_XFER_TYPE long - -#ifdef HAVE_LINUX_REGSETS -typedef void (*regset_fill_func) (struct regcache *, void *); -typedef void (*regset_store_func) (struct regcache *, const void *); -enum regset_type { - GENERAL_REGS, - FP_REGS, - EXTENDED_REGS, - OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */ -}; - -/* The arch's regsets array initializer must be terminated with a NULL - regset. */ -#define NULL_REGSET \ - { 0, 0, 0, -1, (enum regset_type) -1, NULL, NULL } - -struct regset_info -{ - int get_request, set_request; - /* If NT_TYPE isn't 0, it will be passed to ptrace as the 3rd - argument and the 4th argument should be "const struct iovec *". */ - int nt_type; - int size; - enum regset_type type; - regset_fill_func fill_function; - regset_store_func store_function; -}; - -/* Aggregation of all the supported regsets of a given - architecture/mode. */ - -struct regsets_info -{ - /* The regsets array. */ - struct regset_info *regsets; - - /* The number of regsets in the REGSETS array. */ - int num_regsets; - - /* If we get EIO on a regset, do not try it again. Note the set of - supported regsets may depend on processor mode on biarch - machines. This is a (lazily allocated) array holding one boolean - byte (0/1) per regset, with each element corresponding to the - regset in the REGSETS array above at the same offset. */ - char *disabled_regsets; -}; - -#endif - -/* Mapping between the general-purpose registers in `struct user' - format and GDB's register array layout. */ - -struct usrregs_info -{ - /* The number of registers accessible. */ - int num_regs; - - /* The registers map. */ - int *regmap; -}; - -/* All info needed to access an architecture/mode's registers. */ - -struct regs_info -{ - /* Regset support bitmap: 1 for registers that are transferred as a part - of a regset, 0 for ones that need to be handled individually. This - can be NULL if all registers are transferred with regsets or regsets - are not supported. */ - unsigned char *regset_bitmap; - - /* Info used when accessing registers with PTRACE_PEEKUSER / - PTRACE_POKEUSER. This can be NULL if all registers are - transferred with regsets .*/ - struct usrregs_info *usrregs; - -#ifdef HAVE_LINUX_REGSETS - /* Info used when accessing registers with regsets. */ - struct regsets_info *regsets_info; -#endif -}; - -struct process_info_private -{ - /* Arch-specific additions. */ - struct arch_process_info *arch_private; - - /* libthread_db-specific additions. Not NULL if this process has loaded - thread_db, and it is active. */ - struct thread_db *thread_db; - - /* &_r_debug. 0 if not yet determined. -1 if no PT_DYNAMIC in Phdrs. */ - CORE_ADDR r_debug; -}; - -struct lwp_info; - -struct linux_target_ops -{ - /* Architecture-specific setup. */ - void (*arch_setup) (void); - - const struct regs_info *(*regs_info) (void); - int (*cannot_fetch_register) (int); - - /* Returns 0 if we can store the register, 1 if we can not - store the register, and 2 if failure to store the register - is acceptable. */ - int (*cannot_store_register) (int); - - /* Hook to fetch a register in some non-standard way. Used for - example by backends that have read-only registers with hardcoded - values (e.g., IA64's gr0/fr0/fr1). Returns true if register - REGNO was supplied, false if not, and we should fallback to the - standard ptrace methods. */ - int (*fetch_register) (struct regcache *regcache, int regno); - - CORE_ADDR (*get_pc) (struct regcache *regcache); - void (*set_pc) (struct regcache *regcache, CORE_ADDR newpc); - - /* See target.h for details. */ - int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr); - - /* See target.h for details. */ - const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size); - - /* Find the next possible PCs after the current instruction executes. */ - std::vector (*get_next_pcs) (struct regcache *regcache); - - int decr_pc_after_break; - int (*breakpoint_at) (CORE_ADDR pc); - - /* Breakpoint and watchpoint related functions. See target.h for - comments. */ - int (*supports_z_point_type) (char z_type); - int (*insert_point) (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp); - int (*remove_point) (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp); - - int (*stopped_by_watchpoint) (void); - CORE_ADDR (*stopped_data_address) (void); - - /* Hooks to reformat register data for PEEKUSR/POKEUSR (in particular - for registers smaller than an xfer unit). */ - void (*collect_ptrace_register) (struct regcache *regcache, - int regno, char *buf); - void (*supply_ptrace_register) (struct regcache *regcache, - int regno, const char *buf); - - /* Hook to convert from target format to ptrace format and back. - Returns true if any conversion was done; false otherwise. - If DIRECTION is 1, then copy from INF to NATIVE. - If DIRECTION is 0, copy from NATIVE to INF. */ - int (*siginfo_fixup) (siginfo_t *native, gdb_byte *inf, int direction); - - /* Hook to call when a new process is created or attached to. - If extra per-process architecture-specific data is needed, - allocate it here. */ - struct arch_process_info * (*new_process) (void); - - /* Hook to call when a process is being deleted. If extra per-process - architecture-specific data is needed, delete it here. */ - void (*delete_process) (struct arch_process_info *info); - - /* Hook to call when a new thread is detected. - If extra per-thread architecture-specific data is needed, - allocate it here. */ - void (*new_thread) (struct lwp_info *); - - /* Hook to call when a thread is being deleted. If extra per-thread - architecture-specific data is needed, delete it here. */ - void (*delete_thread) (struct arch_lwp_info *); - - /* Hook to call, if any, when a new fork is attached. */ - void (*new_fork) (struct process_info *parent, struct process_info *child); - - /* Hook to call prior to resuming a thread. */ - void (*prepare_to_resume) (struct lwp_info *); - - /* Hook to support target specific qSupported. */ - void (*process_qsupported) (char **, int count); - - /* Returns true if the low target supports tracepoints. */ - int (*supports_tracepoints) (void); - - /* Fill ADDRP with the thread area address of LWPID. Returns 0 on - success, -1 on failure. */ - int (*get_thread_area) (int lwpid, CORE_ADDR *addrp); - - /* Install a fast tracepoint jump pad. See target.h for - comments. */ - int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err); - - /* Return the bytecode operations vector for the current inferior. - Returns NULL if bytecode compilation is not supported. */ - struct emit_ops *(*emit_ops) (void); - - /* Return the minimum length of an instruction that can be safely overwritten - for use as a fast tracepoint. */ - int (*get_min_fast_tracepoint_insn_len) (void); - - /* Returns true if the low target supports range stepping. */ - int (*supports_range_stepping) (void); - - /* See target.h. */ - int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr); - - /* See target.h. */ - int (*supports_hardware_single_step) (void); - - /* Fill *SYSNO with the syscall nr trapped. Only to be called when - inferior is stopped due to SYSCALL_SIGTRAP. */ - void (*get_syscall_trapinfo) (struct regcache *regcache, int *sysno); - - /* See target.h. */ - int (*get_ipa_tdesc_idx) (void); -}; - -extern struct linux_target_ops the_low_target; - -#define get_thread_lwp(thr) ((struct lwp_info *) (thread_target_data (thr))) -#define get_lwp_thread(lwp) ((lwp)->thread) - -/* This struct is recorded in the target_data field of struct thread_info. - - On linux ``all_threads'' is keyed by the LWP ID, which we use as the - GDB protocol representation of the thread ID. Threads also have - a "process ID" (poorly named) which is (presently) the same as the - LWP ID. - - There is also ``all_processes'' is keyed by the "overall process ID", - which GNU/Linux calls tgid, "thread group ID". */ - -struct lwp_info -{ - /* Backlink to the parent object. */ - struct thread_info *thread; - - /* If this flag is set, the next SIGSTOP will be ignored (the - process will be immediately resumed). This means that either we - sent the SIGSTOP to it ourselves and got some other pending event - (so the SIGSTOP is still pending), or that we stopped the - inferior implicitly via PTRACE_ATTACH and have not waited for it - yet. */ - int stop_expected; - - /* When this is true, we shall not try to resume this thread, even - if last_resume_kind isn't resume_stop. */ - int suspended; - - /* If this flag is set, the lwp is known to be stopped right now (stop - event already received in a wait()). */ - int stopped; - - /* Signal whether we are in a SYSCALL_ENTRY or - in a SYSCALL_RETURN event. - Values: - - TARGET_WAITKIND_SYSCALL_ENTRY - - TARGET_WAITKIND_SYSCALL_RETURN */ - enum target_waitkind syscall_state; - - /* When stopped is set, the last wait status recorded for this lwp. */ - int last_status; - - /* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for - this LWP's last event, to pass to GDB without any further - processing. This is used to store extended ptrace event - information or exit status until it can be reported to GDB. */ - struct target_waitstatus waitstatus; - - /* A pointer to the fork child/parent relative. Valid only while - the parent fork event is not reported to higher layers. Used to - avoid wildcard vCont actions resuming a fork child before GDB is - notified about the parent's fork event. */ - struct lwp_info *fork_relative; - - /* When stopped is set, this is where the lwp last stopped, with - decr_pc_after_break already accounted for. If the LWP is - running, this is the address at which the lwp was resumed. */ - CORE_ADDR stop_pc; - - /* If this flag is set, STATUS_PENDING is a waitstatus that has not yet - been reported. */ - int status_pending_p; - int status_pending; - - /* The reason the LWP last stopped, if we need to track it - (breakpoint, watchpoint, etc.) */ - enum target_stop_reason stop_reason; - - /* On architectures where it is possible to know the data address of - a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and - contains such data address. Only valid if STOPPED_BY_WATCHPOINT - is true. */ - CORE_ADDR stopped_data_address; - - /* If this is non-zero, it is a breakpoint to be reinserted at our next - stop (SIGTRAP stops only). */ - CORE_ADDR bp_reinsert; - - /* If this flag is set, the last continue operation at the ptrace - level on this process was a single-step. */ - int stepping; - - /* Range to single step within. This is a copy of the step range - passed along the last resume request. See 'struct - thread_resume'. */ - CORE_ADDR step_range_start; /* Inclusive */ - CORE_ADDR step_range_end; /* Exclusive */ - - /* If this flag is set, we need to set the event request flags the - next time we see this LWP stop. */ - int must_set_ptrace_flags; - - /* If this is non-zero, it points to a chain of signals which need to - be delivered to this process. */ - struct pending_signals *pending_signals; - - /* A link used when resuming. It is initialized from the resume request, - and then processed and cleared in linux_resume_one_lwp. */ - struct thread_resume *resume; - - /* Information bout this lwp's fast tracepoint collection status (is it - currently stopped in the jump pad, and if so, before or at/after the - relocated instruction). Normally, we won't care about this, but we will - if a signal arrives to this lwp while it is collecting. */ - fast_tpoint_collect_result collecting_fast_tracepoint; - - /* If this is non-zero, it points to a chain of signals which need - to be reported to GDB. These were deferred because the thread - was doing a fast tracepoint collect when they arrived. */ - struct pending_signals *pending_signals_to_report; - - /* When collecting_fast_tracepoint is first found to be 1, we insert - a exit-jump-pad-quickly breakpoint. This is it. */ - struct breakpoint *exit_jump_pad_bkpt; - -#ifdef USE_THREAD_DB - int thread_known; - /* The thread handle, used for e.g. TLS access. Only valid if - THREAD_KNOWN is set. */ - td_thrhandle_t th; - - /* The pthread_t handle. */ - thread_t thread_handle; -#endif - - /* Arch-specific additions. */ - struct arch_lwp_info *arch_private; -}; - -int linux_pid_exe_is_elf_64_file (int pid, unsigned int *machine); - -/* Attach to PTID. Returns 0 on success, non-zero otherwise (an - errno). */ -int linux_attach_lwp (ptid_t ptid); - -struct lwp_info *find_lwp_pid (ptid_t ptid); -/* For linux_stop_lwp see nat/linux-nat.h. */ - -#ifdef HAVE_LINUX_REGSETS -void initialize_regsets_info (struct regsets_info *regsets_info); -#endif - -void initialize_low_arch (void); - -void linux_set_pc_32bit (struct regcache *regcache, CORE_ADDR pc); -CORE_ADDR linux_get_pc_32bit (struct regcache *regcache); - -void linux_set_pc_64bit (struct regcache *regcache, CORE_ADDR pc); -CORE_ADDR linux_get_pc_64bit (struct regcache *regcache); - -/* From thread-db.c */ -int thread_db_init (void); -void thread_db_detach (struct process_info *); -void thread_db_mourn (struct process_info *); -int thread_db_handle_monitor_command (char *); -int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, - CORE_ADDR load_module, CORE_ADDR *address); -int thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp); - -/* Called from linux-low.c when a clone event is detected. Upon entry, - both the clone and the parent should be stopped. This function does - whatever is required have the clone under thread_db's control. */ - -void thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid); - -bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len); - -extern int have_ptrace_getregset; - -/* Search for the value with type MATCH in the auxv vector with - entries of length WORDSIZE bytes. If found, store the value in - *VALP and return 1. If not found or if there is an error, return - 0. */ - -int linux_get_auxv (int wordsize, CORE_ADDR match, - CORE_ADDR *valp); - -/* Fetch the AT_HWCAP entry from the auxv vector, where entries are length - WORDSIZE. If no entry was found, return zero. */ - -CORE_ADDR linux_get_hwcap (int wordsize); - -/* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length - WORDSIZE. If no entry was found, return zero. */ - -CORE_ADDR linux_get_hwcap2 (int wordsize); - -#endif /* GDBSERVER_LINUX_LOW_H */ diff --git a/gdb/gdbserver/linux-m32r-low.c b/gdb/gdbserver/linux-m32r-low.c deleted file mode 100644 index c52e816e341..00000000000 --- a/gdb/gdbserver/linux-m32r-low.c +++ /dev/null @@ -1,157 +0,0 @@ -/* GNU/Linux/m32r specific low level interface, for the remote server for GDB. - Copyright (C) 2005-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -#ifdef HAVE_SYS_REG_H -#include -#endif - -/* Defined in auto-generated file reg-m32r.c. */ -void init_registers_m32r (void); -extern const struct target_desc *tdesc_m32r; - -#define m32r_num_regs 25 - -static int m32r_regmap[] = { -#ifdef PT_R0 - PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, - PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU, - PT_PSW, PT_CBR, PT_SPI, PT_SPU, PT_BPC, PT_PC, PT_ACCL, PT_ACCH, PT_EVB -#else - 4 * 4, 4 * 5, 4 * 6, 4 * 7, 4 * 0, 4 * 1, 4 * 2, 4 * 8, - 4 * 9, 4 * 10, 4 * 11, 4 * 12, 4 * 13, 4 * 24, 4 * 25, 4 * 23, - 4 * 19, 4 * 31, 4 * 26, 4 * 23, 4 * 20, 4 * 30, 4 * 16, 4 * 15, 4 * 32 -#endif -}; - -static int -m32r_cannot_store_register (int regno) -{ - return (regno >= m32r_num_regs); -} - -static int -m32r_cannot_fetch_register (int regno) -{ - return (regno >= m32r_num_regs); -} - -static const unsigned short m32r_breakpoint = 0x10f1; -#define m32r_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -m32r_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = m32r_breakpoint_len; - return (const gdb_byte *) &m32r_breakpoint; -} - -static int -m32r_breakpoint_at (CORE_ADDR where) -{ - unsigned short insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, - m32r_breakpoint_len); - if (insn == m32r_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -static void -m32r_arch_setup (void) -{ - current_process ()->tdesc = tdesc_m32r; -} - -/* Support for hardware single step. */ - -static int -m32r_supports_hardware_single_step (void) -{ - return 1; -} - -static struct usrregs_info m32r_usrregs_info = - { - m32r_num_regs, - m32r_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &m32r_usrregs_info, - }; - -static const struct regs_info * -m32r_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - m32r_arch_setup, - m32r_regs_info, - m32r_cannot_fetch_register, - m32r_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_from_pc */ - m32r_sw_breakpoint_from_kind, - NULL, - 0, - m32r_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - m32r_supports_hardware_single_step, -}; - -void -initialize_low_arch (void) -{ - init_registers_m32r (); -} diff --git a/gdb/gdbserver/linux-m68k-low.c b/gdb/gdbserver/linux-m68k-low.c deleted file mode 100644 index 246b295a875..00000000000 --- a/gdb/gdbserver/linux-m68k-low.c +++ /dev/null @@ -1,255 +0,0 @@ -/* GNU/Linux/m68k specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -/* Defined in auto-generated file reg-m68k.c. */ -void init_registers_m68k (void); -extern const struct target_desc *tdesc_m68k; - -#ifdef HAVE_SYS_REG_H -#include -#endif - -#define m68k_num_regs 29 -#define m68k_num_gregs 18 - -/* This table must line up with REGISTER_NAMES in tm-m68k.h */ -static int m68k_regmap[] = -{ -#ifdef PT_D0 - PT_D0 * 4, PT_D1 * 4, PT_D2 * 4, PT_D3 * 4, - PT_D4 * 4, PT_D5 * 4, PT_D6 * 4, PT_D7 * 4, - PT_A0 * 4, PT_A1 * 4, PT_A2 * 4, PT_A3 * 4, - PT_A4 * 4, PT_A5 * 4, PT_A6 * 4, PT_USP * 4, - PT_SR * 4, PT_PC * 4, -#else - 14 * 4, 0 * 4, 1 * 4, 2 * 4, 3 * 4, 4 * 4, 5 * 4, 6 * 4, - 7 * 4, 8 * 4, 9 * 4, 10 * 4, 11 * 4, 12 * 4, 13 * 4, 15 * 4, - 17 * 4, 18 * 4, -#endif -#ifdef PT_FP0 - PT_FP0 * 4, PT_FP1 * 4, PT_FP2 * 4, PT_FP3 * 4, - PT_FP4 * 4, PT_FP5 * 4, PT_FP6 * 4, PT_FP7 * 4, - PT_FPCR * 4, PT_FPSR * 4, PT_FPIAR * 4 -#else - 21 * 4, 24 * 4, 27 * 4, 30 * 4, 33 * 4, 36 * 4, - 39 * 4, 42 * 4, 45 * 4, 46 * 4, 47 * 4 -#endif -}; - -static int -m68k_cannot_store_register (int regno) -{ - return (regno >= m68k_num_regs); -} - -static int -m68k_cannot_fetch_register (int regno) -{ - return (regno >= m68k_num_regs); -} - -#ifdef HAVE_PTRACE_GETREGS -#include -#include "nat/gdb_ptrace.h" - -static void -m68k_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - - for (i = 0; i < m68k_num_gregs; i++) - collect_register (regcache, i, (char *) buf + m68k_regmap[i]); -} - -static void -m68k_store_gregset (struct regcache *regcache, const void *buf) -{ - int i; - - for (i = 0; i < m68k_num_gregs; i++) - supply_register (regcache, i, (const char *) buf + m68k_regmap[i]); -} - -static void -m68k_fill_fpregset (struct regcache *regcache, void *buf) -{ - int i; - - for (i = m68k_num_gregs; i < m68k_num_regs; i++) - collect_register (regcache, i, ((char *) buf - + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs]))); -} - -static void -m68k_store_fpregset (struct regcache *regcache, const void *buf) -{ - int i; - - for (i = m68k_num_gregs; i < m68k_num_regs; i++) - supply_register (regcache, i, ((const char *) buf - + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs]))); -} - -#endif /* HAVE_PTRACE_GETREGS */ - -static struct regset_info m68k_regsets[] = { -#ifdef HAVE_PTRACE_GETREGS - { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), - GENERAL_REGS, - m68k_fill_gregset, m68k_store_gregset }, - { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t), - FP_REGS, - m68k_fill_fpregset, m68k_store_fpregset }, -#endif /* HAVE_PTRACE_GETREGS */ - NULL_REGSET -}; - -static const gdb_byte m68k_breakpoint[] = { 0x4E, 0x4F }; -#define m68k_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -m68k_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = m68k_breakpoint_len; - return m68k_breakpoint; -} - -static int -m68k_breakpoint_at (CORE_ADDR pc) -{ - unsigned char c[2]; - - read_inferior_memory (pc, c, 2); - if (c[0] == 0x4E && c[1] == 0x4F) - return 1; - - return 0; -} - -#include - -#ifdef PTRACE_GET_THREAD_AREA -/* Fetch the thread-local storage pointer for libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *)*base - idx); - - return PS_OK; -} -#endif /* PTRACE_GET_THREAD_AREA */ - -static struct regsets_info m68k_regsets_info = - { - m68k_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info m68k_usrregs_info = - { - m68k_num_regs, - m68k_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &m68k_usrregs_info, - &m68k_regsets_info - }; - -static const struct regs_info * -m68k_regs_info (void) -{ - return ®s_info; -} - -static void -m68k_arch_setup (void) -{ - current_process ()->tdesc = tdesc_m68k; -} - -/* Support for hardware single step. */ - -static int -m68k_supports_hardware_single_step (void) -{ - return 1; -} - -struct linux_target_ops the_low_target = { - m68k_arch_setup, - m68k_regs_info, - m68k_cannot_fetch_register, - m68k_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - m68k_sw_breakpoint_from_kind, - NULL, - 2, - m68k_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - m68k_supports_hardware_single_step, -}; - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ - init_registers_m68k (); - - initialize_regsets_info (&m68k_regsets_info); -} diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c deleted file mode 100644 index f94e141be79..00000000000 --- a/gdb/gdbserver/linux-mips-low.c +++ /dev/null @@ -1,978 +0,0 @@ -/* GNU/Linux/MIPS specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -#include "nat/gdb_ptrace.h" -#include - -#include "nat/mips-linux-watch.h" -#include "gdb_proc_service.h" - -/* Defined in auto-generated file mips-linux.c. */ -void init_registers_mips_linux (void); -extern const struct target_desc *tdesc_mips_linux; - -/* Defined in auto-generated file mips-dsp-linux.c. */ -void init_registers_mips_dsp_linux (void); -extern const struct target_desc *tdesc_mips_dsp_linux; - -/* Defined in auto-generated file mips64-linux.c. */ -void init_registers_mips64_linux (void); -extern const struct target_desc *tdesc_mips64_linux; - -/* Defined in auto-generated file mips64-dsp-linux.c. */ -void init_registers_mips64_dsp_linux (void); -extern const struct target_desc *tdesc_mips64_dsp_linux; - -#ifdef __mips64 -#define tdesc_mips_linux tdesc_mips64_linux -#define tdesc_mips_dsp_linux tdesc_mips64_dsp_linux -#endif - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -#ifdef HAVE_SYS_REG_H -#include -#endif - -#define mips_num_regs 73 -#define mips_dsp_num_regs 80 - -#include - -#ifndef DSP_BASE -#define DSP_BASE 71 -#define DSP_CONTROL 77 -#endif - -union mips_register -{ - unsigned char buf[8]; - - /* Deliberately signed, for proper sign extension. */ - int reg32; - long long reg64; -}; - -/* Return the ptrace ``address'' of register REGNO. */ - -#define mips_base_regs \ - -1, 1, 2, 3, 4, 5, 6, 7, \ - 8, 9, 10, 11, 12, 13, 14, 15, \ - 16, 17, 18, 19, 20, 21, 22, 23, \ - 24, 25, 26, 27, 28, 29, 30, 31, \ - \ - -1, MMLO, MMHI, BADVADDR, CAUSE, PC, \ - \ - FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3, \ - FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7, \ - FPR_BASE + 8, FPR_BASE + 9, FPR_BASE + 10, FPR_BASE + 11, \ - FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15, \ - FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19, \ - FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23, \ - FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27, \ - FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31, \ - FPC_CSR, FPC_EIR - -#define mips_dsp_regs \ - DSP_BASE, DSP_BASE + 1, DSP_BASE + 2, DSP_BASE + 3, \ - DSP_BASE + 4, DSP_BASE + 5, \ - DSP_CONTROL - -static int mips_regmap[mips_num_regs] = { - mips_base_regs, - 0 -}; - -static int mips_dsp_regmap[mips_dsp_num_regs] = { - mips_base_regs, - mips_dsp_regs, - 0 -}; - -/* DSP registers are not in any regset and can only be accessed - individually. */ - -static unsigned char mips_dsp_regset_bitmap[(mips_dsp_num_regs + 7) / 8] = { - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x80 -}; - -static int have_dsp = -1; - -/* Try peeking at an arbitrarily chosen DSP register and pick the available - user register set accordingly. */ - -static const struct target_desc * -mips_read_description (void) -{ - if (have_dsp < 0) - { - int pid = lwpid_of (current_thread); - - errno = 0; - ptrace (PTRACE_PEEKUSER, pid, DSP_CONTROL, 0); - switch (errno) - { - case 0: - have_dsp = 1; - break; - case EIO: - have_dsp = 0; - break; - default: - perror_with_name ("ptrace"); - break; - } - } - - return have_dsp ? tdesc_mips_dsp_linux : tdesc_mips_linux; -} - -static void -mips_arch_setup (void) -{ - current_process ()->tdesc = mips_read_description (); -} - -static struct usrregs_info * -get_usrregs_info (void) -{ - const struct regs_info *regs_info = the_low_target.regs_info (); - - return regs_info->usrregs; -} - -/* Per-process arch-specific data we want to keep. */ - -struct arch_process_info -{ - /* -1 if the kernel and/or CPU do not support watch registers. - 1 if watch_readback is valid and we can read style, num_valid - and the masks. - 0 if we need to read the watch_readback. */ - - int watch_readback_valid; - - /* Cached watch register read values. */ - - struct pt_watch_regs watch_readback; - - /* Current watchpoint requests for this process. */ - - struct mips_watchpoint *current_watches; - - /* The current set of watch register values for writing the - registers. */ - - struct pt_watch_regs watch_mirror; -}; - -/* Per-thread arch-specific data we want to keep. */ - -struct arch_lwp_info -{ - /* Non-zero if our copy differs from what's recorded in the thread. */ - int watch_registers_changed; -}; - -/* From mips-linux-nat.c. */ - -/* Pseudo registers can not be read. ptrace does not provide a way to - read (or set) PS_REGNUM, and there's no point in reading or setting - ZERO_REGNUM, it's always 0. We also can not set BADVADDR, CAUSE, - or FCRIR via ptrace(). */ - -static int -mips_cannot_fetch_register (int regno) -{ - const struct target_desc *tdesc; - - if (get_usrregs_info ()->regmap[regno] == -1) - return 1; - - tdesc = current_process ()->tdesc; - - /* On n32 we can't access 64-bit registers via PTRACE_PEEKUSR. */ - if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE)) - return 1; - - if (find_regno (tdesc, "r0") == regno) - return 1; - - return 0; -} - -static int -mips_cannot_store_register (int regno) -{ - const struct target_desc *tdesc; - - if (get_usrregs_info ()->regmap[regno] == -1) - return 1; - - tdesc = current_process ()->tdesc; - - /* On n32 we can't access 64-bit registers via PTRACE_POKEUSR. */ - if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE)) - return 1; - - if (find_regno (tdesc, "r0") == regno) - return 1; - - if (find_regno (tdesc, "cause") == regno) - return 1; - - if (find_regno (tdesc, "badvaddr") == regno) - return 1; - - if (find_regno (tdesc, "fir") == regno) - return 1; - - return 0; -} - -static int -mips_fetch_register (struct regcache *regcache, int regno) -{ - const struct target_desc *tdesc = current_process ()->tdesc; - - if (find_regno (tdesc, "r0") == regno) - { - supply_register_zeroed (regcache, regno); - return 1; - } - - return 0; -} - -static CORE_ADDR -mips_get_pc (struct regcache *regcache) -{ - union mips_register pc; - collect_register_by_name (regcache, "pc", pc.buf); - return register_size (regcache->tdesc, 0) == 4 ? pc.reg32 : pc.reg64; -} - -static void -mips_set_pc (struct regcache *regcache, CORE_ADDR pc) -{ - union mips_register newpc; - if (register_size (regcache->tdesc, 0) == 4) - newpc.reg32 = pc; - else - newpc.reg64 = pc; - - supply_register_by_name (regcache, "pc", newpc.buf); -} - -/* Correct in either endianness. */ -static const unsigned int mips_breakpoint = 0x0005000d; -#define mips_breakpoint_len 4 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -mips_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = mips_breakpoint_len; - return (const gdb_byte *) &mips_breakpoint; -} - -static int -mips_breakpoint_at (CORE_ADDR where) -{ - unsigned int insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 4); - if (insn == mips_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -/* Mark the watch registers of lwp, represented by ENTRY, as changed. */ - -static void -update_watch_registers_callback (thread_info *thread) -{ - struct lwp_info *lwp = get_thread_lwp (thread); - - /* The actual update is done later just before resuming the lwp, - we just mark that the registers need updating. */ - lwp->arch_private->watch_registers_changed = 1; - - /* If the lwp isn't stopped, force it to momentarily pause, so - we can update its watch registers. */ - if (!lwp->stopped) - linux_stop_lwp (lwp); -} - -/* This is the implementation of linux_target_ops method - new_process. */ - -static struct arch_process_info * -mips_linux_new_process (void) -{ - struct arch_process_info *info = XCNEW (struct arch_process_info); - - return info; -} - -/* This is the implementation of linux_target_ops method - delete_process. */ - -static void -mips_linux_delete_process (struct arch_process_info *info) -{ - xfree (info); -} - -/* This is the implementation of linux_target_ops method new_thread. - Mark the watch registers as changed, so the threads' copies will - be updated. */ - -static void -mips_linux_new_thread (struct lwp_info *lwp) -{ - struct arch_lwp_info *info = XCNEW (struct arch_lwp_info); - - info->watch_registers_changed = 1; - - lwp->arch_private = info; -} - -/* Function to call when a thread is being deleted. */ - -static void -mips_linux_delete_thread (struct arch_lwp_info *arch_lwp) -{ - xfree (arch_lwp); -} - -/* Create a new mips_watchpoint and add it to the list. */ - -static void -mips_add_watchpoint (struct arch_process_info *priv, CORE_ADDR addr, int len, - enum target_hw_bp_type watch_type) -{ - struct mips_watchpoint *new_watch; - struct mips_watchpoint **pw; - - new_watch = XNEW (struct mips_watchpoint); - new_watch->addr = addr; - new_watch->len = len; - new_watch->type = watch_type; - new_watch->next = NULL; - - pw = &priv->current_watches; - while (*pw != NULL) - pw = &(*pw)->next; - *pw = new_watch; -} - -/* Hook to call when a new fork is attached. */ - -static void -mips_linux_new_fork (struct process_info *parent, - struct process_info *child) -{ - struct arch_process_info *parent_private; - struct arch_process_info *child_private; - struct mips_watchpoint *wp; - - /* These are allocated by linux_add_process. */ - gdb_assert (parent->priv != NULL - && parent->priv->arch_private != NULL); - gdb_assert (child->priv != NULL - && child->priv->arch_private != NULL); - - /* Linux kernel before 2.6.33 commit - 72f674d203cd230426437cdcf7dd6f681dad8b0d - will inherit hardware debug registers from parent - on fork/vfork/clone. Newer Linux kernels create such tasks with - zeroed debug registers. - - GDB core assumes the child inherits the watchpoints/hw - breakpoints of the parent, and will remove them all from the - forked off process. Copy the debug registers mirrors into the - new process so that all breakpoints and watchpoints can be - removed together. The debug registers mirror will become zeroed - in the end before detaching the forked off process, thus making - this compatible with older Linux kernels too. */ - - parent_private = parent->priv->arch_private; - child_private = child->priv->arch_private; - - child_private->watch_readback_valid = parent_private->watch_readback_valid; - child_private->watch_readback = parent_private->watch_readback; - - for (wp = parent_private->current_watches; wp != NULL; wp = wp->next) - mips_add_watchpoint (child_private, wp->addr, wp->len, wp->type); - - child_private->watch_mirror = parent_private->watch_mirror; -} -/* This is the implementation of linux_target_ops method - prepare_to_resume. If the watch regs have changed, update the - thread's copies. */ - -static void -mips_linux_prepare_to_resume (struct lwp_info *lwp) -{ - ptid_t ptid = ptid_of (get_lwp_thread (lwp)); - struct process_info *proc = find_process_pid (ptid.pid ()); - struct arch_process_info *priv = proc->priv->arch_private; - - if (lwp->arch_private->watch_registers_changed) - { - /* Only update the watch registers if we have set or unset a - watchpoint already. */ - if (mips_linux_watch_get_num_valid (&priv->watch_mirror) > 0) - { - /* Write the mirrored watch register values. */ - int tid = ptid.lwp (); - - if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid, - &priv->watch_mirror, NULL)) - perror_with_name ("Couldn't write watch register"); - } - - lwp->arch_private->watch_registers_changed = 0; - } -} - -static int -mips_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_WRITE_WP: - case Z_PACKET_READ_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - return 0; - } -} - -/* This is the implementation of linux_target_ops method - insert_point. */ - -static int -mips_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - struct process_info *proc = current_process (); - struct arch_process_info *priv = proc->priv->arch_private; - struct pt_watch_regs regs; - long lwpid; - enum target_hw_bp_type watch_type; - uint32_t irw; - - lwpid = lwpid_of (current_thread); - if (!mips_linux_read_watch_registers (lwpid, - &priv->watch_readback, - &priv->watch_readback_valid, - 0)) - return -1; - - if (len <= 0) - return -1; - - regs = priv->watch_readback; - /* Add the current watches. */ - mips_linux_watch_populate_regs (priv->current_watches, ®s); - - /* Now try to add the new watch. */ - watch_type = raw_bkpt_type_to_target_hw_bp_type (type); - irw = mips_linux_watch_type_to_irw (watch_type); - if (!mips_linux_watch_try_one_watch (®s, addr, len, irw)) - return -1; - - /* It fit. Stick it on the end of the list. */ - mips_add_watchpoint (priv, addr, len, watch_type); - - priv->watch_mirror = regs; - - /* Only update the threads of this process. */ - for_each_thread (proc->pid, update_watch_registers_callback); - - return 0; -} - -/* This is the implementation of linux_target_ops method - remove_point. */ - -static int -mips_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) -{ - struct process_info *proc = current_process (); - struct arch_process_info *priv = proc->priv->arch_private; - - int deleted_one; - enum target_hw_bp_type watch_type; - - struct mips_watchpoint **pw; - struct mips_watchpoint *w; - - /* Search for a known watch that matches. Then unlink and free it. */ - watch_type = raw_bkpt_type_to_target_hw_bp_type (type); - deleted_one = 0; - pw = &priv->current_watches; - while ((w = *pw)) - { - if (w->addr == addr && w->len == len && w->type == watch_type) - { - *pw = w->next; - free (w); - deleted_one = 1; - break; - } - pw = &(w->next); - } - - if (!deleted_one) - return -1; /* We don't know about it, fail doing nothing. */ - - /* At this point watch_readback is known to be valid because we - could not have added the watch without reading it. */ - gdb_assert (priv->watch_readback_valid == 1); - - priv->watch_mirror = priv->watch_readback; - mips_linux_watch_populate_regs (priv->current_watches, - &priv->watch_mirror); - - /* Only update the threads of this process. */ - for_each_thread (proc->pid, update_watch_registers_callback); - - return 0; -} - -/* This is the implementation of linux_target_ops method - stopped_by_watchpoint. The watchhi R and W bits indicate - the watch register triggered. */ - -static int -mips_stopped_by_watchpoint (void) -{ - struct process_info *proc = current_process (); - struct arch_process_info *priv = proc->priv->arch_private; - int n; - int num_valid; - long lwpid = lwpid_of (current_thread); - - if (!mips_linux_read_watch_registers (lwpid, - &priv->watch_readback, - &priv->watch_readback_valid, - 1)) - return 0; - - num_valid = mips_linux_watch_get_num_valid (&priv->watch_readback); - - for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++) - if (mips_linux_watch_get_watchhi (&priv->watch_readback, n) - & (R_MASK | W_MASK)) - return 1; - - return 0; -} - -/* This is the implementation of linux_target_ops method - stopped_data_address. */ - -static CORE_ADDR -mips_stopped_data_address (void) -{ - struct process_info *proc = current_process (); - struct arch_process_info *priv = proc->priv->arch_private; - int n; - int num_valid; - long lwpid = lwpid_of (current_thread); - - /* On MIPS we don't know the low order 3 bits of the data address. - GDB does not support remote targets that can't report the - watchpoint address. So, make our best guess; return the starting - address of a watchpoint request which overlaps the one that - triggered. */ - - if (!mips_linux_read_watch_registers (lwpid, - &priv->watch_readback, - &priv->watch_readback_valid, - 0)) - return 0; - - num_valid = mips_linux_watch_get_num_valid (&priv->watch_readback); - - for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++) - if (mips_linux_watch_get_watchhi (&priv->watch_readback, n) - & (R_MASK | W_MASK)) - { - CORE_ADDR t_low, t_hi; - int t_irw; - struct mips_watchpoint *watch; - - t_low = mips_linux_watch_get_watchlo (&priv->watch_readback, n); - t_irw = t_low & IRW_MASK; - t_hi = (mips_linux_watch_get_watchhi (&priv->watch_readback, n) - | IRW_MASK); - t_low &= ~(CORE_ADDR)t_hi; - - for (watch = priv->current_watches; - watch != NULL; - watch = watch->next) - { - CORE_ADDR addr = watch->addr; - CORE_ADDR last_byte = addr + watch->len - 1; - - if ((t_irw & mips_linux_watch_type_to_irw (watch->type)) == 0) - { - /* Different type. */ - continue; - } - /* Check for overlap of even a single byte. */ - if (last_byte >= t_low && addr <= t_low + t_hi) - return addr; - } - } - - /* Shouldn't happen. */ - return 0; -} - -/* Fetch the thread-local storage pointer for libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *)*base - idx); - - return PS_OK; -} - -static void -mips_collect_register (struct regcache *regcache, - int use_64bit, int regno, union mips_register *reg) -{ - union mips_register tmp_reg; - - if (use_64bit) - { - collect_register (regcache, regno, &tmp_reg.reg64); - *reg = tmp_reg; - } - else - { - collect_register (regcache, regno, &tmp_reg.reg32); - reg->reg64 = tmp_reg.reg32; - } -} - -static void -mips_supply_register (struct regcache *regcache, - int use_64bit, int regno, const union mips_register *reg) -{ - int offset = 0; - - /* For big-endian 32-bit targets, ignore the high four bytes of each - eight-byte slot. */ - if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit) - offset = 4; - - supply_register (regcache, regno, reg->buf + offset); -} - -#ifdef HAVE_PTRACE_GETREGS - -static void -mips_collect_register_32bit (struct regcache *regcache, - int use_64bit, int regno, unsigned char *buf) -{ - union mips_register tmp_reg; - int reg32; - - mips_collect_register (regcache, use_64bit, regno, &tmp_reg); - reg32 = tmp_reg.reg64; - memcpy (buf, ®32, 4); -} - -static void -mips_supply_register_32bit (struct regcache *regcache, - int use_64bit, int regno, const unsigned char *buf) -{ - union mips_register tmp_reg; - int reg32; - - memcpy (®32, buf, 4); - tmp_reg.reg64 = reg32; - mips_supply_register (regcache, use_64bit, regno, &tmp_reg); -} - -static void -mips_fill_gregset (struct regcache *regcache, void *buf) -{ - union mips_register *regset = (union mips_register *) buf; - int i, use_64bit; - const struct target_desc *tdesc = regcache->tdesc; - - use_64bit = (register_size (tdesc, 0) == 8); - - for (i = 1; i < 32; i++) - mips_collect_register (regcache, use_64bit, i, regset + i); - - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "lo"), regset + 32); - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "hi"), regset + 33); - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "pc"), regset + 34); - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "badvaddr"), regset + 35); - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "status"), regset + 36); - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "cause"), regset + 37); - - mips_collect_register (regcache, use_64bit, - find_regno (tdesc, "restart"), regset + 0); -} - -static void -mips_store_gregset (struct regcache *regcache, const void *buf) -{ - const union mips_register *regset = (const union mips_register *) buf; - int i, use_64bit; - - use_64bit = (register_size (regcache->tdesc, 0) == 8); - - supply_register_by_name_zeroed (regcache, "r0"); - - for (i = 1; i < 32; i++) - mips_supply_register (regcache, use_64bit, i, regset + i); - - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "lo"), regset + 32); - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "hi"), regset + 33); - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "pc"), regset + 34); - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "badvaddr"), regset + 35); - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "status"), regset + 36); - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "cause"), regset + 37); - - mips_supply_register (regcache, use_64bit, - find_regno (regcache->tdesc, "restart"), regset + 0); -} - -static void -mips_fill_fpregset (struct regcache *regcache, void *buf) -{ - union mips_register *regset = (union mips_register *) buf; - int i, use_64bit, first_fp, big_endian; - - use_64bit = (register_size (regcache->tdesc, 0) == 8); - first_fp = find_regno (regcache->tdesc, "f0"); - big_endian = (__BYTE_ORDER == __BIG_ENDIAN); - - /* See GDB for a discussion of this peculiar layout. */ - for (i = 0; i < 32; i++) - if (use_64bit) - collect_register (regcache, first_fp + i, regset[i].buf); - else - collect_register (regcache, first_fp + i, - regset[i & ~1].buf + 4 * (big_endian != (i & 1))); - - mips_collect_register_32bit (regcache, use_64bit, - find_regno (regcache->tdesc, "fcsr"), regset[32].buf); - mips_collect_register_32bit (regcache, use_64bit, - find_regno (regcache->tdesc, "fir"), - regset[32].buf + 4); -} - -static void -mips_store_fpregset (struct regcache *regcache, const void *buf) -{ - const union mips_register *regset = (const union mips_register *) buf; - int i, use_64bit, first_fp, big_endian; - - use_64bit = (register_size (regcache->tdesc, 0) == 8); - first_fp = find_regno (regcache->tdesc, "f0"); - big_endian = (__BYTE_ORDER == __BIG_ENDIAN); - - /* See GDB for a discussion of this peculiar layout. */ - for (i = 0; i < 32; i++) - if (use_64bit) - supply_register (regcache, first_fp + i, regset[i].buf); - else - supply_register (regcache, first_fp + i, - regset[i & ~1].buf + 4 * (big_endian != (i & 1))); - - mips_supply_register_32bit (regcache, use_64bit, - find_regno (regcache->tdesc, "fcsr"), - regset[32].buf); - mips_supply_register_32bit (regcache, use_64bit, - find_regno (regcache->tdesc, "fir"), - regset[32].buf + 4); -} -#endif /* HAVE_PTRACE_GETREGS */ - -/* Take care of 32-bit registers with 64-bit ptrace, POKEUSER side. */ - -static void -mips_collect_ptrace_register (struct regcache *regcache, - int regno, char *buf) -{ - int use_64bit = sizeof (PTRACE_XFER_TYPE) == 8; - - if (use_64bit && register_size (regcache->tdesc, regno) == 4) - { - union mips_register reg; - - mips_collect_register (regcache, 0, regno, ®); - memcpy (buf, ®, sizeof (reg)); - } - else - collect_register (regcache, regno, buf); -} - -/* Take care of 32-bit registers with 64-bit ptrace, PEEKUSER side. */ - -static void -mips_supply_ptrace_register (struct regcache *regcache, - int regno, const char *buf) -{ - int use_64bit = sizeof (PTRACE_XFER_TYPE) == 8; - - if (use_64bit && register_size (regcache->tdesc, regno) == 4) - { - union mips_register reg; - - memcpy (®, buf, sizeof (reg)); - mips_supply_register (regcache, 0, regno, ®); - } - else - supply_register (regcache, regno, buf); -} - -static struct regset_info mips_regsets[] = { -#ifdef HAVE_PTRACE_GETREGS - { PTRACE_GETREGS, PTRACE_SETREGS, 0, 38 * 8, GENERAL_REGS, - mips_fill_gregset, mips_store_gregset }, - { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, 33 * 8, FP_REGS, - mips_fill_fpregset, mips_store_fpregset }, -#endif /* HAVE_PTRACE_GETREGS */ - NULL_REGSET -}; - -static struct regsets_info mips_regsets_info = - { - mips_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info mips_dsp_usrregs_info = - { - mips_dsp_num_regs, - mips_dsp_regmap, - }; - -static struct usrregs_info mips_usrregs_info = - { - mips_num_regs, - mips_regmap, - }; - -static struct regs_info dsp_regs_info = - { - mips_dsp_regset_bitmap, - &mips_dsp_usrregs_info, - &mips_regsets_info - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &mips_usrregs_info, - &mips_regsets_info - }; - -static const struct regs_info * -mips_regs_info (void) -{ - if (have_dsp) - return &dsp_regs_info; - else - return ®s_info; -} - -struct linux_target_ops the_low_target = { - mips_arch_setup, - mips_regs_info, - mips_cannot_fetch_register, - mips_cannot_store_register, - mips_fetch_register, - mips_get_pc, - mips_set_pc, - NULL, /* breakpoint_kind_from_pc */ - mips_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, - mips_breakpoint_at, - mips_supports_z_point_type, - mips_insert_point, - mips_remove_point, - mips_stopped_by_watchpoint, - mips_stopped_data_address, - mips_collect_ptrace_register, - mips_supply_ptrace_register, - NULL, /* siginfo_fixup */ - mips_linux_new_process, - mips_linux_delete_process, - mips_linux_new_thread, - mips_linux_delete_thread, - mips_linux_new_fork, - mips_linux_prepare_to_resume -}; - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ - init_registers_mips_linux (); - init_registers_mips_dsp_linux (); - init_registers_mips64_linux (); - init_registers_mips64_dsp_linux (); - - initialize_regsets_info (&mips_regsets_info); -} diff --git a/gdb/gdbserver/linux-nios2-low.c b/gdb/gdbserver/linux-nios2-low.c deleted file mode 100644 index bfc5aee165d..00000000000 --- a/gdb/gdbserver/linux-nios2-low.c +++ /dev/null @@ -1,259 +0,0 @@ -/* GNU/Linux/Nios II specific low level interface, for the remote server for - GDB. - Copyright (C) 2008-2020 Free Software Foundation, Inc. - - Contributed by Mentor Graphics, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "elf/common.h" -#include "nat/gdb_ptrace.h" -#include -#include "gdb_proc_service.h" -#include - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -/* The following definition must agree with the number of registers - defined in "struct user_regs" in GLIBC - (sysdeps/unix/sysv/linux/nios2/sys/user.h), and also with - NIOS2_NUM_REGS in GDB proper. */ - -#define nios2_num_regs 49 - -/* Defined in auto-generated file nios2-linux.c. */ - -void init_registers_nios2_linux (void); -extern const struct target_desc *tdesc_nios2_linux; - -/* This union is used to convert between int and byte buffer - representations of register contents. */ - -union nios2_register -{ - unsigned char buf[4]; - int reg32; -}; - -/* Return the ptrace ``address'' of register REGNO. */ - -static int nios2_regmap[] = { - -1, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, - 0 -}; - -/* Implement the arch_setup linux_target_ops method. */ - -static void -nios2_arch_setup (void) -{ - current_process ()->tdesc = tdesc_nios2_linux; -} - -/* Implement the cannot_fetch_register linux_target_ops method. */ - -static int -nios2_cannot_fetch_register (int regno) -{ - if (nios2_regmap[regno] == -1) - return 1; - - return 0; -} - -/* Implement the cannot_store_register linux_target_ops method. */ - -static int -nios2_cannot_store_register (int regno) -{ - if (nios2_regmap[regno] == -1) - return 1; - - return 0; -} - -/* Breakpoint support. Also see comments on nios2_breakpoint_from_pc - in nios2-tdep.c. */ - -#if defined(__nios2_arch__) && __nios2_arch__ == 2 -#define NIOS2_BREAKPOINT 0xb7fd0020 -#define CDX_BREAKPOINT 0xd7c9 -#else -#define NIOS2_BREAKPOINT 0x003b6ffa -#endif - -/* We only register the 4-byte breakpoint, even on R2 targets which also - support 2-byte breakpoints. Since there is no supports_z_point_type - function provided, gdbserver never inserts software breakpoints itself - and instead relies on GDB to insert the breakpoint of the correct length - via a memory write. */ -static const unsigned int nios2_breakpoint = NIOS2_BREAKPOINT; -#define nios2_breakpoint_len 4 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -nios2_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = nios2_breakpoint_len; - return (const gdb_byte *) &nios2_breakpoint; -} - -/* Implement the breakpoint_at linux_target_ops method. */ - -static int -nios2_breakpoint_at (CORE_ADDR where) -{ - unsigned int insn; - - /* For R2, first check for the 2-byte CDX trap.n breakpoint encoding. */ -#if defined(__nios2_arch__) && __nios2_arch__ == 2 - (*the_target->read_memory) (where, (unsigned char *) &insn, 2); - if (insn == CDX_BREAKPOINT) - return 1; -#endif - - (*the_target->read_memory) (where, (unsigned char *) &insn, 4); - if (insn == nios2_breakpoint) - return 1; - return 0; -} - -/* Fetch the thread-local storage pointer for libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *) *base - idx); - - return PS_OK; -} - -/* Helper functions to collect/supply a single register REGNO. */ - -static void -nios2_collect_register (struct regcache *regcache, int regno, - union nios2_register *reg) -{ - union nios2_register tmp_reg; - - collect_register (regcache, regno, &tmp_reg.reg32); - reg->reg32 = tmp_reg.reg32; -} - -static void -nios2_supply_register (struct regcache *regcache, int regno, - const union nios2_register *reg) -{ - supply_register (regcache, regno, reg->buf); -} - -/* We have only a single register set on Nios II. */ - -static void -nios2_fill_gregset (struct regcache *regcache, void *buf) -{ - union nios2_register *regset = (union nios2_register *) buf; - int i; - - for (i = 1; i < nios2_num_regs; i++) - nios2_collect_register (regcache, i, regset + i); -} - -static void -nios2_store_gregset (struct regcache *regcache, const void *buf) -{ - const union nios2_register *regset = (union nios2_register *) buf; - int i; - - for (i = 0; i < nios2_num_regs; i++) - nios2_supply_register (regcache, i, regset + i); -} - -static struct regset_info nios2_regsets[] = -{ - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, - nios2_num_regs * 4, GENERAL_REGS, - nios2_fill_gregset, nios2_store_gregset }, - NULL_REGSET -}; - -static struct regsets_info nios2_regsets_info = - { - nios2_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info nios2_usrregs_info = - { - nios2_num_regs, - nios2_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &nios2_usrregs_info, - &nios2_regsets_info - }; - -static const struct regs_info * -nios2_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = -{ - nios2_arch_setup, - nios2_regs_info, - nios2_cannot_fetch_register, - nios2_cannot_store_register, - NULL, - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - nios2_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, - nios2_breakpoint_at, -}; - -void -initialize_low_arch (void) -{ - init_registers_nios2_linux (); - - initialize_regsets_info (&nios2_regsets_info); -} diff --git a/gdb/gdbserver/linux-ppc-ipa.c b/gdb/gdbserver/linux-ppc-ipa.c deleted file mode 100644 index 42d668f7d37..00000000000 --- a/gdb/gdbserver/linux-ppc-ipa.c +++ /dev/null @@ -1,259 +0,0 @@ -/* GNU/Linux/PowerPC specific low level interface, for the in-process - agent library for GDB. - - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include -#include "tracepoint.h" -#include "arch/ppc-linux-tdesc.h" -#include "linux-ppc-tdesc-init.h" -#include -#ifdef HAVE_GETAUXVAL -#include -#endif - -/* These macros define the position of registers in the buffer collected - by the fast tracepoint jump pad. */ -#define FT_CR_R0 0 -#define FT_CR_CR 32 -#define FT_CR_XER 33 -#define FT_CR_LR 34 -#define FT_CR_CTR 35 -#define FT_CR_PC 36 -#define FT_CR_GPR(n) (FT_CR_R0 + (n)) - -static const int ppc_ft_collect_regmap[] = { - /* GPRs */ - FT_CR_GPR (0), FT_CR_GPR (1), FT_CR_GPR (2), - FT_CR_GPR (3), FT_CR_GPR (4), FT_CR_GPR (5), - FT_CR_GPR (6), FT_CR_GPR (7), FT_CR_GPR (8), - FT_CR_GPR (9), FT_CR_GPR (10), FT_CR_GPR (11), - FT_CR_GPR (12), FT_CR_GPR (13), FT_CR_GPR (14), - FT_CR_GPR (15), FT_CR_GPR (16), FT_CR_GPR (17), - FT_CR_GPR (18), FT_CR_GPR (19), FT_CR_GPR (20), - FT_CR_GPR (21), FT_CR_GPR (22), FT_CR_GPR (23), - FT_CR_GPR (24), FT_CR_GPR (25), FT_CR_GPR (26), - FT_CR_GPR (27), FT_CR_GPR (28), FT_CR_GPR (29), - FT_CR_GPR (30), FT_CR_GPR (31), - /* FPRs - not collected. */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - FT_CR_PC, /* PC */ - -1, /* MSR */ - FT_CR_CR, /* CR */ - FT_CR_LR, /* LR */ - FT_CR_CTR, /* CTR */ - FT_CR_XER, /* XER */ - -1, /* FPSCR */ -}; - -#define PPC_NUM_FT_COLLECT_GREGS \ - (sizeof (ppc_ft_collect_regmap) / sizeof(ppc_ft_collect_regmap[0])) - -/* Supply registers collected by the fast tracepoint jump pad. - BUF is the second argument we pass to gdb_collect in jump pad. */ - -void -supply_fast_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf) -{ - int i; - - for (i = 0; i < PPC_NUM_FT_COLLECT_GREGS; i++) - { - if (ppc_ft_collect_regmap[i] == -1) - continue; - supply_register (regcache, i, - ((char *) buf) - + ppc_ft_collect_regmap[i] * sizeof (long)); - } -} - -/* Return the value of register REGNUM. RAW_REGS is collected buffer - by jump pad. This function is called by emit_reg. */ - -ULONGEST -get_raw_reg (const unsigned char *raw_regs, int regnum) -{ - if (regnum >= PPC_NUM_FT_COLLECT_GREGS) - return 0; - if (ppc_ft_collect_regmap[regnum] == -1) - return 0; - - return *(unsigned long *) (raw_regs - + ppc_ft_collect_regmap[regnum] * sizeof (long)); -} - -/* Allocate buffer for the jump pads. The branch instruction has a reach - of +/- 32MiB, and the executable is loaded at 0x10000000 (256MiB). - - 64-bit: To maximize the area of executable that can use tracepoints, - try allocating at 0x10000000 - size initially, decreasing until we hit - a free area. - - 32-bit: ld.so loads dynamic libraries right below the executable, so - we cannot depend on that area (dynamic libraries can be quite large). - Instead, aim right after the executable - at sbrk(0). This will - cause future brk to fail, and malloc will fallback to mmap. */ - -void * -alloc_jump_pad_buffer (size_t size) -{ -#ifdef __powerpc64__ - uintptr_t addr; - uintptr_t exec_base = getauxval (AT_PHDR); - int pagesize; - void *res; - - if (exec_base == 0) - exec_base = 0x10000000; - - pagesize = sysconf (_SC_PAGE_SIZE); - if (pagesize == -1) - perror_with_name ("sysconf"); - - addr = exec_base - size; - - /* size should already be page-aligned, but this can't hurt. */ - addr &= ~(pagesize - 1); - - /* Search for a free area. If we hit 0, we're out of luck. */ - for (; addr; addr -= pagesize) - { - /* No MAP_FIXED - we don't want to zap someone's mapping. */ - res = mmap ((void *) addr, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* If we got what we wanted, return. */ - if ((uintptr_t) res == addr) - return res; - - /* If we got a mapping, but at a wrong address, undo it. */ - if (res != MAP_FAILED) - munmap (res, size); - } - - return NULL; -#else - void *target = sbrk (0); - void *res = mmap (target, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - if (res == target) - return res; - - if (res != MAP_FAILED) - munmap (res, size); - - return NULL; -#endif -} - -/* Return target_desc to use for IPA, given the tdesc index passed by - gdbserver. */ - -const struct target_desc * -get_ipa_tdesc (int idx) -{ - switch (idx) - { -#ifdef __powerpc64__ - case PPC_TDESC_BASE: - return tdesc_powerpc_64l; - case PPC_TDESC_ALTIVEC: - return tdesc_powerpc_altivec64l; - case PPC_TDESC_VSX: - return tdesc_powerpc_vsx64l; - case PPC_TDESC_ISA205: - return tdesc_powerpc_isa205_64l; - case PPC_TDESC_ISA205_ALTIVEC: - return tdesc_powerpc_isa205_altivec64l; - case PPC_TDESC_ISA205_VSX: - return tdesc_powerpc_isa205_vsx64l; - case PPC_TDESC_ISA205_PPR_DSCR_VSX: - return tdesc_powerpc_isa205_ppr_dscr_vsx64l; - case PPC_TDESC_ISA207_VSX: - return tdesc_powerpc_isa207_vsx64l; - case PPC_TDESC_ISA207_HTM_VSX: - return tdesc_powerpc_isa207_htm_vsx64l; -#else - case PPC_TDESC_BASE: - return tdesc_powerpc_32l; - case PPC_TDESC_ALTIVEC: - return tdesc_powerpc_altivec32l; - case PPC_TDESC_VSX: - return tdesc_powerpc_vsx32l; - case PPC_TDESC_ISA205: - return tdesc_powerpc_isa205_32l; - case PPC_TDESC_ISA205_ALTIVEC: - return tdesc_powerpc_isa205_altivec32l; - case PPC_TDESC_ISA205_VSX: - return tdesc_powerpc_isa205_vsx32l; - case PPC_TDESC_ISA205_PPR_DSCR_VSX: - return tdesc_powerpc_isa205_ppr_dscr_vsx32l; - case PPC_TDESC_ISA207_VSX: - return tdesc_powerpc_isa207_vsx32l; - case PPC_TDESC_ISA207_HTM_VSX: - return tdesc_powerpc_isa207_htm_vsx32l; - case PPC_TDESC_E500: - return tdesc_powerpc_e500l; -#endif - default: - internal_error (__FILE__, __LINE__, - "unknown ipa tdesc index: %d", idx); -#ifdef __powerpc64__ - return tdesc_powerpc_64l; -#else - return tdesc_powerpc_32l; -#endif - } -} - - -/* Initialize ipa_tdesc and others. */ - -void -initialize_low_tracepoint (void) -{ -#ifdef __powerpc64__ - init_registers_powerpc_64l (); - init_registers_powerpc_altivec64l (); - init_registers_powerpc_vsx64l (); - init_registers_powerpc_isa205_64l (); - init_registers_powerpc_isa205_altivec64l (); - init_registers_powerpc_isa205_vsx64l (); - init_registers_powerpc_isa205_ppr_dscr_vsx64l (); - init_registers_powerpc_isa207_vsx64l (); - init_registers_powerpc_isa207_htm_vsx64l (); -#else - init_registers_powerpc_32l (); - init_registers_powerpc_altivec32l (); - init_registers_powerpc_vsx32l (); - init_registers_powerpc_isa205_32l (); - init_registers_powerpc_isa205_altivec32l (); - init_registers_powerpc_isa205_vsx32l (); - init_registers_powerpc_isa205_ppr_dscr_vsx32l (); - init_registers_powerpc_isa207_vsx32l (); - init_registers_powerpc_isa207_htm_vsx32l (); - init_registers_powerpc_e500l (); -#endif -} diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c deleted file mode 100644 index 5d8d67bec2f..00000000000 --- a/gdb/gdbserver/linux-ppc-low.c +++ /dev/null @@ -1,3441 +0,0 @@ -/* GNU/Linux/PowerPC specific low level interface, for the remote server for - GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -#include "elf/common.h" -#include -#include -#include - -#include "arch/ppc-linux-common.h" -#include "arch/ppc-linux-tdesc.h" -#include "nat/ppc-linux.h" -#include "nat/linux-ptrace.h" -#include "linux-ppc-tdesc-init.h" -#include "ax.h" -#include "tracepoint.h" - -#define PPC_FIELD(value, from, len) \ - (((value) >> (32 - (from) - (len))) & ((1 << (len)) - 1)) -#define PPC_SEXT(v, bs) \ - ((((CORE_ADDR) (v) & (((CORE_ADDR) 1 << (bs)) - 1)) \ - ^ ((CORE_ADDR) 1 << ((bs) - 1))) \ - - ((CORE_ADDR) 1 << ((bs) - 1))) -#define PPC_OP6(insn) PPC_FIELD (insn, 0, 6) -#define PPC_BO(insn) PPC_FIELD (insn, 6, 5) -#define PPC_LI(insn) (PPC_SEXT (PPC_FIELD (insn, 6, 24), 24) << 2) -#define PPC_BD(insn) (PPC_SEXT (PPC_FIELD (insn, 16, 14), 14) << 2) - -/* Holds the AT_HWCAP auxv entry. */ - -static unsigned long ppc_hwcap; - -/* Holds the AT_HWCAP2 auxv entry. */ - -static unsigned long ppc_hwcap2; - - -#define ppc_num_regs 73 - -#ifdef __powerpc64__ -/* We use a constant for FPSCR instead of PT_FPSCR, because - many shipped PPC64 kernels had the wrong value in ptrace.h. */ -static int ppc_regmap[] = - {PT_R0 * 8, PT_R1 * 8, PT_R2 * 8, PT_R3 * 8, - PT_R4 * 8, PT_R5 * 8, PT_R6 * 8, PT_R7 * 8, - PT_R8 * 8, PT_R9 * 8, PT_R10 * 8, PT_R11 * 8, - PT_R12 * 8, PT_R13 * 8, PT_R14 * 8, PT_R15 * 8, - PT_R16 * 8, PT_R17 * 8, PT_R18 * 8, PT_R19 * 8, - PT_R20 * 8, PT_R21 * 8, PT_R22 * 8, PT_R23 * 8, - PT_R24 * 8, PT_R25 * 8, PT_R26 * 8, PT_R27 * 8, - PT_R28 * 8, PT_R29 * 8, PT_R30 * 8, PT_R31 * 8, - PT_FPR0*8, PT_FPR0*8 + 8, PT_FPR0*8+16, PT_FPR0*8+24, - PT_FPR0*8+32, PT_FPR0*8+40, PT_FPR0*8+48, PT_FPR0*8+56, - PT_FPR0*8+64, PT_FPR0*8+72, PT_FPR0*8+80, PT_FPR0*8+88, - PT_FPR0*8+96, PT_FPR0*8+104, PT_FPR0*8+112, PT_FPR0*8+120, - PT_FPR0*8+128, PT_FPR0*8+136, PT_FPR0*8+144, PT_FPR0*8+152, - PT_FPR0*8+160, PT_FPR0*8+168, PT_FPR0*8+176, PT_FPR0*8+184, - PT_FPR0*8+192, PT_FPR0*8+200, PT_FPR0*8+208, PT_FPR0*8+216, - PT_FPR0*8+224, PT_FPR0*8+232, PT_FPR0*8+240, PT_FPR0*8+248, - PT_NIP * 8, PT_MSR * 8, PT_CCR * 8, PT_LNK * 8, - PT_CTR * 8, PT_XER * 8, PT_FPR0*8 + 256, - PT_ORIG_R3 * 8, PT_TRAP * 8 }; -#else -/* Currently, don't check/send MQ. */ -static int ppc_regmap[] = - {PT_R0 * 4, PT_R1 * 4, PT_R2 * 4, PT_R3 * 4, - PT_R4 * 4, PT_R5 * 4, PT_R6 * 4, PT_R7 * 4, - PT_R8 * 4, PT_R9 * 4, PT_R10 * 4, PT_R11 * 4, - PT_R12 * 4, PT_R13 * 4, PT_R14 * 4, PT_R15 * 4, - PT_R16 * 4, PT_R17 * 4, PT_R18 * 4, PT_R19 * 4, - PT_R20 * 4, PT_R21 * 4, PT_R22 * 4, PT_R23 * 4, - PT_R24 * 4, PT_R25 * 4, PT_R26 * 4, PT_R27 * 4, - PT_R28 * 4, PT_R29 * 4, PT_R30 * 4, PT_R31 * 4, - PT_FPR0*4, PT_FPR0*4 + 8, PT_FPR0*4+16, PT_FPR0*4+24, - PT_FPR0*4+32, PT_FPR0*4+40, PT_FPR0*4+48, PT_FPR0*4+56, - PT_FPR0*4+64, PT_FPR0*4+72, PT_FPR0*4+80, PT_FPR0*4+88, - PT_FPR0*4+96, PT_FPR0*4+104, PT_FPR0*4+112, PT_FPR0*4+120, - PT_FPR0*4+128, PT_FPR0*4+136, PT_FPR0*4+144, PT_FPR0*4+152, - PT_FPR0*4+160, PT_FPR0*4+168, PT_FPR0*4+176, PT_FPR0*4+184, - PT_FPR0*4+192, PT_FPR0*4+200, PT_FPR0*4+208, PT_FPR0*4+216, - PT_FPR0*4+224, PT_FPR0*4+232, PT_FPR0*4+240, PT_FPR0*4+248, - PT_NIP * 4, PT_MSR * 4, PT_CCR * 4, PT_LNK * 4, - PT_CTR * 4, PT_XER * 4, PT_FPSCR * 4, - PT_ORIG_R3 * 4, PT_TRAP * 4 - }; - -static int ppc_regmap_e500[] = - {PT_R0 * 4, PT_R1 * 4, PT_R2 * 4, PT_R3 * 4, - PT_R4 * 4, PT_R5 * 4, PT_R6 * 4, PT_R7 * 4, - PT_R8 * 4, PT_R9 * 4, PT_R10 * 4, PT_R11 * 4, - PT_R12 * 4, PT_R13 * 4, PT_R14 * 4, PT_R15 * 4, - PT_R16 * 4, PT_R17 * 4, PT_R18 * 4, PT_R19 * 4, - PT_R20 * 4, PT_R21 * 4, PT_R22 * 4, PT_R23 * 4, - PT_R24 * 4, PT_R25 * 4, PT_R26 * 4, PT_R27 * 4, - PT_R28 * 4, PT_R29 * 4, PT_R30 * 4, PT_R31 * 4, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - PT_NIP * 4, PT_MSR * 4, PT_CCR * 4, PT_LNK * 4, - PT_CTR * 4, PT_XER * 4, -1, - PT_ORIG_R3 * 4, PT_TRAP * 4 - }; -#endif - -/* Check whether the kernel provides a register set with number - REGSET_ID of size REGSETSIZE for process/thread TID. */ - -static int -ppc_check_regset (int tid, int regset_id, int regsetsize) -{ - void *buf = alloca (regsetsize); - struct iovec iov; - - iov.iov_base = buf; - iov.iov_len = regsetsize; - - if (ptrace (PTRACE_GETREGSET, tid, regset_id, &iov) >= 0 - || errno == ENODATA) - return 1; - return 0; -} - -static int -ppc_cannot_store_register (int regno) -{ - const struct target_desc *tdesc = current_process ()->tdesc; - -#ifndef __powerpc64__ - /* Some kernels do not allow us to store fpscr. */ - if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE) - && regno == find_regno (tdesc, "fpscr")) - return 2; -#endif - - /* Some kernels do not allow us to store orig_r3 or trap. */ - if (regno == find_regno (tdesc, "orig_r3") - || regno == find_regno (tdesc, "trap")) - return 2; - - return 0; -} - -static int -ppc_cannot_fetch_register (int regno) -{ - return 0; -} - -static void -ppc_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) -{ - memset (buf, 0, sizeof (long)); - - if (__BYTE_ORDER == __LITTLE_ENDIAN) - { - /* Little-endian values always sit at the left end of the buffer. */ - collect_register (regcache, regno, buf); - } - else if (__BYTE_ORDER == __BIG_ENDIAN) - { - /* Big-endian values sit at the right end of the buffer. In case of - registers whose sizes are smaller than sizeof (long), we must use a - padding to access them correctly. */ - int size = register_size (regcache->tdesc, regno); - - if (size < sizeof (long)) - collect_register (regcache, regno, buf + sizeof (long) - size); - else - collect_register (regcache, regno, buf); - } - else - perror_with_name ("Unexpected byte order"); -} - -static void -ppc_supply_ptrace_register (struct regcache *regcache, - int regno, const char *buf) -{ - if (__BYTE_ORDER == __LITTLE_ENDIAN) - { - /* Little-endian values always sit at the left end of the buffer. */ - supply_register (regcache, regno, buf); - } - else if (__BYTE_ORDER == __BIG_ENDIAN) - { - /* Big-endian values sit at the right end of the buffer. In case of - registers whose sizes are smaller than sizeof (long), we must use a - padding to access them correctly. */ - int size = register_size (regcache->tdesc, regno); - - if (size < sizeof (long)) - supply_register (regcache, regno, buf + sizeof (long) - size); - else - supply_register (regcache, regno, buf); - } - else - perror_with_name ("Unexpected byte order"); -} - -static CORE_ADDR -ppc_get_pc (struct regcache *regcache) -{ - if (register_size (regcache->tdesc, 0) == 4) - { - unsigned int pc; - collect_register_by_name (regcache, "pc", &pc); - return (CORE_ADDR) pc; - } - else - { - unsigned long pc; - collect_register_by_name (regcache, "pc", &pc); - return (CORE_ADDR) pc; - } -} - -static void -ppc_set_pc (struct regcache *regcache, CORE_ADDR pc) -{ - if (register_size (regcache->tdesc, 0) == 4) - { - unsigned int newpc = pc; - supply_register_by_name (regcache, "pc", &newpc); - } - else - { - unsigned long newpc = pc; - supply_register_by_name (regcache, "pc", &newpc); - } -} - -#ifndef __powerpc64__ -static int ppc_regmap_adjusted; -#endif - - -/* Correct in either endianness. - This instruction is "twge r2, r2", which GDB uses as a software - breakpoint. */ -static const unsigned int ppc_breakpoint = 0x7d821008; -#define ppc_breakpoint_len 4 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -ppc_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = ppc_breakpoint_len; - return (const gdb_byte *) &ppc_breakpoint; -} - -static int -ppc_breakpoint_at (CORE_ADDR where) -{ - unsigned int insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 4); - if (insn == ppc_breakpoint) - return 1; - /* If necessary, recognize more trap instructions here. GDB only uses - the one. */ - - return 0; -} - -/* Implement supports_z_point_type target-ops. - Returns true if type Z_TYPE breakpoint is supported. - - Handling software breakpoint at server side, so tracepoints - and breakpoints can be inserted at the same location. */ - -static int -ppc_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - return 1; - case Z_PACKET_HW_BP: - case Z_PACKET_WRITE_WP: - case Z_PACKET_ACCESS_WP: - default: - return 0; - } -} - -/* Implement insert_point target-ops. - Returns 0 on success, -1 on failure and 1 on unsupported. */ - -static int -ppc_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - switch (type) - { - case raw_bkpt_type_sw: - return insert_memory_breakpoint (bp); - - case raw_bkpt_type_hw: - case raw_bkpt_type_write_wp: - case raw_bkpt_type_access_wp: - default: - /* Unsupported. */ - return 1; - } -} - -/* Implement remove_point target-ops. - Returns 0 on success, -1 on failure and 1 on unsupported. */ - -static int -ppc_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - switch (type) - { - case raw_bkpt_type_sw: - return remove_memory_breakpoint (bp); - - case raw_bkpt_type_hw: - case raw_bkpt_type_write_wp: - case raw_bkpt_type_access_wp: - default: - /* Unsupported. */ - return 1; - } -} - -/* Provide only a fill function for the general register set. ps_lgetregs - will use this for NPTL support. */ - -static void ppc_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - - for (i = 0; i < 32; i++) - ppc_collect_ptrace_register (regcache, i, (char *) buf + ppc_regmap[i]); - - for (i = 64; i < 70; i++) - ppc_collect_ptrace_register (regcache, i, (char *) buf + ppc_regmap[i]); - - for (i = 71; i < 73; i++) - ppc_collect_ptrace_register (regcache, i, (char *) buf + ppc_regmap[i]); -} - -/* Program Priority Register regset fill function. */ - -static void -ppc_fill_pprregset (struct regcache *regcache, void *buf) -{ - char *ppr = (char *) buf; - - collect_register_by_name (regcache, "ppr", ppr); -} - -/* Program Priority Register regset store function. */ - -static void -ppc_store_pprregset (struct regcache *regcache, const void *buf) -{ - const char *ppr = (const char *) buf; - - supply_register_by_name (regcache, "ppr", ppr); -} - -/* Data Stream Control Register regset fill function. */ - -static void -ppc_fill_dscrregset (struct regcache *regcache, void *buf) -{ - char *dscr = (char *) buf; - - collect_register_by_name (regcache, "dscr", dscr); -} - -/* Data Stream Control Register regset store function. */ - -static void -ppc_store_dscrregset (struct regcache *regcache, const void *buf) -{ - const char *dscr = (const char *) buf; - - supply_register_by_name (regcache, "dscr", dscr); -} - -/* Target Address Register regset fill function. */ - -static void -ppc_fill_tarregset (struct regcache *regcache, void *buf) -{ - char *tar = (char *) buf; - - collect_register_by_name (regcache, "tar", tar); -} - -/* Target Address Register regset store function. */ - -static void -ppc_store_tarregset (struct regcache *regcache, const void *buf) -{ - const char *tar = (const char *) buf; - - supply_register_by_name (regcache, "tar", tar); -} - -/* Event-Based Branching regset store function. Unless the inferior - has a perf event open, ptrace can return in error when reading and - writing to the regset, with ENODATA. For reading, the registers - will correctly show as unavailable. For writing, gdbserver - currently only caches any register writes from P and G packets and - the stub always tries to write all the regsets when resuming the - inferior, which would result in frequent warnings. For this - reason, we don't define a fill function. This also means that the - client-side regcache will be dirty if the user tries to write to - the EBB registers. G packets that the client sends to write to - unrelated registers will also include data for EBB registers, even - if they are unavailable. */ - -static void -ppc_store_ebbregset (struct regcache *regcache, const void *buf) -{ - const char *regset = (const char *) buf; - - /* The order in the kernel regset is: EBBRR, EBBHR, BESCR. In the - .dat file is BESCR, EBBHR, EBBRR. */ - supply_register_by_name (regcache, "ebbrr", ®set[0]); - supply_register_by_name (regcache, "ebbhr", ®set[8]); - supply_register_by_name (regcache, "bescr", ®set[16]); -} - -/* Performance Monitoring Unit regset fill function. */ - -static void -ppc_fill_pmuregset (struct regcache *regcache, void *buf) -{ - char *regset = (char *) buf; - - /* The order in the kernel regset is SIAR, SDAR, SIER, MMCR2, MMCR0. - In the .dat file is MMCR0, MMCR2, SIAR, SDAR, SIER. */ - collect_register_by_name (regcache, "siar", ®set[0]); - collect_register_by_name (regcache, "sdar", ®set[8]); - collect_register_by_name (regcache, "sier", ®set[16]); - collect_register_by_name (regcache, "mmcr2", ®set[24]); - collect_register_by_name (regcache, "mmcr0", ®set[32]); -} - -/* Performance Monitoring Unit regset store function. */ - -static void -ppc_store_pmuregset (struct regcache *regcache, const void *buf) -{ - const char *regset = (const char *) buf; - - supply_register_by_name (regcache, "siar", ®set[0]); - supply_register_by_name (regcache, "sdar", ®set[8]); - supply_register_by_name (regcache, "sier", ®set[16]); - supply_register_by_name (regcache, "mmcr2", ®set[24]); - supply_register_by_name (regcache, "mmcr0", ®set[32]); -} - -/* Hardware Transactional Memory special-purpose register regset fill - function. */ - -static void -ppc_fill_tm_sprregset (struct regcache *regcache, void *buf) -{ - int i, base; - char *regset = (char *) buf; - - base = find_regno (regcache->tdesc, "tfhar"); - for (i = 0; i < 3; i++) - collect_register (regcache, base + i, ®set[i * 8]); -} - -/* Hardware Transactional Memory special-purpose register regset store - function. */ - -static void -ppc_store_tm_sprregset (struct regcache *regcache, const void *buf) -{ - int i, base; - const char *regset = (const char *) buf; - - base = find_regno (regcache->tdesc, "tfhar"); - for (i = 0; i < 3; i++) - supply_register (regcache, base + i, ®set[i * 8]); -} - -/* For the same reasons as the EBB regset, none of the HTM - checkpointed regsets have a fill function. These registers are - only available if the inferior is in a transaction. */ - -/* Hardware Transactional Memory checkpointed general-purpose regset - store function. */ - -static void -ppc_store_tm_cgprregset (struct regcache *regcache, const void *buf) -{ - int i, base, size, endian_offset; - const char *regset = (const char *) buf; - - base = find_regno (regcache->tdesc, "cr0"); - size = register_size (regcache->tdesc, base); - - gdb_assert (size == 4 || size == 8); - - for (i = 0; i < 32; i++) - supply_register (regcache, base + i, ®set[i * size]); - - endian_offset = 0; - - if ((size == 8) && (__BYTE_ORDER == __BIG_ENDIAN)) - endian_offset = 4; - - supply_register_by_name (regcache, "ccr", - ®set[PT_CCR * size + endian_offset]); - - supply_register_by_name (regcache, "cxer", - ®set[PT_XER * size + endian_offset]); - - supply_register_by_name (regcache, "clr", ®set[PT_LNK * size]); - supply_register_by_name (regcache, "cctr", ®set[PT_CTR * size]); -} - -/* Hardware Transactional Memory checkpointed floating-point regset - store function. */ - -static void -ppc_store_tm_cfprregset (struct regcache *regcache, const void *buf) -{ - int i, base; - const char *regset = (const char *) buf; - - base = find_regno (regcache->tdesc, "cf0"); - - for (i = 0; i < 32; i++) - supply_register (regcache, base + i, ®set[i * 8]); - - supply_register_by_name (regcache, "cfpscr", ®set[32 * 8]); -} - -/* Hardware Transactional Memory checkpointed vector regset store - function. */ - -static void -ppc_store_tm_cvrregset (struct regcache *regcache, const void *buf) -{ - int i, base; - const char *regset = (const char *) buf; - int vscr_offset = 0; - - base = find_regno (regcache->tdesc, "cvr0"); - - for (i = 0; i < 32; i++) - supply_register (regcache, base + i, ®set[i * 16]); - - if (__BYTE_ORDER == __BIG_ENDIAN) - vscr_offset = 12; - - supply_register_by_name (regcache, "cvscr", - ®set[32 * 16 + vscr_offset]); - - supply_register_by_name (regcache, "cvrsave", ®set[33 * 16]); -} - -/* Hardware Transactional Memory checkpointed vector-scalar regset - store function. */ - -static void -ppc_store_tm_cvsxregset (struct regcache *regcache, const void *buf) -{ - int i, base; - const char *regset = (const char *) buf; - - base = find_regno (regcache->tdesc, "cvs0h"); - for (i = 0; i < 32; i++) - supply_register (regcache, base + i, ®set[i * 8]); -} - -/* Hardware Transactional Memory checkpointed Program Priority - Register regset store function. */ - -static void -ppc_store_tm_cpprregset (struct regcache *regcache, const void *buf) -{ - const char *cppr = (const char *) buf; - - supply_register_by_name (regcache, "cppr", cppr); -} - -/* Hardware Transactional Memory checkpointed Data Stream Control - Register regset store function. */ - -static void -ppc_store_tm_cdscrregset (struct regcache *regcache, const void *buf) -{ - const char *cdscr = (const char *) buf; - - supply_register_by_name (regcache, "cdscr", cdscr); -} - -/* Hardware Transactional Memory checkpointed Target Address Register - regset store function. */ - -static void -ppc_store_tm_ctarregset (struct regcache *regcache, const void *buf) -{ - const char *ctar = (const char *) buf; - - supply_register_by_name (regcache, "ctar", ctar); -} - -static void -ppc_fill_vsxregset (struct regcache *regcache, void *buf) -{ - int i, base; - char *regset = (char *) buf; - - base = find_regno (regcache->tdesc, "vs0h"); - for (i = 0; i < 32; i++) - collect_register (regcache, base + i, ®set[i * 8]); -} - -static void -ppc_store_vsxregset (struct regcache *regcache, const void *buf) -{ - int i, base; - const char *regset = (const char *) buf; - - base = find_regno (regcache->tdesc, "vs0h"); - for (i = 0; i < 32; i++) - supply_register (regcache, base + i, ®set[i * 8]); -} - -static void -ppc_fill_vrregset (struct regcache *regcache, void *buf) -{ - int i, base; - char *regset = (char *) buf; - int vscr_offset = 0; - - base = find_regno (regcache->tdesc, "vr0"); - for (i = 0; i < 32; i++) - collect_register (regcache, base + i, ®set[i * 16]); - - if (__BYTE_ORDER == __BIG_ENDIAN) - vscr_offset = 12; - - collect_register_by_name (regcache, "vscr", - ®set[32 * 16 + vscr_offset]); - - collect_register_by_name (regcache, "vrsave", ®set[33 * 16]); -} - -static void -ppc_store_vrregset (struct regcache *regcache, const void *buf) -{ - int i, base; - const char *regset = (const char *) buf; - int vscr_offset = 0; - - base = find_regno (regcache->tdesc, "vr0"); - for (i = 0; i < 32; i++) - supply_register (regcache, base + i, ®set[i * 16]); - - if (__BYTE_ORDER == __BIG_ENDIAN) - vscr_offset = 12; - - supply_register_by_name (regcache, "vscr", - ®set[32 * 16 + vscr_offset]); - supply_register_by_name (regcache, "vrsave", ®set[33 * 16]); -} - -struct gdb_evrregset_t -{ - unsigned long evr[32]; - unsigned long long acc; - unsigned long spefscr; -}; - -static void -ppc_fill_evrregset (struct regcache *regcache, void *buf) -{ - int i, ev0; - struct gdb_evrregset_t *regset = (struct gdb_evrregset_t *) buf; - - ev0 = find_regno (regcache->tdesc, "ev0h"); - for (i = 0; i < 32; i++) - collect_register (regcache, ev0 + i, ®set->evr[i]); - - collect_register_by_name (regcache, "acc", ®set->acc); - collect_register_by_name (regcache, "spefscr", ®set->spefscr); -} - -static void -ppc_store_evrregset (struct regcache *regcache, const void *buf) -{ - int i, ev0; - const struct gdb_evrregset_t *regset = (const struct gdb_evrregset_t *) buf; - - ev0 = find_regno (regcache->tdesc, "ev0h"); - for (i = 0; i < 32; i++) - supply_register (regcache, ev0 + i, ®set->evr[i]); - - supply_register_by_name (regcache, "acc", ®set->acc); - supply_register_by_name (regcache, "spefscr", ®set->spefscr); -} - -/* Support for hardware single step. */ - -static int -ppc_supports_hardware_single_step (void) -{ - return 1; -} - -static struct regset_info ppc_regsets[] = { - /* List the extra register sets before GENERAL_REGS. That way we will - fetch them every time, but still fall back to PTRACE_PEEKUSER for the - general registers. Some kernels support these, but not the newer - PPC_PTRACE_GETREGS. */ - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CTAR, 0, EXTENDED_REGS, - NULL, ppc_store_tm_ctarregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CDSCR, 0, EXTENDED_REGS, - NULL, ppc_store_tm_cdscrregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CPPR, 0, EXTENDED_REGS, - NULL, ppc_store_tm_cpprregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CVSX, 0, EXTENDED_REGS, - NULL, ppc_store_tm_cvsxregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CVMX, 0, EXTENDED_REGS, - NULL, ppc_store_tm_cvrregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CFPR, 0, EXTENDED_REGS, - NULL, ppc_store_tm_cfprregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CGPR, 0, EXTENDED_REGS, - NULL, ppc_store_tm_cgprregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_SPR, 0, EXTENDED_REGS, - ppc_fill_tm_sprregset, ppc_store_tm_sprregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_EBB, 0, EXTENDED_REGS, - NULL, ppc_store_ebbregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_PMU, 0, EXTENDED_REGS, - ppc_fill_pmuregset, ppc_store_pmuregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TAR, 0, EXTENDED_REGS, - ppc_fill_tarregset, ppc_store_tarregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_PPR, 0, EXTENDED_REGS, - ppc_fill_pprregset, ppc_store_pprregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_DSCR, 0, EXTENDED_REGS, - ppc_fill_dscrregset, ppc_store_dscrregset }, - { PTRACE_GETVSXREGS, PTRACE_SETVSXREGS, 0, 0, EXTENDED_REGS, - ppc_fill_vsxregset, ppc_store_vsxregset }, - { PTRACE_GETVRREGS, PTRACE_SETVRREGS, 0, 0, EXTENDED_REGS, - ppc_fill_vrregset, ppc_store_vrregset }, - { PTRACE_GETEVRREGS, PTRACE_SETEVRREGS, 0, 0, EXTENDED_REGS, - ppc_fill_evrregset, ppc_store_evrregset }, - { 0, 0, 0, 0, GENERAL_REGS, ppc_fill_gregset, NULL }, - NULL_REGSET -}; - -static struct usrregs_info ppc_usrregs_info = - { - ppc_num_regs, - ppc_regmap, - }; - -static struct regsets_info ppc_regsets_info = - { - ppc_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &ppc_usrregs_info, - &ppc_regsets_info - }; - -static const struct regs_info * -ppc_regs_info (void) -{ - return ®s_info; -} - -static void -ppc_arch_setup (void) -{ - const struct target_desc *tdesc; - struct regset_info *regset; - struct ppc_linux_features features = ppc_linux_no_features; - - int tid = lwpid_of (current_thread); - - features.wordsize = ppc_linux_target_wordsize (tid); - - if (features.wordsize == 4) - tdesc = tdesc_powerpc_32l; - else - tdesc = tdesc_powerpc_64l; - - current_process ()->tdesc = tdesc; - - /* The value of current_process ()->tdesc needs to be set for this - call. */ - ppc_hwcap = linux_get_hwcap (features.wordsize); - ppc_hwcap2 = linux_get_hwcap2 (features.wordsize); - - features.isa205 = ppc_linux_has_isa205 (ppc_hwcap); - - if (ppc_hwcap & PPC_FEATURE_HAS_VSX) - features.vsx = true; - - if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC) - features.altivec = true; - - if ((ppc_hwcap2 & PPC_FEATURE2_DSCR) - && ppc_check_regset (tid, NT_PPC_DSCR, PPC_LINUX_SIZEOF_DSCRREGSET) - && ppc_check_regset (tid, NT_PPC_PPR, PPC_LINUX_SIZEOF_PPRREGSET)) - { - features.ppr_dscr = true; - if ((ppc_hwcap2 & PPC_FEATURE2_ARCH_2_07) - && (ppc_hwcap2 & PPC_FEATURE2_TAR) - && (ppc_hwcap2 & PPC_FEATURE2_EBB) - && ppc_check_regset (tid, NT_PPC_TAR, - PPC_LINUX_SIZEOF_TARREGSET) - && ppc_check_regset (tid, NT_PPC_EBB, - PPC_LINUX_SIZEOF_EBBREGSET) - && ppc_check_regset (tid, NT_PPC_PMU, - PPC_LINUX_SIZEOF_PMUREGSET)) - { - features.isa207 = true; - if ((ppc_hwcap2 & PPC_FEATURE2_HTM) - && ppc_check_regset (tid, NT_PPC_TM_SPR, - PPC_LINUX_SIZEOF_TM_SPRREGSET)) - features.htm = true; - } - } - - tdesc = ppc_linux_match_description (features); - - /* On 32-bit machines, check for SPE registers. - Set the low target's regmap field as appropriately. */ -#ifndef __powerpc64__ - if (ppc_hwcap & PPC_FEATURE_HAS_SPE) - tdesc = tdesc_powerpc_e500l; - - if (!ppc_regmap_adjusted) - { - if (ppc_hwcap & PPC_FEATURE_HAS_SPE) - ppc_usrregs_info.regmap = ppc_regmap_e500; - - /* If the FPSCR is 64-bit wide, we need to fetch the whole - 64-bit slot and not just its second word. The PT_FPSCR - supplied in a 32-bit GDB compilation doesn't reflect - this. */ - if (register_size (tdesc, 70) == 8) - ppc_regmap[70] = (48 + 2*32) * sizeof (long); - - ppc_regmap_adjusted = 1; - } -#endif - - current_process ()->tdesc = tdesc; - - for (regset = ppc_regsets; regset->size >= 0; regset++) - switch (regset->get_request) - { - case PTRACE_GETVRREGS: - regset->size = features.altivec ? PPC_LINUX_SIZEOF_VRREGSET : 0; - break; - case PTRACE_GETVSXREGS: - regset->size = features.vsx ? PPC_LINUX_SIZEOF_VSXREGSET : 0; - break; - case PTRACE_GETEVRREGS: - if (ppc_hwcap & PPC_FEATURE_HAS_SPE) - regset->size = 32 * 4 + 8 + 4; - else - regset->size = 0; - break; - case PTRACE_GETREGSET: - switch (regset->nt_type) - { - case NT_PPC_PPR: - regset->size = (features.ppr_dscr ? - PPC_LINUX_SIZEOF_PPRREGSET : 0); - break; - case NT_PPC_DSCR: - regset->size = (features.ppr_dscr ? - PPC_LINUX_SIZEOF_DSCRREGSET : 0); - break; - case NT_PPC_TAR: - regset->size = (features.isa207 ? - PPC_LINUX_SIZEOF_TARREGSET : 0); - break; - case NT_PPC_EBB: - regset->size = (features.isa207 ? - PPC_LINUX_SIZEOF_EBBREGSET : 0); - break; - case NT_PPC_PMU: - regset->size = (features.isa207 ? - PPC_LINUX_SIZEOF_PMUREGSET : 0); - break; - case NT_PPC_TM_SPR: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_TM_SPRREGSET : 0); - break; - case NT_PPC_TM_CGPR: - if (features.wordsize == 4) - regset->size = (features.htm ? - PPC32_LINUX_SIZEOF_CGPRREGSET : 0); - else - regset->size = (features.htm ? - PPC64_LINUX_SIZEOF_CGPRREGSET : 0); - break; - case NT_PPC_TM_CFPR: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_CFPRREGSET : 0); - break; - case NT_PPC_TM_CVMX: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_CVMXREGSET : 0); - break; - case NT_PPC_TM_CVSX: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_CVSXREGSET : 0); - break; - case NT_PPC_TM_CPPR: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_CPPRREGSET : 0); - break; - case NT_PPC_TM_CDSCR: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_CDSCRREGSET : 0); - break; - case NT_PPC_TM_CTAR: - regset->size = (features.htm ? - PPC_LINUX_SIZEOF_CTARREGSET : 0); - break; - default: - break; - } - break; - default: - break; - } -} - -/* Implementation of linux_target_ops method "supports_tracepoints". */ - -static int -ppc_supports_tracepoints (void) -{ - return 1; -} - -/* Get the thread area address. This is used to recognize which - thread is which when tracing with the in-process agent library. We - don't read anything from the address, and treat it as opaque; it's - the address itself that we assume is unique per-thread. */ - -static int -ppc_get_thread_area (int lwpid, CORE_ADDR *addr) -{ - struct lwp_info *lwp = find_lwp_pid (ptid_t (lwpid)); - struct thread_info *thr = get_lwp_thread (lwp); - struct regcache *regcache = get_thread_regcache (thr, 1); - ULONGEST tp = 0; - -#ifdef __powerpc64__ - if (register_size (regcache->tdesc, 0) == 8) - collect_register_by_name (regcache, "r13", &tp); - else -#endif - collect_register_by_name (regcache, "r2", &tp); - - *addr = tp; - - return 0; -} - -#ifdef __powerpc64__ - -/* Older glibc doesn't provide this. */ - -#ifndef EF_PPC64_ABI -#define EF_PPC64_ABI 3 -#endif - -/* Returns 1 if inferior is using ELFv2 ABI. Undefined for 32-bit - inferiors. */ - -static int -is_elfv2_inferior (void) -{ - /* To be used as fallback if we're unable to determine the right result - - assume inferior uses the same ABI as gdbserver. */ -#if _CALL_ELF == 2 - const int def_res = 1; -#else - const int def_res = 0; -#endif - CORE_ADDR phdr; - Elf64_Ehdr ehdr; - - const struct target_desc *tdesc = current_process ()->tdesc; - int wordsize = register_size (tdesc, 0); - - if (!linux_get_auxv (wordsize, AT_PHDR, &phdr)) - return def_res; - - /* Assume ELF header is at the beginning of the page where program headers - are located. If it doesn't look like one, bail. */ - - read_inferior_memory (phdr & ~0xfff, (unsigned char *) &ehdr, sizeof ehdr); - if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG)) - return def_res; - - return (ehdr.e_flags & EF_PPC64_ABI) == 2; -} - -#endif - -/* Generate a ds-form instruction in BUF and return the number of bytes written - - 0 6 11 16 30 32 - | OPCD | RST | RA | DS |XO| */ - -__attribute__((unused)) /* Maybe unused due to conditional compilation. */ -static int -gen_ds_form (uint32_t *buf, int opcd, int rst, int ra, int ds, int xo) -{ - uint32_t insn; - - gdb_assert ((opcd & ~0x3f) == 0); - gdb_assert ((rst & ~0x1f) == 0); - gdb_assert ((ra & ~0x1f) == 0); - gdb_assert ((xo & ~0x3) == 0); - - insn = (rst << 21) | (ra << 16) | (ds & 0xfffc) | (xo & 0x3); - *buf = (opcd << 26) | insn; - return 1; -} - -/* Followings are frequently used ds-form instructions. */ - -#define GEN_STD(buf, rs, ra, offset) gen_ds_form (buf, 62, rs, ra, offset, 0) -#define GEN_STDU(buf, rs, ra, offset) gen_ds_form (buf, 62, rs, ra, offset, 1) -#define GEN_LD(buf, rt, ra, offset) gen_ds_form (buf, 58, rt, ra, offset, 0) -#define GEN_LDU(buf, rt, ra, offset) gen_ds_form (buf, 58, rt, ra, offset, 1) - -/* Generate a d-form instruction in BUF. - - 0 6 11 16 32 - | OPCD | RST | RA | D | */ - -static int -gen_d_form (uint32_t *buf, int opcd, int rst, int ra, int si) -{ - uint32_t insn; - - gdb_assert ((opcd & ~0x3f) == 0); - gdb_assert ((rst & ~0x1f) == 0); - gdb_assert ((ra & ~0x1f) == 0); - - insn = (rst << 21) | (ra << 16) | (si & 0xffff); - *buf = (opcd << 26) | insn; - return 1; -} - -/* Followings are frequently used d-form instructions. */ - -#define GEN_ADDI(buf, rt, ra, si) gen_d_form (buf, 14, rt, ra, si) -#define GEN_ADDIS(buf, rt, ra, si) gen_d_form (buf, 15, rt, ra, si) -#define GEN_LI(buf, rt, si) GEN_ADDI (buf, rt, 0, si) -#define GEN_LIS(buf, rt, si) GEN_ADDIS (buf, rt, 0, si) -#define GEN_ORI(buf, rt, ra, si) gen_d_form (buf, 24, rt, ra, si) -#define GEN_ORIS(buf, rt, ra, si) gen_d_form (buf, 25, rt, ra, si) -#define GEN_LWZ(buf, rt, ra, si) gen_d_form (buf, 32, rt, ra, si) -#define GEN_STW(buf, rt, ra, si) gen_d_form (buf, 36, rt, ra, si) -#define GEN_STWU(buf, rt, ra, si) gen_d_form (buf, 37, rt, ra, si) - -/* Generate a xfx-form instruction in BUF and return the number of bytes - written. - - 0 6 11 21 31 32 - | OPCD | RST | RI | XO |/| */ - -static int -gen_xfx_form (uint32_t *buf, int opcd, int rst, int ri, int xo) -{ - uint32_t insn; - unsigned int n = ((ri & 0x1f) << 5) | ((ri >> 5) & 0x1f); - - gdb_assert ((opcd & ~0x3f) == 0); - gdb_assert ((rst & ~0x1f) == 0); - gdb_assert ((xo & ~0x3ff) == 0); - - insn = (rst << 21) | (n << 11) | (xo << 1); - *buf = (opcd << 26) | insn; - return 1; -} - -/* Followings are frequently used xfx-form instructions. */ - -#define GEN_MFSPR(buf, rt, spr) gen_xfx_form (buf, 31, rt, spr, 339) -#define GEN_MTSPR(buf, rt, spr) gen_xfx_form (buf, 31, rt, spr, 467) -#define GEN_MFCR(buf, rt) gen_xfx_form (buf, 31, rt, 0, 19) -#define GEN_MTCR(buf, rt) gen_xfx_form (buf, 31, rt, 0x3cf, 144) -#define GEN_SYNC(buf, L, E) gen_xfx_form (buf, 31, L & 0x3, \ - E & 0xf, 598) -#define GEN_LWSYNC(buf) GEN_SYNC (buf, 1, 0) - - -/* Generate a x-form instruction in BUF and return the number of bytes written. - - 0 6 11 16 21 31 32 - | OPCD | RST | RA | RB | XO |RC| */ - -static int -gen_x_form (uint32_t *buf, int opcd, int rst, int ra, int rb, int xo, int rc) -{ - uint32_t insn; - - gdb_assert ((opcd & ~0x3f) == 0); - gdb_assert ((rst & ~0x1f) == 0); - gdb_assert ((ra & ~0x1f) == 0); - gdb_assert ((rb & ~0x1f) == 0); - gdb_assert ((xo & ~0x3ff) == 0); - gdb_assert ((rc & ~1) == 0); - - insn = (rst << 21) | (ra << 16) | (rb << 11) | (xo << 1) | rc; - *buf = (opcd << 26) | insn; - return 1; -} - -/* Followings are frequently used x-form instructions. */ - -#define GEN_OR(buf, ra, rs, rb) gen_x_form (buf, 31, rs, ra, rb, 444, 0) -#define GEN_MR(buf, ra, rs) GEN_OR (buf, ra, rs, rs) -#define GEN_LWARX(buf, rt, ra, rb) gen_x_form (buf, 31, rt, ra, rb, 20, 0) -#define GEN_STWCX(buf, rs, ra, rb) gen_x_form (buf, 31, rs, ra, rb, 150, 1) -/* Assume bf = cr7. */ -#define GEN_CMPW(buf, ra, rb) gen_x_form (buf, 31, 28, ra, rb, 0, 0) - - -/* Generate a md-form instruction in BUF and return the number of bytes written. - - 0 6 11 16 21 27 30 31 32 - | OPCD | RS | RA | sh | mb | XO |sh|Rc| */ - -static int -gen_md_form (uint32_t *buf, int opcd, int rs, int ra, int sh, int mb, - int xo, int rc) -{ - uint32_t insn; - unsigned int n = ((mb & 0x1f) << 1) | ((mb >> 5) & 0x1); - unsigned int sh0_4 = sh & 0x1f; - unsigned int sh5 = (sh >> 5) & 1; - - gdb_assert ((opcd & ~0x3f) == 0); - gdb_assert ((rs & ~0x1f) == 0); - gdb_assert ((ra & ~0x1f) == 0); - gdb_assert ((sh & ~0x3f) == 0); - gdb_assert ((mb & ~0x3f) == 0); - gdb_assert ((xo & ~0x7) == 0); - gdb_assert ((rc & ~0x1) == 0); - - insn = (rs << 21) | (ra << 16) | (sh0_4 << 11) | (n << 5) - | (sh5 << 1) | (xo << 2) | (rc & 1); - *buf = (opcd << 26) | insn; - return 1; -} - -/* The following are frequently used md-form instructions. */ - -#define GEN_RLDICL(buf, ra, rs ,sh, mb) \ - gen_md_form (buf, 30, rs, ra, sh, mb, 0, 0) -#define GEN_RLDICR(buf, ra, rs ,sh, mb) \ - gen_md_form (buf, 30, rs, ra, sh, mb, 1, 0) - -/* Generate a i-form instruction in BUF and return the number of bytes written. - - 0 6 30 31 32 - | OPCD | LI |AA|LK| */ - -static int -gen_i_form (uint32_t *buf, int opcd, int li, int aa, int lk) -{ - uint32_t insn; - - gdb_assert ((opcd & ~0x3f) == 0); - - insn = (li & 0x3fffffc) | (aa & 1) | (lk & 1); - *buf = (opcd << 26) | insn; - return 1; -} - -/* The following are frequently used i-form instructions. */ - -#define GEN_B(buf, li) gen_i_form (buf, 18, li, 0, 0) -#define GEN_BL(buf, li) gen_i_form (buf, 18, li, 0, 1) - -/* Generate a b-form instruction in BUF and return the number of bytes written. - - 0 6 11 16 30 31 32 - | OPCD | BO | BI | BD |AA|LK| */ - -static int -gen_b_form (uint32_t *buf, int opcd, int bo, int bi, int bd, - int aa, int lk) -{ - uint32_t insn; - - gdb_assert ((opcd & ~0x3f) == 0); - gdb_assert ((bo & ~0x1f) == 0); - gdb_assert ((bi & ~0x1f) == 0); - - insn = (bo << 21) | (bi << 16) | (bd & 0xfffc) | (aa & 1) | (lk & 1); - *buf = (opcd << 26) | insn; - return 1; -} - -/* The following are frequently used b-form instructions. */ -/* Assume bi = cr7. */ -#define GEN_BNE(buf, bd) gen_b_form (buf, 16, 0x4, (7 << 2) | 2, bd, 0 ,0) - -/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32 - respectively. They are primary used for save/restore GPRs in jump-pad, - not used for bytecode compiling. */ - -#ifdef __powerpc64__ -#define GEN_LOAD(buf, rt, ra, si, is_64) (is_64 ? \ - GEN_LD (buf, rt, ra, si) : \ - GEN_LWZ (buf, rt, ra, si)) -#define GEN_STORE(buf, rt, ra, si, is_64) (is_64 ? \ - GEN_STD (buf, rt, ra, si) : \ - GEN_STW (buf, rt, ra, si)) -#else -#define GEN_LOAD(buf, rt, ra, si, is_64) GEN_LWZ (buf, rt, ra, si) -#define GEN_STORE(buf, rt, ra, si, is_64) GEN_STW (buf, rt, ra, si) -#endif - -/* Generate a sequence of instructions to load IMM in the register REG. - Write the instructions in BUF and return the number of bytes written. */ - -static int -gen_limm (uint32_t *buf, int reg, uint64_t imm, int is_64) -{ - uint32_t *p = buf; - - if ((imm + 32768) < 65536) - { - /* li reg, imm[15:0] */ - p += GEN_LI (p, reg, imm); - } - else if ((imm >> 32) == 0) - { - /* lis reg, imm[31:16] - ori reg, reg, imm[15:0] - rldicl reg, reg, 0, 32 */ - p += GEN_LIS (p, reg, (imm >> 16) & 0xffff); - if ((imm & 0xffff) != 0) - p += GEN_ORI (p, reg, reg, imm & 0xffff); - /* Clear upper 32-bit if sign-bit is set. */ - if (imm & (1u << 31) && is_64) - p += GEN_RLDICL (p, reg, reg, 0, 32); - } - else - { - gdb_assert (is_64); - /* lis reg, - ori reg, reg, - rldicr reg, reg, 32, 31 - oris reg, reg, - ori reg, reg, */ - p += GEN_LIS (p, reg, ((imm >> 48) & 0xffff)); - if (((imm >> 32) & 0xffff) != 0) - p += GEN_ORI (p, reg, reg, ((imm >> 32) & 0xffff)); - p += GEN_RLDICR (p, reg, reg, 32, 31); - if (((imm >> 16) & 0xffff) != 0) - p += GEN_ORIS (p, reg, reg, ((imm >> 16) & 0xffff)); - if ((imm & 0xffff) != 0) - p += GEN_ORI (p, reg, reg, (imm & 0xffff)); - } - - return p - buf; -} - -/* Generate a sequence for atomically exchange at location LOCK. - This code sequence clobbers r6, r7, r8. LOCK is the location for - the atomic-xchg, OLD_VALUE is expected old value stored in the - location, and R_NEW is a register for the new value. */ - -static int -gen_atomic_xchg (uint32_t *buf, CORE_ADDR lock, int old_value, int r_new, - int is_64) -{ - const int r_lock = 6; - const int r_old = 7; - const int r_tmp = 8; - uint32_t *p = buf; - - /* - 1: lwarx TMP, 0, LOCK - cmpwi TMP, OLD - bne 1b - stwcx. NEW, 0, LOCK - bne 1b */ - - p += gen_limm (p, r_lock, lock, is_64); - p += gen_limm (p, r_old, old_value, is_64); - - p += GEN_LWARX (p, r_tmp, 0, r_lock); - p += GEN_CMPW (p, r_tmp, r_old); - p += GEN_BNE (p, -8); - p += GEN_STWCX (p, r_new, 0, r_lock); - p += GEN_BNE (p, -16); - - return p - buf; -} - -/* Generate a sequence of instructions for calling a function - at address of FN. Return the number of bytes are written in BUF. */ - -static int -gen_call (uint32_t *buf, CORE_ADDR fn, int is_64, int is_opd) -{ - uint32_t *p = buf; - - /* Must be called by r12 for caller to calculate TOC address. */ - p += gen_limm (p, 12, fn, is_64); - if (is_opd) - { - p += GEN_LOAD (p, 11, 12, 16, is_64); - p += GEN_LOAD (p, 2, 12, 8, is_64); - p += GEN_LOAD (p, 12, 12, 0, is_64); - } - p += GEN_MTSPR (p, 12, 9); /* mtctr r12 */ - *p++ = 0x4e800421; /* bctrl */ - - return p - buf; -} - -/* Copy the instruction from OLDLOC to *TO, and update *TO to *TO + size - of instruction. This function is used to adjust pc-relative instructions - when copying. */ - -static void -ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc) -{ - uint32_t insn, op6; - long rel, newrel; - - read_inferior_memory (oldloc, (unsigned char *) &insn, 4); - op6 = PPC_OP6 (insn); - - if (op6 == 18 && (insn & 2) == 0) - { - /* branch && AA = 0 */ - rel = PPC_LI (insn); - newrel = (oldloc - *to) + rel; - - /* Out of range. Cannot relocate instruction. */ - if (newrel >= (1 << 25) || newrel < -(1 << 25)) - return; - - insn = (insn & ~0x3fffffc) | (newrel & 0x3fffffc); - } - else if (op6 == 16 && (insn & 2) == 0) - { - /* conditional branch && AA = 0 */ - - /* If the new relocation is too big for even a 26-bit unconditional - branch, there is nothing we can do. Just abort. - - Otherwise, if it can be fit in 16-bit conditional branch, just - copy the instruction and relocate the address. - - If the it's big for conditional-branch (16-bit), try to invert the - condition and jump with 26-bit branch. For example, - - beq .Lgoto - INSN1 - - => - - bne 1f (+8) - b .Lgoto - 1:INSN1 - - After this transform, we are actually jump from *TO+4 instead of *TO, - so check the relocation again because it will be 1-insn farther then - before if *TO is after OLDLOC. - - - For BDNZT (or so) is transformed from - - bdnzt eq, .Lgoto - INSN1 - - => - - bdz 1f (+12) - bf eq, 1f (+8) - b .Lgoto - 1:INSN1 - - See also "BO field encodings". */ - - rel = PPC_BD (insn); - newrel = (oldloc - *to) + rel; - - if (newrel < (1 << 15) && newrel >= -(1 << 15)) - insn = (insn & ~0xfffc) | (newrel & 0xfffc); - else if ((PPC_BO (insn) & 0x14) == 0x4 || (PPC_BO (insn) & 0x14) == 0x10) - { - newrel -= 4; - - /* Out of range. Cannot relocate instruction. */ - if (newrel >= (1 << 25) || newrel < -(1 << 25)) - return; - - if ((PPC_BO (insn) & 0x14) == 0x4) - insn ^= (1 << 24); - else if ((PPC_BO (insn) & 0x14) == 0x10) - insn ^= (1 << 22); - - /* Jump over the unconditional branch. */ - insn = (insn & ~0xfffc) | 0x8; - target_write_memory (*to, (unsigned char *) &insn, 4); - *to += 4; - - /* Build a unconditional branch and copy LK bit. */ - insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3); - target_write_memory (*to, (unsigned char *) &insn, 4); - *to += 4; - - return; - } - else if ((PPC_BO (insn) & 0x14) == 0) - { - uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12; - uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8; - - newrel -= 8; - - /* Out of range. Cannot relocate instruction. */ - if (newrel >= (1 << 25) || newrel < -(1 << 25)) - return; - - /* Copy BI field. */ - bf_insn |= (insn & 0x1f0000); - - /* Invert condition. */ - bdnz_insn |= (insn ^ (1 << 22)) & (1 << 22); - bf_insn |= (insn ^ (1 << 24)) & (1 << 24); - - target_write_memory (*to, (unsigned char *) &bdnz_insn, 4); - *to += 4; - target_write_memory (*to, (unsigned char *) &bf_insn, 4); - *to += 4; - - /* Build a unconditional branch and copy LK bit. */ - insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3); - target_write_memory (*to, (unsigned char *) &insn, 4); - *to += 4; - - return; - } - else /* (BO & 0x14) == 0x14, branch always. */ - { - /* Out of range. Cannot relocate instruction. */ - if (newrel >= (1 << 25) || newrel < -(1 << 25)) - return; - - /* Build a unconditional branch and copy LK bit. */ - insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3); - target_write_memory (*to, (unsigned char *) &insn, 4); - *to += 4; - - return; - } - } - - target_write_memory (*to, (unsigned char *) &insn, 4); - *to += 4; -} - -/* Implement install_fast_tracepoint_jump_pad of target_ops. - See target.h for details. */ - -static int -ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ - uint32_t buf[256]; - uint32_t *p = buf; - int j, offset; - CORE_ADDR buildaddr = *jump_entry; - const CORE_ADDR entryaddr = *jump_entry; - int rsz, min_frame, frame_size, tp_reg; -#ifdef __powerpc64__ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - int is_64 = register_size (regcache->tdesc, 0) == 8; - int is_opd = is_64 && !is_elfv2_inferior (); -#else - int is_64 = 0, is_opd = 0; -#endif - -#ifdef __powerpc64__ - if (is_64) - { - /* Minimum frame size is 32 bytes for ELFv2, and 112 bytes for ELFv1. */ - rsz = 8; - min_frame = 112; - frame_size = (40 * rsz) + min_frame; - tp_reg = 13; - } - else - { -#endif - rsz = 4; - min_frame = 16; - frame_size = (40 * rsz) + min_frame; - tp_reg = 2; -#ifdef __powerpc64__ - } -#endif - - /* Stack frame layout for this jump pad, - - High thread_area (r13/r2) | - tpoint - collecting_t obj - PC/ | +36 - CTR | +35 - LR | +34 - XER | +33 - CR | +32 - R31 | - R29 | - ... | - R1 | +1 - R0 - collected registers - ... | - ... | - Low Back-chain - - - - The code flow of this jump pad, - - 1. Adjust SP - 2. Save GPR and SPR - 3. Prepare argument - 4. Call gdb_collector - 5. Restore GPR and SPR - 6. Restore SP - 7. Build a jump for back to the program - 8. Copy/relocate original instruction - 9. Build a jump for replacing original instruction. */ - - /* Adjust stack pointer. */ - if (is_64) - p += GEN_STDU (p, 1, 1, -frame_size); /* stdu r1,-frame_size(r1) */ - else - p += GEN_STWU (p, 1, 1, -frame_size); /* stwu r1,-frame_size(r1) */ - - /* Store GPRs. Save R1 later, because it had just been modified, but - we want the original value. */ - for (j = 2; j < 32; j++) - p += GEN_STORE (p, j, 1, min_frame + j * rsz, is_64); - p += GEN_STORE (p, 0, 1, min_frame + 0 * rsz, is_64); - /* Set r0 to the original value of r1 before adjusting stack frame, - and then save it. */ - p += GEN_ADDI (p, 0, 1, frame_size); - p += GEN_STORE (p, 0, 1, min_frame + 1 * rsz, is_64); - - /* Save CR, XER, LR, and CTR. */ - p += GEN_MFCR (p, 3); /* mfcr r3 */ - p += GEN_MFSPR (p, 4, 1); /* mfxer r4 */ - p += GEN_MFSPR (p, 5, 8); /* mflr r5 */ - p += GEN_MFSPR (p, 6, 9); /* mfctr r6 */ - p += GEN_STORE (p, 3, 1, min_frame + 32 * rsz, is_64);/* std r3, 32(r1) */ - p += GEN_STORE (p, 4, 1, min_frame + 33 * rsz, is_64);/* std r4, 33(r1) */ - p += GEN_STORE (p, 5, 1, min_frame + 34 * rsz, is_64);/* std r5, 34(r1) */ - p += GEN_STORE (p, 6, 1, min_frame + 35 * rsz, is_64);/* std r6, 35(r1) */ - - /* Save PC */ - p += gen_limm (p, 3, tpaddr, is_64); - p += GEN_STORE (p, 3, 1, min_frame + 36 * rsz, is_64); - - - /* Setup arguments to collector. */ - /* Set r4 to collected registers. */ - p += GEN_ADDI (p, 4, 1, min_frame); - /* Set r3 to TPOINT. */ - p += gen_limm (p, 3, tpoint, is_64); - - /* Prepare collecting_t object for lock. */ - p += GEN_STORE (p, 3, 1, min_frame + 37 * rsz, is_64); - p += GEN_STORE (p, tp_reg, 1, min_frame + 38 * rsz, is_64); - /* Set R5 to collecting object. */ - p += GEN_ADDI (p, 5, 1, 37 * rsz); - - p += GEN_LWSYNC (p); - p += gen_atomic_xchg (p, lockaddr, 0, 5, is_64); - p += GEN_LWSYNC (p); - - /* Call to collector. */ - p += gen_call (p, collector, is_64, is_opd); - - /* Simply write 0 to release the lock. */ - p += gen_limm (p, 3, lockaddr, is_64); - p += gen_limm (p, 4, 0, is_64); - p += GEN_LWSYNC (p); - p += GEN_STORE (p, 4, 3, 0, is_64); - - /* Restore stack and registers. */ - p += GEN_LOAD (p, 3, 1, min_frame + 32 * rsz, is_64); /* ld r3, 32(r1) */ - p += GEN_LOAD (p, 4, 1, min_frame + 33 * rsz, is_64); /* ld r4, 33(r1) */ - p += GEN_LOAD (p, 5, 1, min_frame + 34 * rsz, is_64); /* ld r5, 34(r1) */ - p += GEN_LOAD (p, 6, 1, min_frame + 35 * rsz, is_64); /* ld r6, 35(r1) */ - p += GEN_MTCR (p, 3); /* mtcr r3 */ - p += GEN_MTSPR (p, 4, 1); /* mtxer r4 */ - p += GEN_MTSPR (p, 5, 8); /* mtlr r5 */ - p += GEN_MTSPR (p, 6, 9); /* mtctr r6 */ - - /* Restore GPRs. */ - for (j = 2; j < 32; j++) - p += GEN_LOAD (p, j, 1, min_frame + j * rsz, is_64); - p += GEN_LOAD (p, 0, 1, min_frame + 0 * rsz, is_64); - /* Restore SP. */ - p += GEN_ADDI (p, 1, 1, frame_size); - - /* Flush instructions to inferior memory. */ - target_write_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4); - - /* Now, insert the original instruction to execute in the jump pad. */ - *adjusted_insn_addr = buildaddr + (p - buf) * 4; - *adjusted_insn_addr_end = *adjusted_insn_addr; - ppc_relocate_instruction (adjusted_insn_addr_end, tpaddr); - - /* Verify the relocation size. If should be 4 for normal copy, - 8 or 12 for some conditional branch. */ - if ((*adjusted_insn_addr_end - *adjusted_insn_addr == 0) - || (*adjusted_insn_addr_end - *adjusted_insn_addr > 12)) - { - sprintf (err, "E.Unexpected instruction length = %d" - "when relocate instruction.", - (int) (*adjusted_insn_addr_end - *adjusted_insn_addr)); - return 1; - } - - buildaddr = *adjusted_insn_addr_end; - p = buf; - /* Finally, write a jump back to the program. */ - offset = (tpaddr + 4) - buildaddr; - if (offset >= (1 << 25) || offset < -(1 << 25)) - { - sprintf (err, "E.Jump back from jump pad too far from tracepoint " - "(offset 0x%x > 26-bit).", offset); - return 1; - } - /* b */ - p += GEN_B (p, offset); - target_write_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4); - *jump_entry = buildaddr + (p - buf) * 4; - - /* The jump pad is now built. Wire in a jump to our jump pad. This - is always done last (by our caller actually), so that we can - install fast tracepoints with threads running. This relies on - the agent's atomic write support. */ - offset = entryaddr - tpaddr; - if (offset >= (1 << 25) || offset < -(1 << 25)) - { - sprintf (err, "E.Jump back from jump pad too far from tracepoint " - "(offset 0x%x > 26-bit).", offset); - return 1; - } - /* b */ - GEN_B ((uint32_t *) jjump_pad_insn, offset); - *jjump_pad_insn_size = 4; - - return 0; -} - -/* Returns the minimum instruction length for installing a tracepoint. */ - -static int -ppc_get_min_fast_tracepoint_insn_len (void) -{ - return 4; -} - -/* Emits a given buffer into the target at current_insn_ptr. Length - is in units of 32-bit words. */ - -static void -emit_insns (uint32_t *buf, int n) -{ - n = n * sizeof (uint32_t); - target_write_memory (current_insn_ptr, (unsigned char *) buf, n); - current_insn_ptr += n; -} - -#define __EMIT_ASM(NAME, INSNS) \ - do \ - { \ - extern uint32_t start_bcax_ ## NAME []; \ - extern uint32_t end_bcax_ ## NAME []; \ - emit_insns (start_bcax_ ## NAME, \ - end_bcax_ ## NAME - start_bcax_ ## NAME); \ - __asm__ (".section .text.__ppcbcax\n\t" \ - "start_bcax_" #NAME ":\n\t" \ - INSNS "\n\t" \ - "end_bcax_" #NAME ":\n\t" \ - ".previous\n\t"); \ - } while (0) - -#define _EMIT_ASM(NAME, INSNS) __EMIT_ASM (NAME, INSNS) -#define EMIT_ASM(INSNS) _EMIT_ASM (__LINE__, INSNS) - -/* - - Bytecode execution stack frame - 32-bit - - | LR save area (SP + 4) - SP' -> +- Back chain (SP + 0) - | Save r31 for access saved arguments - | Save r30 for bytecode stack pointer - | Save r4 for incoming argument *value - | Save r3 for incoming argument regs - r30 -> +- Bytecode execution stack - | - | 64-byte (8 doublewords) at initial. - | Expand stack as needed. - | - +- - | Some padding for minimum stack frame and 16-byte alignment. - | 16 bytes. - SP +- Back-chain (SP') - - initial frame size - = 16 + (4 * 4) + 64 - = 96 - - r30 is the stack-pointer for bytecode machine. - It should point to next-empty, so we can use LDU for pop. - r3 is used for cache of the high part of TOP value. - It was the first argument, pointer to regs. - r4 is used for cache of the low part of TOP value. - It was the second argument, pointer to the result. - We should set *result = TOP after leaving this function. - - Note: - * To restore stack at epilogue - => sp = r31 - * To check stack is big enough for bytecode execution. - => r30 - 8 > SP + 8 - * To return execution result. - => 0(r4) = TOP - - */ - -/* Regardless of endian, register 3 is always high part, 4 is low part. - These defines are used when the register pair is stored/loaded. - Likewise, to simplify code, have a similiar define for 5:6. */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define TOP_FIRST "4" -#define TOP_SECOND "3" -#define TMP_FIRST "6" -#define TMP_SECOND "5" -#else -#define TOP_FIRST "3" -#define TOP_SECOND "4" -#define TMP_FIRST "5" -#define TMP_SECOND "6" -#endif - -/* Emit prologue in inferior memory. See above comments. */ - -static void -ppc_emit_prologue (void) -{ - EMIT_ASM (/* Save return address. */ - "mflr 0 \n" - "stw 0, 4(1) \n" - /* Adjust SP. 96 is the initial frame size. */ - "stwu 1, -96(1) \n" - /* Save r30 and incoming arguments. */ - "stw 31, 96-4(1) \n" - "stw 30, 96-8(1) \n" - "stw 4, 96-12(1) \n" - "stw 3, 96-16(1) \n" - /* Point r31 to original r1 for access arguments. */ - "addi 31, 1, 96 \n" - /* Set r30 to pointing stack-top. */ - "addi 30, 1, 64 \n" - /* Initial r3/TOP to 0. */ - "li 3, 0 \n" - "li 4, 0 \n"); -} - -/* Emit epilogue in inferior memory. See above comments. */ - -static void -ppc_emit_epilogue (void) -{ - EMIT_ASM (/* *result = TOP */ - "lwz 5, -12(31) \n" - "stw " TOP_FIRST ", 0(5) \n" - "stw " TOP_SECOND ", 4(5) \n" - /* Restore registers. */ - "lwz 31, -4(31) \n" - "lwz 30, -8(31) \n" - /* Restore SP. */ - "lwz 1, 0(1) \n" - /* Restore LR. */ - "lwz 0, 4(1) \n" - /* Return 0 for no-error. */ - "li 3, 0 \n" - "mtlr 0 \n" - "blr \n"); -} - -/* TOP = stack[--sp] + TOP */ - -static void -ppc_emit_add (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30)\n" - "addc 4, 6, 4 \n" - "adde 3, 5, 3 \n"); -} - -/* TOP = stack[--sp] - TOP */ - -static void -ppc_emit_sub (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "subfc 4, 4, 6 \n" - "subfe 3, 3, 5 \n"); -} - -/* TOP = stack[--sp] * TOP */ - -static void -ppc_emit_mul (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "mulhwu 7, 6, 4 \n" - "mullw 3, 6, 3 \n" - "mullw 5, 4, 5 \n" - "mullw 4, 6, 4 \n" - "add 3, 5, 3 \n" - "add 3, 7, 3 \n"); -} - -/* TOP = stack[--sp] << TOP */ - -static void -ppc_emit_lsh (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "subfic 3, 4, 32\n" /* r3 = 32 - TOP */ - "addi 7, 4, -32\n" /* r7 = TOP - 32 */ - "slw 5, 5, 4\n" /* Shift high part left */ - "slw 4, 6, 4\n" /* Shift low part left */ - "srw 3, 6, 3\n" /* Shift low to high if shift < 32 */ - "slw 7, 6, 7\n" /* Shift low to high if shift >= 32 */ - "or 3, 5, 3\n" - "or 3, 7, 3\n"); /* Assemble high part */ -} - -/* Top = stack[--sp] >> TOP - (Arithmetic shift right) */ - -static void -ppc_emit_rsh_signed (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "addi 7, 4, -32\n" /* r7 = TOP - 32 */ - "sraw 3, 5, 4\n" /* Shift high part right */ - "cmpwi 7, 1\n" - "blt 0, 1f\n" /* If shift <= 32, goto 1: */ - "sraw 4, 5, 7\n" /* Shift high to low */ - "b 2f\n" - "1:\n" - "subfic 7, 4, 32\n" /* r7 = 32 - TOP */ - "srw 4, 6, 4\n" /* Shift low part right */ - "slw 5, 5, 7\n" /* Shift high to low */ - "or 4, 4, 5\n" /* Assemble low part */ - "2:\n"); -} - -/* Top = stack[--sp] >> TOP - (Logical shift right) */ - -static void -ppc_emit_rsh_unsigned (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "subfic 3, 4, 32\n" /* r3 = 32 - TOP */ - "addi 7, 4, -32\n" /* r7 = TOP - 32 */ - "srw 6, 6, 4\n" /* Shift low part right */ - "slw 3, 5, 3\n" /* Shift high to low if shift < 32 */ - "srw 7, 5, 7\n" /* Shift high to low if shift >= 32 */ - "or 6, 6, 3\n" - "srw 3, 5, 4\n" /* Shift high part right */ - "or 4, 6, 7\n"); /* Assemble low part */ -} - -/* Emit code for signed-extension specified by ARG. */ - -static void -ppc_emit_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM ("extsb 4, 4\n" - "srawi 3, 4, 31"); - break; - case 16: - EMIT_ASM ("extsh 4, 4\n" - "srawi 3, 4, 31"); - break; - case 32: - EMIT_ASM ("srawi 3, 4, 31"); - break; - default: - emit_error = 1; - } -} - -/* Emit code for zero-extension specified by ARG. */ - -static void -ppc_emit_zero_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM ("clrlwi 4,4,24\n" - "li 3, 0\n"); - break; - case 16: - EMIT_ASM ("clrlwi 4,4,16\n" - "li 3, 0\n"); - break; - case 32: - EMIT_ASM ("li 3, 0"); - break; - default: - emit_error = 1; - } -} - -/* TOP = !TOP - i.e., TOP = (TOP == 0) ? 1 : 0; */ - -static void -ppc_emit_log_not (void) -{ - EMIT_ASM ("or 4, 3, 4 \n" - "cntlzw 4, 4 \n" - "srwi 4, 4, 5 \n" - "li 3, 0 \n"); -} - -/* TOP = stack[--sp] & TOP */ - -static void -ppc_emit_bit_and (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "and 4, 6, 4 \n" - "and 3, 5, 3 \n"); -} - -/* TOP = stack[--sp] | TOP */ - -static void -ppc_emit_bit_or (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "or 4, 6, 4 \n" - "or 3, 5, 3 \n"); -} - -/* TOP = stack[--sp] ^ TOP */ - -static void -ppc_emit_bit_xor (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "xor 4, 6, 4 \n" - "xor 3, 5, 3 \n"); -} - -/* TOP = ~TOP - i.e., TOP = ~(TOP | TOP) */ - -static void -ppc_emit_bit_not (void) -{ - EMIT_ASM ("nor 3, 3, 3 \n" - "nor 4, 4, 4 \n"); -} - -/* TOP = stack[--sp] == TOP */ - -static void -ppc_emit_equal (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "xor 4, 6, 4 \n" - "xor 3, 5, 3 \n" - "or 4, 3, 4 \n" - "cntlzw 4, 4 \n" - "srwi 4, 4, 5 \n" - "li 3, 0 \n"); -} - -/* TOP = stack[--sp] < TOP - (Signed comparison) */ - -static void -ppc_emit_less_signed (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "cmplw 6, 6, 4 \n" - "cmpw 7, 5, 3 \n" - /* CR6 bit 0 = low less and high equal */ - "crand 6*4+0, 6*4+0, 7*4+2\n" - /* CR7 bit 0 = (low less and high equal) or high less */ - "cror 7*4+0, 7*4+0, 6*4+0\n" - "mfcr 4 \n" - "rlwinm 4, 4, 29, 31, 31 \n" - "li 3, 0 \n"); -} - -/* TOP = stack[--sp] < TOP - (Unsigned comparison) */ - -static void -ppc_emit_less_unsigned (void) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "cmplw 6, 6, 4 \n" - "cmplw 7, 5, 3 \n" - /* CR6 bit 0 = low less and high equal */ - "crand 6*4+0, 6*4+0, 7*4+2\n" - /* CR7 bit 0 = (low less and high equal) or high less */ - "cror 7*4+0, 7*4+0, 6*4+0\n" - "mfcr 4 \n" - "rlwinm 4, 4, 29, 31, 31 \n" - "li 3, 0 \n"); -} - -/* Access the memory address in TOP in size of SIZE. - Zero-extend the read value. */ - -static void -ppc_emit_ref (int size) -{ - switch (size) - { - case 1: - EMIT_ASM ("lbz 4, 0(4)\n" - "li 3, 0"); - break; - case 2: - EMIT_ASM ("lhz 4, 0(4)\n" - "li 3, 0"); - break; - case 4: - EMIT_ASM ("lwz 4, 0(4)\n" - "li 3, 0"); - break; - case 8: - if (__BYTE_ORDER == __LITTLE_ENDIAN) - EMIT_ASM ("lwz 3, 4(4)\n" - "lwz 4, 0(4)"); - else - EMIT_ASM ("lwz 3, 0(4)\n" - "lwz 4, 4(4)"); - break; - } -} - -/* TOP = NUM */ - -static void -ppc_emit_const (LONGEST num) -{ - uint32_t buf[10]; - uint32_t *p = buf; - - p += gen_limm (p, 3, num >> 32 & 0xffffffff, 0); - p += gen_limm (p, 4, num & 0xffffffff, 0); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Set TOP to the value of register REG by calling get_raw_reg function - with two argument, collected buffer and register number. */ - -static void -ppc_emit_reg (int reg) -{ - uint32_t buf[13]; - uint32_t *p = buf; - - /* fctx->regs is passed in r3 and then saved in -16(31). */ - p += GEN_LWZ (p, 3, 31, -16); - p += GEN_LI (p, 4, reg); /* li r4, reg */ - p += gen_call (p, get_raw_reg_func_addr (), 0, 0); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); - - if (__BYTE_ORDER == __LITTLE_ENDIAN) - { - EMIT_ASM ("mr 5, 4\n" - "mr 4, 3\n" - "mr 3, 5\n"); - } -} - -/* TOP = stack[--sp] */ - -static void -ppc_emit_pop (void) -{ - EMIT_ASM ("lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30) \n"); -} - -/* stack[sp++] = TOP - - Because we may use up bytecode stack, expand 8 doublewords more - if needed. */ - -static void -ppc_emit_stack_flush (void) -{ - /* Make sure bytecode stack is big enough before push. - Otherwise, expand 64-byte more. */ - - EMIT_ASM (" stw " TOP_FIRST ", 0(30) \n" - " stw " TOP_SECOND ", 4(30)\n" - " addi 5, 30, -(8 + 8) \n" - " cmpw 7, 5, 1 \n" - " bgt 7, 1f \n" - " stwu 31, -64(1) \n" - "1:addi 30, 30, -8 \n"); -} - -/* Swap TOP and stack[sp-1] */ - -static void -ppc_emit_swap (void) -{ - EMIT_ASM ("lwz " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 12(30) \n" - "stw " TOP_FIRST ", 8(30) \n" - "stw " TOP_SECOND ", 12(30) \n" - "mr 3, 5 \n" - "mr 4, 6 \n"); -} - -/* Discard N elements in the stack. Also used for ppc64. */ - -static void -ppc_emit_stack_adjust (int n) -{ - uint32_t buf[6]; - uint32_t *p = buf; - - n = n << 3; - if ((n >> 15) != 0) - { - emit_error = 1; - return; - } - - p += GEN_ADDI (p, 30, 30, n); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Call function FN. */ - -static void -ppc_emit_call (CORE_ADDR fn) -{ - uint32_t buf[11]; - uint32_t *p = buf; - - p += gen_call (p, fn, 0, 0); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* FN's prototype is `LONGEST(*fn)(int)'. - TOP = fn (arg1) - */ - -static void -ppc_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[15]; - uint32_t *p = buf; - - /* Setup argument. arg1 is a 16-bit value. */ - p += gen_limm (p, 3, (uint32_t) arg1, 0); - p += gen_call (p, fn, 0, 0); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); - - if (__BYTE_ORDER == __LITTLE_ENDIAN) - { - EMIT_ASM ("mr 5, 4\n" - "mr 4, 3\n" - "mr 3, 5\n"); - } -} - -/* FN's prototype is `void(*fn)(int,LONGEST)'. - fn (arg1, TOP) - - TOP should be preserved/restored before/after the call. */ - -static void -ppc_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[21]; - uint32_t *p = buf; - - /* Save TOP. 0(30) is next-empty. */ - p += GEN_STW (p, 3, 30, 0); - p += GEN_STW (p, 4, 30, 4); - - /* Setup argument. arg1 is a 16-bit value. */ - if (__BYTE_ORDER == __LITTLE_ENDIAN) - { - p += GEN_MR (p, 5, 4); - p += GEN_MR (p, 6, 3); - } - else - { - p += GEN_MR (p, 5, 3); - p += GEN_MR (p, 6, 4); - } - p += gen_limm (p, 3, (uint32_t) arg1, 0); - p += gen_call (p, fn, 0, 0); - - /* Restore TOP */ - p += GEN_LWZ (p, 3, 30, 0); - p += GEN_LWZ (p, 4, 30, 4); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Note in the following goto ops: - - When emitting goto, the target address is later relocated by - write_goto_address. OFFSET_P is the offset of the branch instruction - in the code sequence, and SIZE_P is how to relocate the instruction, - recognized by ppc_write_goto_address. In current implementation, - SIZE can be either 24 or 14 for branch of conditional-branch instruction. - */ - -/* If TOP is true, goto somewhere. Otherwise, just fall-through. */ - -static void -ppc_emit_if_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("or. 3, 3, 4 \n" - "lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30) \n" - "1:bne 0, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Unconditional goto. Also used for ppc64. */ - -static void -ppc_emit_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("1:b 1b"); - - if (offset_p) - *offset_p = 0; - if (size_p) - *size_p = 24; -} - -/* Goto if stack[--sp] == TOP */ - -static void -ppc_emit_eq_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "xor 4, 6, 4 \n" - "xor 3, 5, 3 \n" - "or. 3, 3, 4 \n" - "lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30) \n" - "1:beq 0, 1b \n"); - - if (offset_p) - *offset_p = 28; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] != TOP */ - -static void -ppc_emit_ne_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "xor 4, 6, 4 \n" - "xor 3, 5, 3 \n" - "or. 3, 3, 4 \n" - "lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30) \n" - "1:bne 0, 1b \n"); - - if (offset_p) - *offset_p = 28; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] < TOP */ - -static void -ppc_emit_lt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "cmplw 6, 6, 4 \n" - "cmpw 7, 5, 3 \n" - /* CR6 bit 0 = low less and high equal */ - "crand 6*4+0, 6*4+0, 7*4+2\n" - /* CR7 bit 0 = (low less and high equal) or high less */ - "cror 7*4+0, 7*4+0, 6*4+0\n" - "lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30)\n" - "1:blt 7, 1b \n"); - - if (offset_p) - *offset_p = 32; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] <= TOP */ - -static void -ppc_emit_le_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "cmplw 6, 6, 4 \n" - "cmpw 7, 5, 3 \n" - /* CR6 bit 0 = low less/equal and high equal */ - "crandc 6*4+0, 7*4+2, 6*4+1\n" - /* CR7 bit 0 = (low less/eq and high equal) or high less */ - "cror 7*4+0, 7*4+0, 6*4+0\n" - "lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30)\n" - "1:blt 7, 1b \n"); - - if (offset_p) - *offset_p = 32; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] > TOP */ - -static void -ppc_emit_gt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "cmplw 6, 6, 4 \n" - "cmpw 7, 5, 3 \n" - /* CR6 bit 0 = low greater and high equal */ - "crand 6*4+0, 6*4+1, 7*4+2\n" - /* CR7 bit 0 = (low greater and high equal) or high greater */ - "cror 7*4+0, 7*4+1, 6*4+0\n" - "lwzu " TOP_FIRST ", 8(30) \n" - "lwz " TOP_SECOND ", 4(30)\n" - "1:blt 7, 1b \n"); - - if (offset_p) - *offset_p = 32; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] >= TOP */ - -static void -ppc_emit_ge_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" - "lwz " TMP_SECOND ", 4(30) \n" - "cmplw 6, 6, 4 \n" - "cmpw 7, 5, 3 \n" - /* CR6 bit 0 = low ge and high equal */ - "crandc 6*4+0, 7*4+2, 6*4+0\n" - /* CR7 bit 0 = (low ge and high equal) or high greater */ - "cror 7*4+0, 7*4+1, 6*4+0\n" - "lwzu " TOP_FIRST ", 8(30)\n" - "lwz " TOP_SECOND ", 4(30)\n" - "1:blt 7, 1b \n"); - - if (offset_p) - *offset_p = 32; - if (size_p) - *size_p = 14; -} - -/* Relocate previous emitted branch instruction. FROM is the address - of the branch instruction, TO is the goto target address, and SIZE - if the value we set by *SIZE_P before. Currently, it is either - 24 or 14 of branch and conditional-branch instruction. - Also used for ppc64. */ - -static void -ppc_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) -{ - long rel = to - from; - uint32_t insn; - int opcd; - - read_inferior_memory (from, (unsigned char *) &insn, 4); - opcd = (insn >> 26) & 0x3f; - - switch (size) - { - case 14: - if (opcd != 16 - || (rel >= (1 << 15) || rel < -(1 << 15))) - emit_error = 1; - insn = (insn & ~0xfffc) | (rel & 0xfffc); - break; - case 24: - if (opcd != 18 - || (rel >= (1 << 25) || rel < -(1 << 25))) - emit_error = 1; - insn = (insn & ~0x3fffffc) | (rel & 0x3fffffc); - break; - default: - emit_error = 1; - } - - if (!emit_error) - target_write_memory (from, (unsigned char *) &insn, 4); -} - -/* Table of emit ops for 32-bit. */ - -static struct emit_ops ppc_emit_ops_impl = -{ - ppc_emit_prologue, - ppc_emit_epilogue, - ppc_emit_add, - ppc_emit_sub, - ppc_emit_mul, - ppc_emit_lsh, - ppc_emit_rsh_signed, - ppc_emit_rsh_unsigned, - ppc_emit_ext, - ppc_emit_log_not, - ppc_emit_bit_and, - ppc_emit_bit_or, - ppc_emit_bit_xor, - ppc_emit_bit_not, - ppc_emit_equal, - ppc_emit_less_signed, - ppc_emit_less_unsigned, - ppc_emit_ref, - ppc_emit_if_goto, - ppc_emit_goto, - ppc_write_goto_address, - ppc_emit_const, - ppc_emit_call, - ppc_emit_reg, - ppc_emit_pop, - ppc_emit_stack_flush, - ppc_emit_zero_ext, - ppc_emit_swap, - ppc_emit_stack_adjust, - ppc_emit_int_call_1, - ppc_emit_void_call_2, - ppc_emit_eq_goto, - ppc_emit_ne_goto, - ppc_emit_lt_goto, - ppc_emit_le_goto, - ppc_emit_gt_goto, - ppc_emit_ge_goto -}; - -#ifdef __powerpc64__ - -/* - - Bytecode execution stack frame - 64-bit - - | LR save area (SP + 16) - | CR save area (SP + 8) - SP' -> +- Back chain (SP + 0) - | Save r31 for access saved arguments - | Save r30 for bytecode stack pointer - | Save r4 for incoming argument *value - | Save r3 for incoming argument regs - r30 -> +- Bytecode execution stack - | - | 64-byte (8 doublewords) at initial. - | Expand stack as needed. - | - +- - | Some padding for minimum stack frame. - | 112 for ELFv1. - SP +- Back-chain (SP') - - initial frame size - = 112 + (4 * 8) + 64 - = 208 - - r30 is the stack-pointer for bytecode machine. - It should point to next-empty, so we can use LDU for pop. - r3 is used for cache of TOP value. - It was the first argument, pointer to regs. - r4 is the second argument, pointer to the result. - We should set *result = TOP after leaving this function. - - Note: - * To restore stack at epilogue - => sp = r31 - * To check stack is big enough for bytecode execution. - => r30 - 8 > SP + 112 - * To return execution result. - => 0(r4) = TOP - - */ - -/* Emit prologue in inferior memory. See above comments. */ - -static void -ppc64v1_emit_prologue (void) -{ - /* On ELFv1, function pointers really point to function descriptor, - so emit one here. We don't care about contents of words 1 and 2, - so let them just overlap out code. */ - uint64_t opd = current_insn_ptr + 8; - uint32_t buf[2]; - - /* Mind the strict aliasing rules. */ - memcpy (buf, &opd, sizeof buf); - emit_insns(buf, 2); - EMIT_ASM (/* Save return address. */ - "mflr 0 \n" - "std 0, 16(1) \n" - /* Save r30 and incoming arguments. */ - "std 31, -8(1) \n" - "std 30, -16(1) \n" - "std 4, -24(1) \n" - "std 3, -32(1) \n" - /* Point r31 to current r1 for access arguments. */ - "mr 31, 1 \n" - /* Adjust SP. 208 is the initial frame size. */ - "stdu 1, -208(1) \n" - /* Set r30 to pointing stack-top. */ - "addi 30, 1, 168 \n" - /* Initial r3/TOP to 0. */ - "li 3, 0 \n"); -} - -/* Emit prologue in inferior memory. See above comments. */ - -static void -ppc64v2_emit_prologue (void) -{ - EMIT_ASM (/* Save return address. */ - "mflr 0 \n" - "std 0, 16(1) \n" - /* Save r30 and incoming arguments. */ - "std 31, -8(1) \n" - "std 30, -16(1) \n" - "std 4, -24(1) \n" - "std 3, -32(1) \n" - /* Point r31 to current r1 for access arguments. */ - "mr 31, 1 \n" - /* Adjust SP. 208 is the initial frame size. */ - "stdu 1, -208(1) \n" - /* Set r30 to pointing stack-top. */ - "addi 30, 1, 168 \n" - /* Initial r3/TOP to 0. */ - "li 3, 0 \n"); -} - -/* Emit epilogue in inferior memory. See above comments. */ - -static void -ppc64_emit_epilogue (void) -{ - EMIT_ASM (/* Restore SP. */ - "ld 1, 0(1) \n" - /* *result = TOP */ - "ld 4, -24(1) \n" - "std 3, 0(4) \n" - /* Restore registers. */ - "ld 31, -8(1) \n" - "ld 30, -16(1) \n" - /* Restore LR. */ - "ld 0, 16(1) \n" - /* Return 0 for no-error. */ - "li 3, 0 \n" - "mtlr 0 \n" - "blr \n"); -} - -/* TOP = stack[--sp] + TOP */ - -static void -ppc64_emit_add (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "add 3, 4, 3 \n"); -} - -/* TOP = stack[--sp] - TOP */ - -static void -ppc64_emit_sub (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "sub 3, 4, 3 \n"); -} - -/* TOP = stack[--sp] * TOP */ - -static void -ppc64_emit_mul (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "mulld 3, 4, 3 \n"); -} - -/* TOP = stack[--sp] << TOP */ - -static void -ppc64_emit_lsh (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "sld 3, 4, 3 \n"); -} - -/* Top = stack[--sp] >> TOP - (Arithmetic shift right) */ - -static void -ppc64_emit_rsh_signed (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "srad 3, 4, 3 \n"); -} - -/* Top = stack[--sp] >> TOP - (Logical shift right) */ - -static void -ppc64_emit_rsh_unsigned (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "srd 3, 4, 3 \n"); -} - -/* Emit code for signed-extension specified by ARG. */ - -static void -ppc64_emit_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM ("extsb 3, 3"); - break; - case 16: - EMIT_ASM ("extsh 3, 3"); - break; - case 32: - EMIT_ASM ("extsw 3, 3"); - break; - default: - emit_error = 1; - } -} - -/* Emit code for zero-extension specified by ARG. */ - -static void -ppc64_emit_zero_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM ("rldicl 3,3,0,56"); - break; - case 16: - EMIT_ASM ("rldicl 3,3,0,48"); - break; - case 32: - EMIT_ASM ("rldicl 3,3,0,32"); - break; - default: - emit_error = 1; - } -} - -/* TOP = !TOP - i.e., TOP = (TOP == 0) ? 1 : 0; */ - -static void -ppc64_emit_log_not (void) -{ - EMIT_ASM ("cntlzd 3, 3 \n" - "srdi 3, 3, 6 \n"); -} - -/* TOP = stack[--sp] & TOP */ - -static void -ppc64_emit_bit_and (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "and 3, 4, 3 \n"); -} - -/* TOP = stack[--sp] | TOP */ - -static void -ppc64_emit_bit_or (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "or 3, 4, 3 \n"); -} - -/* TOP = stack[--sp] ^ TOP */ - -static void -ppc64_emit_bit_xor (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "xor 3, 4, 3 \n"); -} - -/* TOP = ~TOP - i.e., TOP = ~(TOP | TOP) */ - -static void -ppc64_emit_bit_not (void) -{ - EMIT_ASM ("nor 3, 3, 3 \n"); -} - -/* TOP = stack[--sp] == TOP */ - -static void -ppc64_emit_equal (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "xor 3, 3, 4 \n" - "cntlzd 3, 3 \n" - "srdi 3, 3, 6 \n"); -} - -/* TOP = stack[--sp] < TOP - (Signed comparison) */ - -static void -ppc64_emit_less_signed (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "mfcr 3 \n" - "rlwinm 3, 3, 29, 31, 31 \n"); -} - -/* TOP = stack[--sp] < TOP - (Unsigned comparison) */ - -static void -ppc64_emit_less_unsigned (void) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpld 7, 4, 3 \n" - "mfcr 3 \n" - "rlwinm 3, 3, 29, 31, 31 \n"); -} - -/* Access the memory address in TOP in size of SIZE. - Zero-extend the read value. */ - -static void -ppc64_emit_ref (int size) -{ - switch (size) - { - case 1: - EMIT_ASM ("lbz 3, 0(3)"); - break; - case 2: - EMIT_ASM ("lhz 3, 0(3)"); - break; - case 4: - EMIT_ASM ("lwz 3, 0(3)"); - break; - case 8: - EMIT_ASM ("ld 3, 0(3)"); - break; - } -} - -/* TOP = NUM */ - -static void -ppc64_emit_const (LONGEST num) -{ - uint32_t buf[5]; - uint32_t *p = buf; - - p += gen_limm (p, 3, num, 1); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Set TOP to the value of register REG by calling get_raw_reg function - with two argument, collected buffer and register number. */ - -static void -ppc64v1_emit_reg (int reg) -{ - uint32_t buf[15]; - uint32_t *p = buf; - - /* fctx->regs is passed in r3 and then saved in 176(1). */ - p += GEN_LD (p, 3, 31, -32); - p += GEN_LI (p, 4, reg); - p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ - p += gen_call (p, get_raw_reg_func_addr (), 1, 1); - p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Likewise, for ELFv2. */ - -static void -ppc64v2_emit_reg (int reg) -{ - uint32_t buf[12]; - uint32_t *p = buf; - - /* fctx->regs is passed in r3 and then saved in 176(1). */ - p += GEN_LD (p, 3, 31, -32); - p += GEN_LI (p, 4, reg); - p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ - p += gen_call (p, get_raw_reg_func_addr (), 1, 0); - p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* TOP = stack[--sp] */ - -static void -ppc64_emit_pop (void) -{ - EMIT_ASM ("ldu 3, 8(30)"); -} - -/* stack[sp++] = TOP - - Because we may use up bytecode stack, expand 8 doublewords more - if needed. */ - -static void -ppc64_emit_stack_flush (void) -{ - /* Make sure bytecode stack is big enough before push. - Otherwise, expand 64-byte more. */ - - EMIT_ASM (" std 3, 0(30) \n" - " addi 4, 30, -(112 + 8) \n" - " cmpd 7, 4, 1 \n" - " bgt 7, 1f \n" - " stdu 31, -64(1) \n" - "1:addi 30, 30, -8 \n"); -} - -/* Swap TOP and stack[sp-1] */ - -static void -ppc64_emit_swap (void) -{ - EMIT_ASM ("ld 4, 8(30) \n" - "std 3, 8(30) \n" - "mr 3, 4 \n"); -} - -/* Call function FN - ELFv1. */ - -static void -ppc64v1_emit_call (CORE_ADDR fn) -{ - uint32_t buf[13]; - uint32_t *p = buf; - - p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ - p += gen_call (p, fn, 1, 1); - p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Call function FN - ELFv2. */ - -static void -ppc64v2_emit_call (CORE_ADDR fn) -{ - uint32_t buf[10]; - uint32_t *p = buf; - - p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ - p += gen_call (p, fn, 1, 0); - p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* FN's prototype is `LONGEST(*fn)(int)'. - TOP = fn (arg1) - */ - -static void -ppc64v1_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[13]; - uint32_t *p = buf; - - /* Setup argument. arg1 is a 16-bit value. */ - p += gen_limm (p, 3, arg1, 1); - p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ - p += gen_call (p, fn, 1, 1); - p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Likewise for ELFv2. */ - -static void -ppc64v2_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[10]; - uint32_t *p = buf; - - /* Setup argument. arg1 is a 16-bit value. */ - p += gen_limm (p, 3, arg1, 1); - p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ - p += gen_call (p, fn, 1, 0); - p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* FN's prototype is `void(*fn)(int,LONGEST)'. - fn (arg1, TOP) - - TOP should be preserved/restored before/after the call. */ - -static void -ppc64v1_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[17]; - uint32_t *p = buf; - - /* Save TOP. 0(30) is next-empty. */ - p += GEN_STD (p, 3, 30, 0); - - /* Setup argument. arg1 is a 16-bit value. */ - p += GEN_MR (p, 4, 3); /* mr r4, r3 */ - p += gen_limm (p, 3, arg1, 1); - p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ - p += gen_call (p, fn, 1, 1); - p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ - - /* Restore TOP */ - p += GEN_LD (p, 3, 30, 0); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* Likewise for ELFv2. */ - -static void -ppc64v2_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - uint32_t buf[14]; - uint32_t *p = buf; - - /* Save TOP. 0(30) is next-empty. */ - p += GEN_STD (p, 3, 30, 0); - - /* Setup argument. arg1 is a 16-bit value. */ - p += GEN_MR (p, 4, 3); /* mr r4, r3 */ - p += gen_limm (p, 3, arg1, 1); - p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ - p += gen_call (p, fn, 1, 0); - p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ - - /* Restore TOP */ - p += GEN_LD (p, 3, 30, 0); - - emit_insns (buf, p - buf); - gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); -} - -/* If TOP is true, goto somewhere. Otherwise, just fall-through. */ - -static void -ppc64_emit_if_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("cmpdi 7, 3, 0 \n" - "ldu 3, 8(30) \n" - "1:bne 7, 1b \n"); - - if (offset_p) - *offset_p = 8; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] == TOP */ - -static void -ppc64_emit_eq_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "ldu 3, 8(30) \n" - "1:beq 7, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] != TOP */ - -static void -ppc64_emit_ne_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "ldu 3, 8(30) \n" - "1:bne 7, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] < TOP */ - -static void -ppc64_emit_lt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "ldu 3, 8(30) \n" - "1:blt 7, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] <= TOP */ - -static void -ppc64_emit_le_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "ldu 3, 8(30) \n" - "1:ble 7, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] > TOP */ - -static void -ppc64_emit_gt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "ldu 3, 8(30) \n" - "1:bgt 7, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Goto if stack[--sp] >= TOP */ - -static void -ppc64_emit_ge_goto (int *offset_p, int *size_p) -{ - EMIT_ASM ("ldu 4, 8(30) \n" - "cmpd 7, 4, 3 \n" - "ldu 3, 8(30) \n" - "1:bge 7, 1b \n"); - - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 14; -} - -/* Table of emit ops for 64-bit ELFv1. */ - -static struct emit_ops ppc64v1_emit_ops_impl = -{ - ppc64v1_emit_prologue, - ppc64_emit_epilogue, - ppc64_emit_add, - ppc64_emit_sub, - ppc64_emit_mul, - ppc64_emit_lsh, - ppc64_emit_rsh_signed, - ppc64_emit_rsh_unsigned, - ppc64_emit_ext, - ppc64_emit_log_not, - ppc64_emit_bit_and, - ppc64_emit_bit_or, - ppc64_emit_bit_xor, - ppc64_emit_bit_not, - ppc64_emit_equal, - ppc64_emit_less_signed, - ppc64_emit_less_unsigned, - ppc64_emit_ref, - ppc64_emit_if_goto, - ppc_emit_goto, - ppc_write_goto_address, - ppc64_emit_const, - ppc64v1_emit_call, - ppc64v1_emit_reg, - ppc64_emit_pop, - ppc64_emit_stack_flush, - ppc64_emit_zero_ext, - ppc64_emit_swap, - ppc_emit_stack_adjust, - ppc64v1_emit_int_call_1, - ppc64v1_emit_void_call_2, - ppc64_emit_eq_goto, - ppc64_emit_ne_goto, - ppc64_emit_lt_goto, - ppc64_emit_le_goto, - ppc64_emit_gt_goto, - ppc64_emit_ge_goto -}; - -/* Table of emit ops for 64-bit ELFv2. */ - -static struct emit_ops ppc64v2_emit_ops_impl = -{ - ppc64v2_emit_prologue, - ppc64_emit_epilogue, - ppc64_emit_add, - ppc64_emit_sub, - ppc64_emit_mul, - ppc64_emit_lsh, - ppc64_emit_rsh_signed, - ppc64_emit_rsh_unsigned, - ppc64_emit_ext, - ppc64_emit_log_not, - ppc64_emit_bit_and, - ppc64_emit_bit_or, - ppc64_emit_bit_xor, - ppc64_emit_bit_not, - ppc64_emit_equal, - ppc64_emit_less_signed, - ppc64_emit_less_unsigned, - ppc64_emit_ref, - ppc64_emit_if_goto, - ppc_emit_goto, - ppc_write_goto_address, - ppc64_emit_const, - ppc64v2_emit_call, - ppc64v2_emit_reg, - ppc64_emit_pop, - ppc64_emit_stack_flush, - ppc64_emit_zero_ext, - ppc64_emit_swap, - ppc_emit_stack_adjust, - ppc64v2_emit_int_call_1, - ppc64v2_emit_void_call_2, - ppc64_emit_eq_goto, - ppc64_emit_ne_goto, - ppc64_emit_lt_goto, - ppc64_emit_le_goto, - ppc64_emit_gt_goto, - ppc64_emit_ge_goto -}; - -#endif - -/* Implementation of linux_target_ops method "emit_ops". */ - -static struct emit_ops * -ppc_emit_ops (void) -{ -#ifdef __powerpc64__ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - if (register_size (regcache->tdesc, 0) == 8) - { - if (is_elfv2_inferior ()) - return &ppc64v2_emit_ops_impl; - else - return &ppc64v1_emit_ops_impl; - } -#endif - return &ppc_emit_ops_impl; -} - -/* Implementation of linux_target_ops method "get_ipa_tdesc_idx". */ - -static int -ppc_get_ipa_tdesc_idx (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - const struct target_desc *tdesc = regcache->tdesc; - -#ifdef __powerpc64__ - if (tdesc == tdesc_powerpc_64l) - return PPC_TDESC_BASE; - if (tdesc == tdesc_powerpc_altivec64l) - return PPC_TDESC_ALTIVEC; - if (tdesc == tdesc_powerpc_vsx64l) - return PPC_TDESC_VSX; - if (tdesc == tdesc_powerpc_isa205_64l) - return PPC_TDESC_ISA205; - if (tdesc == tdesc_powerpc_isa205_altivec64l) - return PPC_TDESC_ISA205_ALTIVEC; - if (tdesc == tdesc_powerpc_isa205_vsx64l) - return PPC_TDESC_ISA205_VSX; - if (tdesc == tdesc_powerpc_isa205_ppr_dscr_vsx64l) - return PPC_TDESC_ISA205_PPR_DSCR_VSX; - if (tdesc == tdesc_powerpc_isa207_vsx64l) - return PPC_TDESC_ISA207_VSX; - if (tdesc == tdesc_powerpc_isa207_htm_vsx64l) - return PPC_TDESC_ISA207_HTM_VSX; -#endif - - if (tdesc == tdesc_powerpc_32l) - return PPC_TDESC_BASE; - if (tdesc == tdesc_powerpc_altivec32l) - return PPC_TDESC_ALTIVEC; - if (tdesc == tdesc_powerpc_vsx32l) - return PPC_TDESC_VSX; - if (tdesc == tdesc_powerpc_isa205_32l) - return PPC_TDESC_ISA205; - if (tdesc == tdesc_powerpc_isa205_altivec32l) - return PPC_TDESC_ISA205_ALTIVEC; - if (tdesc == tdesc_powerpc_isa205_vsx32l) - return PPC_TDESC_ISA205_VSX; - if (tdesc == tdesc_powerpc_isa205_ppr_dscr_vsx32l) - return PPC_TDESC_ISA205_PPR_DSCR_VSX; - if (tdesc == tdesc_powerpc_isa207_vsx32l) - return PPC_TDESC_ISA207_VSX; - if (tdesc == tdesc_powerpc_isa207_htm_vsx32l) - return PPC_TDESC_ISA207_HTM_VSX; - if (tdesc == tdesc_powerpc_e500l) - return PPC_TDESC_E500; - - return 0; -} - -struct linux_target_ops the_low_target = { - ppc_arch_setup, - ppc_regs_info, - ppc_cannot_fetch_register, - ppc_cannot_store_register, - NULL, /* fetch_register */ - ppc_get_pc, - ppc_set_pc, - NULL, /* breakpoint_kind_from_pc */ - ppc_sw_breakpoint_from_kind, - NULL, - 0, - ppc_breakpoint_at, - ppc_supports_z_point_type, - ppc_insert_point, - ppc_remove_point, - NULL, - NULL, - ppc_collect_ptrace_register, - ppc_supply_ptrace_register, - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - ppc_supports_tracepoints, - ppc_get_thread_area, - ppc_install_fast_tracepoint_jump_pad, - ppc_emit_ops, - ppc_get_min_fast_tracepoint_insn_len, - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - ppc_supports_hardware_single_step, - NULL, /* get_syscall_trapinfo */ - ppc_get_ipa_tdesc_idx, -}; - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ - - init_registers_powerpc_32l (); - init_registers_powerpc_altivec32l (); - init_registers_powerpc_vsx32l (); - init_registers_powerpc_isa205_32l (); - init_registers_powerpc_isa205_altivec32l (); - init_registers_powerpc_isa205_vsx32l (); - init_registers_powerpc_isa205_ppr_dscr_vsx32l (); - init_registers_powerpc_isa207_vsx32l (); - init_registers_powerpc_isa207_htm_vsx32l (); - init_registers_powerpc_e500l (); -#if __powerpc64__ - init_registers_powerpc_64l (); - init_registers_powerpc_altivec64l (); - init_registers_powerpc_vsx64l (); - init_registers_powerpc_isa205_64l (); - init_registers_powerpc_isa205_altivec64l (); - init_registers_powerpc_isa205_vsx64l (); - init_registers_powerpc_isa205_ppr_dscr_vsx64l (); - init_registers_powerpc_isa207_vsx64l (); - init_registers_powerpc_isa207_htm_vsx64l (); -#endif - - initialize_regsets_info (&ppc_regsets_info); -} diff --git a/gdb/gdbserver/linux-ppc-tdesc-init.h b/gdb/gdbserver/linux-ppc-tdesc-init.h deleted file mode 100644 index 3afd78baee3..00000000000 --- a/gdb/gdbserver/linux-ppc-tdesc-init.h +++ /dev/null @@ -1,106 +0,0 @@ -/* Low level support for ppc, shared between gdbserver and IPA. - - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_PPC_TDESC_INIT_H -#define GDBSERVER_LINUX_PPC_TDESC_INIT_H - -/* Note: since IPA obviously knows what ABI it's running on (32 vs 64), - it's sufficient to pass only the register set here. This, together with - the ABI known at IPA compile time, maps to a tdesc. */ - -enum ppc_linux_tdesc { - PPC_TDESC_BASE, - PPC_TDESC_ALTIVEC, - PPC_TDESC_CELL, /* No longer used, but kept to avoid ABI changes. */ - PPC_TDESC_VSX, - PPC_TDESC_ISA205, - PPC_TDESC_ISA205_ALTIVEC, - PPC_TDESC_ISA205_VSX, - PPC_TDESC_ISA205_PPR_DSCR_VSX, - PPC_TDESC_ISA207_VSX, - PPC_TDESC_ISA207_HTM_VSX, - PPC_TDESC_E500, -}; - -#if !defined __powerpc64__ || !defined IN_PROCESS_AGENT - -/* Defined in auto-generated file powerpc-32l.c. */ -void init_registers_powerpc_32l (void); - -/* Defined in auto-generated file powerpc-altivec32l.c. */ -void init_registers_powerpc_altivec32l (void); - -/* Defined in auto-generated file powerpc-vsx32l.c. */ -void init_registers_powerpc_vsx32l (void); - -/* Defined in auto-generated file powerpc-isa205-32l.c. */ -void init_registers_powerpc_isa205_32l (void); - -/* Defined in auto-generated file powerpc-isa205-altivec32l.c. */ -void init_registers_powerpc_isa205_altivec32l (void); - -/* Defined in auto-generated file powerpc-isa205-vsx32l.c. */ -void init_registers_powerpc_isa205_vsx32l (void); - -/* Defined in auto-generated file powerpc-isa205-ppr-dscr-vsx32l.c. */ -void init_registers_powerpc_isa205_ppr_dscr_vsx32l (void); - -/* Defined in auto-generated file powerpc-isa207-vsx32l.c. */ -void init_registers_powerpc_isa207_vsx32l (void); - -/* Defined in auto-generated file powerpc-isa207-htm-vsx32l.c. */ -void init_registers_powerpc_isa207_htm_vsx32l (void); - -/* Defined in auto-generated file powerpc-e500l.c. */ -void init_registers_powerpc_e500l (void); - -#endif - -#if defined __powerpc64__ - -/* Defined in auto-generated file powerpc-64l.c. */ -void init_registers_powerpc_64l (void); - -/* Defined in auto-generated file powerpc-altivec64l.c. */ -void init_registers_powerpc_altivec64l (void); - -/* Defined in auto-generated file powerpc-vsx64l.c. */ -void init_registers_powerpc_vsx64l (void); - -/* Defined in auto-generated file powerpc-isa205-64l.c. */ -void init_registers_powerpc_isa205_64l (void); - -/* Defined in auto-generated file powerpc-isa205-altivec64l.c. */ -void init_registers_powerpc_isa205_altivec64l (void); - -/* Defined in auto-generated file powerpc-isa205-vsx64l.c. */ -void init_registers_powerpc_isa205_vsx64l (void); - -/* Defined in auto-generated file powerpc-isa205-ppr-dscr-vsx64l.c. */ -void init_registers_powerpc_isa205_ppr_dscr_vsx64l (void); - -/* Defined in auto-generated file powerpc-isa207-vsx64l.c. */ -void init_registers_powerpc_isa207_vsx64l (void); - -/* Defined in auto-generated file powerpc-isa207-htm-vsx64l.c. */ -void init_registers_powerpc_isa207_htm_vsx64l (void); - -#endif - -#endif /* GDBSERVER_LINUX_PPC_TDESC_INIT_H */ diff --git a/gdb/gdbserver/linux-s390-ipa.c b/gdb/gdbserver/linux-s390-ipa.c deleted file mode 100644 index 5b90302b1eb..00000000000 --- a/gdb/gdbserver/linux-s390-ipa.c +++ /dev/null @@ -1,463 +0,0 @@ -/* GNU/Linux S/390 specific low level interface, for the in-process - agent library for GDB. - - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include -#include "tracepoint.h" -#include "linux-s390-tdesc.h" -#include -#ifdef HAVE_GETAUXVAL -#include -#endif - -#define FT_FPR(x) (0x000 + (x) * 0x10) -#define FT_VR(x) (0x000 + (x) * 0x10) -#define FT_VR_L(x) (0x008 + (x) * 0x10) -#define FT_GPR(x) (0x200 + (x) * 8) -#define FT_GPR_U(x) (0x200 + (x) * 8) -#define FT_GPR_L(x) (0x204 + (x) * 8) -#define FT_GPR(x) (0x200 + (x) * 8) -#define FT_ACR(x) (0x280 + (x) * 4) -#define FT_PSWM 0x2c0 -#define FT_PSWM_U 0x2c0 -#define FT_PSWA 0x2c8 -#define FT_PSWA_L 0x2cc -#define FT_FPC 0x2d0 - -/* Mappings between registers collected by the jump pad and GDB's register - array layout used by regcache. - - See linux-s390-low.c (s390_install_fast_tracepoint_jump_pad) for more - details. */ - -#ifndef __s390x__ - -/* Used for s390-linux32, s390-linux32v1, s390-linux32v2. */ - -static const int s390_linux32_ft_collect_regmap[] = { - /* 32-bit PSWA and PSWM. */ - FT_PSWM_U, FT_PSWA_L, - /* 32-bit GPRs (mapped to lower halves of 64-bit slots). */ - FT_GPR_L (0), FT_GPR_L (1), FT_GPR_L (2), FT_GPR_L (3), - FT_GPR_L (4), FT_GPR_L (5), FT_GPR_L (6), FT_GPR_L (7), - FT_GPR_L (8), FT_GPR_L (9), FT_GPR_L (10), FT_GPR_L (11), - FT_GPR_L (12), FT_GPR_L (13), FT_GPR_L (14), FT_GPR_L (15), - /* ACRs */ - FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), - FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), - FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), - FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), - /* FPRs (mapped to upper halves of 128-bit VR slots). */ - FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), - FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), - FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), - FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), - /* orig_r2, last_break, system_call */ - -1, -1, -1, -}; - -/* Used for s390-linux64, s390-linux64v1, s390-linux64v2, s390-vx-linux64. */ - -static const int s390_linux64_ft_collect_regmap[] = { - /* 32-bit PSWA and PSWM. */ - FT_PSWM_U, FT_PSWA_L, - /* 32-bit halves of 64-bit GPRs. */ - FT_GPR_U (0), FT_GPR_L (0), - FT_GPR_U (1), FT_GPR_L (1), - FT_GPR_U (2), FT_GPR_L (2), - FT_GPR_U (3), FT_GPR_L (3), - FT_GPR_U (4), FT_GPR_L (4), - FT_GPR_U (5), FT_GPR_L (5), - FT_GPR_U (6), FT_GPR_L (6), - FT_GPR_U (7), FT_GPR_L (7), - FT_GPR_U (8), FT_GPR_L (8), - FT_GPR_U (9), FT_GPR_L (9), - FT_GPR_U (10), FT_GPR_L (10), - FT_GPR_U (11), FT_GPR_L (11), - FT_GPR_U (12), FT_GPR_L (12), - FT_GPR_U (13), FT_GPR_L (13), - FT_GPR_U (14), FT_GPR_L (14), - FT_GPR_U (15), FT_GPR_L (15), - /* ACRs */ - FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), - FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), - FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), - FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), - /* FPRs (mapped to upper halves of 128-bit VR slots). */ - FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), - FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), - FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), - FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), - /* orig_r2, last_break, system_call */ - -1, -1, -1, - /* Lower halves of 128-bit VRs. */ - FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), - FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), - FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), - FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), - /* And the next 16 VRs. */ - FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), - FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), - FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), - FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), -}; - -/* Used for s390-te-linux64, s390-tevx-linux64, and s390-gs-linux64. */ - -static const int s390_te_linux64_ft_collect_regmap[] = { - /* 32-bit PSWA and PSWM. */ - FT_PSWM_U, FT_PSWA_L, - /* 32-bit halves of 64-bit GPRs. */ - FT_GPR_U (0), FT_GPR_L (0), - FT_GPR_U (1), FT_GPR_L (1), - FT_GPR_U (2), FT_GPR_L (2), - FT_GPR_U (3), FT_GPR_L (3), - FT_GPR_U (4), FT_GPR_L (4), - FT_GPR_U (5), FT_GPR_L (5), - FT_GPR_U (6), FT_GPR_L (6), - FT_GPR_U (7), FT_GPR_L (7), - FT_GPR_U (8), FT_GPR_L (8), - FT_GPR_U (9), FT_GPR_L (9), - FT_GPR_U (10), FT_GPR_L (10), - FT_GPR_U (11), FT_GPR_L (11), - FT_GPR_U (12), FT_GPR_L (12), - FT_GPR_U (13), FT_GPR_L (13), - FT_GPR_U (14), FT_GPR_L (14), - FT_GPR_U (15), FT_GPR_L (15), - /* ACRs */ - FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), - FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), - FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), - FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), - /* FPRs (mapped to upper halves of 128-bit VR slots). */ - FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), - FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), - FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), - FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), - /* orig_r2, last_break, system_call */ - -1, -1, -1, - /* TDB */ - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - /* Lower halves of 128-bit VRs. */ - FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), - FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), - FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), - FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), - /* And the next 16 VRs. */ - FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), - FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), - FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), - FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), -}; - -#else /* __s390x__ */ - -/* Used for s390x-linux64, s390x-linux64v1, s390x-linux64v2, s390x-vx-linux64. */ - -static const int s390x_ft_collect_regmap[] = { - /* 64-bit PSWA and PSWM. */ - FT_PSWM, FT_PSWA, - /* 64-bit GPRs. */ - FT_GPR (0), FT_GPR (1), FT_GPR (2), FT_GPR (3), - FT_GPR (4), FT_GPR (5), FT_GPR (6), FT_GPR (7), - FT_GPR (8), FT_GPR (9), FT_GPR (10), FT_GPR (11), - FT_GPR (12), FT_GPR (13), FT_GPR (14), FT_GPR (15), - /* ACRs */ - FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), - FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), - FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), - FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), - /* FPRs (mapped to upper halves of 128-bit VR slots). */ - FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), - FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), - FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), - FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), - /* orig_r2, last_break, system_call */ - -1, -1, -1, - /* Lower halves of 128-bit VRs. */ - FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), - FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), - FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), - FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), - /* And the next 16 VRs. */ - FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), - FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), - FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), - FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), -}; - -/* Used for s390x-te-linux64, s390x-tevx-linux64, and - s390x-gs-linux64. */ - -static const int s390x_te_ft_collect_regmap[] = { - /* 64-bit PSWA and PSWM. */ - FT_PSWM, FT_PSWA, - /* 64-bit GPRs. */ - FT_GPR (0), FT_GPR (1), FT_GPR (2), FT_GPR (3), - FT_GPR (4), FT_GPR (5), FT_GPR (6), FT_GPR (7), - FT_GPR (8), FT_GPR (9), FT_GPR (10), FT_GPR (11), - FT_GPR (12), FT_GPR (13), FT_GPR (14), FT_GPR (15), - /* ACRs */ - FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), - FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), - FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), - FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), - /* FPRs (mapped to upper halves of 128-bit VR slots). */ - FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), - FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), - FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), - FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), - /* orig_r2, last_break, system_call */ - -1, -1, -1, - /* TDB */ - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - /* Lower halves of 128-bit VRs. */ - FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), - FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), - FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), - FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), - /* And the next 16 VRs. */ - FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), - FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), - FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), - FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), -}; - -#endif - -/* Initialized by get_ipa_tdesc according to the tdesc in use. */ - -static const int *s390_regmap; -static int s390_regnum; - -/* Fill in REGCACHE with registers saved by the jump pad in BUF. */ - -void -supply_fast_tracepoint_registers (struct regcache *regcache, - const unsigned char *buf) -{ - int i; - for (i = 0; i < s390_regnum; i++) - if (s390_regmap[i] != -1) - supply_register (regcache, i, ((char *) buf) + s390_regmap[i]); -} - -ULONGEST -get_raw_reg (const unsigned char *raw_regs, int regnum) -{ - int offset; - if (regnum >= s390_regnum) - return 0; - offset = s390_regmap[regnum]; - if (offset == -1) - return 0; - - /* The regnums are variable, better to figure out size by FT offset. */ - - /* 64-bit ones. */ - if (offset < FT_VR(16) -#ifdef __s390x__ - || (offset >= FT_GPR(0) && offset < FT_ACR(0)) - || offset == FT_PSWM - || offset == FT_PSWA -#endif - ) - return *(uint64_t *) (raw_regs + offset); - - if (offset >= FT_ACR(0 && offset < FT_PSWM) - || offset == FT_FPC -#ifndef __s390x__ - || (offset >= FT_GPR(0) && offset < FT_ACR(0)) - || offset == FT_PSWM_U - || offset == FT_PSWA_L -#endif - ) - return *(uint32_t *) (raw_regs + offset); - - /* This leaves 128-bit VX. No way to return them. */ - return 0; -} - -/* Return target_desc to use for IPA, given the tdesc index passed by - gdbserver. For s390, it also sets s390_regmap and s390_regnum. */ - -const struct target_desc * -get_ipa_tdesc (int idx) -{ -#define SET_REGMAP(regmap, skip_last) \ - do { \ - s390_regmap = regmap; \ - s390_regnum = (sizeof regmap / sizeof regmap[0]) - skip_last; \ - } while(0) - switch (idx) - { -#ifdef __s390x__ - case S390_TDESC_64: - /* Subtract number of VX regs. */ - SET_REGMAP(s390x_ft_collect_regmap, 32); - return tdesc_s390x_linux64; - case S390_TDESC_64V1: - SET_REGMAP(s390x_ft_collect_regmap, 32); - return tdesc_s390x_linux64v1; - case S390_TDESC_64V2: - SET_REGMAP(s390x_ft_collect_regmap, 32); - return tdesc_s390x_linux64v2; - case S390_TDESC_TE: - SET_REGMAP(s390x_te_ft_collect_regmap, 32); - return tdesc_s390x_te_linux64; - case S390_TDESC_VX: - SET_REGMAP(s390x_ft_collect_regmap, 0); - return tdesc_s390x_vx_linux64; - case S390_TDESC_TEVX: - SET_REGMAP(s390x_te_ft_collect_regmap, 0); - return tdesc_s390x_tevx_linux64; - case S390_TDESC_GS: - SET_REGMAP(s390x_te_ft_collect_regmap, 0); - return tdesc_s390x_gs_linux64; -#else - case S390_TDESC_32: - SET_REGMAP(s390_linux32_ft_collect_regmap, 0); - return tdesc_s390_linux32; - case S390_TDESC_32V1: - SET_REGMAP(s390_linux32_ft_collect_regmap, 0); - return tdesc_s390_linux32v1; - case S390_TDESC_32V2: - SET_REGMAP(s390_linux32_ft_collect_regmap, 0); - return tdesc_s390_linux32v2; - case S390_TDESC_64: - SET_REGMAP(s390_linux64_ft_collect_regmap, 32); - return tdesc_s390_linux64; - case S390_TDESC_64V1: - SET_REGMAP(s390_linux64_ft_collect_regmap, 32); - return tdesc_s390_linux64v1; - case S390_TDESC_64V2: - SET_REGMAP(s390_linux64_ft_collect_regmap, 32); - return tdesc_s390_linux64v2; - case S390_TDESC_TE: - SET_REGMAP(s390_te_linux64_ft_collect_regmap, 32); - return tdesc_s390_te_linux64; - case S390_TDESC_VX: - SET_REGMAP(s390_linux64_ft_collect_regmap, 0); - return tdesc_s390_vx_linux64; - case S390_TDESC_TEVX: - SET_REGMAP(s390_te_linux64_ft_collect_regmap, 0); - return tdesc_s390_tevx_linux64; - case S390_TDESC_GS: - SET_REGMAP(s390_te_linux64_ft_collect_regmap, 0); - return tdesc_s390_gs_linux64; -#endif - default: - internal_error (__FILE__, __LINE__, - "unknown ipa tdesc index: %d", idx); -#ifdef __s390x__ - return tdesc_s390x_linux64; -#else - return tdesc_s390_linux32; -#endif - } -} - -/* Allocate buffer for the jump pads. On 31-bit, JG reaches everywhere, - so just allocate normally. On 64-bit, we have +/-4GiB of reach, and - the executable is usually mapped at 0x80000000 - aim for somewhere - below it. */ - -void * -alloc_jump_pad_buffer (size_t size) -{ -#ifdef __s390x__ - uintptr_t addr; - uintptr_t exec_base = getauxval (AT_PHDR); - int pagesize; - void *res; - - if (exec_base == 0) - exec_base = 0x80000000; - - pagesize = sysconf (_SC_PAGE_SIZE); - if (pagesize == -1) - perror_with_name ("sysconf"); - - addr = exec_base - size; - - /* size should already be page-aligned, but this can't hurt. */ - addr &= ~(pagesize - 1); - - /* Search for a free area. If we hit 0, we're out of luck. */ - for (; addr; addr -= pagesize) - { - /* No MAP_FIXED - we don't want to zap someone's mapping. */ - res = mmap ((void *) addr, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - /* If we got what we wanted, return. */ - if ((uintptr_t) res == addr) - return res; - - /* If we got a mapping, but at a wrong address, undo it. */ - if (res != MAP_FAILED) - munmap (res, size); - } - - return NULL; -#else - void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - if (res == MAP_FAILED) - return NULL; - - return res; -#endif -} - -void -initialize_low_tracepoint (void) -{ -#ifdef __s390x__ - init_registers_s390x_linux64 (); - init_registers_s390x_linux64v1 (); - init_registers_s390x_linux64v2 (); - init_registers_s390x_te_linux64 (); - init_registers_s390x_vx_linux64 (); - init_registers_s390x_tevx_linux64 (); - init_registers_s390x_gs_linux64 (); -#else - init_registers_s390_linux32 (); - init_registers_s390_linux32v1 (); - init_registers_s390_linux32v2 (); - init_registers_s390_linux64 (); - init_registers_s390_linux64v1 (); - init_registers_s390_linux64v2 (); - init_registers_s390_te_linux64 (); - init_registers_s390_vx_linux64 (); - init_registers_s390_tevx_linux64 (); - init_registers_s390_gs_linux64 (); -#endif -} diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c deleted file mode 100644 index f3d6f093099..00000000000 --- a/gdb/gdbserver/linux-s390-low.c +++ /dev/null @@ -1,2860 +0,0 @@ -/* GNU/Linux S/390 specific low level interface, for the remote server - for GDB. - Copyright (C) 2001-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -/* This file is used for both 31-bit and 64-bit S/390 systems. */ - -#include "server.h" -#include "linux-low.h" -#include "elf/common.h" -#include "ax.h" -#include "tracepoint.h" - -#include -#include "nat/gdb_ptrace.h" -#include -#include -#include - -#include "linux-s390-tdesc.h" - -#ifndef HWCAP_S390_HIGH_GPRS -#define HWCAP_S390_HIGH_GPRS 512 -#endif - -#ifndef HWCAP_S390_TE -#define HWCAP_S390_TE 1024 -#endif - -#ifndef HWCAP_S390_VX -#define HWCAP_S390_VX 2048 -#endif - -#ifndef HWCAP_S390_GS -#define HWCAP_S390_GS 16384 -#endif - -#define s390_num_regs 52 - -static int s390_regmap[] = { - PT_PSWMASK, PT_PSWADDR, - - PT_GPR0, PT_GPR1, PT_GPR2, PT_GPR3, - PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7, - PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11, - PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15, - - PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3, - PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7, - PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11, - PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15, - - PT_FPC, - -#ifndef __s390x__ - PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI, - PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI, - PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI, - PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI, -#else - PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3, - PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7, - PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11, - PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15, -#endif - - PT_ORIGGPR2, -}; - -#define s390_num_regs_3264 68 - -#ifdef __s390x__ -static int s390_regmap_3264[] = { - PT_PSWMASK, PT_PSWADDR, - - PT_GPR0, PT_GPR0, PT_GPR1, PT_GPR1, - PT_GPR2, PT_GPR2, PT_GPR3, PT_GPR3, - PT_GPR4, PT_GPR4, PT_GPR5, PT_GPR5, - PT_GPR6, PT_GPR6, PT_GPR7, PT_GPR7, - PT_GPR8, PT_GPR8, PT_GPR9, PT_GPR9, - PT_GPR10, PT_GPR10, PT_GPR11, PT_GPR11, - PT_GPR12, PT_GPR12, PT_GPR13, PT_GPR13, - PT_GPR14, PT_GPR14, PT_GPR15, PT_GPR15, - - PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3, - PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7, - PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11, - PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15, - - PT_FPC, - - PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3, - PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7, - PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11, - PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15, - - PT_ORIGGPR2, -}; -#else -static int s390_regmap_3264[] = { - PT_PSWMASK, PT_PSWADDR, - - -1, PT_GPR0, -1, PT_GPR1, - -1, PT_GPR2, -1, PT_GPR3, - -1, PT_GPR4, -1, PT_GPR5, - -1, PT_GPR6, -1, PT_GPR7, - -1, PT_GPR8, -1, PT_GPR9, - -1, PT_GPR10, -1, PT_GPR11, - -1, PT_GPR12, -1, PT_GPR13, - -1, PT_GPR14, -1, PT_GPR15, - - PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3, - PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7, - PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11, - PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15, - - PT_FPC, - - PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI, - PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI, - PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI, - PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI, - - PT_ORIGGPR2, -}; -#endif - - -static int -s390_cannot_fetch_register (int regno) -{ - return 0; -} - -static int -s390_cannot_store_register (int regno) -{ - return 0; -} - -static void -s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) -{ - int size = register_size (regcache->tdesc, regno); - const struct regs_info *regs_info = (*the_low_target.regs_info) (); - struct usrregs_info *usr = regs_info->usrregs; - int regaddr = usr->regmap[regno]; - - if (size < sizeof (long)) - { - memset (buf, 0, sizeof (long)); - - if ((regno ^ 1) < usr->num_regs - && usr->regmap[regno ^ 1] == regaddr) - { - collect_register (regcache, regno & ~1, buf); - collect_register (regcache, (regno & ~1) + 1, - buf + sizeof (long) - size); - } - else if (regaddr == PT_PSWMASK) - { - /* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying - the basic addressing mode bit from the PSW address. */ - gdb_byte *addr = (gdb_byte *) alloca (register_size (regcache->tdesc, regno ^ 1)); - collect_register (regcache, regno, buf); - collect_register (regcache, regno ^ 1, addr); - buf[1] &= ~0x8; - buf[size] |= (addr[0] & 0x80); - } - else if (regaddr == PT_PSWADDR) - { - /* Convert 4-byte PSW address to 8 bytes by clearing the addressing - mode bit (which gets copied to the PSW mask instead). */ - collect_register (regcache, regno, buf + sizeof (long) - size); - buf[sizeof (long) - size] &= ~0x80; - } - else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15) - || regaddr == PT_ORIGGPR2) - collect_register (regcache, regno, buf + sizeof (long) - size); - else - collect_register (regcache, regno, buf); - } - else if (regaddr != -1) - collect_register (regcache, regno, buf); -} - -static void -s390_supply_ptrace_register (struct regcache *regcache, - int regno, const char *buf) -{ - int size = register_size (regcache->tdesc, regno); - const struct regs_info *regs_info = (*the_low_target.regs_info) (); - struct usrregs_info *usr = regs_info->usrregs; - int regaddr = usr->regmap[regno]; - - if (size < sizeof (long)) - { - if ((regno ^ 1) < usr->num_regs - && usr->regmap[regno ^ 1] == regaddr) - { - supply_register (regcache, regno & ~1, buf); - supply_register (regcache, (regno & ~1) + 1, - buf + sizeof (long) - size); - } - else if (regaddr == PT_PSWMASK) - { - /* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying - the basic addressing mode into the PSW address. */ - gdb_byte *mask = (gdb_byte *) alloca (size); - gdb_byte *addr = (gdb_byte *) alloca (register_size (regcache->tdesc, regno ^ 1)); - memcpy (mask, buf, size); - mask[1] |= 0x8; - supply_register (regcache, regno, mask); - - collect_register (regcache, regno ^ 1, addr); - addr[0] &= ~0x80; - addr[0] |= (buf[size] & 0x80); - supply_register (regcache, regno ^ 1, addr); - } - else if (regaddr == PT_PSWADDR) - { - /* Convert 8-byte PSW address to 4 bytes by truncating, but - keeping the addressing mode bit (which was set from the mask). */ - gdb_byte *addr = (gdb_byte *) alloca (size); - char amode; - collect_register (regcache, regno, addr); - amode = addr[0] & 0x80; - memcpy (addr, buf + sizeof (long) - size, size); - addr[0] &= ~0x80; - addr[0] |= amode; - supply_register (regcache, regno, addr); - } - else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15) - || regaddr == PT_ORIGGPR2) - supply_register (regcache, regno, buf + sizeof (long) - size); - else - supply_register (regcache, regno, buf); - } - else if (regaddr != -1) - supply_register (regcache, regno, buf); -} - -/* Provide only a fill function for the general register set. ps_lgetregs - will use this for NPTL support. */ - -static void -s390_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - const struct regs_info *regs_info = (*the_low_target.regs_info) (); - struct usrregs_info *usr = regs_info->usrregs; - - for (i = 0; i < usr->num_regs; i++) - { - if (usr->regmap[i] < PT_PSWMASK - || usr->regmap[i] > PT_ACR15) - continue; - - s390_collect_ptrace_register (regcache, i, - (char *) buf + usr->regmap[i]); - } -} - -/* Fill and store functions for extended register sets. */ - -#ifndef __s390x__ -static void -s390_fill_gprs_high (struct regcache *regcache, void *buf) -{ - int r0h = find_regno (regcache->tdesc, "r0h"); - int i; - - for (i = 0; i < 16; i++) - collect_register (regcache, r0h + 2 * i, (char *) buf + 4 * i); -} - -static void -s390_store_gprs_high (struct regcache *regcache, const void *buf) -{ - int r0h = find_regno (regcache->tdesc, "r0h"); - int i; - - for (i = 0; i < 16; i++) - supply_register (regcache, r0h + 2 * i, (const char *) buf + 4 * i); -} -#endif - -static void -s390_store_last_break (struct regcache *regcache, const void *buf) -{ - const char *p; - - p = (const char *) buf + 8 - register_size (regcache->tdesc, 0); - supply_register_by_name (regcache, "last_break", p); -} - -static void -s390_fill_system_call (struct regcache *regcache, void *buf) -{ - collect_register_by_name (regcache, "system_call", buf); -} - -static void -s390_store_system_call (struct regcache *regcache, const void *buf) -{ - supply_register_by_name (regcache, "system_call", buf); -} - -static void -s390_store_tdb (struct regcache *regcache, const void *buf) -{ - int tdb0 = find_regno (regcache->tdesc, "tdb0"); - int tr0 = find_regno (regcache->tdesc, "tr0"); - int i; - - for (i = 0; i < 4; i++) - supply_register (regcache, tdb0 + i, (const char *) buf + 8 * i); - - for (i = 0; i < 16; i++) - supply_register (regcache, tr0 + i, (const char *) buf + 8 * (16 + i)); -} - -static void -s390_fill_vxrs_low (struct regcache *regcache, void *buf) -{ - int v0 = find_regno (regcache->tdesc, "v0l"); - int i; - - for (i = 0; i < 16; i++) - collect_register (regcache, v0 + i, (char *) buf + 8 * i); -} - -static void -s390_store_vxrs_low (struct regcache *regcache, const void *buf) -{ - int v0 = find_regno (regcache->tdesc, "v0l"); - int i; - - for (i = 0; i < 16; i++) - supply_register (regcache, v0 + i, (const char *) buf + 8 * i); -} - -static void -s390_fill_vxrs_high (struct regcache *regcache, void *buf) -{ - int v16 = find_regno (regcache->tdesc, "v16"); - int i; - - for (i = 0; i < 16; i++) - collect_register (regcache, v16 + i, (char *) buf + 16 * i); -} - -static void -s390_store_vxrs_high (struct regcache *regcache, const void *buf) -{ - int v16 = find_regno (regcache->tdesc, "v16"); - int i; - - for (i = 0; i < 16; i++) - supply_register (regcache, v16 + i, (const char *) buf + 16 * i); -} - -static void -s390_store_gs (struct regcache *regcache, const void *buf) -{ - int gsd = find_regno (regcache->tdesc, "gsd"); - int i; - - for (i = 0; i < 3; i++) - supply_register (regcache, gsd + i, (const char *) buf + 8 * (i + 1)); -} - -static void -s390_store_gsbc (struct regcache *regcache, const void *buf) -{ - int bc_gsd = find_regno (regcache->tdesc, "bc_gsd"); - int i; - - for (i = 0; i < 3; i++) - supply_register (regcache, bc_gsd + i, (const char *) buf + 8 * (i + 1)); -} - -static struct regset_info s390_regsets[] = { - { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL }, -#ifndef __s390x__ - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_HIGH_GPRS, 0, - EXTENDED_REGS, s390_fill_gprs_high, s390_store_gprs_high }, -#endif - /* Last break address is read-only; no fill function. */ - { PTRACE_GETREGSET, -1, NT_S390_LAST_BREAK, 0, EXTENDED_REGS, - NULL, s390_store_last_break }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_SYSTEM_CALL, 0, - EXTENDED_REGS, s390_fill_system_call, s390_store_system_call }, - /* TDB is read-only. */ - { PTRACE_GETREGSET, -1, NT_S390_TDB, 0, EXTENDED_REGS, - NULL, s390_store_tdb }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_VXRS_LOW, 0, - EXTENDED_REGS, s390_fill_vxrs_low, s390_store_vxrs_low }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_VXRS_HIGH, 0, - EXTENDED_REGS, s390_fill_vxrs_high, s390_store_vxrs_high }, - /* Guarded storage registers are read-only. */ - { PTRACE_GETREGSET, -1, NT_S390_GS_CB, 0, EXTENDED_REGS, - NULL, s390_store_gs }, - { PTRACE_GETREGSET, -1, NT_S390_GS_BC, 0, EXTENDED_REGS, - NULL, s390_store_gsbc }, - NULL_REGSET -}; - - -static const gdb_byte s390_breakpoint[] = { 0, 1 }; -#define s390_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -s390_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = s390_breakpoint_len; - return s390_breakpoint; -} - -static CORE_ADDR -s390_get_pc (struct regcache *regcache) -{ - if (register_size (regcache->tdesc, 0) == 4) - { - unsigned int pswa; - collect_register_by_name (regcache, "pswa", &pswa); - return pswa & 0x7fffffff; - } - else - { - unsigned long pc; - collect_register_by_name (regcache, "pswa", &pc); - return pc; - } -} - -static void -s390_set_pc (struct regcache *regcache, CORE_ADDR newpc) -{ - if (register_size (regcache->tdesc, 0) == 4) - { - unsigned int pswa; - collect_register_by_name (regcache, "pswa", &pswa); - pswa = (pswa & 0x80000000) | (newpc & 0x7fffffff); - supply_register_by_name (regcache, "pswa", &pswa); - } - else - { - unsigned long pc = newpc; - supply_register_by_name (regcache, "pswa", &pc); - } -} - -/* Determine the word size for the given PID, in bytes. */ - -#ifdef __s390x__ -static int -s390_get_wordsize (int pid) -{ - errno = 0; - PTRACE_XFER_TYPE pswm = ptrace (PTRACE_PEEKUSER, pid, - (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) 0); - if (errno != 0) - { - warning (_("Couldn't determine word size, assuming 64-bit.")); - return 8; - } - /* Derive word size from extended addressing mode (PSW bit 31). */ - return pswm & (1L << 32) ? 8 : 4; -} -#else -#define s390_get_wordsize(pid) 4 -#endif - -static int -s390_check_regset (int pid, int regset, int regsize) -{ - void *buf = alloca (regsize); - struct iovec iov; - - iov.iov_base = buf; - iov.iov_len = regsize; - - if (ptrace (PTRACE_GETREGSET, pid, (long) regset, (long) &iov) >= 0 - || errno == ENODATA) - return 1; - return 0; -} - -/* For a 31-bit inferior, whether the kernel supports using the full - 64-bit GPRs. */ -static int have_hwcap_s390_high_gprs = 0; -static int have_hwcap_s390_vx = 0; - -static void -s390_arch_setup (void) -{ - const struct target_desc *tdesc; - struct regset_info *regset; - - /* Determine word size and HWCAP. */ - int pid = pid_of (current_thread); - int wordsize = s390_get_wordsize (pid); - unsigned long hwcap = linux_get_hwcap (wordsize); - - /* Check whether the kernel supports extra register sets. */ - int have_regset_last_break - = s390_check_regset (pid, NT_S390_LAST_BREAK, 8); - int have_regset_system_call - = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4); - int have_regset_tdb - = (s390_check_regset (pid, NT_S390_TDB, 256) - && (hwcap & HWCAP_S390_TE) != 0); - int have_regset_vxrs - = (s390_check_regset (pid, NT_S390_VXRS_LOW, 128) - && s390_check_regset (pid, NT_S390_VXRS_HIGH, 256) - && (hwcap & HWCAP_S390_VX) != 0); - int have_regset_gs - = (s390_check_regset (pid, NT_S390_GS_CB, 32) - && s390_check_regset (pid, NT_S390_GS_BC, 32) - && (hwcap & HWCAP_S390_GS) != 0); - - { -#ifdef __s390x__ - if (wordsize == 8) - { - if (have_regset_gs) - tdesc = tdesc_s390x_gs_linux64; - else if (have_regset_vxrs) - tdesc = (have_regset_tdb ? tdesc_s390x_tevx_linux64 : - tdesc_s390x_vx_linux64); - else if (have_regset_tdb) - tdesc = tdesc_s390x_te_linux64; - else if (have_regset_system_call) - tdesc = tdesc_s390x_linux64v2; - else if (have_regset_last_break) - tdesc = tdesc_s390x_linux64v1; - else - tdesc = tdesc_s390x_linux64; - } - - /* For a 31-bit inferior, check whether the kernel supports - using the full 64-bit GPRs. */ - else -#endif - if (hwcap & HWCAP_S390_HIGH_GPRS) - { - have_hwcap_s390_high_gprs = 1; - if (have_regset_gs) - tdesc = tdesc_s390_gs_linux64; - else if (have_regset_vxrs) - tdesc = (have_regset_tdb ? tdesc_s390_tevx_linux64 : - tdesc_s390_vx_linux64); - else if (have_regset_tdb) - tdesc = tdesc_s390_te_linux64; - else if (have_regset_system_call) - tdesc = tdesc_s390_linux64v2; - else if (have_regset_last_break) - tdesc = tdesc_s390_linux64v1; - else - tdesc = tdesc_s390_linux64; - } - else - { - /* Assume 31-bit inferior process. */ - if (have_regset_system_call) - tdesc = tdesc_s390_linux32v2; - else if (have_regset_last_break) - tdesc = tdesc_s390_linux32v1; - else - tdesc = tdesc_s390_linux32; - } - - have_hwcap_s390_vx = have_regset_vxrs; - } - - /* Update target_regsets according to available register sets. */ - for (regset = s390_regsets; regset->size >= 0; regset++) - if (regset->get_request == PTRACE_GETREGSET) - switch (regset->nt_type) - { -#ifndef __s390x__ - case NT_S390_HIGH_GPRS: - regset->size = have_hwcap_s390_high_gprs ? 64 : 0; - break; -#endif - case NT_S390_LAST_BREAK: - regset->size = have_regset_last_break ? 8 : 0; - break; - case NT_S390_SYSTEM_CALL: - regset->size = have_regset_system_call ? 4 : 0; - break; - case NT_S390_TDB: - regset->size = have_regset_tdb ? 256 : 0; - break; - case NT_S390_VXRS_LOW: - regset->size = have_regset_vxrs ? 128 : 0; - break; - case NT_S390_VXRS_HIGH: - regset->size = have_regset_vxrs ? 256 : 0; - break; - case NT_S390_GS_CB: - case NT_S390_GS_BC: - regset->size = have_regset_gs ? 32 : 0; - default: - break; - } - - current_process ()->tdesc = tdesc; -} - - -static int -s390_breakpoint_at (CORE_ADDR pc) -{ - unsigned char c[s390_breakpoint_len]; - read_inferior_memory (pc, c, s390_breakpoint_len); - return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0; -} - -/* Breakpoint/Watchpoint support. */ - -/* The "supports_z_point_type" linux_target_ops method. */ - -static int -s390_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - return 1; - default: - return 0; - } -} - -/* Support for hardware single step. */ - -static int -s390_supports_hardware_single_step (void) -{ - return 1; -} - -static struct usrregs_info s390_usrregs_info = - { - s390_num_regs, - s390_regmap, - }; - -static struct regsets_info s390_regsets_info = - { - s390_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &s390_usrregs_info, - &s390_regsets_info - }; - -static struct usrregs_info s390_usrregs_info_3264 = - { - s390_num_regs_3264, - s390_regmap_3264 - }; - -static struct regsets_info s390_regsets_info_3264 = - { - s390_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct regs_info regs_info_3264 = - { - NULL, /* regset_bitmap */ - &s390_usrregs_info_3264, - &s390_regsets_info_3264 - }; - -static const struct regs_info * -s390_regs_info (void) -{ - if (have_hwcap_s390_high_gprs) - { -#ifdef __s390x__ - const struct target_desc *tdesc = current_process ()->tdesc; - - if (register_size (tdesc, 0) == 4) - return ®s_info_3264; -#else - return ®s_info_3264; -#endif - } - return ®s_info; -} - -/* The "supports_tracepoints" linux_target_ops method. */ - -static int -s390_supports_tracepoints (void) -{ - return 1; -} - -/* Implementation of linux_target_ops method "get_thread_area". */ - -static int -s390_get_thread_area (int lwpid, CORE_ADDR *addrp) -{ - CORE_ADDR res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_ACR0, (long) 0); -#ifdef __s390x__ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - if (register_size (regcache->tdesc, 0) == 4) - res &= 0xffffffffull; -#endif - *addrp = res; - return 0; -} - - -/* Fast tracepoint support. - - The register save area on stack is identical for all targets: - - 0x000+i*0x10: VR0-VR31 - 0x200+i*8: GR0-GR15 - 0x280+i*4: AR0-AR15 - 0x2c0: PSWM [64-bit] - 0x2c8: PSWA [64-bit] - 0x2d0: FPC - - If we're on 31-bit linux, we just don't store the high parts of the GPRs. - Likewise, if there's no VX support, we just store the FRs into the slots - of low VR halves. The agent code is responsible for rearranging that - into regcache. */ - -/* Code sequence saving GPRs for 31-bit target with no high GPRs. There's - one trick used at the very beginning: since there's no way to allocate - stack space without destroying CC (lay instruction can do it, but it's - only supported on later CPUs), we take 4 different execution paths for - every possible value of CC, allocate stack space, save %r0, stuff the - CC value in %r0 (shifted to match its position in PSWM high word), - then branch to common path. */ - -static const unsigned char s390_ft_entry_gpr_esa[] = { - 0xa7, 0x14, 0x00, 0x1e, /* jo .Lcc3 */ - 0xa7, 0x24, 0x00, 0x14, /* jh .Lcc2 */ - 0xa7, 0x44, 0x00, 0x0a, /* jl .Lcc1 */ - /* CC = 0 */ - 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ - 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ - 0xa7, 0x08, 0x00, 0x00, /* lhi %r0, 0 */ - 0xa7, 0xf4, 0x00, 0x18, /* j .Lccdone */ - /* .Lcc1: */ - 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ - 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ - 0xa7, 0x08, 0x10, 0x00, /* lhi %r0, 0x1000 */ - 0xa7, 0xf4, 0x00, 0x10, /* j .Lccdone */ - /* .Lcc2: */ - 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ - 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ - 0xa7, 0x08, 0x20, 0x00, /* lhi %r0, 0x2000 */ - 0xa7, 0xf4, 0x00, 0x08, /* j .Lccdone */ - /* .Lcc3: */ - 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ - 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ - 0xa7, 0x08, 0x30, 0x00, /* lhi %r0, 0x3000 */ - /* .Lccdone: */ - 0x50, 0x10, 0xf2, 0x0c, /* st %r1, 0x20c(%r15) */ - 0x50, 0x20, 0xf2, 0x14, /* st %r2, 0x214(%r15) */ - 0x50, 0x30, 0xf2, 0x1c, /* st %r3, 0x21c(%r15) */ - 0x50, 0x40, 0xf2, 0x24, /* st %r4, 0x224(%r15) */ - 0x50, 0x50, 0xf2, 0x2c, /* st %r5, 0x22c(%r15) */ - 0x50, 0x60, 0xf2, 0x34, /* st %r6, 0x234(%r15) */ - 0x50, 0x70, 0xf2, 0x3c, /* st %r7, 0x23c(%r15) */ - 0x50, 0x80, 0xf2, 0x44, /* st %r8, 0x244(%r15) */ - 0x50, 0x90, 0xf2, 0x4c, /* st %r9, 0x24c(%r15) */ - 0x50, 0xa0, 0xf2, 0x54, /* st %r10, 0x254(%r15) */ - 0x50, 0xb0, 0xf2, 0x5c, /* st %r11, 0x25c(%r15) */ - 0x50, 0xc0, 0xf2, 0x64, /* st %r12, 0x264(%r15) */ - 0x50, 0xd0, 0xf2, 0x6c, /* st %r13, 0x26c(%r15) */ - 0x50, 0xe0, 0xf2, 0x74, /* st %r14, 0x274(%r15) */ - /* Compute original value of %r15 and store it. We use ahi instead - of la to preserve the whole value, and not just the low 31 bits. - This is not particularly important here, but essential in the - zarch case where someone might be using the high word of %r15 - as an extra register. */ - 0x18, 0x1f, /* lr %r1, %r15 */ - 0xa7, 0x1a, 0x03, 0x00, /* ahi %r1, 0x300 */ - 0x50, 0x10, 0xf2, 0x7c, /* st %r1, 0x27c(%r15) */ -}; - -/* Code sequence saving GPRs for 31-bit target with high GPRs and for 64-bit - target. Same as above, except this time we can use load/store multiple, - since the 64-bit regs are tightly packed. */ - -static const unsigned char s390_ft_entry_gpr_zarch[] = { - 0xa7, 0x14, 0x00, 0x21, /* jo .Lcc3 */ - 0xa7, 0x24, 0x00, 0x16, /* jh .Lcc2 */ - 0xa7, 0x44, 0x00, 0x0b, /* jl .Lcc1 */ - /* CC = 0 */ - 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ - 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ - 0xa7, 0x08, 0x00, 0x00, /* lhi %r0, 0 */ - 0xa7, 0xf4, 0x00, 0x1b, /* j .Lccdone */ - /* .Lcc1: */ - 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ - 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ - 0xa7, 0x08, 0x10, 0x00, /* lhi %r0, 0x1000 */ - 0xa7, 0xf4, 0x00, 0x12, /* j .Lccdone */ - /* .Lcc2: */ - 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ - 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ - 0xa7, 0x08, 0x20, 0x00, /* lhi %r0, 0x2000 */ - 0xa7, 0xf4, 0x00, 0x09, /* j .Lccdone */ - /* .Lcc3: */ - 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ - 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ - 0xa7, 0x08, 0x30, 0x00, /* lhi %r0, 0x3000 */ - /* .Lccdone: */ - 0xb9, 0x04, 0x00, 0x1f, /* lgr %r1, %r15 */ - 0xa7, 0x1b, 0x03, 0x00, /* aghi %r1, 0x300 */ - 0xe3, 0x10, 0xf2, 0x78, 0x00, 0x24, /* stg %r1, 0x278(%r15) */ -}; - -/* Code sequence saving ARs, PSWM and FPC. PSWM has to be assembled from - current PSWM (read by epsw) and CC from entry (in %r0). */ - -static const unsigned char s390_ft_entry_misc[] = { - 0x9b, 0x0f, 0xf2, 0x80, /* stam %a0, %a15, 0x20(%%r15) */ - 0xb9, 0x8d, 0x00, 0x23, /* epsw %r2, %r3 */ - 0xa7, 0x18, 0xcf, 0xff, /* lhi %r1, ~0x3000 */ - 0x14, 0x21, /* nr %r2, %r1 */ - 0x16, 0x20, /* or %r2, %r0 */ - 0x50, 0x20, 0xf2, 0xc0, /* st %r2, 0x2c0(%r15) */ - 0x50, 0x30, 0xf2, 0xc4, /* st %r3, 0x2c4(%r15) */ - 0xb2, 0x9c, 0xf2, 0xd0, /* stfpc 0x2d0(%r15) */ -}; - -/* Code sequence saving FRs, used if VX not supported. */ - -static const unsigned char s390_ft_entry_fr[] = { - 0x60, 0x00, 0xf0, 0x00, /* std %f0, 0x000(%r15) */ - 0x60, 0x10, 0xf0, 0x10, /* std %f1, 0x010(%r15) */ - 0x60, 0x20, 0xf0, 0x20, /* std %f2, 0x020(%r15) */ - 0x60, 0x30, 0xf0, 0x30, /* std %f3, 0x030(%r15) */ - 0x60, 0x40, 0xf0, 0x40, /* std %f4, 0x040(%r15) */ - 0x60, 0x50, 0xf0, 0x50, /* std %f5, 0x050(%r15) */ - 0x60, 0x60, 0xf0, 0x60, /* std %f6, 0x060(%r15) */ - 0x60, 0x70, 0xf0, 0x70, /* std %f7, 0x070(%r15) */ - 0x60, 0x80, 0xf0, 0x80, /* std %f8, 0x080(%r15) */ - 0x60, 0x90, 0xf0, 0x90, /* std %f9, 0x090(%r15) */ - 0x60, 0xa0, 0xf0, 0xa0, /* std %f10, 0x0a0(%r15) */ - 0x60, 0xb0, 0xf0, 0xb0, /* std %f11, 0x0b0(%r15) */ - 0x60, 0xc0, 0xf0, 0xc0, /* std %f12, 0x0c0(%r15) */ - 0x60, 0xd0, 0xf0, 0xd0, /* std %f13, 0x0d0(%r15) */ - 0x60, 0xe0, 0xf0, 0xe0, /* std %f14, 0x0e0(%r15) */ - 0x60, 0xf0, 0xf0, 0xf0, /* std %f15, 0x0f0(%r15) */ -}; - -/* Code sequence saving VRs, used if VX not supported. */ - -static const unsigned char s390_ft_entry_vr[] = { - 0xe7, 0x0f, 0xf0, 0x00, 0x00, 0x3e, /* vstm %v0, %v15, 0x000(%r15) */ - 0xe7, 0x0f, 0xf1, 0x00, 0x0c, 0x3e, /* vstm %v16, %v31, 0x100(%r15) */ -}; - -/* Code sequence doing the collection call for 31-bit target. %r1 contains - the address of the literal pool. */ - -static const unsigned char s390_ft_main_31[] = { - /* Load the literals into registers. */ - 0x58, 0x50, 0x10, 0x00, /* l %r5, 0x0(%r1) */ - 0x58, 0x20, 0x10, 0x04, /* l %r2, 0x4(%r1) */ - 0x58, 0x40, 0x10, 0x08, /* l %r4, 0x8(%r1) */ - 0x58, 0x60, 0x10, 0x0c, /* l %r6, 0xc(%r1) */ - /* Save original PSWA (tracepoint address | 0x80000000). */ - 0x50, 0x50, 0xf2, 0xcc, /* st %r5, 0x2cc(%r15) */ - /* Construct a collecting_t object at %r15+0x2e0. */ - 0x50, 0x20, 0xf2, 0xe0, /* st %r2, 0x2e0(%r15) */ - 0x9b, 0x00, 0xf2, 0xe4, /* stam %a0, %a0, 0x2e4(%r15) */ - /* Move its address to %r0. */ - 0x41, 0x00, 0xf2, 0xe0, /* la %r0, 0x2e0(%r15) */ - /* Take the lock. */ - /* .Lloop: */ - 0xa7, 0x18, 0x00, 0x00, /* lhi %r1, 0 */ - 0xba, 0x10, 0x60, 0x00, /* cs %r1, %r0, 0(%r6) */ - 0xa7, 0x74, 0xff, 0xfc, /* jne .Lloop */ - /* Address of the register save block to %r3. */ - 0x18, 0x3f, /* lr %r3, %r15 */ - /* Make a stack frame, so that we can call the collector. */ - 0xa7, 0xfa, 0xff, 0xa0, /* ahi %r15, -0x60 */ - /* Call it. */ - 0x0d, 0xe4, /* basr %r14, %r4 */ - /* And get rid of the stack frame again. */ - 0x41, 0xf0, 0xf0, 0x60, /* la %r15, 0x60(%r15) */ - /* Leave the lock. */ - 0x07, 0xf0, /* br %r0 */ - 0xa7, 0x18, 0x00, 0x00, /* lhi %r1, 0 */ - 0x50, 0x10, 0x60, 0x00, /* st %t1, 0(%r6) */ -}; - -/* Code sequence doing the collection call for 64-bit target. %r1 contains - the address of the literal pool. */ - -static const unsigned char s390_ft_main_64[] = { - /* Load the literals into registers. */ - 0xe3, 0x50, 0x10, 0x00, 0x00, 0x04, /* lg %r5, 0x00(%r1) */ - 0xe3, 0x20, 0x10, 0x08, 0x00, 0x04, /* lg %r2, 0x08(%r1) */ - 0xe3, 0x40, 0x10, 0x10, 0x00, 0x04, /* lg %r4, 0x10(%r1) */ - 0xe3, 0x60, 0x10, 0x18, 0x00, 0x04, /* lg %r6, 0x18(%r1) */ - /* Save original PSWA (tracepoint address). */ - 0xe3, 0x50, 0xf2, 0xc8, 0x00, 0x24, /* stg %r5, 0x2c8(%r15) */ - /* Construct a collecting_t object at %r15+0x2e0. */ - 0xe3, 0x20, 0xf2, 0xe0, 0x00, 0x24, /* stg %r2, 0x2e0(%r15) */ - 0x9b, 0x01, 0xf2, 0xe8, /* stam %a0, %a1, 0x2e8(%r15) */ - /* Move its address to %r0. */ - 0x41, 0x00, 0xf2, 0xe0, /* la %r0, 0x2e0(%r15) */ - /* Take the lock. */ - /* .Lloop: */ - 0xa7, 0x19, 0x00, 0x00, /* lghi %r1, 0 */ - 0xeb, 0x10, 0x60, 0x00, 0x00, 0x30, /* csg %r1, %r0, 0(%r6) */ - 0xa7, 0x74, 0xff, 0xfb, /* jne .Lloop */ - /* Address of the register save block to %r3. */ - 0xb9, 0x04, 0x00, 0x3f, /* lgr %r3, %r15 */ - /* Make a stack frame, so that we can call the collector. */ - 0xa7, 0xfb, 0xff, 0x60, /* aghi %r15, -0xa0 */ - /* Call it. */ - 0x0d, 0xe4, /* basr %r14, %r4 */ - /* And get rid of the stack frame again. */ - 0x41, 0xf0, 0xf0, 0xa0, /* la %r15, 0xa0(%r15) */ - /* Leave the lock. */ - 0x07, 0xf0, /* br %r0 */ - 0xa7, 0x19, 0x00, 0x00, /* lghi %r1, 0 */ - 0xe3, 0x10, 0x60, 0x00, 0x00, 0x24, /* stg %t1, 0(%r6) */ -}; - -/* Code sequence restoring FRs, for targets with no VX support. */ - -static const unsigned char s390_ft_exit_fr[] = { - 0x68, 0x00, 0xf0, 0x00, /* ld %f0, 0x000(%r15) */ - 0x68, 0x10, 0xf0, 0x10, /* ld %f1, 0x010(%r15) */ - 0x68, 0x20, 0xf0, 0x20, /* ld %f2, 0x020(%r15) */ - 0x68, 0x30, 0xf0, 0x30, /* ld %f3, 0x030(%r15) */ - 0x68, 0x40, 0xf0, 0x40, /* ld %f4, 0x040(%r15) */ - 0x68, 0x50, 0xf0, 0x50, /* ld %f5, 0x050(%r15) */ - 0x68, 0x60, 0xf0, 0x60, /* ld %f6, 0x060(%r15) */ - 0x68, 0x70, 0xf0, 0x70, /* ld %f7, 0x070(%r15) */ - 0x68, 0x80, 0xf0, 0x80, /* ld %f8, 0x080(%r15) */ - 0x68, 0x90, 0xf0, 0x90, /* ld %f9, 0x090(%r15) */ - 0x68, 0xa0, 0xf0, 0xa0, /* ld %f10, 0x0a0(%r15) */ - 0x68, 0xb0, 0xf0, 0xb0, /* ld %f11, 0x0b0(%r15) */ - 0x68, 0xc0, 0xf0, 0xc0, /* ld %f12, 0x0c0(%r15) */ - 0x68, 0xd0, 0xf0, 0xd0, /* ld %f13, 0x0d0(%r15) */ - 0x68, 0xe0, 0xf0, 0xe0, /* ld %f14, 0x0e0(%r15) */ - 0x68, 0xf0, 0xf0, 0xf0, /* ld %f15, 0x0f0(%r15) */ -}; - -/* Code sequence restoring VRs. */ - -static const unsigned char s390_ft_exit_vr[] = { - 0xe7, 0x0f, 0xf0, 0x00, 0x00, 0x36, /* vlm %v0, %v15, 0x000(%r15) */ - 0xe7, 0x0f, 0xf1, 0x00, 0x0c, 0x36, /* vlm %v16, %v31, 0x100(%r15) */ -}; - -/* Code sequence restoring misc registers. As for PSWM, only CC should be - modified by C code, so we use the alr instruction to restore it by - manufacturing an operand that'll result in the original flags. */ - -static const unsigned char s390_ft_exit_misc[] = { - 0xb2, 0x9d, 0xf2, 0xd0, /* lfpc 0x2d0(%r15) */ - 0x58, 0x00, 0xf2, 0xc0, /* l %r0, 0x2c0(%r15) */ - /* Extract CC to high 2 bits of %r0. */ - 0x88, 0x00, 0x00, 0x0c, /* srl %r0, 12 */ - 0x89, 0x00, 0x00, 0x1e, /* sll %r0, 30 */ - /* Add %r0 to itself. Result will be nonzero iff CC bit 0 is set, and - will have carry iff CC bit 1 is set - resulting in the same flags - as the original. */ - 0x1e, 0x00, /* alr %r0, %r0 */ - 0x9a, 0x0f, 0xf2, 0x80, /* lam %a0, %a15, 0x280(%r15) */ -}; - -/* Code sequence restoring GPRs, for 31-bit targets with no high GPRs. */ - -static const unsigned char s390_ft_exit_gpr_esa[] = { - 0x58, 0x00, 0xf2, 0x04, /* l %r0, 0x204(%r15) */ - 0x58, 0x10, 0xf2, 0x0c, /* l %r1, 0x20c(%r15) */ - 0x58, 0x20, 0xf2, 0x14, /* l %r2, 0x214(%r15) */ - 0x58, 0x30, 0xf2, 0x1c, /* l %r3, 0x21c(%r15) */ - 0x58, 0x40, 0xf2, 0x24, /* l %r4, 0x224(%r15) */ - 0x58, 0x50, 0xf2, 0x2c, /* l %r5, 0x22c(%r15) */ - 0x58, 0x60, 0xf2, 0x34, /* l %r6, 0x234(%r15) */ - 0x58, 0x70, 0xf2, 0x3c, /* l %r7, 0x23c(%r15) */ - 0x58, 0x80, 0xf2, 0x44, /* l %r8, 0x244(%r15) */ - 0x58, 0x90, 0xf2, 0x4c, /* l %r9, 0x24c(%r15) */ - 0x58, 0xa0, 0xf2, 0x54, /* l %r10, 0x254(%r15) */ - 0x58, 0xb0, 0xf2, 0x5c, /* l %r11, 0x25c(%r15) */ - 0x58, 0xc0, 0xf2, 0x64, /* l %r12, 0x264(%r15) */ - 0x58, 0xd0, 0xf2, 0x6c, /* l %r13, 0x26c(%r15) */ - 0x58, 0xe0, 0xf2, 0x74, /* l %r14, 0x274(%r15) */ - 0x58, 0xf0, 0xf2, 0x7c, /* l %r15, 0x27c(%r15) */ -}; - -/* Code sequence restoring GPRs, for 64-bit targets and 31-bit targets - with high GPRs. */ - -static const unsigned char s390_ft_exit_gpr_zarch[] = { - 0xeb, 0x0f, 0xf2, 0x00, 0x00, 0x04, /* lmg %r0, %r15, 0x200(%r15) */ -}; - -/* Writes instructions to target, updating the to pointer. */ - -static void -append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf) -{ - target_write_memory (*to, buf, len); - *to += len; -} - -/* Relocates an instruction from oldloc to *to, updating to. */ - -static int -s390_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc, int is_64) -{ - gdb_byte buf[6]; - int ilen; - int op2; - /* 0: no fixup, 1: PC16DBL fixup, 2: PC32DBL fixup. */ - int mode = 0; - int is_bras = 0; - read_inferior_memory (oldloc, buf, sizeof buf); - if (buf[0] < 0x40) - ilen = 2; - else if (buf[0] < 0xc0) - ilen = 4; - else - ilen = 6; - switch (buf[0]) - { - case 0x05: /* BALR */ - case 0x0c: /* BASSM */ - case 0x0d: /* BASR */ - case 0x45: /* BAL */ - case 0x4d: /* BAS */ - /* These save a return address and mess around with registers. - We can't relocate them. */ - return 1; - case 0x84: /* BRXH */ - case 0x85: /* BRXLE */ - mode = 1; - break; - case 0xa7: - op2 = buf[1] & 0xf; - /* BRC, BRAS, BRCT, BRCTG */ - if (op2 >= 4 && op2 <= 7) - mode = 1; - /* BRAS */ - if (op2 == 5) - is_bras = 1; - break; - case 0xc0: - op2 = buf[1] & 0xf; - /* LARL, BRCL, BRASL */ - if (op2 == 0 || op2 == 4 || op2 == 5) - mode = 2; - /* BRASL */ - if (op2 == 5) - is_bras = 1; - break; - case 0xc4: - case 0xc6: - /* PC-relative addressing instructions. */ - mode = 2; - break; - case 0xc5: /* BPRP */ - case 0xc7: /* BPP */ - /* Branch prediction - just skip it. */ - return 0; - case 0xcc: - op2 = buf[1] & 0xf; - /* BRCTH */ - if (op2 == 6) - mode = 2; - break; - case 0xec: - op2 = buf[5]; - switch (op2) - { - case 0x44: /* BRXHG */ - case 0x45: /* BRXLG */ - case 0x64: /* CGRJ */ - case 0x65: /* CLGRJ */ - case 0x76: /* CRJ */ - case 0x77: /* CLRJ */ - mode = 1; - break; - } - break; - } - - if (mode != 0) - { - /* We'll have to relocate an instruction with a PC-relative field. - First, compute the target. */ - int64_t loffset = 0; - CORE_ADDR target; - if (mode == 1) - { - int16_t soffset = 0; - memcpy (&soffset, buf + 2, 2); - loffset = soffset; - } - else if (mode == 2) - { - int32_t soffset = 0; - memcpy (&soffset, buf + 2, 4); - loffset = soffset; - } - target = oldloc + loffset * 2; - if (!is_64) - target &= 0x7fffffff; - - if (is_bras) - { - /* BRAS or BRASL was used. We cannot just relocate those, since - they save the return address in a register. We can, however, - replace them with a LARL+JG sequence. */ - - /* Make the LARL. */ - int32_t soffset; - buf[0] = 0xc0; - buf[1] &= 0xf0; - loffset = oldloc + ilen - *to; - loffset >>= 1; - soffset = loffset; - if (soffset != loffset && is_64) - return 1; - memcpy (buf + 2, &soffset, 4); - append_insns (to, 6, buf); - - /* Note: this is not fully correct. In 31-bit mode, LARL will write - an address with the top bit 0, while BRAS/BRASL will write it - with top bit 1. It should not matter much, since linux compilers - use BR and not BSM to return from functions, but it could confuse - some poor stack unwinder. */ - - /* We'll now be writing a JG. */ - mode = 2; - buf[0] = 0xc0; - buf[1] = 0xf4; - ilen = 6; - } - - /* Compute the new offset and write it to the buffer. */ - loffset = target - *to; - loffset >>= 1; - - if (mode == 1) - { - int16_t soffset = loffset; - if (soffset != loffset) - return 1; - memcpy (buf + 2, &soffset, 2); - } - else if (mode == 2) - { - int32_t soffset = loffset; - if (soffset != loffset && is_64) - return 1; - memcpy (buf + 2, &soffset, 4); - } - } - append_insns (to, ilen, buf); - return 0; -} - -/* Implementation of linux_target_ops method - "install_fast_tracepoint_jump_pad". */ - -static int -s390_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, - CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ - int i; - int64_t loffset; - int32_t offset; - unsigned char jbuf[6] = { 0xc0, 0xf4, 0, 0, 0, 0 }; /* jg ... */ - CORE_ADDR buildaddr = *jump_entry; -#ifdef __s390x__ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - int is_64 = register_size (regcache->tdesc, 0) == 8; - int is_zarch = is_64 || have_hwcap_s390_high_gprs; - int has_vx = have_hwcap_s390_vx; -#else - int is_64 = 0, is_zarch = 0, has_vx = 0; -#endif - CORE_ADDR literals[4] = { - tpaddr, - tpoint, - collector, - lockaddr, - }; - - /* First, store the GPRs. */ - if (is_zarch) - append_insns (&buildaddr, sizeof s390_ft_entry_gpr_zarch, - s390_ft_entry_gpr_zarch); - else - append_insns (&buildaddr, sizeof s390_ft_entry_gpr_esa, - s390_ft_entry_gpr_esa); - - /* Second, misc registers (ARs, PSWM, FPC). PSWA will be stored below. */ - append_insns (&buildaddr, sizeof s390_ft_entry_misc, s390_ft_entry_misc); - - /* Third, FRs or VRs. */ - if (has_vx) - append_insns (&buildaddr, sizeof s390_ft_entry_vr, s390_ft_entry_vr); - else - append_insns (&buildaddr, sizeof s390_ft_entry_fr, s390_ft_entry_fr); - - /* Now, the main part of code - store PSWA, take lock, call collector, - leave lock. First, we'll need to fetch 4 literals. */ - if (is_64) { - unsigned char buf[] = { - 0x07, 0x07, /* nopr %r7 */ - 0x07, 0x07, /* nopr %r7 */ - 0x07, 0x07, /* nopr %r7 */ - 0xa7, 0x15, 0x00, 0x12, /* bras %r1, .Lend */ - 0, 0, 0, 0, 0, 0, 0, 0, /* tpaddr */ - 0, 0, 0, 0, 0, 0, 0, 0, /* tpoint */ - 0, 0, 0, 0, 0, 0, 0, 0, /* collector */ - 0, 0, 0, 0, 0, 0, 0, 0, /* lockaddr */ - /* .Lend: */ - }; - /* Find the proper start place in buf, so that literals will be - aligned. */ - int bufpos = (buildaddr + 2) & 7; - /* Stuff the literals into the buffer. */ - for (i = 0; i < 4; i++) { - uint64_t lit = literals[i]; - memcpy (&buf[sizeof buf - 32 + i * 8], &lit, 8); - } - append_insns (&buildaddr, sizeof buf - bufpos, buf + bufpos); - append_insns (&buildaddr, sizeof s390_ft_main_64, s390_ft_main_64); - } else { - unsigned char buf[] = { - 0x07, 0x07, /* nopr %r7 */ - 0xa7, 0x15, 0x00, 0x0a, /* bras %r1, .Lend */ - 0, 0, 0, 0, /* tpaddr */ - 0, 0, 0, 0, /* tpoint */ - 0, 0, 0, 0, /* collector */ - 0, 0, 0, 0, /* lockaddr */ - /* .Lend: */ - }; - /* Find the proper start place in buf, so that literals will be - aligned. */ - int bufpos = (buildaddr + 2) & 3; - /* First literal will be saved as the PSWA, make sure it has the high bit - set. */ - literals[0] |= 0x80000000; - /* Stuff the literals into the buffer. */ - for (i = 0; i < 4; i++) { - uint32_t lit = literals[i]; - memcpy (&buf[sizeof buf - 16 + i * 4], &lit, 4); - } - append_insns (&buildaddr, sizeof buf - bufpos, buf + bufpos); - append_insns (&buildaddr, sizeof s390_ft_main_31, s390_ft_main_31); - } - - /* Restore FRs or VRs. */ - if (has_vx) - append_insns (&buildaddr, sizeof s390_ft_exit_vr, s390_ft_exit_vr); - else - append_insns (&buildaddr, sizeof s390_ft_exit_fr, s390_ft_exit_fr); - - /* Restore misc registers. */ - append_insns (&buildaddr, sizeof s390_ft_exit_misc, s390_ft_exit_misc); - - /* Restore the GPRs. */ - if (is_zarch) - append_insns (&buildaddr, sizeof s390_ft_exit_gpr_zarch, - s390_ft_exit_gpr_zarch); - else - append_insns (&buildaddr, sizeof s390_ft_exit_gpr_esa, - s390_ft_exit_gpr_esa); - - /* Now, adjust the original instruction to execute in the jump - pad. */ - *adjusted_insn_addr = buildaddr; - if (s390_relocate_instruction (&buildaddr, tpaddr, is_64)) - { - sprintf (err, "E.Could not relocate instruction for tracepoint."); - return 1; - } - *adjusted_insn_addr_end = buildaddr; - - /* Finally, write a jump back to the program. */ - - loffset = (tpaddr + orig_size) - buildaddr; - loffset >>= 1; - offset = loffset; - if (is_64 && offset != loffset) - { - sprintf (err, - "E.Jump back from jump pad too far from tracepoint " - "(offset 0x%" PRIx64 " > int33).", loffset); - return 1; - } - memcpy (jbuf + 2, &offset, 4); - append_insns (&buildaddr, sizeof jbuf, jbuf); - - /* The jump pad is now built. Wire in a jump to our jump pad. This - is always done last (by our caller actually), so that we can - install fast tracepoints with threads running. This relies on - the agent's atomic write support. */ - loffset = *jump_entry - tpaddr; - loffset >>= 1; - offset = loffset; - if (is_64 && offset != loffset) - { - sprintf (err, - "E.Jump back from jump pad too far from tracepoint " - "(offset 0x%" PRIx64 " > int33).", loffset); - return 1; - } - memcpy (jbuf + 2, &offset, 4); - memcpy (jjump_pad_insn, jbuf, sizeof jbuf); - *jjump_pad_insn_size = sizeof jbuf; - - /* Return the end address of our pad. */ - *jump_entry = buildaddr; - - return 0; -} - -/* Implementation of linux_target_ops method - "get_min_fast_tracepoint_insn_len". */ - -static int -s390_get_min_fast_tracepoint_insn_len (void) -{ - /* We only support using 6-byte jumps to reach the tracepoint code. - If the tracepoint buffer were allocated sufficiently close (64kiB) - to the executable code, and the traced instruction itself was close - enough to the beginning, we could use 4-byte jumps, but this doesn't - seem to be worth the effort. */ - return 6; -} - -/* Implementation of linux_target_ops method "get_ipa_tdesc_idx". */ - -static int -s390_get_ipa_tdesc_idx (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - const struct target_desc *tdesc = regcache->tdesc; - -#ifdef __s390x__ - if (tdesc == tdesc_s390x_linux64) - return S390_TDESC_64; - if (tdesc == tdesc_s390x_linux64v1) - return S390_TDESC_64V1; - if (tdesc == tdesc_s390x_linux64v2) - return S390_TDESC_64V2; - if (tdesc == tdesc_s390x_te_linux64) - return S390_TDESC_TE; - if (tdesc == tdesc_s390x_vx_linux64) - return S390_TDESC_VX; - if (tdesc == tdesc_s390x_tevx_linux64) - return S390_TDESC_TEVX; - if (tdesc == tdesc_s390x_gs_linux64) - return S390_TDESC_GS; -#endif - - if (tdesc == tdesc_s390_linux32) - return S390_TDESC_32; - if (tdesc == tdesc_s390_linux32v1) - return S390_TDESC_32V1; - if (tdesc == tdesc_s390_linux32v2) - return S390_TDESC_32V2; - if (tdesc == tdesc_s390_linux64) - return S390_TDESC_64; - if (tdesc == tdesc_s390_linux64v1) - return S390_TDESC_64V1; - if (tdesc == tdesc_s390_linux64v2) - return S390_TDESC_64V2; - if (tdesc == tdesc_s390_te_linux64) - return S390_TDESC_TE; - if (tdesc == tdesc_s390_vx_linux64) - return S390_TDESC_VX; - if (tdesc == tdesc_s390_tevx_linux64) - return S390_TDESC_TEVX; - if (tdesc == tdesc_s390_gs_linux64) - return S390_TDESC_GS; - - return 0; -} - -/* Appends given buffer to current_insn_ptr in the target. */ - -static void -add_insns (const unsigned char *start, int len) -{ - CORE_ADDR buildaddr = current_insn_ptr; - - if (debug_threads) - debug_printf ("Adding %d bytes of insn at %s\n", - len, paddress (buildaddr)); - - append_insns (&buildaddr, len, start); - current_insn_ptr = buildaddr; -} - -/* Register usage in emit: - - - %r0, %r1: temp - - %r2: top of stack (high word for 31-bit) - - %r3: low word of top of stack (for 31-bit) - - %r4, %r5: temp - - %r6, %r7, %r8: don't use - - %r9: saved arg1 - - %r10: saved arg2 - - %r11: frame pointer - - %r12: saved top of stack for void_call_2 (high word for 31-bit) - - %r13: low word of saved top of stack (for 31-bit) - - %r14: return address for calls - - %r15: stack pointer - - */ - -/* The "emit_prologue" emit_ops method for s390. */ - -static void -s390_emit_prologue (void) -{ - static const unsigned char buf[] = { - 0x90, 0x9f, 0xf0, 0x24, /* stm %r9, %r15, 0x24(%r15) */ - 0x18, 0x92, /* lr %r9, %r2 */ - 0x18, 0xa3, /* lr %r10, %r3 */ - 0x18, 0xbf, /* lr %r11, %r15 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_epilogue" emit_ops method for s390. */ - -static void -s390_emit_epilogue (void) -{ - static const unsigned char buf[] = { - 0x90, 0x23, 0xa0, 0x00, /* stm %r2, %r3, 0(%r10) */ - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0x98, 0x9f, 0xb0, 0x24, /* lm %r9, %r15, 0x24(%r11) */ - 0x07, 0xfe, /* br %r14 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_add" emit_ops method for s390. */ - -static void -s390_emit_add (void) -{ - static const unsigned char buf[] = { - 0x5e, 0x30, 0xf0, 0x04, /* al %r3, 4(%r15) */ - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x98, /* al %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_sub" emit_ops method for s390. */ - -static void -s390_emit_sub (void) -{ - static const unsigned char buf[] = { - 0x98, 0x45, 0xf0, 0x00, /* lm %r4, %r5, 0(%r15) */ - 0x1f, 0x53, /* slr %r5, %r3 */ - 0xb9, 0x99, 0x00, 0x42, /* slbr %r4, %r2 */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - 0x18, 0x35, /* lr %r3, %r5 */ - 0x18, 0x24, /* lr %r2, %r4 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_mul" emit_ops method for s390. */ - -static void -s390_emit_mul (void) -{ - emit_error = 1; -} - -/* The "emit_lsh" emit_ops method for s390. */ - -static void -s390_emit_lsh (void) -{ - static const unsigned char buf[] = { - 0x18, 0x43, /* lr %r4, %r3 */ - 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ - 0x8d, 0x20, 0x40, 0x00, /* sldl %r2, 0(%r4) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_rsh_signed" emit_ops method for s390. */ - -static void -s390_emit_rsh_signed (void) -{ - static const unsigned char buf[] = { - 0x18, 0x43, /* lr %r4, %r3 */ - 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ - 0x8e, 0x20, 0x40, 0x00, /* srda %r2, 0(%r4) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_rsh_unsigned" emit_ops method for s390. */ - -static void -s390_emit_rsh_unsigned (void) -{ - static const unsigned char buf[] = { - 0x18, 0x43, /* lr %r4, %r3 */ - 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ - 0x8c, 0x20, 0x40, 0x00, /* srdl %r2, 0(%r4) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_ext" emit_ops method for s390. */ - -static void -s390_emit_ext (int arg) -{ - unsigned char buf[] = { - 0x8d, 0x20, 0x00, (unsigned char) (64 - arg), /* sldl %r2, <64-arg> */ - 0x8e, 0x20, 0x00, (unsigned char) (64 - arg), /* srda %r2, <64-arg> */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_log_not" emit_ops method for s390. */ - -static void -s390_emit_log_not (void) -{ - static const unsigned char buf[] = { - 0x16, 0x23, /* or %r2, %r3 */ - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */ - 0xa7, 0x74, 0x00, 0x04, /* jne .Lskip */ - 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */ - /* .Lskip: */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_and" emit_ops method for s390. */ - -static void -s390_emit_bit_and (void) -{ - static const unsigned char buf[] = { - 0x54, 0x20, 0xf0, 0x00, /* n %r2, 0(%r15) */ - 0x54, 0x30, 0xf0, 0x04, /* n %r3, 4(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_or" emit_ops method for s390. */ - -static void -s390_emit_bit_or (void) -{ - static const unsigned char buf[] = { - 0x56, 0x20, 0xf0, 0x00, /* o %r2, 0(%r15) */ - 0x56, 0x30, 0xf0, 0x04, /* o %r3, 4(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_xor" emit_ops method for s390. */ - -static void -s390_emit_bit_xor (void) -{ - static const unsigned char buf[] = { - 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */ - 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_not" emit_ops method for s390. */ - -static void -s390_emit_bit_not (void) -{ - static const unsigned char buf[] = { - 0xa7, 0x48, 0xff, 0xff, /* lhi %r4, -1 */ - 0x17, 0x24, /* xr %r2, %r4 */ - 0x17, 0x34, /* xr %r3, %r4 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_equal" emit_ops method for s390. */ - -static void -s390_emit_equal (void) -{ - s390_emit_bit_xor (); - s390_emit_log_not (); -} - -/* The "emit_less_signed" emit_ops method for s390. */ - -static void -s390_emit_less_signed (void) -{ - static const unsigned char buf[] = { - 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ - 0xa7, 0x24, 0x00, 0x0c, /* jh .Lless */ - 0xa7, 0x44, 0x00, 0x06, /* jl .Lhigh */ - 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ - 0xa7, 0x24, 0x00, 0x06, /* jh .Lless */ - /* .Lhigh: */ - 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */ - 0xa7, 0xf4, 0x00, 0x04, /* j .Lend */ - /* .Lless: */ - 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */ - /* .Lend: */ - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_less_unsigned" emit_ops method for s390. */ - -static void -s390_emit_less_unsigned (void) -{ - static const unsigned char buf[] = { - 0x55, 0x20, 0xf0, 0x00, /* cl %r2, 0(%r15) */ - 0xa7, 0x24, 0x00, 0x0c, /* jh .Lless */ - 0xa7, 0x44, 0x00, 0x06, /* jl .Lhigh */ - 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ - 0xa7, 0x24, 0x00, 0x06, /* jh .Lless */ - /* .Lhigh: */ - 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */ - 0xa7, 0xf4, 0x00, 0x04, /* j .Lend */ - /* .Lless: */ - 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */ - /* .Lend: */ - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_ref" emit_ops method for s390. */ - -static void -s390_emit_ref (int size) -{ - static const unsigned char buf1[] = { - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0x43, 0x30, 0x30, 0x00, /* ic %r3, 0(%r3) */ - }; - static const unsigned char buf2[] = { - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0x48, 0x30, 0x30, 0x00, /* lh %r3, 0(%r3) */ - }; - static const unsigned char buf4[] = { - 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ - 0x58, 0x30, 0x30, 0x00, /* l %r3, 0(%r3) */ - }; - static const unsigned char buf8[] = { - 0x98, 0x23, 0x30, 0x00, /* lm %r2, %r3, 0(%r3) */ - }; - switch (size) - { - case 1: - add_insns (buf1, sizeof buf1); - break; - case 2: - add_insns (buf2, sizeof buf2); - break; - case 4: - add_insns (buf4, sizeof buf4); - break; - case 8: - add_insns (buf8, sizeof buf8); - break; - default: - emit_error = 1; - } -} - -/* The "emit_if_goto" emit_ops method for s390. */ - -static void -s390_emit_if_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x16, 0x23, /* or %r2, %r3 */ - 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00 /* jgne */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 12; - if (size_p) - *size_p = 4; -} - -/* The "emit_goto" emit_ops method for s390 and s390x. */ - -static void -s390_emit_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 2; - if (size_p) - *size_p = 4; -} - -/* The "write_goto_address" emit_ops method for s390 and s390x. */ - -static void -s390_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) -{ - long diff = ((long) (to - (from - 2))) / 2; - int sdiff = diff; - unsigned char buf[sizeof sdiff]; - - /* We're only doing 4-byte sizes at the moment. */ - if (size != sizeof sdiff || sdiff != diff) - { - emit_error = 1; - return; - } - - memcpy (buf, &sdiff, sizeof sdiff); - target_write_memory (from, buf, sizeof sdiff); -} - -/* Preparation for emitting a literal pool of given size. Loads the address - of the pool into %r1, and jumps over it. Called should emit the pool data - immediately afterwards. Used for both s390 and s390x. */ - -static void -s390_emit_litpool (int size) -{ - static const unsigned char nop[] = { - 0x07, 0x07, - }; - unsigned char buf[] = { - 0xa7, 0x15, 0x00, - (unsigned char) ((size + 4) / 2), /* bras %r1, .Lend+size */ - /* .Lend: */ - }; - if (size == 4) - { - /* buf needs to start at even halfword for litpool to be aligned */ - if (current_insn_ptr & 2) - add_insns (nop, sizeof nop); - } - else - { - while ((current_insn_ptr & 6) != 4) - add_insns (nop, sizeof nop); - } - add_insns (buf, sizeof buf); -} - -/* The "emit_const" emit_ops method for s390. */ - -static void -s390_emit_const (LONGEST num) -{ - unsigned long long n = num; - unsigned char buf_s[] = { - /* lhi %r3, */ - 0xa7, 0x38, - (unsigned char) (num >> 8), (unsigned char) num, - /* xr %r2, %r2 */ - 0x17, 0x22, - }; - static const unsigned char buf_l[] = { - 0x98, 0x23, 0x10, 0x00, /* lm %r2, %r3, 0(%r1) */ - }; - if (num < 0x8000 && num >= 0) - { - add_insns (buf_s, sizeof buf_s); - } - else - { - s390_emit_litpool (8); - add_insns ((unsigned char *) &n, sizeof n); - add_insns (buf_l, sizeof buf_l); - } -} - -/* The "emit_call" emit_ops method for s390. */ - -static void -s390_emit_call (CORE_ADDR fn) -{ - unsigned int n = fn; - static const unsigned char buf[] = { - 0x58, 0x10, 0x10, 0x00, /* l %r1, 0(%r1) */ - 0xa7, 0xfa, 0xff, 0xa0, /* ahi %r15, -0x60 */ - 0x0d, 0xe1, /* basr %r14, %r1 */ - 0xa7, 0xfa, 0x00, 0x60, /* ahi %r15, 0x60 */ - }; - s390_emit_litpool (4); - add_insns ((unsigned char *) &n, sizeof n); - add_insns (buf, sizeof buf); -} - -/* The "emit_reg" emit_ops method for s390. */ - -static void -s390_emit_reg (int reg) -{ - unsigned char bufpre[] = { - /* lr %r2, %r9 */ - 0x18, 0x29, - /* lhi %r3, */ - 0xa7, 0x38, (unsigned char) (reg >> 8), (unsigned char) reg, - }; - add_insns (bufpre, sizeof bufpre); - s390_emit_call (get_raw_reg_func_addr ()); -} - -/* The "emit_pop" emit_ops method for s390. */ - -static void -s390_emit_pop (void) -{ - static const unsigned char buf[] = { - 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_stack_flush" emit_ops method for s390. */ - -static void -s390_emit_stack_flush (void) -{ - static const unsigned char buf[] = { - 0xa7, 0xfa, 0xff, 0xf8, /* ahi %r15, -8 */ - 0x90, 0x23, 0xf0, 0x00, /* stm %r2, %r3, 0(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_zero_ext" emit_ops method for s390. */ - -static void -s390_emit_zero_ext (int arg) -{ - unsigned char buf[] = { - 0x8d, 0x20, 0x00, (unsigned char) (64 - arg), /* sldl %r2, <64-arg> */ - 0x8c, 0x20, 0x00, (unsigned char) (64 - arg), /* srdl %r2, <64-arg> */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_swap" emit_ops method for s390. */ - -static void -s390_emit_swap (void) -{ - static const unsigned char buf[] = { - 0x98, 0x45, 0xf0, 0x00, /* lm %r4, %r5, 0(%r15) */ - 0x90, 0x23, 0xf0, 0x00, /* stm %r2, %r3, 0(%r15) */ - 0x18, 0x24, /* lr %r2, %r4 */ - 0x18, 0x35, /* lr %r3, %r5 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_stack_adjust" emit_ops method for s390. */ - -static void -s390_emit_stack_adjust (int n) -{ - unsigned char buf[] = { - /* ahi %r15, 8*n */ - 0xa7, 0xfa, - (unsigned char ) (n * 8 >> 8), (unsigned char) (n * 8), - }; - add_insns (buf, sizeof buf); -} - -/* Sets %r2 to a 32-bit constant. */ - -static void -s390_emit_set_r2 (int arg1) -{ - unsigned char buf_s[] = { - /* lhi %r2, */ - 0xa7, 0x28, (unsigned char) (arg1 >> 8), (unsigned char) arg1, - }; - static const unsigned char buf_l[] = { - 0x58, 0x20, 0x10, 0x00, /* l %r2, 0(%r1) */ - }; - if (arg1 < 0x8000 && arg1 >= -0x8000) - { - add_insns (buf_s, sizeof buf_s); - } - else - { - s390_emit_litpool (4); - add_insns ((unsigned char *) &arg1, sizeof arg1); - add_insns (buf_l, sizeof buf_l); - } -} - -/* The "emit_int_call_1" emit_ops method for s390. */ - -static void -s390_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - /* FN's prototype is `LONGEST(*fn)(int)'. */ - s390_emit_set_r2 (arg1); - s390_emit_call (fn); -} - -/* The "emit_void_call_2" emit_ops method for s390. */ - -static void -s390_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - /* FN's prototype is `void(*fn)(int,LONGEST)'. */ - static const unsigned char buf[] = { - 0x18, 0xc2, /* lr %r12, %r2 */ - 0x18, 0xd3, /* lr %r13, %r3 */ - 0x18, 0x43, /* lr %r4, %r3 */ - 0x18, 0x32, /* lr %r3, %r2 */ - }; - static const unsigned char buf2[] = { - 0x18, 0x2c, /* lr %r2, %r12 */ - 0x18, 0x3d, /* lr %r3, %r13 */ - }; - add_insns (buf, sizeof buf); - s390_emit_set_r2 (arg1); - s390_emit_call (fn); - add_insns (buf2, sizeof buf2); -} - -/* The "emit_eq_goto" emit_ops method for s390. */ - -static void -s390_emit_eq_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */ - 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */ - 0x16, 0x23, /* or %r2, %r3 */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0x84, 0x00, 0x00, 0x00, 0x00, /* jge */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 20; - if (size_p) - *size_p = 4; -} - -/* The "emit_ne_goto" emit_ops method for s390. */ - -static void -s390_emit_ne_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */ - 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */ - 0x16, 0x23, /* or %r2, %r3 */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 20; - if (size_p) - *size_p = 4; -} - -/* The "emit_lt_goto" emit_ops method for s390. */ - -static void -s390_emit_lt_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ - 0xa7, 0x24, 0x00, 0x0e, /* jh .Ltrue */ - 0xa7, 0x44, 0x00, 0x06, /* jl .Lfalse */ - 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ - 0xa7, 0x24, 0x00, 0x08, /* jh .Ltrue */ - /* .Lfalse: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ - /* .Ltrue: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ - /* .Lend: */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 42; - if (size_p) - *size_p = 4; -} - -/* The "emit_le_goto" emit_ops method for s390. */ - -static void -s390_emit_le_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ - 0xa7, 0x24, 0x00, 0x0e, /* jh .Ltrue */ - 0xa7, 0x44, 0x00, 0x06, /* jl .Lfalse */ - 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ - 0xa7, 0xa4, 0x00, 0x08, /* jhe .Ltrue */ - /* .Lfalse: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ - /* .Ltrue: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ - /* .Lend: */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 42; - if (size_p) - *size_p = 4; -} - -/* The "emit_gt_goto" emit_ops method for s390. */ - -static void -s390_emit_gt_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ - 0xa7, 0x44, 0x00, 0x0e, /* jl .Ltrue */ - 0xa7, 0x24, 0x00, 0x06, /* jh .Lfalse */ - 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ - 0xa7, 0x44, 0x00, 0x08, /* jl .Ltrue */ - /* .Lfalse: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ - /* .Ltrue: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ - /* .Lend: */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 42; - if (size_p) - *size_p = 4; -} - -/* The "emit_ge_goto" emit_ops method for s390. */ - -static void -s390_emit_ge_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ - 0xa7, 0x44, 0x00, 0x0e, /* jl .Ltrue */ - 0xa7, 0x24, 0x00, 0x06, /* jh .Lfalse */ - 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ - 0xa7, 0xc4, 0x00, 0x08, /* jle .Ltrue */ - /* .Lfalse: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ - /* .Ltrue: */ - 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ - /* .Lend: */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 42; - if (size_p) - *size_p = 4; -} - -/* The "emit_ops" structure for s390. Named _impl to avoid name - collision with s390_emit_ops function. */ - -static struct emit_ops s390_emit_ops_impl = - { - s390_emit_prologue, - s390_emit_epilogue, - s390_emit_add, - s390_emit_sub, - s390_emit_mul, - s390_emit_lsh, - s390_emit_rsh_signed, - s390_emit_rsh_unsigned, - s390_emit_ext, - s390_emit_log_not, - s390_emit_bit_and, - s390_emit_bit_or, - s390_emit_bit_xor, - s390_emit_bit_not, - s390_emit_equal, - s390_emit_less_signed, - s390_emit_less_unsigned, - s390_emit_ref, - s390_emit_if_goto, - s390_emit_goto, - s390_write_goto_address, - s390_emit_const, - s390_emit_call, - s390_emit_reg, - s390_emit_pop, - s390_emit_stack_flush, - s390_emit_zero_ext, - s390_emit_swap, - s390_emit_stack_adjust, - s390_emit_int_call_1, - s390_emit_void_call_2, - s390_emit_eq_goto, - s390_emit_ne_goto, - s390_emit_lt_goto, - s390_emit_le_goto, - s390_emit_gt_goto, - s390_emit_ge_goto - }; - -#ifdef __s390x__ - -/* The "emit_prologue" emit_ops method for s390x. */ - -static void -s390x_emit_prologue (void) -{ - static const unsigned char buf[] = { - 0xeb, 0x9f, 0xf0, 0x48, 0x00, 0x24, /* stmg %r9, %r15, 0x48(%r15) */ - 0xb9, 0x04, 0x00, 0x92, /* lgr %r9, %r2 */ - 0xb9, 0x04, 0x00, 0xa3, /* lgr %r10, %r3 */ - 0xb9, 0x04, 0x00, 0xbf, /* lgr %r11, %r15 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_epilogue" emit_ops method for s390x. */ - -static void -s390x_emit_epilogue (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xa0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r10) */ - 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */ - 0xeb, 0x9f, 0xf0, 0x48, 0x00, 0x04, /* lmg %r9, %r15, 0x48(%r15) */ - 0x07, 0xfe, /* br %r14 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_add" emit_ops method for s390x. */ - -static void -s390x_emit_add (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x0a, /* alg %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_sub" emit_ops method for s390x. */ - -static void -s390x_emit_sub (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ - 0xb9, 0x0b, 0x00, 0x32, /* slgr %r3, %r2 */ - 0xb9, 0x04, 0x00, 0x23, /* lgr %r2, %r3 */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_mul" emit_ops method for s390x. */ - -static void -s390x_emit_mul (void) -{ - emit_error = 1; -} - -/* The "emit_lsh" emit_ops method for s390x. */ - -static void -s390x_emit_lsh (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ - 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0d, /* sllg %r2, %r3, 0(%r2) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_rsh_signed" emit_ops method for s390x. */ - -static void -s390x_emit_rsh_signed (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ - 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0a, /* srag %r2, %r3, 0(%r2) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_rsh_unsigned" emit_ops method for s390x. */ - -static void -s390x_emit_rsh_unsigned (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ - 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0c, /* srlg %r2, %r3, 0(%r2) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_ext" emit_ops method for s390x. */ - -static void -s390x_emit_ext (int arg) -{ - unsigned char buf[] = { - /* sllg %r2, %r2, <64-arg> */ - 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0d, - /* srag %r2, %r2, <64-arg> */ - 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0a, - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_log_not" emit_ops method for s390x. */ - -static void -s390x_emit_log_not (void) -{ - static const unsigned char buf[] = { - 0xb9, 0x00, 0x00, 0x22, /* lpgr %r2, %r2 */ - 0xa7, 0x2b, 0xff, 0xff, /* aghi %r2, -1 */ - 0xeb, 0x22, 0x00, 0x3f, 0x00, 0x0c, /* srlg %r2, %r2, 63 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_and" emit_ops method for s390x. */ - -static void -s390x_emit_bit_and (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x80, /* ng %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_or" emit_ops method for s390x. */ - -static void -s390x_emit_bit_or (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x81, /* og %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_xor" emit_ops method for s390x. */ - -static void -s390x_emit_bit_xor (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x82, /* xg %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_bit_not" emit_ops method for s390x. */ - -static void -s390x_emit_bit_not (void) -{ - static const unsigned char buf[] = { - 0xa7, 0x39, 0xff, 0xff, /* lghi %r3, -1 */ - 0xb9, 0x82, 0x00, 0x23, /* xgr %r2, %r3 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_equal" emit_ops method for s390x. */ - -static void -s390x_emit_equal (void) -{ - s390x_emit_bit_xor (); - s390x_emit_log_not (); -} - -/* The "emit_less_signed" emit_ops method for s390x. */ - -static void -s390x_emit_less_signed (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xa7, 0x29, 0x00, 0x01, /* lghi %r2, 1 */ - 0xa7, 0x24, 0x00, 0x04, /* jh .Lend */ - 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */ - /* .Lend: */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_less_unsigned" emit_ops method for s390x. */ - -static void -s390x_emit_less_unsigned (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x21, /* clg %r2, 0(%r15) */ - 0xa7, 0x29, 0x00, 0x01, /* lghi %r2, 1 */ - 0xa7, 0x24, 0x00, 0x04, /* jh .Lend */ - 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */ - /* .Lend: */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_ref" emit_ops method for s390x. */ - -static void -s390x_emit_ref (int size) -{ - static const unsigned char buf1[] = { - 0xe3, 0x20, 0x20, 0x00, 0x00, 0x90, /* llgc %r2, 0(%r2) */ - }; - static const unsigned char buf2[] = { - 0xe3, 0x20, 0x20, 0x00, 0x00, 0x91 /* llgh %r2, 0(%r2) */ - }; - static const unsigned char buf4[] = { - 0xe3, 0x20, 0x20, 0x00, 0x00, 0x16, /* llgf %r2, 0(%r2) */ - }; - static const unsigned char buf8[] = { - 0xe3, 0x20, 0x20, 0x00, 0x00, 0x04, /* lg %r2, 0(%r2) */ - }; - switch (size) - { - case 1: - add_insns (buf1, sizeof buf1); - break; - case 2: - add_insns (buf2, sizeof buf2); - break; - case 4: - add_insns (buf4, sizeof buf4); - break; - case 8: - add_insns (buf8, sizeof buf8); - break; - default: - emit_error = 1; - } -} - -/* The "emit_if_goto" emit_ops method for s390x. */ - -static void -s390x_emit_if_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xb9, 0x02, 0x00, 0x22, /* ltgr %r2, %r2 */ - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x04, /* lg %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 16; - if (size_p) - *size_p = 4; -} - -/* The "emit_const" emit_ops method for s390x. */ - -static void -s390x_emit_const (LONGEST num) -{ - unsigned long long n = num; - unsigned char buf_s[] = { - /* lghi %r2, */ - 0xa7, 0x29, (unsigned char) (num >> 8), (unsigned char) num, - }; - static const unsigned char buf_l[] = { - 0xe3, 0x20, 0x10, 0x00, 0x00, 0x04, /* lg %r2, 0(%r1) */ - }; - if (num < 0x8000 && num >= -0x8000) - { - add_insns (buf_s, sizeof buf_s); - } - else - { - s390_emit_litpool (8); - add_insns ((unsigned char *) &n, sizeof n); - add_insns (buf_l, sizeof buf_l); - } -} - -/* The "emit_call" emit_ops method for s390x. */ - -static void -s390x_emit_call (CORE_ADDR fn) -{ - unsigned long n = fn; - static const unsigned char buf[] = { - 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, /* lg %r1, 0(%r1) */ - 0xa7, 0xfb, 0xff, 0x60, /* aghi %r15, -0xa0 */ - 0x0d, 0xe1, /* basr %r14, %r1 */ - 0xa7, 0xfb, 0x00, 0xa0, /* aghi %r15, 0xa0 */ - }; - s390_emit_litpool (8); - add_insns ((unsigned char *) &n, sizeof n); - add_insns (buf, sizeof buf); -} - -/* The "emit_reg" emit_ops method for s390x. */ - -static void -s390x_emit_reg (int reg) -{ - unsigned char buf[] = { - /* lgr %r2, %r9 */ - 0xb9, 0x04, 0x00, 0x29, - /* lghi %r3, */ - 0xa7, 0x39, (unsigned char) (reg >> 8), (unsigned char) reg, - }; - add_insns (buf, sizeof buf); - s390x_emit_call (get_raw_reg_func_addr ()); -} - -/* The "emit_pop" emit_ops method for s390x. */ - -static void -s390x_emit_pop (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x04, /* lg %r2, 0(%r15) */ - 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_stack_flush" emit_ops method for s390x. */ - -static void -s390x_emit_stack_flush (void) -{ - static const unsigned char buf[] = { - 0xa7, 0xfb, 0xff, 0xf8, /* aghi %r15, -8 */ - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r15) */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_zero_ext" emit_ops method for s390x. */ - -static void -s390x_emit_zero_ext (int arg) -{ - unsigned char buf[] = { - /* sllg %r2, %r2, <64-arg> */ - 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0d, - /* srlg %r2, %r2, <64-arg> */ - 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0c, - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_swap" emit_ops method for s390x. */ - -static void -s390x_emit_swap (void) -{ - static const unsigned char buf[] = { - 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r15) */ - 0xb9, 0x04, 0x00, 0x23, /* lgr %r2, %r3 */ - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_stack_adjust" emit_ops method for s390x. */ - -static void -s390x_emit_stack_adjust (int n) -{ - unsigned char buf[] = { - /* aghi %r15, 8*n */ - 0xa7, 0xfb, - (unsigned char) (n * 8 >> 8), (unsigned char) (n * 8), - }; - add_insns (buf, sizeof buf); -} - -/* The "emit_int_call_1" emit_ops method for s390x. */ - -static void -s390x_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - /* FN's prototype is `LONGEST(*fn)(int)'. */ - s390x_emit_const (arg1); - s390x_emit_call (fn); -} - -/* The "emit_void_call_2" emit_ops method for s390x. */ - -static void -s390x_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - /* FN's prototype is `void(*fn)(int,LONGEST)'. */ - static const unsigned char buf[] = { - 0xb9, 0x04, 0x00, 0x32, /* lgr %r3, %r2 */ - 0xb9, 0x04, 0x00, 0xc2, /* lgr %r12, %r2 */ - }; - static const unsigned char buf2[] = { - 0xb9, 0x04, 0x00, 0x2c, /* lgr %r2, %r12 */ - }; - add_insns (buf, sizeof buf); - s390x_emit_const (arg1); - s390x_emit_call (fn); - add_insns (buf2, sizeof buf2); -} - -/* The "emit_eq_goto" emit_ops method for s390x. */ - -static void -s390x_emit_eq_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0x84, 0x00, 0x00, 0x00, 0x00, /* jge */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -/* The "emit_ne_goto" emit_ops method for s390x. */ - -static void -s390x_emit_ne_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -/* The "emit_lt_goto" emit_ops method for s390x. */ - -static void -s390x_emit_lt_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0x24, 0x00, 0x00, 0x00, 0x00, /* jgh */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -/* The "emit_le_goto" emit_ops method for s390x. */ - -static void -s390x_emit_le_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0xa4, 0x00, 0x00, 0x00, 0x00, /* jghe */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -/* The "emit_gt_goto" emit_ops method for s390x. */ - -static void -s390x_emit_gt_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0x44, 0x00, 0x00, 0x00, 0x00, /* jgl */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -/* The "emit_ge_goto" emit_ops method for s390x. */ - -static void -s390x_emit_ge_goto (int *offset_p, int *size_p) -{ - static const unsigned char buf[] = { - 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ - 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ - 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ - 0xc0, 0xc4, 0x00, 0x00, 0x00, 0x00, /* jgle */ - }; - add_insns (buf, sizeof buf); - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -/* The "emit_ops" structure for s390x. */ - -static struct emit_ops s390x_emit_ops = - { - s390x_emit_prologue, - s390x_emit_epilogue, - s390x_emit_add, - s390x_emit_sub, - s390x_emit_mul, - s390x_emit_lsh, - s390x_emit_rsh_signed, - s390x_emit_rsh_unsigned, - s390x_emit_ext, - s390x_emit_log_not, - s390x_emit_bit_and, - s390x_emit_bit_or, - s390x_emit_bit_xor, - s390x_emit_bit_not, - s390x_emit_equal, - s390x_emit_less_signed, - s390x_emit_less_unsigned, - s390x_emit_ref, - s390x_emit_if_goto, - s390_emit_goto, - s390_write_goto_address, - s390x_emit_const, - s390x_emit_call, - s390x_emit_reg, - s390x_emit_pop, - s390x_emit_stack_flush, - s390x_emit_zero_ext, - s390x_emit_swap, - s390x_emit_stack_adjust, - s390x_emit_int_call_1, - s390x_emit_void_call_2, - s390x_emit_eq_goto, - s390x_emit_ne_goto, - s390x_emit_lt_goto, - s390x_emit_le_goto, - s390x_emit_gt_goto, - s390x_emit_ge_goto - }; -#endif - -/* The "emit_ops" linux_target_ops method. */ - -static struct emit_ops * -s390_emit_ops (void) -{ -#ifdef __s390x__ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - if (register_size (regcache->tdesc, 0) == 8) - return &s390x_emit_ops; - else -#endif - return &s390_emit_ops_impl; -} - -struct linux_target_ops the_low_target = { - s390_arch_setup, - s390_regs_info, - s390_cannot_fetch_register, - s390_cannot_store_register, - NULL, /* fetch_register */ - s390_get_pc, - s390_set_pc, - NULL, /* breakpoint_kind_from_pc */ - s390_sw_breakpoint_from_kind, - NULL, - s390_breakpoint_len, - s390_breakpoint_at, - s390_supports_z_point_type, - NULL, - NULL, - NULL, - NULL, - s390_collect_ptrace_register, - s390_supply_ptrace_register, - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - s390_supports_tracepoints, - s390_get_thread_area, - s390_install_fast_tracepoint_jump_pad, - s390_emit_ops, - s390_get_min_fast_tracepoint_insn_len, - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - s390_supports_hardware_single_step, - NULL, /* get_syscall_trapinfo */ - s390_get_ipa_tdesc_idx, -}; - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ - - init_registers_s390_linux32 (); - init_registers_s390_linux32v1 (); - init_registers_s390_linux32v2 (); - init_registers_s390_linux64 (); - init_registers_s390_linux64v1 (); - init_registers_s390_linux64v2 (); - init_registers_s390_te_linux64 (); - init_registers_s390_vx_linux64 (); - init_registers_s390_tevx_linux64 (); - init_registers_s390_gs_linux64 (); -#ifdef __s390x__ - init_registers_s390x_linux64 (); - init_registers_s390x_linux64v1 (); - init_registers_s390x_linux64v2 (); - init_registers_s390x_te_linux64 (); - init_registers_s390x_vx_linux64 (); - init_registers_s390x_tevx_linux64 (); - init_registers_s390x_gs_linux64 (); -#endif - - initialize_regsets_info (&s390_regsets_info); - initialize_regsets_info (&s390_regsets_info_3264); -} diff --git a/gdb/gdbserver/linux-s390-tdesc.h b/gdb/gdbserver/linux-s390-tdesc.h deleted file mode 100644 index e02d853bf5b..00000000000 --- a/gdb/gdbserver/linux-s390-tdesc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* Low level support for s390, shared between gdbserver and IPA. - - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_S390_TDESC_H -#define GDBSERVER_LINUX_S390_TDESC_H - -/* Note: since IPA obviously knows what ABI it's running on (s390 vs s390x), - it's sufficient to pass only the register set here. This, together with - the ABI known at IPA compile time, maps to a tdesc. */ - -enum s390_linux_tdesc { - S390_TDESC_32, - S390_TDESC_32V1, - S390_TDESC_32V2, - S390_TDESC_64, - S390_TDESC_64V1, - S390_TDESC_64V2, - S390_TDESC_TE, - S390_TDESC_VX, - S390_TDESC_TEVX, - S390_TDESC_GS, -}; - -#ifdef __s390x__ - -/* Defined in auto-generated file s390x-linux64.c. */ -void init_registers_s390x_linux64 (void); -extern const struct target_desc *tdesc_s390x_linux64; - -/* Defined in auto-generated file s390x-linux64v1.c. */ -void init_registers_s390x_linux64v1 (void); -extern const struct target_desc *tdesc_s390x_linux64v1; - -/* Defined in auto-generated file s390x-linux64v2.c. */ -void init_registers_s390x_linux64v2 (void); -extern const struct target_desc *tdesc_s390x_linux64v2; - -/* Defined in auto-generated file s390x-te-linux64.c. */ -void init_registers_s390x_te_linux64 (void); -extern const struct target_desc *tdesc_s390x_te_linux64; - -/* Defined in auto-generated file s390x-vx-linux64.c. */ -void init_registers_s390x_vx_linux64 (void); -extern const struct target_desc *tdesc_s390x_vx_linux64; - -/* Defined in auto-generated file s390x-tevx-linux64.c. */ -void init_registers_s390x_tevx_linux64 (void); -extern const struct target_desc *tdesc_s390x_tevx_linux64; - -/* Defined in auto-generated file s390x-gs-linux64.c. */ -void init_registers_s390x_gs_linux64 (void); -extern const struct target_desc *tdesc_s390x_gs_linux64; - -#endif - -#if !defined __s390x__ || !defined IN_PROCESS_AGENT - -/* Defined in auto-generated file s390-linux32.c. */ -void init_registers_s390_linux32 (void); -extern const struct target_desc *tdesc_s390_linux32; - -/* Defined in auto-generated file s390-linux32v1.c. */ -void init_registers_s390_linux32v1 (void); -extern const struct target_desc *tdesc_s390_linux32v1; - -/* Defined in auto-generated file s390-linux32v2.c. */ -void init_registers_s390_linux32v2 (void); -extern const struct target_desc *tdesc_s390_linux32v2; - -/* Defined in auto-generated file s390-linux64.c. */ -void init_registers_s390_linux64 (void); -extern const struct target_desc *tdesc_s390_linux64; - -/* Defined in auto-generated file s390-linux64v1.c. */ -void init_registers_s390_linux64v1 (void); -extern const struct target_desc *tdesc_s390_linux64v1; - -/* Defined in auto-generated file s390-linux64v2.c. */ -void init_registers_s390_linux64v2 (void); -extern const struct target_desc *tdesc_s390_linux64v2; - -/* Defined in auto-generated file s390-te-linux64.c. */ -void init_registers_s390_te_linux64 (void); -extern const struct target_desc *tdesc_s390_te_linux64; - -/* Defined in auto-generated file s390-vx-linux64.c. */ -void init_registers_s390_vx_linux64 (void); -extern const struct target_desc *tdesc_s390_vx_linux64; - -/* Defined in auto-generated file s390-tevx-linux64.c. */ -void init_registers_s390_tevx_linux64 (void); -extern const struct target_desc *tdesc_s390_tevx_linux64; - -/* Defined in auto-generated file s390-gs-linux64.c. */ -void init_registers_s390_gs_linux64 (void); -extern const struct target_desc *tdesc_s390_gs_linux64; - -#endif - -#endif /* GDBSERVER_LINUX_S390_TDESC_H */ diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c deleted file mode 100644 index abe71ff4766..00000000000 --- a/gdb/gdbserver/linux-sh-low.c +++ /dev/null @@ -1,189 +0,0 @@ -/* GNU/Linux/SH specific low level interface, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -/* Defined in auto-generated file reg-sh.c. */ -void init_registers_sh (void); -extern const struct target_desc *tdesc_sh; - -#ifdef HAVE_SYS_REG_H -#include -#endif - -#include - -#define sh_num_regs 41 - -/* Currently, don't check/send MQ. */ -static int sh_regmap[] = { - 0, 4, 8, 12, 16, 20, 24, 28, - 32, 36, 40, 44, 48, 52, 56, 60, - - REG_PC*4, REG_PR*4, REG_GBR*4, -1, - REG_MACH*4, REG_MACL*4, REG_SR*4, - REG_FPUL*4, REG_FPSCR*4, - - REG_FPREG0*4+0, REG_FPREG0*4+4, REG_FPREG0*4+8, REG_FPREG0*4+12, - REG_FPREG0*4+16, REG_FPREG0*4+20, REG_FPREG0*4+24, REG_FPREG0*4+28, - REG_FPREG0*4+32, REG_FPREG0*4+36, REG_FPREG0*4+40, REG_FPREG0*4+44, - REG_FPREG0*4+48, REG_FPREG0*4+52, REG_FPREG0*4+56, REG_FPREG0*4+60, -}; - -static int -sh_cannot_store_register (int regno) -{ - return 0; -} - -static int -sh_cannot_fetch_register (int regno) -{ - return 0; -} - -/* Correct in either endianness, obviously. */ -static const unsigned short sh_breakpoint = 0xc3c3; -#define sh_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -sh_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = sh_breakpoint_len; - return (const gdb_byte *) &sh_breakpoint; -} - -static int -sh_breakpoint_at (CORE_ADDR where) -{ - unsigned short insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 2); - if (insn == sh_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -/* Support for hardware single step. */ - -static int -sh_supports_hardware_single_step (void) -{ - return 1; -} - -/* Provide only a fill function for the general register set. ps_lgetregs - will use this for NPTL support. */ - -static void sh_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - - for (i = 0; i < 23; i++) - if (sh_regmap[i] != -1) - collect_register (regcache, i, (char *) buf + sh_regmap[i]); -} - -static struct regset_info sh_regsets[] = { - { 0, 0, 0, 0, GENERAL_REGS, sh_fill_gregset, NULL }, - NULL_REGSET -}; - -static struct regsets_info sh_regsets_info = - { - sh_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info sh_usrregs_info = - { - sh_num_regs, - sh_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &sh_usrregs_info, - &sh_regsets_info - }; - -static const struct regs_info * -sh_regs_info (void) -{ - return ®s_info; -} - -static void -sh_arch_setup (void) -{ - current_process ()->tdesc = tdesc_sh; -} - -struct linux_target_ops the_low_target = { - sh_arch_setup, - sh_regs_info, - sh_cannot_fetch_register, - sh_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - sh_sw_breakpoint_from_kind, - NULL, - 0, - sh_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - sh_supports_hardware_single_step, -}; - -void -initialize_low_arch (void) -{ - init_registers_sh (); - - initialize_regsets_info (&sh_regsets_info); -} diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c deleted file mode 100644 index cfa76c0b8e6..00000000000 --- a/gdb/gdbserver/linux-sparc-low.c +++ /dev/null @@ -1,326 +0,0 @@ -/* Low level interface to ptrace, for the remote server for GDB. - Copyright (C) 1995-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -#include "nat/gdb_ptrace.h" - -#include "gdb_proc_service.h" - -/* The stack pointer is offset from the stack frame by a BIAS of 2047 - (0x7ff) for 64-bit code. BIAS is likely to be defined on SPARC - hosts, so undefine it first. */ -#undef BIAS -#define BIAS 2047 - -#ifdef HAVE_SYS_REG_H -#include -#endif - -#define INSN_SIZE 4 - -#define SPARC_R_REGS_NUM 32 -#define SPARC_F_REGS_NUM 48 -#define SPARC_CONTROL_REGS_NUM 6 - -#define sparc_num_regs \ - (SPARC_R_REGS_NUM + SPARC_F_REGS_NUM + SPARC_CONTROL_REGS_NUM) - -/* Each offset is multiplied by 8, because of the register size. - These offsets apply to the buffer sent/filled by ptrace. - Additionally, the array elements order corresponds to the .dat file, and the - gdb's registers enumeration order. */ - -static int sparc_regmap[] = { - /* These offsets correspond to GET/SETREGSET. */ - -1, 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, /* g0 .. g7 */ - 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, /* o0 .. o5, sp, o7 */ - -1, -1, -1, -1, -1, -1, -1, -1, /* l0 .. l7 */ - -1, -1, -1, -1, -1, -1, -1, -1, /* i0 .. i5, fp, i7 */ - - /* Floating point registers offsets correspond to GET/SETFPREGSET. */ - 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4, /* f0 .. f7 */ - 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4, /* f8 .. f15 */ - 16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4, /* f16 .. f23 */ - 24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4, /* f24 .. f31 */ - - /* F32 offset starts next to f31: 31*4+4 = 16 * 8. */ - 16*8, 17*8, 18*8, 19*8, 20*8, 21*8, 22*8, 23*8, /* f32 .. f46 */ - 24*8, 25*8, 26*8, 27*8, 28*8, 29*8, 30*8, 31*8, /* f48 .. f62 */ - - 17 *8, /* pc */ - 18 *8, /* npc */ - 16 *8, /* state */ - /* FSR offset also corresponds to GET/SETFPREGSET, ans is placed - next to f62. */ - 32 *8, /* fsr */ - -1, /* fprs */ - /* Y register is 32-bits length, but gdb takes care of that. */ - 19 *8, /* y */ - -}; - - -struct regs_range_t -{ - int regno_start; - int regno_end; -}; - -static const struct regs_range_t gregs_ranges[] = { - { 0, 31 }, /* g0 .. i7 */ - { 80, 82 }, /* pc .. state */ - { 84, 85 } /* fprs .. y */ -}; - -#define N_GREGS_RANGES (sizeof (gregs_ranges) / sizeof (struct regs_range_t)) - -static const struct regs_range_t fpregs_ranges[] = { - { 32, 79 }, /* f0 .. f62 */ - { 83, 83 } /* fsr */ -}; - -#define N_FPREGS_RANGES (sizeof (fpregs_ranges) / sizeof (struct regs_range_t)) - -/* Defined in auto-generated file reg-sparc64.c. */ -void init_registers_sparc64 (void); -extern const struct target_desc *tdesc_sparc64; - -static int -sparc_cannot_store_register (int regno) -{ - return (regno >= sparc_num_regs || sparc_regmap[regno] == -1); -} - -static int -sparc_cannot_fetch_register (int regno) -{ - return (regno >= sparc_num_regs || sparc_regmap[regno] == -1); -} - -static void -sparc_fill_gregset_to_stack (struct regcache *regcache, const void *buf) -{ - int i; - CORE_ADDR addr = 0; - unsigned char tmp_reg_buf[8]; - const int l0_regno = find_regno (regcache->tdesc, "l0"); - const int i7_regno = l0_regno + 15; - - /* These registers have to be stored in the stack. */ - memcpy (&addr, - ((char *) buf) + sparc_regmap[find_regno (regcache->tdesc, "sp")], - sizeof (addr)); - - addr += BIAS; - - for (i = l0_regno; i <= i7_regno; i++) - { - collect_register (regcache, i, tmp_reg_buf); - (*the_target->write_memory) (addr, tmp_reg_buf, sizeof (tmp_reg_buf)); - addr += sizeof (tmp_reg_buf); - } -} - -static void -sparc_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - int range; - - for (range = 0; range < N_GREGS_RANGES; range++) - for (i = gregs_ranges[range].regno_start; - i <= gregs_ranges[range].regno_end; i++) - if (sparc_regmap[i] != -1) - collect_register (regcache, i, ((char *) buf) + sparc_regmap[i]); - - sparc_fill_gregset_to_stack (regcache, buf); -} - -static void -sparc_fill_fpregset (struct regcache *regcache, void *buf) -{ - int i; - int range; - - for (range = 0; range < N_FPREGS_RANGES; range++) - for (i = fpregs_ranges[range].regno_start; - i <= fpregs_ranges[range].regno_end; i++) - collect_register (regcache, i, ((char *) buf) + sparc_regmap[i]); - -} - -static void -sparc_store_gregset_from_stack (struct regcache *regcache, const void *buf) -{ - int i; - CORE_ADDR addr = 0; - unsigned char tmp_reg_buf[8]; - const int l0_regno = find_regno (regcache->tdesc, "l0"); - const int i7_regno = l0_regno + 15; - - /* These registers have to be obtained from the stack. */ - memcpy (&addr, - ((char *) buf) + sparc_regmap[find_regno (regcache->tdesc, "sp")], - sizeof (addr)); - - addr += BIAS; - - for (i = l0_regno; i <= i7_regno; i++) - { - (*the_target->read_memory) (addr, tmp_reg_buf, sizeof (tmp_reg_buf)); - supply_register (regcache, i, tmp_reg_buf); - addr += sizeof (tmp_reg_buf); - } -} - -static void -sparc_store_gregset (struct regcache *regcache, const void *buf) -{ - int i; - char zerobuf[8]; - int range; - - memset (zerobuf, 0, sizeof (zerobuf)); - - for (range = 0; range < N_GREGS_RANGES; range++) - for (i = gregs_ranges[range].regno_start; - i <= gregs_ranges[range].regno_end; i++) - if (sparc_regmap[i] != -1) - supply_register (regcache, i, ((char *) buf) + sparc_regmap[i]); - else - supply_register (regcache, i, zerobuf); - - sparc_store_gregset_from_stack (regcache, buf); -} - -static void -sparc_store_fpregset (struct regcache *regcache, const void *buf) -{ - int i; - int range; - - for (range = 0; range < N_FPREGS_RANGES; range++) - for (i = fpregs_ranges[range].regno_start; - i <= fpregs_ranges[range].regno_end; - i++) - supply_register (regcache, i, ((char *) buf) + sparc_regmap[i]); -} - -static const gdb_byte sparc_breakpoint[INSN_SIZE] = { - 0x91, 0xd0, 0x20, 0x01 -}; -#define sparc_breakpoint_len INSN_SIZE - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const unsigned char * -sparc_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = sparc_breakpoint_len; - return sparc_breakpoint; -} - -static int -sparc_breakpoint_at (CORE_ADDR where) -{ - unsigned char insn[INSN_SIZE]; - - (*the_target->read_memory) (where, (unsigned char *) insn, sizeof (insn)); - - if (memcmp (sparc_breakpoint, insn, sizeof (insn)) == 0) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only - uses TRAP Always. */ - - return 0; -} - -static void -sparc_arch_setup (void) -{ - current_process ()->tdesc = tdesc_sparc64; -} - -static struct regset_info sparc_regsets[] = { - { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), - GENERAL_REGS, - sparc_fill_gregset, sparc_store_gregset }, - { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (fpregset_t), - FP_REGS, - sparc_fill_fpregset, sparc_store_fpregset }, - NULL_REGSET -}; - -static struct regsets_info sparc_regsets_info = - { - sparc_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info sparc_usrregs_info = - { - sparc_num_regs, - /* No regmap needs to be provided since this impl. doesn't use - USRREGS. */ - NULL - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &sparc_usrregs_info, - &sparc_regsets_info - }; - -static const struct regs_info * -sparc_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - sparc_arch_setup, - sparc_regs_info, - sparc_cannot_fetch_register, - sparc_cannot_store_register, - NULL, /* fetch_register */ - linux_get_pc_64bit, - /* No sparc_set_pc is needed. */ - NULL, - NULL, /* breakpoint_kind_from_pc */ - sparc_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, - sparc_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, NULL, NULL, NULL, - NULL, NULL -}; - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ - init_registers_sparc64 (); - - initialize_regsets_info (&sparc_regsets_info); -} diff --git a/gdb/gdbserver/linux-tic6x-low.c b/gdb/gdbserver/linux-tic6x-low.c deleted file mode 100644 index 51a31c7876a..00000000000 --- a/gdb/gdbserver/linux-tic6x-low.c +++ /dev/null @@ -1,455 +0,0 @@ -/* Target dependent code for GDB on TI C6x systems. - - Copyright (C) 2010-2020 Free Software Foundation, Inc. - Contributed by Andrew Jenner - Contributed by Yao Qi - - 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 3 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, see . */ - -#include "server.h" -#include "linux-low.h" -#include "arch/tic6x.h" -#include "tdesc.h" - -#include "nat/gdb_ptrace.h" -#include - -#include "gdb_proc_service.h" - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -/* There are at most 69 registers accessible in ptrace. */ -#define TIC6X_NUM_REGS 69 - -#include - -/* Defined in auto-generated file tic6x-c64xp-linux.c. */ -void init_registers_tic6x_c64xp_linux (void); -extern const struct target_desc *tdesc_tic6x_c64xp_linux; - -/* Defined in auto-generated file tic6x-c64x-linux.c. */ -void init_registers_tic6x_c64x_linux (void); -extern const struct target_desc *tdesc_tic6x_c64x_linux; - -/* Defined in auto-generated file tic62x-c6xp-linux.c. */ -void init_registers_tic6x_c62x_linux (void); -extern const struct target_desc *tdesc_tic6x_c62x_linux; - -union tic6x_register -{ - unsigned char buf[4]; - - int reg32; -}; - -/* Return the ptrace ``address'' of register REGNO. */ - -#if __BYTE_ORDER == __BIG_ENDIAN -static int tic6x_regmap_c64xp[] = { - /* A0 - A15 */ - 53, 52, 55, 54, 57, 56, 59, 58, - 61, 60, 63, 62, 65, 64, 67, 66, - /* B0 - B15 */ - 23, 22, 25, 24, 27, 26, 29, 28, - 31, 30, 33, 32, 35, 34, 69, 68, - /* CSR PC */ - 5, 4, - /* A16 - A31 */ - 37, 36, 39, 38, 41, 40, 43, 42, - 45, 44, 47, 46, 49, 48, 51, 50, - /* B16 - B31 */ - 7, 6, 9, 8, 11, 10, 13, 12, - 15, 14, 17, 16, 19, 18, 21, 20, - /* TSR, ILC, RILC */ - 1, 2, 3 -}; - -static int tic6x_regmap_c64x[] = { - /* A0 - A15 */ - 51, 50, 53, 52, 55, 54, 57, 56, - 59, 58, 61, 60, 63, 62, 65, 64, - /* B0 - B15 */ - 21, 20, 23, 22, 25, 24, 27, 26, - 29, 28, 31, 30, 33, 32, 67, 66, - /* CSR PC */ - 3, 2, - /* A16 - A31 */ - 35, 34, 37, 36, 39, 38, 41, 40, - 43, 42, 45, 44, 47, 46, 49, 48, - /* B16 - B31 */ - 5, 4, 7, 6, 9, 8, 11, 10, - 13, 12, 15, 14, 17, 16, 19, 18, - -1, -1, -1 -}; - -static int tic6x_regmap_c62x[] = { - /* A0 - A15 */ - 19, 18, 21, 20, 23, 22, 25, 24, - 27, 26, 29, 28, 31, 30, 33, 32, - /* B0 - B15 */ - 5, 4, 7, 6, 9, 8, 11, 10, - 13, 12, 15, 14, 17, 16, 35, 34, - /* CSR, PC */ - 3, 2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1 -}; - -#else -static int tic6x_regmap_c64xp[] = { - /* A0 - A15 */ - 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, - /* B0 - B15 */ - 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 68, 69, - /* CSR PC */ - 4, 5, - /* A16 - A31 */ - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, - /* B16 -B31 */ - 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 31, - /* TSR, ILC, RILC */ - 0, 3, 2 -}; - -static int tic6x_regmap_c64x[] = { - /* A0 - A15 */ - 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, - /* B0 - B15 */ - 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 66, 67, - /* CSR PC */ - 2, 3, - /* A16 - A31 */ - 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, - /* B16 - B31 */ - 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, - -1, -1, -1 -}; - -static int tic6x_regmap_c62x[] = { - /* A0 - A15 */ - 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, - /* B0 - B15 */ - 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 34, 35, - /* CSR PC */ - 2, 3, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1 -}; - -#endif - -extern struct linux_target_ops the_low_target; - -static int *tic6x_regmap; -static unsigned int tic6x_breakpoint; -#define tic6x_breakpoint_len 4 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -tic6x_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = tic6x_breakpoint_len; - return (const gdb_byte *) &tic6x_breakpoint; -} - -static struct usrregs_info tic6x_usrregs_info = - { - TIC6X_NUM_REGS, - NULL, /* Set in tic6x_read_description. */ - }; - -static const struct target_desc * -tic6x_read_description (enum c6x_feature feature) -{ - static target_desc *tdescs[C6X_LAST] = { }; - struct target_desc **tdesc = &tdescs[feature]; - - if (*tdesc == NULL) - { - *tdesc = tic6x_create_target_description (feature); - static const char *expedite_regs[] = { "A15", "PC", NULL }; - init_target_desc (*tdesc, expedite_regs); - } - - return *tdesc; -} - -static int -tic6x_cannot_fetch_register (int regno) -{ - return (tic6x_regmap[regno] == -1); -} - -static int -tic6x_cannot_store_register (int regno) -{ - return (tic6x_regmap[regno] == -1); -} - -static CORE_ADDR -tic6x_get_pc (struct regcache *regcache) -{ - union tic6x_register pc; - - collect_register_by_name (regcache, "PC", pc.buf); - return pc.reg32; -} - -static void -tic6x_set_pc (struct regcache *regcache, CORE_ADDR pc) -{ - union tic6x_register newpc; - - newpc.reg32 = pc; - supply_register_by_name (regcache, "PC", newpc.buf); -} - -static int -tic6x_breakpoint_at (CORE_ADDR where) -{ - unsigned int insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 4); - if (insn == tic6x_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -/* Fetch the thread-local storage pointer for libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *) *base - idx); - - return PS_OK; -} - -static void -tic6x_collect_register (struct regcache *regcache, int regno, - union tic6x_register *reg) -{ - union tic6x_register tmp_reg; - - collect_register (regcache, regno, &tmp_reg.reg32); - reg->reg32 = tmp_reg.reg32; -} - -static void -tic6x_supply_register (struct regcache *regcache, int regno, - const union tic6x_register *reg) -{ - int offset = 0; - - supply_register (regcache, regno, reg->buf + offset); -} - -static void -tic6x_fill_gregset (struct regcache *regcache, void *buf) -{ - auto regset = static_cast (buf); - int i; - - for (i = 0; i < TIC6X_NUM_REGS; i++) - if (tic6x_regmap[i] != -1) - tic6x_collect_register (regcache, i, regset + tic6x_regmap[i]); -} - -static void -tic6x_store_gregset (struct regcache *regcache, const void *buf) -{ - const auto regset = static_cast (buf); - int i; - - for (i = 0; i < TIC6X_NUM_REGS; i++) - if (tic6x_regmap[i] != -1) - tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]); -} - -static struct regset_info tic6x_regsets[] = { - { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS, - tic6x_fill_gregset, tic6x_store_gregset }, - NULL_REGSET -}; - -static void -tic6x_arch_setup (void) -{ - register unsigned int csr asm ("B2"); - unsigned int cpuid; - enum c6x_feature feature = C6X_CORE; - - /* Determine the CPU we're running on to find the register order. */ - __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :); - cpuid = csr >> 24; - switch (cpuid) - { - case 0x00: /* C62x */ - case 0x02: /* C67x */ - tic6x_regmap = tic6x_regmap_c62x; - tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ - feature = C6X_CORE; - break; - case 0x03: /* C67x+ */ - tic6x_regmap = tic6x_regmap_c64x; - tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ - feature = C6X_GP; - break; - case 0x0c: /* C64x */ - tic6x_regmap = tic6x_regmap_c64x; - tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ - feature = C6X_GP; - break; - case 0x10: /* C64x+ */ - case 0x14: /* C674x */ - case 0x15: /* C66x */ - tic6x_regmap = tic6x_regmap_c64xp; - tic6x_breakpoint = 0x56454314; /* illegal opcode */ - feature = C6X_C6XP; - break; - default: - error ("Unknown CPU ID 0x%02x", cpuid); - } - tic6x_usrregs_info.regmap = tic6x_regmap; - - current_process ()->tdesc = tic6x_read_description (feature); -} - -/* Support for hardware single step. */ - -static int -tic6x_supports_hardware_single_step (void) -{ - return 1; -} - -static struct regsets_info tic6x_regsets_info = - { - tic6x_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &tic6x_usrregs_info, - &tic6x_regsets_info - }; - -static const struct regs_info * -tic6x_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - tic6x_arch_setup, - tic6x_regs_info, - tic6x_cannot_fetch_register, - tic6x_cannot_store_register, - NULL, /* fetch_register */ - tic6x_get_pc, - tic6x_set_pc, - NULL, /* breakpoint_kind_from_pc */ - tic6x_sw_breakpoint_from_kind, - NULL, - 0, - tic6x_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - tic6x_supports_hardware_single_step, -}; - -#if GDB_SELF_TEST -#include "gdbsupport/selftest.h" - -namespace selftests { -namespace tdesc { -static void -tic6x_tdesc_test () -{ - SELF_CHECK (*tdesc_tic6x_c62x_linux == *tic6x_read_description (C6X_CORE)); - SELF_CHECK (*tdesc_tic6x_c64x_linux == *tic6x_read_description (C6X_GP)); - SELF_CHECK (*tdesc_tic6x_c64xp_linux == *tic6x_read_description (C6X_C6XP)); -} -} -} -#endif - -void -initialize_low_arch (void) -{ -#if GDB_SELF_TEST - /* Initialize the Linux target descriptions. */ - init_registers_tic6x_c64xp_linux (); - init_registers_tic6x_c64x_linux (); - init_registers_tic6x_c62x_linux (); - - selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test); -#endif - - initialize_regsets_info (&tic6x_regsets_info); -} diff --git a/gdb/gdbserver/linux-tile-low.c b/gdb/gdbserver/linux-tile-low.c deleted file mode 100644 index cd85e945a46..00000000000 --- a/gdb/gdbserver/linux-tile-low.c +++ /dev/null @@ -1,222 +0,0 @@ -/* GNU/Linux/TILE-Gx specific low level interface, GDBserver. - - Copyright (C) 2012-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "linux-low.h" - -#include -#include "nat/gdb_ptrace.h" - -/* Defined in auto-generated file reg-tilegx.c. */ -void init_registers_tilegx (void); -extern const struct target_desc *tdesc_tilegx; - -/* Defined in auto-generated file reg-tilegx32.c. */ -void init_registers_tilegx32 (void); -extern const struct target_desc *tdesc_tilegx32; - -#define tile_num_regs 65 - -static int tile_regmap[] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - -1, -1, -1, -1, -1, -1, -1, -1, - 56 -}; - -static int -tile_cannot_fetch_register (int regno) -{ - if (regno >= 0 && regno < 56) - return 0; - else if (regno == 64) - return 0; - else - return 1; -} - -static int -tile_cannot_store_register (int regno) -{ - if (regno >= 0 && regno < 56) - return 0; - else if (regno == 64) - return 0; - else - return 1; -} - -static uint64_t tile_breakpoint = 0x400b3cae70166000ULL; -#define tile_breakpoint_len 8 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -tile_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = tile_breakpoint_len; - return (const gdb_byte *) &tile_breakpoint; -} - -static int -tile_breakpoint_at (CORE_ADDR where) -{ - uint64_t insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, 8); - if (insn == tile_breakpoint) - return 1; - - /* If necessary, recognize more trap instructions here. GDB only uses the - one. */ - return 0; -} - -static void -tile_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - - for (i = 0; i < tile_num_regs; i++) - if (tile_regmap[i] != -1) - collect_register (regcache, i, ((uint_reg_t *) buf) + tile_regmap[i]); -} - -static void -tile_store_gregset (struct regcache *regcache, const void *buf) -{ - int i; - - for (i = 0; i < tile_num_regs; i++) - if (tile_regmap[i] != -1) - supply_register (regcache, i, ((uint_reg_t *) buf) + tile_regmap[i]); -} - -static struct regset_info tile_regsets[] = -{ - { PTRACE_GETREGS, PTRACE_SETREGS, 0, tile_num_regs * 8, - GENERAL_REGS, tile_fill_gregset, tile_store_gregset }, - NULL_REGSET -}; - -static struct regsets_info tile_regsets_info = - { - tile_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct usrregs_info tile_usrregs_info = - { - tile_num_regs, - tile_regmap, - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - &tile_usrregs_info, - &tile_regsets_info, - }; - -static const struct regs_info * -tile_regs_info (void) -{ - return ®s_info; -} - -static void -tile_arch_setup (void) -{ - int pid = pid_of (current_thread); - unsigned int machine; - int is_elf64 = linux_pid_exe_is_elf_64_file (pid, &machine); - - if (sizeof (void *) == 4) - if (is_elf64 > 0) - error (_("Can't debug 64-bit process with 32-bit GDBserver")); - - if (!is_elf64) - current_process ()->tdesc = tdesc_tilegx32; - else - current_process ()->tdesc = tdesc_tilegx; -} - -/* Support for hardware single step. */ - -static int -tile_supports_hardware_single_step (void) -{ - return 1; -} - - -struct linux_target_ops the_low_target = -{ - tile_arch_setup, - tile_regs_info, - tile_cannot_fetch_register, - tile_cannot_store_register, - NULL, - linux_get_pc_64bit, - linux_set_pc_64bit, - NULL, /* breakpoint_kind_from_pc */ - tile_sw_breakpoint_from_kind, - NULL, - 0, - tile_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - tile_supports_hardware_single_step, -}; - -void -initialize_low_arch (void) -{ - init_registers_tilegx32(); - init_registers_tilegx(); - - initialize_regsets_info (&tile_regsets_info); -} diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c deleted file mode 100644 index 09ec22ff678..00000000000 --- a/gdb/gdbserver/linux-x86-low.c +++ /dev/null @@ -1,2922 +0,0 @@ -/* GNU/Linux/x86-64 specific low level interface, for the remote server - for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include -#include -#include -#include "linux-low.h" -#include "i387-fp.h" -#include "x86-low.h" -#include "gdbsupport/x86-xstate.h" -#include "nat/gdb_ptrace.h" - -#ifdef __x86_64__ -#include "nat/amd64-linux-siginfo.h" -#endif - -#include "gdb_proc_service.h" -/* Don't include elf/common.h if linux/elf.h got included by - gdb_proc_service.h. */ -#ifndef ELFMAG0 -#include "elf/common.h" -#endif - -#include "gdbsupport/agent.h" -#include "tdesc.h" -#include "tracepoint.h" -#include "ax.h" -#include "nat/linux-nat.h" -#include "nat/x86-linux.h" -#include "nat/x86-linux-dregs.h" -#include "linux-x86-tdesc.h" - -#ifdef __x86_64__ -static struct target_desc *tdesc_amd64_linux_no_xml; -#endif -static struct target_desc *tdesc_i386_linux_no_xml; - - -static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 }; -static unsigned char small_jump_insn[] = { 0x66, 0xe9, 0, 0 }; - -/* Backward compatibility for gdb without XML support. */ - -static const char *xmltarget_i386_linux_no_xml = "@\ -i386\ -GNU/Linux\ -"; - -#ifdef __x86_64__ -static const char *xmltarget_amd64_linux_no_xml = "@\ -i386:x86-64\ -GNU/Linux\ -"; -#endif - -#include -#include -#include - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -/* This definition comes from prctl.h, but some kernels may not have it. */ -#ifndef PTRACE_ARCH_PRCTL -#define PTRACE_ARCH_PRCTL 30 -#endif - -/* The following definitions come from prctl.h, but may be absent - for certain configurations. */ -#ifndef ARCH_GET_FS -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 -#endif - -/* Per-process arch-specific data we want to keep. */ - -struct arch_process_info -{ - struct x86_debug_reg_state debug_reg_state; -}; - -#ifdef __x86_64__ - -/* Mapping between the general-purpose registers in `struct user' - format and GDB's register array layout. - Note that the transfer layout uses 64-bit regs. */ -static /*const*/ int i386_regmap[] = -{ - RAX * 8, RCX * 8, RDX * 8, RBX * 8, - RSP * 8, RBP * 8, RSI * 8, RDI * 8, - RIP * 8, EFLAGS * 8, CS * 8, SS * 8, - DS * 8, ES * 8, FS * 8, GS * 8 -}; - -#define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) - -/* So code below doesn't have to care, i386 or amd64. */ -#define ORIG_EAX ORIG_RAX -#define REGSIZE 8 - -static const int x86_64_regmap[] = -{ - RAX * 8, RBX * 8, RCX * 8, RDX * 8, - RSI * 8, RDI * 8, RBP * 8, RSP * 8, - R8 * 8, R9 * 8, R10 * 8, R11 * 8, - R12 * 8, R13 * 8, R14 * 8, R15 * 8, - RIP * 8, EFLAGS * 8, CS * 8, SS * 8, - DS * 8, ES * 8, FS * 8, GS * 8, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, - -1, -1, -1, -1, -1, -1, -1, -1, - ORIG_RAX * 8, -#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - 21 * 8, 22 * 8, -#else - -1, -1, -#endif - -1, -1, -1, -1, /* MPX registers BND0 ... BND3. */ - -1, -1, /* MPX registers BNDCFGU, BNDSTATUS. */ - -1, -1, -1, -1, -1, -1, -1, -1, /* xmm16 ... xmm31 (AVX512) */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* ymm16 ... ymm31 (AVX512) */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* k0 ... k7 (AVX512) */ - -1, -1, -1, -1, -1, -1, -1, -1, /* zmm0 ... zmm31 (AVX512) */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1 /* pkru */ -}; - -#define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0])) -#define X86_64_USER_REGS (GS + 1) - -#else /* ! __x86_64__ */ - -/* Mapping between the general-purpose registers in `struct user' - format and GDB's register array layout. */ -static /*const*/ int i386_regmap[] = -{ - EAX * 4, ECX * 4, EDX * 4, EBX * 4, - UESP * 4, EBP * 4, ESI * 4, EDI * 4, - EIP * 4, EFL * 4, CS * 4, SS * 4, - DS * 4, ES * 4, FS * 4, GS * 4 -}; - -#define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) - -#define REGSIZE 4 - -#endif - -#ifdef __x86_64__ - -/* Returns true if the current inferior belongs to a x86-64 process, - per the tdesc. */ - -static int -is_64bit_tdesc (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - return register_size (regcache->tdesc, 0) == 8; -} - -#endif - - -/* Called by libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ -#ifdef __x86_64__ - int use_64bit = is_64bit_tdesc (); - - if (use_64bit) - { - switch (idx) - { - case FS: - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0) - return PS_OK; - break; - case GS: - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0) - return PS_OK; - break; - default: - return PS_BADADDR; - } - return PS_ERR; - } -#endif - - { - unsigned int desc[4]; - - if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, - (void *) (intptr_t) idx, (unsigned long) &desc) < 0) - return PS_ERR; - - /* Ensure we properly extend the value to 64-bits for x86_64. */ - *base = (void *) (uintptr_t) desc[1]; - return PS_OK; - } -} - -/* Get the thread area address. This is used to recognize which - thread is which when tracing with the in-process agent library. We - don't read anything from the address, and treat it as opaque; it's - the address itself that we assume is unique per-thread. */ - -static int -x86_get_thread_area (int lwpid, CORE_ADDR *addr) -{ -#ifdef __x86_64__ - int use_64bit = is_64bit_tdesc (); - - if (use_64bit) - { - void *base; - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_FS) == 0) - { - *addr = (CORE_ADDR) (uintptr_t) base; - return 0; - } - - return -1; - } -#endif - - { - struct lwp_info *lwp = find_lwp_pid (ptid_t (lwpid)); - struct thread_info *thr = get_lwp_thread (lwp); - struct regcache *regcache = get_thread_regcache (thr, 1); - unsigned int desc[4]; - ULONGEST gs = 0; - const int reg_thread_area = 3; /* bits to scale down register value. */ - int idx; - - collect_register_by_name (regcache, "gs", &gs); - - idx = gs >> reg_thread_area; - - if (ptrace (PTRACE_GET_THREAD_AREA, - lwpid_of (thr), - (void *) (long) idx, (unsigned long) &desc) < 0) - return -1; - - *addr = desc[1]; - return 0; - } -} - - - -static int -x86_cannot_store_register (int regno) -{ -#ifdef __x86_64__ - if (is_64bit_tdesc ()) - return 0; -#endif - - return regno >= I386_NUM_REGS; -} - -static int -x86_cannot_fetch_register (int regno) -{ -#ifdef __x86_64__ - if (is_64bit_tdesc ()) - return 0; -#endif - - return regno >= I386_NUM_REGS; -} - -static void -x86_fill_gregset (struct regcache *regcache, void *buf) -{ - int i; - -#ifdef __x86_64__ - if (register_size (regcache->tdesc, 0) == 8) - { - for (i = 0; i < X86_64_NUM_REGS; i++) - if (x86_64_regmap[i] != -1) - collect_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); - -#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - { - unsigned long base; - int lwpid = lwpid_of (current_thread); - - collect_register_by_name (regcache, "fs_base", &base); - ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_SET_FS); - - collect_register_by_name (regcache, "gs_base", &base); - ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_SET_GS); - } -#endif - - return; - } - - /* 32-bit inferior registers need to be zero-extended. - Callers would read uninitialized memory otherwise. */ - memset (buf, 0x00, X86_64_USER_REGS * 8); -#endif - - for (i = 0; i < I386_NUM_REGS; i++) - collect_register (regcache, i, ((char *) buf) + i386_regmap[i]); - - collect_register_by_name (regcache, "orig_eax", - ((char *) buf) + ORIG_EAX * REGSIZE); - -#ifdef __x86_64__ - /* Sign extend EAX value to avoid potential syscall restart - problems. - - See amd64_linux_collect_native_gregset() in gdb/amd64-linux-nat.c - for a detailed explanation. */ - if (register_size (regcache->tdesc, 0) == 4) - { - void *ptr = ((gdb_byte *) buf - + i386_regmap[find_regno (regcache->tdesc, "eax")]); - - *(int64_t *) ptr = *(int32_t *) ptr; - } -#endif -} - -static void -x86_store_gregset (struct regcache *regcache, const void *buf) -{ - int i; - -#ifdef __x86_64__ - if (register_size (regcache->tdesc, 0) == 8) - { - for (i = 0; i < X86_64_NUM_REGS; i++) - if (x86_64_regmap[i] != -1) - supply_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); - -#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - { - unsigned long base; - int lwpid = lwpid_of (current_thread); - - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_FS) == 0) - supply_register_by_name (regcache, "fs_base", &base); - - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_GS) == 0) - supply_register_by_name (regcache, "gs_base", &base); - } -#endif - return; - } -#endif - - for (i = 0; i < I386_NUM_REGS; i++) - supply_register (regcache, i, ((char *) buf) + i386_regmap[i]); - - supply_register_by_name (regcache, "orig_eax", - ((char *) buf) + ORIG_EAX * REGSIZE); -} - -static void -x86_fill_fpregset (struct regcache *regcache, void *buf) -{ -#ifdef __x86_64__ - i387_cache_to_fxsave (regcache, buf); -#else - i387_cache_to_fsave (regcache, buf); -#endif -} - -static void -x86_store_fpregset (struct regcache *regcache, const void *buf) -{ -#ifdef __x86_64__ - i387_fxsave_to_cache (regcache, buf); -#else - i387_fsave_to_cache (regcache, buf); -#endif -} - -#ifndef __x86_64__ - -static void -x86_fill_fpxregset (struct regcache *regcache, void *buf) -{ - i387_cache_to_fxsave (regcache, buf); -} - -static void -x86_store_fpxregset (struct regcache *regcache, const void *buf) -{ - i387_fxsave_to_cache (regcache, buf); -} - -#endif - -static void -x86_fill_xstateregset (struct regcache *regcache, void *buf) -{ - i387_cache_to_xsave (regcache, buf); -} - -static void -x86_store_xstateregset (struct regcache *regcache, const void *buf) -{ - i387_xsave_to_cache (regcache, buf); -} - -/* ??? The non-biarch i386 case stores all the i387 regs twice. - Once in i387_.*fsave.* and once in i387_.*fxsave.*. - This is, presumably, to handle the case where PTRACE_[GS]ETFPXREGS - doesn't work. IWBN to avoid the duplication in the case where it - does work. Maybe the arch_setup routine could check whether it works - and update the supported regsets accordingly. */ - -static struct regset_info x86_regsets[] = -{ -#ifdef HAVE_PTRACE_GETREGS - { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), - GENERAL_REGS, - x86_fill_gregset, x86_store_gregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_XSTATE, 0, - EXTENDED_REGS, x86_fill_xstateregset, x86_store_xstateregset }, -# ifndef __x86_64__ -# ifdef HAVE_PTRACE_GETFPXREGS - { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, 0, sizeof (elf_fpxregset_t), - EXTENDED_REGS, - x86_fill_fpxregset, x86_store_fpxregset }, -# endif -# endif - { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t), - FP_REGS, - x86_fill_fpregset, x86_store_fpregset }, -#endif /* HAVE_PTRACE_GETREGS */ - NULL_REGSET -}; - -static CORE_ADDR -x86_get_pc (struct regcache *regcache) -{ - int use_64bit = register_size (regcache->tdesc, 0) == 8; - - if (use_64bit) - { - uint64_t pc; - - collect_register_by_name (regcache, "rip", &pc); - return (CORE_ADDR) pc; - } - else - { - uint32_t pc; - - collect_register_by_name (regcache, "eip", &pc); - return (CORE_ADDR) pc; - } -} - -static void -x86_set_pc (struct regcache *regcache, CORE_ADDR pc) -{ - int use_64bit = register_size (regcache->tdesc, 0) == 8; - - if (use_64bit) - { - uint64_t newpc = pc; - - supply_register_by_name (regcache, "rip", &newpc); - } - else - { - uint32_t newpc = pc; - - supply_register_by_name (regcache, "eip", &newpc); - } -} - -static const gdb_byte x86_breakpoint[] = { 0xCC }; -#define x86_breakpoint_len 1 - -static int -x86_breakpoint_at (CORE_ADDR pc) -{ - unsigned char c; - - (*the_target->read_memory) (pc, &c, 1); - if (c == 0xCC) - return 1; - - return 0; -} - -/* Low-level function vector. */ -struct x86_dr_low_type x86_dr_low = - { - x86_linux_dr_set_control, - x86_linux_dr_set_addr, - x86_linux_dr_get_addr, - x86_linux_dr_get_status, - x86_linux_dr_get_control, - sizeof (void *), - }; - -/* Breakpoint/Watchpoint support. */ - -static int -x86_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - case Z_PACKET_HW_BP: - case Z_PACKET_WRITE_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - return 0; - } -} - -static int -x86_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - struct process_info *proc = current_process (); - - switch (type) - { - case raw_bkpt_type_hw: - case raw_bkpt_type_write_wp: - case raw_bkpt_type_access_wp: - { - enum target_hw_bp_type hw_type - = raw_bkpt_type_to_target_hw_bp_type (type); - struct x86_debug_reg_state *state - = &proc->priv->arch_private->debug_reg_state; - - return x86_dr_insert_watchpoint (state, hw_type, addr, size); - } - - default: - /* Unsupported. */ - return 1; - } -} - -static int -x86_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - struct process_info *proc = current_process (); - - switch (type) - { - case raw_bkpt_type_hw: - case raw_bkpt_type_write_wp: - case raw_bkpt_type_access_wp: - { - enum target_hw_bp_type hw_type - = raw_bkpt_type_to_target_hw_bp_type (type); - struct x86_debug_reg_state *state - = &proc->priv->arch_private->debug_reg_state; - - return x86_dr_remove_watchpoint (state, hw_type, addr, size); - } - default: - /* Unsupported. */ - return 1; - } -} - -static int -x86_stopped_by_watchpoint (void) -{ - struct process_info *proc = current_process (); - return x86_dr_stopped_by_watchpoint (&proc->priv->arch_private->debug_reg_state); -} - -static CORE_ADDR -x86_stopped_data_address (void) -{ - struct process_info *proc = current_process (); - CORE_ADDR addr; - if (x86_dr_stopped_data_address (&proc->priv->arch_private->debug_reg_state, - &addr)) - return addr; - return 0; -} - -/* Called when a new process is created. */ - -static struct arch_process_info * -x86_linux_new_process (void) -{ - struct arch_process_info *info = XCNEW (struct arch_process_info); - - x86_low_init_dregs (&info->debug_reg_state); - - return info; -} - -/* Called when a process is being deleted. */ - -static void -x86_linux_delete_process (struct arch_process_info *info) -{ - xfree (info); -} - -/* Target routine for linux_new_fork. */ - -static void -x86_linux_new_fork (struct process_info *parent, struct process_info *child) -{ - /* These are allocated by linux_add_process. */ - gdb_assert (parent->priv != NULL - && parent->priv->arch_private != NULL); - gdb_assert (child->priv != NULL - && child->priv->arch_private != NULL); - - /* Linux kernel before 2.6.33 commit - 72f674d203cd230426437cdcf7dd6f681dad8b0d - will inherit hardware debug registers from parent - on fork/vfork/clone. Newer Linux kernels create such tasks with - zeroed debug registers. - - GDB core assumes the child inherits the watchpoints/hw - breakpoints of the parent, and will remove them all from the - forked off process. Copy the debug registers mirrors into the - new process so that all breakpoints and watchpoints can be - removed together. The debug registers mirror will become zeroed - in the end before detaching the forked off process, thus making - this compatible with older Linux kernels too. */ - - *child->priv->arch_private = *parent->priv->arch_private; -} - -/* See nat/x86-dregs.h. */ - -struct x86_debug_reg_state * -x86_debug_reg_state (pid_t pid) -{ - struct process_info *proc = find_process_pid (pid); - - return &proc->priv->arch_private->debug_reg_state; -} - -/* When GDBSERVER is built as a 64-bit application on linux, the - PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since - debugging a 32-bit inferior with a 64-bit GDBSERVER should look the same - as debugging it with a 32-bit GDBSERVER, we do the 32-bit <-> 64-bit - conversion in-place ourselves. */ - -/* Convert a ptrace/host siginfo object, into/from the siginfo in the - layout of the inferiors' architecture. Returns true if any - conversion was done; false otherwise. If DIRECTION is 1, then copy - from INF to PTRACE. If DIRECTION is 0, copy from PTRACE to - INF. */ - -static int -x86_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction) -{ -#ifdef __x86_64__ - unsigned int machine; - int tid = lwpid_of (current_thread); - int is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); - - /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ - if (!is_64bit_tdesc ()) - return amd64_linux_siginfo_fixup_common (ptrace, inf, direction, - FIXUP_32); - /* No fixup for native x32 GDB. */ - else if (!is_elf64 && sizeof (void *) == 8) - return amd64_linux_siginfo_fixup_common (ptrace, inf, direction, - FIXUP_X32); -#endif - - return 0; -} - -static int use_xml; - -/* Format of XSAVE extended state is: - struct - { - fxsave_bytes[0..463] - sw_usable_bytes[464..511] - xstate_hdr_bytes[512..575] - avx_bytes[576..831] - future_state etc - }; - - Same memory layout will be used for the coredump NT_X86_XSTATE - representing the XSAVE extended state registers. - - The first 8 bytes of the sw_usable_bytes[464..467] is the OS enabled - extended state mask, which is the same as the extended control register - 0 (the XFEATURE_ENABLED_MASK register), XCR0. We can use this mask - together with the mask saved in the xstate_hdr_bytes to determine what - states the processor/OS supports and what state, used or initialized, - the process/thread is in. */ -#define I386_LINUX_XSAVE_XCR0_OFFSET 464 - -/* Does the current host support the GETFPXREGS request? The header - file may or may not define it, and even if it is defined, the - kernel will return EIO if it's running on a pre-SSE processor. */ -int have_ptrace_getfpxregs = -#ifdef HAVE_PTRACE_GETFPXREGS - -1 -#else - 0 -#endif -; - -/* Get Linux/x86 target description from running target. */ - -static const struct target_desc * -x86_linux_read_description (void) -{ - unsigned int machine; - int is_elf64; - int xcr0_features; - int tid; - static uint64_t xcr0; - struct regset_info *regset; - - tid = lwpid_of (current_thread); - - is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); - - if (sizeof (void *) == 4) - { - if (is_elf64 > 0) - error (_("Can't debug 64-bit process with 32-bit GDBserver")); -#ifndef __x86_64__ - else if (machine == EM_X86_64) - error (_("Can't debug x86-64 process with 32-bit GDBserver")); -#endif - } - -#if !defined __x86_64__ && defined HAVE_PTRACE_GETFPXREGS - if (machine == EM_386 && have_ptrace_getfpxregs == -1) - { - elf_fpxregset_t fpxregs; - - if (ptrace (PTRACE_GETFPXREGS, tid, 0, (long) &fpxregs) < 0) - { - have_ptrace_getfpxregs = 0; - have_ptrace_getregset = 0; - return i386_linux_read_description (X86_XSTATE_X87); - } - else - have_ptrace_getfpxregs = 1; - } -#endif - - if (!use_xml) - { - x86_xcr0 = X86_XSTATE_SSE_MASK; - - /* Don't use XML. */ -#ifdef __x86_64__ - if (machine == EM_X86_64) - return tdesc_amd64_linux_no_xml; - else -#endif - return tdesc_i386_linux_no_xml; - } - - if (have_ptrace_getregset == -1) - { - uint64_t xstateregs[(X86_XSTATE_SSE_SIZE / sizeof (uint64_t))]; - struct iovec iov; - - iov.iov_base = xstateregs; - iov.iov_len = sizeof (xstateregs); - - /* Check if PTRACE_GETREGSET works. */ - if (ptrace (PTRACE_GETREGSET, tid, - (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) - have_ptrace_getregset = 0; - else - { - have_ptrace_getregset = 1; - - /* Get XCR0 from XSAVE extended state. */ - xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET - / sizeof (uint64_t))]; - - /* Use PTRACE_GETREGSET if it is available. */ - for (regset = x86_regsets; - regset->fill_function != NULL; regset++) - if (regset->get_request == PTRACE_GETREGSET) - regset->size = X86_XSTATE_SIZE (xcr0); - else if (regset->type != GENERAL_REGS) - regset->size = 0; - } - } - - /* Check the native XCR0 only if PTRACE_GETREGSET is available. */ - xcr0_features = (have_ptrace_getregset - && (xcr0 & X86_XSTATE_ALL_MASK)); - - if (xcr0_features) - x86_xcr0 = xcr0; - - if (machine == EM_X86_64) - { -#ifdef __x86_64__ - const target_desc *tdesc = NULL; - - if (xcr0_features) - { - tdesc = amd64_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK, - !is_elf64); - } - - if (tdesc == NULL) - tdesc = amd64_linux_read_description (X86_XSTATE_SSE_MASK, !is_elf64); - return tdesc; -#endif - } - else - { - const target_desc *tdesc = NULL; - - if (xcr0_features) - tdesc = i386_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK); - - if (tdesc == NULL) - tdesc = i386_linux_read_description (X86_XSTATE_SSE); - - return tdesc; - } - - gdb_assert_not_reached ("failed to return tdesc"); -} - -/* Update all the target description of all processes; a new GDB - connected, and it may or not support xml target descriptions. */ - -static void -x86_linux_update_xmltarget (void) -{ - struct thread_info *saved_thread = current_thread; - - /* Before changing the register cache's internal layout, flush the - contents of the current valid caches back to the threads, and - release the current regcache objects. */ - regcache_release (); - - for_each_process ([] (process_info *proc) { - int pid = proc->pid; - - /* Look up any thread of this process. */ - current_thread = find_any_thread_of_pid (pid); - - the_low_target.arch_setup (); - }); - - current_thread = saved_thread; -} - -/* Process qSupported query, "xmlRegisters=". Update the buffer size for - PTRACE_GETREGSET. */ - -static void -x86_linux_process_qsupported (char **features, int count) -{ - int i; - - /* Return if gdb doesn't support XML. If gdb sends "xmlRegisters=" - with "i386" in qSupported query, it supports x86 XML target - descriptions. */ - use_xml = 0; - for (i = 0; i < count; i++) - { - const char *feature = features[i]; - - if (startswith (feature, "xmlRegisters=")) - { - char *copy = xstrdup (feature + 13); - - char *saveptr; - for (char *p = strtok_r (copy, ",", &saveptr); - p != NULL; - p = strtok_r (NULL, ",", &saveptr)) - { - if (strcmp (p, "i386") == 0) - { - use_xml = 1; - break; - } - } - - free (copy); - } - } - x86_linux_update_xmltarget (); -} - -/* Common for x86/x86-64. */ - -static struct regsets_info x86_regsets_info = - { - x86_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -#ifdef __x86_64__ -static struct regs_info amd64_linux_regs_info = - { - NULL, /* regset_bitmap */ - NULL, /* usrregs_info */ - &x86_regsets_info - }; -#endif -static struct usrregs_info i386_linux_usrregs_info = - { - I386_NUM_REGS, - i386_regmap, - }; - -static struct regs_info i386_linux_regs_info = - { - NULL, /* regset_bitmap */ - &i386_linux_usrregs_info, - &x86_regsets_info - }; - -static const struct regs_info * -x86_linux_regs_info (void) -{ -#ifdef __x86_64__ - if (is_64bit_tdesc ()) - return &amd64_linux_regs_info; - else -#endif - return &i386_linux_regs_info; -} - -/* Initialize the target description for the architecture of the - inferior. */ - -static void -x86_arch_setup (void) -{ - current_process ()->tdesc = x86_linux_read_description (); -} - -/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return - code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ - -static void -x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno) -{ - int use_64bit = register_size (regcache->tdesc, 0) == 8; - - if (use_64bit) - { - long l_sysno; - - collect_register_by_name (regcache, "orig_rax", &l_sysno); - *sysno = (int) l_sysno; - } - else - collect_register_by_name (regcache, "orig_eax", sysno); -} - -static int -x86_supports_tracepoints (void) -{ - return 1; -} - -static void -append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf) -{ - target_write_memory (*to, buf, len); - *to += len; -} - -static int -push_opcode (unsigned char *buf, const char *op) -{ - unsigned char *buf_org = buf; - - while (1) - { - char *endptr; - unsigned long ul = strtoul (op, &endptr, 16); - - if (endptr == op) - break; - - *buf++ = ul; - op = endptr; - } - - return buf - buf_org; -} - -#ifdef __x86_64__ - -/* Build a jump pad that saves registers and calls a collection - function. Writes a jump instruction to the jump pad to - JJUMPAD_INSN. The caller is responsible to write it in at the - tracepoint address. */ - -static int -amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ - unsigned char buf[40]; - int i, offset; - int64_t loffset; - - CORE_ADDR buildaddr = *jump_entry; - - /* Build the jump pad. */ - - /* First, do tracepoint data collection. Save registers. */ - i = 0; - /* Need to ensure stack pointer saved first. */ - buf[i++] = 0x54; /* push %rsp */ - buf[i++] = 0x55; /* push %rbp */ - buf[i++] = 0x57; /* push %rdi */ - buf[i++] = 0x56; /* push %rsi */ - buf[i++] = 0x52; /* push %rdx */ - buf[i++] = 0x51; /* push %rcx */ - buf[i++] = 0x53; /* push %rbx */ - buf[i++] = 0x50; /* push %rax */ - buf[i++] = 0x41; buf[i++] = 0x57; /* push %r15 */ - buf[i++] = 0x41; buf[i++] = 0x56; /* push %r14 */ - buf[i++] = 0x41; buf[i++] = 0x55; /* push %r13 */ - buf[i++] = 0x41; buf[i++] = 0x54; /* push %r12 */ - buf[i++] = 0x41; buf[i++] = 0x53; /* push %r11 */ - buf[i++] = 0x41; buf[i++] = 0x52; /* push %r10 */ - buf[i++] = 0x41; buf[i++] = 0x51; /* push %r9 */ - buf[i++] = 0x41; buf[i++] = 0x50; /* push %r8 */ - buf[i++] = 0x9c; /* pushfq */ - buf[i++] = 0x48; /* movabs ,%rdi */ - buf[i++] = 0xbf; - memcpy (buf + i, &tpaddr, 8); - i += 8; - buf[i++] = 0x57; /* push %rdi */ - append_insns (&buildaddr, i, buf); - - /* Stack space for the collecting_t object. */ - i = 0; - i += push_opcode (&buf[i], "48 83 ec 18"); /* sub $0x18,%rsp */ - i += push_opcode (&buf[i], "48 b8"); /* mov ,%rax */ - memcpy (buf + i, &tpoint, 8); - i += 8; - i += push_opcode (&buf[i], "48 89 04 24"); /* mov %rax,(%rsp) */ - i += push_opcode (&buf[i], - "64 48 8b 04 25 00 00 00 00"); /* mov %fs:0x0,%rax */ - i += push_opcode (&buf[i], "48 89 44 24 08"); /* mov %rax,0x8(%rsp) */ - append_insns (&buildaddr, i, buf); - - /* spin-lock. */ - i = 0; - i += push_opcode (&buf[i], "48 be"); /* movl ,%rsi */ - memcpy (&buf[i], (void *) &lockaddr, 8); - i += 8; - i += push_opcode (&buf[i], "48 89 e1"); /* mov %rsp,%rcx */ - i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ - i += push_opcode (&buf[i], "f0 48 0f b1 0e"); /* lock cmpxchg %rcx,(%rsi) */ - i += push_opcode (&buf[i], "48 85 c0"); /* test %rax,%rax */ - i += push_opcode (&buf[i], "75 f4"); /* jne */ - append_insns (&buildaddr, i, buf); - - /* Set up the gdb_collect call. */ - /* At this point, (stack pointer + 0x18) is the base of our saved - register block. */ - - i = 0; - i += push_opcode (&buf[i], "48 89 e6"); /* mov %rsp,%rsi */ - i += push_opcode (&buf[i], "48 83 c6 18"); /* add $0x18,%rsi */ - - /* tpoint address may be 64-bit wide. */ - i += push_opcode (&buf[i], "48 bf"); /* movl ,%rdi */ - memcpy (buf + i, &tpoint, 8); - i += 8; - append_insns (&buildaddr, i, buf); - - /* The collector function being in the shared library, may be - >31-bits away off the jump pad. */ - i = 0; - i += push_opcode (&buf[i], "48 b8"); /* mov $collector,%rax */ - memcpy (buf + i, &collector, 8); - i += 8; - i += push_opcode (&buf[i], "ff d0"); /* callq *%rax */ - append_insns (&buildaddr, i, buf); - - /* Clear the spin-lock. */ - i = 0; - i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ - i += push_opcode (&buf[i], "48 a3"); /* mov %rax, lockaddr */ - memcpy (buf + i, &lockaddr, 8); - i += 8; - append_insns (&buildaddr, i, buf); - - /* Remove stack that had been used for the collect_t object. */ - i = 0; - i += push_opcode (&buf[i], "48 83 c4 18"); /* add $0x18,%rsp */ - append_insns (&buildaddr, i, buf); - - /* Restore register state. */ - i = 0; - buf[i++] = 0x48; /* add $0x8,%rsp */ - buf[i++] = 0x83; - buf[i++] = 0xc4; - buf[i++] = 0x08; - buf[i++] = 0x9d; /* popfq */ - buf[i++] = 0x41; buf[i++] = 0x58; /* pop %r8 */ - buf[i++] = 0x41; buf[i++] = 0x59; /* pop %r9 */ - buf[i++] = 0x41; buf[i++] = 0x5a; /* pop %r10 */ - buf[i++] = 0x41; buf[i++] = 0x5b; /* pop %r11 */ - buf[i++] = 0x41; buf[i++] = 0x5c; /* pop %r12 */ - buf[i++] = 0x41; buf[i++] = 0x5d; /* pop %r13 */ - buf[i++] = 0x41; buf[i++] = 0x5e; /* pop %r14 */ - buf[i++] = 0x41; buf[i++] = 0x5f; /* pop %r15 */ - buf[i++] = 0x58; /* pop %rax */ - buf[i++] = 0x5b; /* pop %rbx */ - buf[i++] = 0x59; /* pop %rcx */ - buf[i++] = 0x5a; /* pop %rdx */ - buf[i++] = 0x5e; /* pop %rsi */ - buf[i++] = 0x5f; /* pop %rdi */ - buf[i++] = 0x5d; /* pop %rbp */ - buf[i++] = 0x5c; /* pop %rsp */ - append_insns (&buildaddr, i, buf); - - /* Now, adjust the original instruction to execute in the jump - pad. */ - *adjusted_insn_addr = buildaddr; - relocate_instruction (&buildaddr, tpaddr); - *adjusted_insn_addr_end = buildaddr; - - /* Finally, write a jump back to the program. */ - - loffset = (tpaddr + orig_size) - (buildaddr + sizeof (jump_insn)); - if (loffset > INT_MAX || loffset < INT_MIN) - { - sprintf (err, - "E.Jump back from jump pad too far from tracepoint " - "(offset 0x%" PRIx64 " > int32).", loffset); - return 1; - } - - offset = (int) loffset; - memcpy (buf, jump_insn, sizeof (jump_insn)); - memcpy (buf + 1, &offset, 4); - append_insns (&buildaddr, sizeof (jump_insn), buf); - - /* The jump pad is now built. Wire in a jump to our jump pad. This - is always done last (by our caller actually), so that we can - install fast tracepoints with threads running. This relies on - the agent's atomic write support. */ - loffset = *jump_entry - (tpaddr + sizeof (jump_insn)); - if (loffset > INT_MAX || loffset < INT_MIN) - { - sprintf (err, - "E.Jump pad too far from tracepoint " - "(offset 0x%" PRIx64 " > int32).", loffset); - return 1; - } - - offset = (int) loffset; - - memcpy (buf, jump_insn, sizeof (jump_insn)); - memcpy (buf + 1, &offset, 4); - memcpy (jjump_pad_insn, buf, sizeof (jump_insn)); - *jjump_pad_insn_size = sizeof (jump_insn); - - /* Return the end address of our pad. */ - *jump_entry = buildaddr; - - return 0; -} - -#endif /* __x86_64__ */ - -/* Build a jump pad that saves registers and calls a collection - function. Writes a jump instruction to the jump pad to - JJUMPAD_INSN. The caller is responsible to write it in at the - tracepoint address. */ - -static int -i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ - unsigned char buf[0x100]; - int i, offset; - CORE_ADDR buildaddr = *jump_entry; - - /* Build the jump pad. */ - - /* First, do tracepoint data collection. Save registers. */ - i = 0; - buf[i++] = 0x60; /* pushad */ - buf[i++] = 0x68; /* push tpaddr aka $pc */ - *((int *)(buf + i)) = (int) tpaddr; - i += 4; - buf[i++] = 0x9c; /* pushf */ - buf[i++] = 0x1e; /* push %ds */ - buf[i++] = 0x06; /* push %es */ - buf[i++] = 0x0f; /* push %fs */ - buf[i++] = 0xa0; - buf[i++] = 0x0f; /* push %gs */ - buf[i++] = 0xa8; - buf[i++] = 0x16; /* push %ss */ - buf[i++] = 0x0e; /* push %cs */ - append_insns (&buildaddr, i, buf); - - /* Stack space for the collecting_t object. */ - i = 0; - i += push_opcode (&buf[i], "83 ec 08"); /* sub $0x8,%esp */ - - /* Build the object. */ - i += push_opcode (&buf[i], "b8"); /* mov ,%eax */ - memcpy (buf + i, &tpoint, 4); - i += 4; - i += push_opcode (&buf[i], "89 04 24"); /* mov %eax,(%esp) */ - - i += push_opcode (&buf[i], "65 a1 00 00 00 00"); /* mov %gs:0x0,%eax */ - i += push_opcode (&buf[i], "89 44 24 04"); /* mov %eax,0x4(%esp) */ - append_insns (&buildaddr, i, buf); - - /* spin-lock. Note this is using cmpxchg, which leaves i386 behind. - If we cared for it, this could be using xchg alternatively. */ - - i = 0; - i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ - i += push_opcode (&buf[i], "f0 0f b1 25"); /* lock cmpxchg - %esp, */ - memcpy (&buf[i], (void *) &lockaddr, 4); - i += 4; - i += push_opcode (&buf[i], "85 c0"); /* test %eax,%eax */ - i += push_opcode (&buf[i], "75 f2"); /* jne */ - append_insns (&buildaddr, i, buf); - - - /* Set up arguments to the gdb_collect call. */ - i = 0; - i += push_opcode (&buf[i], "89 e0"); /* mov %esp,%eax */ - i += push_opcode (&buf[i], "83 c0 08"); /* add $0x08,%eax */ - i += push_opcode (&buf[i], "89 44 24 fc"); /* mov %eax,-0x4(%esp) */ - append_insns (&buildaddr, i, buf); - - i = 0; - i += push_opcode (&buf[i], "83 ec 08"); /* sub $0x8,%esp */ - append_insns (&buildaddr, i, buf); - - i = 0; - i += push_opcode (&buf[i], "c7 04 24"); /* movl ,(%esp) */ - memcpy (&buf[i], (void *) &tpoint, 4); - i += 4; - append_insns (&buildaddr, i, buf); - - buf[0] = 0xe8; /* call */ - offset = collector - (buildaddr + sizeof (jump_insn)); - memcpy (buf + 1, &offset, 4); - append_insns (&buildaddr, 5, buf); - /* Clean up after the call. */ - buf[0] = 0x83; /* add $0x8,%esp */ - buf[1] = 0xc4; - buf[2] = 0x08; - append_insns (&buildaddr, 3, buf); - - - /* Clear the spin-lock. This would need the LOCK prefix on older - broken archs. */ - i = 0; - i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ - i += push_opcode (&buf[i], "a3"); /* mov %eax, lockaddr */ - memcpy (buf + i, &lockaddr, 4); - i += 4; - append_insns (&buildaddr, i, buf); - - - /* Remove stack that had been used for the collect_t object. */ - i = 0; - i += push_opcode (&buf[i], "83 c4 08"); /* add $0x08,%esp */ - append_insns (&buildaddr, i, buf); - - i = 0; - buf[i++] = 0x83; /* add $0x4,%esp (no pop of %cs, assume unchanged) */ - buf[i++] = 0xc4; - buf[i++] = 0x04; - buf[i++] = 0x17; /* pop %ss */ - buf[i++] = 0x0f; /* pop %gs */ - buf[i++] = 0xa9; - buf[i++] = 0x0f; /* pop %fs */ - buf[i++] = 0xa1; - buf[i++] = 0x07; /* pop %es */ - buf[i++] = 0x1f; /* pop %ds */ - buf[i++] = 0x9d; /* popf */ - buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */ - buf[i++] = 0xc4; - buf[i++] = 0x04; - buf[i++] = 0x61; /* popad */ - append_insns (&buildaddr, i, buf); - - /* Now, adjust the original instruction to execute in the jump - pad. */ - *adjusted_insn_addr = buildaddr; - relocate_instruction (&buildaddr, tpaddr); - *adjusted_insn_addr_end = buildaddr; - - /* Write the jump back to the program. */ - offset = (tpaddr + orig_size) - (buildaddr + sizeof (jump_insn)); - memcpy (buf, jump_insn, sizeof (jump_insn)); - memcpy (buf + 1, &offset, 4); - append_insns (&buildaddr, sizeof (jump_insn), buf); - - /* The jump pad is now built. Wire in a jump to our jump pad. This - is always done last (by our caller actually), so that we can - install fast tracepoints with threads running. This relies on - the agent's atomic write support. */ - if (orig_size == 4) - { - /* Create a trampoline. */ - *trampoline_size = sizeof (jump_insn); - if (!claim_trampoline_space (*trampoline_size, trampoline)) - { - /* No trampoline space available. */ - strcpy (err, - "E.Cannot allocate trampoline space needed for fast " - "tracepoints on 4-byte instructions."); - return 1; - } - - offset = *jump_entry - (*trampoline + sizeof (jump_insn)); - memcpy (buf, jump_insn, sizeof (jump_insn)); - memcpy (buf + 1, &offset, 4); - target_write_memory (*trampoline, buf, sizeof (jump_insn)); - - /* Use a 16-bit relative jump instruction to jump to the trampoline. */ - offset = (*trampoline - (tpaddr + sizeof (small_jump_insn))) & 0xffff; - memcpy (buf, small_jump_insn, sizeof (small_jump_insn)); - memcpy (buf + 2, &offset, 2); - memcpy (jjump_pad_insn, buf, sizeof (small_jump_insn)); - *jjump_pad_insn_size = sizeof (small_jump_insn); - } - else - { - /* Else use a 32-bit relative jump instruction. */ - offset = *jump_entry - (tpaddr + sizeof (jump_insn)); - memcpy (buf, jump_insn, sizeof (jump_insn)); - memcpy (buf + 1, &offset, 4); - memcpy (jjump_pad_insn, buf, sizeof (jump_insn)); - *jjump_pad_insn_size = sizeof (jump_insn); - } - - /* Return the end address of our pad. */ - *jump_entry = buildaddr; - - return 0; -} - -static int -x86_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) -{ -#ifdef __x86_64__ - if (is_64bit_tdesc ()) - return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr, - collector, lockaddr, - orig_size, jump_entry, - trampoline, trampoline_size, - jjump_pad_insn, - jjump_pad_insn_size, - adjusted_insn_addr, - adjusted_insn_addr_end, - err); -#endif - - return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr, - collector, lockaddr, - orig_size, jump_entry, - trampoline, trampoline_size, - jjump_pad_insn, - jjump_pad_insn_size, - adjusted_insn_addr, - adjusted_insn_addr_end, - err); -} - -/* Return the minimum instruction length for fast tracepoints on x86/x86-64 - architectures. */ - -static int -x86_get_min_fast_tracepoint_insn_len (void) -{ - static int warned_about_fast_tracepoints = 0; - -#ifdef __x86_64__ - /* On x86-64, 5-byte jump instructions with a 4-byte offset are always - used for fast tracepoints. */ - if (is_64bit_tdesc ()) - return 5; -#endif - - if (agent_loaded_p ()) - { - char errbuf[IPA_BUFSIZ]; - - errbuf[0] = '\0'; - - /* On x86, if trampolines are available, then 4-byte jump instructions - with a 2-byte offset may be used, otherwise 5-byte jump instructions - with a 4-byte offset are used instead. */ - if (have_fast_tracepoint_trampoline_buffer (errbuf)) - return 4; - else - { - /* GDB has no channel to explain to user why a shorter fast - tracepoint is not possible, but at least make GDBserver - mention that something has gone awry. */ - if (!warned_about_fast_tracepoints) - { - warning ("4-byte fast tracepoints not available; %s", errbuf); - warned_about_fast_tracepoints = 1; - } - return 5; - } - } - else - { - /* Indicate that the minimum length is currently unknown since the IPA - has not loaded yet. */ - return 0; - } -} - -static void -add_insns (unsigned char *start, int len) -{ - CORE_ADDR buildaddr = current_insn_ptr; - - if (debug_threads) - debug_printf ("Adding %d bytes of insn at %s\n", - len, paddress (buildaddr)); - - append_insns (&buildaddr, len, start); - current_insn_ptr = buildaddr; -} - -/* Our general strategy for emitting code is to avoid specifying raw - bytes whenever possible, and instead copy a block of inline asm - that is embedded in the function. This is a little messy, because - we need to keep the compiler from discarding what looks like dead - code, plus suppress various warnings. */ - -#define EMIT_ASM(NAME, INSNS) \ - do \ - { \ - extern unsigned char start_ ## NAME, end_ ## NAME; \ - add_insns (&start_ ## NAME, &end_ ## NAME - &start_ ## NAME); \ - __asm__ ("jmp end_" #NAME "\n" \ - "\t" "start_" #NAME ":" \ - "\t" INSNS "\n" \ - "\t" "end_" #NAME ":"); \ - } while (0) - -#ifdef __x86_64__ - -#define EMIT_ASM32(NAME,INSNS) \ - do \ - { \ - extern unsigned char start_ ## NAME, end_ ## NAME; \ - add_insns (&start_ ## NAME, &end_ ## NAME - &start_ ## NAME); \ - __asm__ (".code32\n" \ - "\t" "jmp end_" #NAME "\n" \ - "\t" "start_" #NAME ":\n" \ - "\t" INSNS "\n" \ - "\t" "end_" #NAME ":\n" \ - ".code64\n"); \ - } while (0) - -#else - -#define EMIT_ASM32(NAME,INSNS) EMIT_ASM(NAME,INSNS) - -#endif - -#ifdef __x86_64__ - -static void -amd64_emit_prologue (void) -{ - EMIT_ASM (amd64_prologue, - "pushq %rbp\n\t" - "movq %rsp,%rbp\n\t" - "sub $0x20,%rsp\n\t" - "movq %rdi,-8(%rbp)\n\t" - "movq %rsi,-16(%rbp)"); -} - - -static void -amd64_emit_epilogue (void) -{ - EMIT_ASM (amd64_epilogue, - "movq -16(%rbp),%rdi\n\t" - "movq %rax,(%rdi)\n\t" - "xor %rax,%rax\n\t" - "leave\n\t" - "ret"); -} - -static void -amd64_emit_add (void) -{ - EMIT_ASM (amd64_add, - "add (%rsp),%rax\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_sub (void) -{ - EMIT_ASM (amd64_sub, - "sub %rax,(%rsp)\n\t" - "pop %rax"); -} - -static void -amd64_emit_mul (void) -{ - emit_error = 1; -} - -static void -amd64_emit_lsh (void) -{ - emit_error = 1; -} - -static void -amd64_emit_rsh_signed (void) -{ - emit_error = 1; -} - -static void -amd64_emit_rsh_unsigned (void) -{ - emit_error = 1; -} - -static void -amd64_emit_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM (amd64_ext_8, - "cbtw\n\t" - "cwtl\n\t" - "cltq"); - break; - case 16: - EMIT_ASM (amd64_ext_16, - "cwtl\n\t" - "cltq"); - break; - case 32: - EMIT_ASM (amd64_ext_32, - "cltq"); - break; - default: - emit_error = 1; - } -} - -static void -amd64_emit_log_not (void) -{ - EMIT_ASM (amd64_log_not, - "test %rax,%rax\n\t" - "sete %cl\n\t" - "movzbq %cl,%rax"); -} - -static void -amd64_emit_bit_and (void) -{ - EMIT_ASM (amd64_and, - "and (%rsp),%rax\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_bit_or (void) -{ - EMIT_ASM (amd64_or, - "or (%rsp),%rax\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_bit_xor (void) -{ - EMIT_ASM (amd64_xor, - "xor (%rsp),%rax\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_bit_not (void) -{ - EMIT_ASM (amd64_bit_not, - "xorq $0xffffffffffffffff,%rax"); -} - -static void -amd64_emit_equal (void) -{ - EMIT_ASM (amd64_equal, - "cmp %rax,(%rsp)\n\t" - "je .Lamd64_equal_true\n\t" - "xor %rax,%rax\n\t" - "jmp .Lamd64_equal_end\n\t" - ".Lamd64_equal_true:\n\t" - "mov $0x1,%rax\n\t" - ".Lamd64_equal_end:\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_less_signed (void) -{ - EMIT_ASM (amd64_less_signed, - "cmp %rax,(%rsp)\n\t" - "jl .Lamd64_less_signed_true\n\t" - "xor %rax,%rax\n\t" - "jmp .Lamd64_less_signed_end\n\t" - ".Lamd64_less_signed_true:\n\t" - "mov $1,%rax\n\t" - ".Lamd64_less_signed_end:\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_less_unsigned (void) -{ - EMIT_ASM (amd64_less_unsigned, - "cmp %rax,(%rsp)\n\t" - "jb .Lamd64_less_unsigned_true\n\t" - "xor %rax,%rax\n\t" - "jmp .Lamd64_less_unsigned_end\n\t" - ".Lamd64_less_unsigned_true:\n\t" - "mov $1,%rax\n\t" - ".Lamd64_less_unsigned_end:\n\t" - "lea 0x8(%rsp),%rsp"); -} - -static void -amd64_emit_ref (int size) -{ - switch (size) - { - case 1: - EMIT_ASM (amd64_ref1, - "movb (%rax),%al"); - break; - case 2: - EMIT_ASM (amd64_ref2, - "movw (%rax),%ax"); - break; - case 4: - EMIT_ASM (amd64_ref4, - "movl (%rax),%eax"); - break; - case 8: - EMIT_ASM (amd64_ref8, - "movq (%rax),%rax"); - break; - } -} - -static void -amd64_emit_if_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_if_goto, - "mov %rax,%rcx\n\t" - "pop %rax\n\t" - "cmp $0,%rcx\n\t" - ".byte 0x0f, 0x85, 0x0, 0x0, 0x0, 0x0"); - if (offset_p) - *offset_p = 10; - if (size_p) - *size_p = 4; -} - -static void -amd64_emit_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_goto, - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0"); - if (offset_p) - *offset_p = 1; - if (size_p) - *size_p = 4; -} - -static void -amd64_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) -{ - int diff = (to - (from + size)); - unsigned char buf[sizeof (int)]; - - if (size != 4) - { - emit_error = 1; - return; - } - - memcpy (buf, &diff, sizeof (int)); - target_write_memory (from, buf, sizeof (int)); -} - -static void -amd64_emit_const (LONGEST num) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr = current_insn_ptr; - - i = 0; - buf[i++] = 0x48; buf[i++] = 0xb8; /* mov $,%rax */ - memcpy (&buf[i], &num, sizeof (num)); - i += 8; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; -} - -static void -amd64_emit_call (CORE_ADDR fn) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - LONGEST offset64; - - /* The destination function being in the shared library, may be - >31-bits away off the compiled code pad. */ - - buildaddr = current_insn_ptr; - - offset64 = fn - (buildaddr + 1 /* call op */ + 4 /* 32-bit offset */); - - i = 0; - - if (offset64 > INT_MAX || offset64 < INT_MIN) - { - /* Offset is too large for a call. Use callq, but that requires - a register, so avoid it if possible. Use r10, since it is - call-clobbered, we don't have to push/pop it. */ - buf[i++] = 0x48; /* mov $fn,%r10 */ - buf[i++] = 0xba; - memcpy (buf + i, &fn, 8); - i += 8; - buf[i++] = 0xff; /* callq *%r10 */ - buf[i++] = 0xd2; - } - else - { - int offset32 = offset64; /* we know we can't overflow here. */ - - buf[i++] = 0xe8; /* call */ - memcpy (buf + i, &offset32, 4); - i += 4; - } - - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; -} - -static void -amd64_emit_reg (int reg) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - - /* Assume raw_regs is still in %rdi. */ - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xbe; /* mov $,%esi */ - memcpy (&buf[i], ®, sizeof (reg)); - i += 4; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; - amd64_emit_call (get_raw_reg_func_addr ()); -} - -static void -amd64_emit_pop (void) -{ - EMIT_ASM (amd64_pop, - "pop %rax"); -} - -static void -amd64_emit_stack_flush (void) -{ - EMIT_ASM (amd64_stack_flush, - "push %rax"); -} - -static void -amd64_emit_zero_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM (amd64_zero_ext_8, - "and $0xff,%rax"); - break; - case 16: - EMIT_ASM (amd64_zero_ext_16, - "and $0xffff,%rax"); - break; - case 32: - EMIT_ASM (amd64_zero_ext_32, - "mov $0xffffffff,%rcx\n\t" - "and %rcx,%rax"); - break; - default: - emit_error = 1; - } -} - -static void -amd64_emit_swap (void) -{ - EMIT_ASM (amd64_swap, - "mov %rax,%rcx\n\t" - "pop %rax\n\t" - "push %rcx"); -} - -static void -amd64_emit_stack_adjust (int n) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr = current_insn_ptr; - - i = 0; - buf[i++] = 0x48; /* lea $(%rsp),%rsp */ - buf[i++] = 0x8d; - buf[i++] = 0x64; - buf[i++] = 0x24; - /* This only handles adjustments up to 16, but we don't expect any more. */ - buf[i++] = n * 8; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; -} - -/* FN's prototype is `LONGEST(*fn)(int)'. */ - -static void -amd64_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xbf; /* movl $,%edi */ - memcpy (&buf[i], &arg1, sizeof (arg1)); - i += 4; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; - amd64_emit_call (fn); -} - -/* FN's prototype is `void(*fn)(int,LONGEST)'. */ - -static void -amd64_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xbf; /* movl $,%edi */ - memcpy (&buf[i], &arg1, sizeof (arg1)); - i += 4; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; - EMIT_ASM (amd64_void_call_2_a, - /* Save away a copy of the stack top. */ - "push %rax\n\t" - /* Also pass top as the second argument. */ - "mov %rax,%rsi"); - amd64_emit_call (fn); - EMIT_ASM (amd64_void_call_2_b, - /* Restore the stack top, %rax may have been trashed. */ - "pop %rax"); -} - -static void -amd64_emit_eq_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_eq, - "cmp %rax,(%rsp)\n\t" - "jne .Lamd64_eq_fallthru\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lamd64_eq_fallthru:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax"); - - if (offset_p) - *offset_p = 13; - if (size_p) - *size_p = 4; -} - -static void -amd64_emit_ne_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_ne, - "cmp %rax,(%rsp)\n\t" - "je .Lamd64_ne_fallthru\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lamd64_ne_fallthru:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax"); - - if (offset_p) - *offset_p = 13; - if (size_p) - *size_p = 4; -} - -static void -amd64_emit_lt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_lt, - "cmp %rax,(%rsp)\n\t" - "jnl .Lamd64_lt_fallthru\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lamd64_lt_fallthru:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax"); - - if (offset_p) - *offset_p = 13; - if (size_p) - *size_p = 4; -} - -static void -amd64_emit_le_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_le, - "cmp %rax,(%rsp)\n\t" - "jnle .Lamd64_le_fallthru\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lamd64_le_fallthru:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax"); - - if (offset_p) - *offset_p = 13; - if (size_p) - *size_p = 4; -} - -static void -amd64_emit_gt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_gt, - "cmp %rax,(%rsp)\n\t" - "jng .Lamd64_gt_fallthru\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lamd64_gt_fallthru:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax"); - - if (offset_p) - *offset_p = 13; - if (size_p) - *size_p = 4; -} - -static void -amd64_emit_ge_goto (int *offset_p, int *size_p) -{ - EMIT_ASM (amd64_ge, - "cmp %rax,(%rsp)\n\t" - "jnge .Lamd64_ge_fallthru\n\t" - ".Lamd64_ge_jump:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lamd64_ge_fallthru:\n\t" - "lea 0x8(%rsp),%rsp\n\t" - "pop %rax"); - - if (offset_p) - *offset_p = 13; - if (size_p) - *size_p = 4; -} - -struct emit_ops amd64_emit_ops = - { - amd64_emit_prologue, - amd64_emit_epilogue, - amd64_emit_add, - amd64_emit_sub, - amd64_emit_mul, - amd64_emit_lsh, - amd64_emit_rsh_signed, - amd64_emit_rsh_unsigned, - amd64_emit_ext, - amd64_emit_log_not, - amd64_emit_bit_and, - amd64_emit_bit_or, - amd64_emit_bit_xor, - amd64_emit_bit_not, - amd64_emit_equal, - amd64_emit_less_signed, - amd64_emit_less_unsigned, - amd64_emit_ref, - amd64_emit_if_goto, - amd64_emit_goto, - amd64_write_goto_address, - amd64_emit_const, - amd64_emit_call, - amd64_emit_reg, - amd64_emit_pop, - amd64_emit_stack_flush, - amd64_emit_zero_ext, - amd64_emit_swap, - amd64_emit_stack_adjust, - amd64_emit_int_call_1, - amd64_emit_void_call_2, - amd64_emit_eq_goto, - amd64_emit_ne_goto, - amd64_emit_lt_goto, - amd64_emit_le_goto, - amd64_emit_gt_goto, - amd64_emit_ge_goto - }; - -#endif /* __x86_64__ */ - -static void -i386_emit_prologue (void) -{ - EMIT_ASM32 (i386_prologue, - "push %ebp\n\t" - "mov %esp,%ebp\n\t" - "push %ebx"); - /* At this point, the raw regs base address is at 8(%ebp), and the - value pointer is at 12(%ebp). */ -} - -static void -i386_emit_epilogue (void) -{ - EMIT_ASM32 (i386_epilogue, - "mov 12(%ebp),%ecx\n\t" - "mov %eax,(%ecx)\n\t" - "mov %ebx,0x4(%ecx)\n\t" - "xor %eax,%eax\n\t" - "pop %ebx\n\t" - "pop %ebp\n\t" - "ret"); -} - -static void -i386_emit_add (void) -{ - EMIT_ASM32 (i386_add, - "add (%esp),%eax\n\t" - "adc 0x4(%esp),%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_sub (void) -{ - EMIT_ASM32 (i386_sub, - "subl %eax,(%esp)\n\t" - "sbbl %ebx,4(%esp)\n\t" - "pop %eax\n\t" - "pop %ebx\n\t"); -} - -static void -i386_emit_mul (void) -{ - emit_error = 1; -} - -static void -i386_emit_lsh (void) -{ - emit_error = 1; -} - -static void -i386_emit_rsh_signed (void) -{ - emit_error = 1; -} - -static void -i386_emit_rsh_unsigned (void) -{ - emit_error = 1; -} - -static void -i386_emit_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM32 (i386_ext_8, - "cbtw\n\t" - "cwtl\n\t" - "movl %eax,%ebx\n\t" - "sarl $31,%ebx"); - break; - case 16: - EMIT_ASM32 (i386_ext_16, - "cwtl\n\t" - "movl %eax,%ebx\n\t" - "sarl $31,%ebx"); - break; - case 32: - EMIT_ASM32 (i386_ext_32, - "movl %eax,%ebx\n\t" - "sarl $31,%ebx"); - break; - default: - emit_error = 1; - } -} - -static void -i386_emit_log_not (void) -{ - EMIT_ASM32 (i386_log_not, - "or %ebx,%eax\n\t" - "test %eax,%eax\n\t" - "sete %cl\n\t" - "xor %ebx,%ebx\n\t" - "movzbl %cl,%eax"); -} - -static void -i386_emit_bit_and (void) -{ - EMIT_ASM32 (i386_and, - "and (%esp),%eax\n\t" - "and 0x4(%esp),%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_bit_or (void) -{ - EMIT_ASM32 (i386_or, - "or (%esp),%eax\n\t" - "or 0x4(%esp),%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_bit_xor (void) -{ - EMIT_ASM32 (i386_xor, - "xor (%esp),%eax\n\t" - "xor 0x4(%esp),%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_bit_not (void) -{ - EMIT_ASM32 (i386_bit_not, - "xor $0xffffffff,%eax\n\t" - "xor $0xffffffff,%ebx\n\t"); -} - -static void -i386_emit_equal (void) -{ - EMIT_ASM32 (i386_equal, - "cmpl %ebx,4(%esp)\n\t" - "jne .Li386_equal_false\n\t" - "cmpl %eax,(%esp)\n\t" - "je .Li386_equal_true\n\t" - ".Li386_equal_false:\n\t" - "xor %eax,%eax\n\t" - "jmp .Li386_equal_end\n\t" - ".Li386_equal_true:\n\t" - "mov $1,%eax\n\t" - ".Li386_equal_end:\n\t" - "xor %ebx,%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_less_signed (void) -{ - EMIT_ASM32 (i386_less_signed, - "cmpl %ebx,4(%esp)\n\t" - "jl .Li386_less_signed_true\n\t" - "jne .Li386_less_signed_false\n\t" - "cmpl %eax,(%esp)\n\t" - "jl .Li386_less_signed_true\n\t" - ".Li386_less_signed_false:\n\t" - "xor %eax,%eax\n\t" - "jmp .Li386_less_signed_end\n\t" - ".Li386_less_signed_true:\n\t" - "mov $1,%eax\n\t" - ".Li386_less_signed_end:\n\t" - "xor %ebx,%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_less_unsigned (void) -{ - EMIT_ASM32 (i386_less_unsigned, - "cmpl %ebx,4(%esp)\n\t" - "jb .Li386_less_unsigned_true\n\t" - "jne .Li386_less_unsigned_false\n\t" - "cmpl %eax,(%esp)\n\t" - "jb .Li386_less_unsigned_true\n\t" - ".Li386_less_unsigned_false:\n\t" - "xor %eax,%eax\n\t" - "jmp .Li386_less_unsigned_end\n\t" - ".Li386_less_unsigned_true:\n\t" - "mov $1,%eax\n\t" - ".Li386_less_unsigned_end:\n\t" - "xor %ebx,%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_ref (int size) -{ - switch (size) - { - case 1: - EMIT_ASM32 (i386_ref1, - "movb (%eax),%al"); - break; - case 2: - EMIT_ASM32 (i386_ref2, - "movw (%eax),%ax"); - break; - case 4: - EMIT_ASM32 (i386_ref4, - "movl (%eax),%eax"); - break; - case 8: - EMIT_ASM32 (i386_ref8, - "movl 4(%eax),%ebx\n\t" - "movl (%eax),%eax"); - break; - } -} - -static void -i386_emit_if_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (i386_if_goto, - "mov %eax,%ecx\n\t" - "or %ebx,%ecx\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - "cmpl $0,%ecx\n\t" - /* Don't trust the assembler to choose the right jump */ - ".byte 0x0f, 0x85, 0x0, 0x0, 0x0, 0x0"); - - if (offset_p) - *offset_p = 11; /* be sure that this matches the sequence above */ - if (size_p) - *size_p = 4; -} - -static void -i386_emit_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (i386_goto, - /* Don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0"); - if (offset_p) - *offset_p = 1; - if (size_p) - *size_p = 4; -} - -static void -i386_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) -{ - int diff = (to - (from + size)); - unsigned char buf[sizeof (int)]; - - /* We're only doing 4-byte sizes at the moment. */ - if (size != 4) - { - emit_error = 1; - return; - } - - memcpy (buf, &diff, sizeof (int)); - target_write_memory (from, buf, sizeof (int)); -} - -static void -i386_emit_const (LONGEST num) -{ - unsigned char buf[16]; - int i, hi, lo; - CORE_ADDR buildaddr = current_insn_ptr; - - i = 0; - buf[i++] = 0xb8; /* mov $,%eax */ - lo = num & 0xffffffff; - memcpy (&buf[i], &lo, sizeof (lo)); - i += 4; - hi = ((num >> 32) & 0xffffffff); - if (hi) - { - buf[i++] = 0xbb; /* mov $,%ebx */ - memcpy (&buf[i], &hi, sizeof (hi)); - i += 4; - } - else - { - buf[i++] = 0x31; buf[i++] = 0xdb; /* xor %ebx,%ebx */ - } - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; -} - -static void -i386_emit_call (CORE_ADDR fn) -{ - unsigned char buf[16]; - int i, offset; - CORE_ADDR buildaddr; - - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xe8; /* call */ - offset = ((int) fn) - (buildaddr + 5); - memcpy (buf + 1, &offset, 4); - append_insns (&buildaddr, 5, buf); - current_insn_ptr = buildaddr; -} - -static void -i386_emit_reg (int reg) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - - EMIT_ASM32 (i386_reg_a, - "sub $0x8,%esp"); - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xb8; /* mov $,%eax */ - memcpy (&buf[i], ®, sizeof (reg)); - i += 4; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; - EMIT_ASM32 (i386_reg_b, - "mov %eax,4(%esp)\n\t" - "mov 8(%ebp),%eax\n\t" - "mov %eax,(%esp)"); - i386_emit_call (get_raw_reg_func_addr ()); - EMIT_ASM32 (i386_reg_c, - "xor %ebx,%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -static void -i386_emit_pop (void) -{ - EMIT_ASM32 (i386_pop, - "pop %eax\n\t" - "pop %ebx"); -} - -static void -i386_emit_stack_flush (void) -{ - EMIT_ASM32 (i386_stack_flush, - "push %ebx\n\t" - "push %eax"); -} - -static void -i386_emit_zero_ext (int arg) -{ - switch (arg) - { - case 8: - EMIT_ASM32 (i386_zero_ext_8, - "and $0xff,%eax\n\t" - "xor %ebx,%ebx"); - break; - case 16: - EMIT_ASM32 (i386_zero_ext_16, - "and $0xffff,%eax\n\t" - "xor %ebx,%ebx"); - break; - case 32: - EMIT_ASM32 (i386_zero_ext_32, - "xor %ebx,%ebx"); - break; - default: - emit_error = 1; - } -} - -static void -i386_emit_swap (void) -{ - EMIT_ASM32 (i386_swap, - "mov %eax,%ecx\n\t" - "mov %ebx,%edx\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - "push %edx\n\t" - "push %ecx"); -} - -static void -i386_emit_stack_adjust (int n) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr = current_insn_ptr; - - i = 0; - buf[i++] = 0x8d; /* lea $(%esp),%esp */ - buf[i++] = 0x64; - buf[i++] = 0x24; - buf[i++] = n * 8; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; -} - -/* FN's prototype is `LONGEST(*fn)(int)'. */ - -static void -i386_emit_int_call_1 (CORE_ADDR fn, int arg1) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - - EMIT_ASM32 (i386_int_call_1_a, - /* Reserve a bit of stack space. */ - "sub $0x8,%esp"); - /* Put the one argument on the stack. */ - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xc7; /* movl $,(%esp) */ - buf[i++] = 0x04; - buf[i++] = 0x24; - memcpy (&buf[i], &arg1, sizeof (arg1)); - i += 4; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; - i386_emit_call (fn); - EMIT_ASM32 (i386_int_call_1_c, - "mov %edx,%ebx\n\t" - "lea 0x8(%esp),%esp"); -} - -/* FN's prototype is `void(*fn)(int,LONGEST)'. */ - -static void -i386_emit_void_call_2 (CORE_ADDR fn, int arg1) -{ - unsigned char buf[16]; - int i; - CORE_ADDR buildaddr; - - EMIT_ASM32 (i386_void_call_2_a, - /* Preserve %eax only; we don't have to worry about %ebx. */ - "push %eax\n\t" - /* Reserve a bit of stack space for arguments. */ - "sub $0x10,%esp\n\t" - /* Copy "top" to the second argument position. (Note that - we can't assume function won't scribble on its - arguments, so don't try to restore from this.) */ - "mov %eax,4(%esp)\n\t" - "mov %ebx,8(%esp)"); - /* Put the first argument on the stack. */ - buildaddr = current_insn_ptr; - i = 0; - buf[i++] = 0xc7; /* movl $,(%esp) */ - buf[i++] = 0x04; - buf[i++] = 0x24; - memcpy (&buf[i], &arg1, sizeof (arg1)); - i += 4; - append_insns (&buildaddr, i, buf); - current_insn_ptr = buildaddr; - i386_emit_call (fn); - EMIT_ASM32 (i386_void_call_2_b, - "lea 0x10(%esp),%esp\n\t" - /* Restore original stack top. */ - "pop %eax"); -} - - -static void -i386_emit_eq_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (eq, - /* Check low half first, more likely to be decider */ - "cmpl %eax,(%esp)\n\t" - "jne .Leq_fallthru\n\t" - "cmpl %ebx,4(%esp)\n\t" - "jne .Leq_fallthru\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Leq_fallthru:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx"); - - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -static void -i386_emit_ne_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (ne, - /* Check low half first, more likely to be decider */ - "cmpl %eax,(%esp)\n\t" - "jne .Lne_jump\n\t" - "cmpl %ebx,4(%esp)\n\t" - "je .Lne_fallthru\n\t" - ".Lne_jump:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lne_fallthru:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx"); - - if (offset_p) - *offset_p = 18; - if (size_p) - *size_p = 4; -} - -static void -i386_emit_lt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (lt, - "cmpl %ebx,4(%esp)\n\t" - "jl .Llt_jump\n\t" - "jne .Llt_fallthru\n\t" - "cmpl %eax,(%esp)\n\t" - "jnl .Llt_fallthru\n\t" - ".Llt_jump:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Llt_fallthru:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx"); - - if (offset_p) - *offset_p = 20; - if (size_p) - *size_p = 4; -} - -static void -i386_emit_le_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (le, - "cmpl %ebx,4(%esp)\n\t" - "jle .Lle_jump\n\t" - "jne .Lle_fallthru\n\t" - "cmpl %eax,(%esp)\n\t" - "jnle .Lle_fallthru\n\t" - ".Lle_jump:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lle_fallthru:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx"); - - if (offset_p) - *offset_p = 20; - if (size_p) - *size_p = 4; -} - -static void -i386_emit_gt_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (gt, - "cmpl %ebx,4(%esp)\n\t" - "jg .Lgt_jump\n\t" - "jne .Lgt_fallthru\n\t" - "cmpl %eax,(%esp)\n\t" - "jng .Lgt_fallthru\n\t" - ".Lgt_jump:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lgt_fallthru:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx"); - - if (offset_p) - *offset_p = 20; - if (size_p) - *size_p = 4; -} - -static void -i386_emit_ge_goto (int *offset_p, int *size_p) -{ - EMIT_ASM32 (ge, - "cmpl %ebx,4(%esp)\n\t" - "jge .Lge_jump\n\t" - "jne .Lge_fallthru\n\t" - "cmpl %eax,(%esp)\n\t" - "jnge .Lge_fallthru\n\t" - ".Lge_jump:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx\n\t" - /* jmp, but don't trust the assembler to choose the right jump */ - ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" - ".Lge_fallthru:\n\t" - "lea 0x8(%esp),%esp\n\t" - "pop %eax\n\t" - "pop %ebx"); - - if (offset_p) - *offset_p = 20; - if (size_p) - *size_p = 4; -} - -struct emit_ops i386_emit_ops = - { - i386_emit_prologue, - i386_emit_epilogue, - i386_emit_add, - i386_emit_sub, - i386_emit_mul, - i386_emit_lsh, - i386_emit_rsh_signed, - i386_emit_rsh_unsigned, - i386_emit_ext, - i386_emit_log_not, - i386_emit_bit_and, - i386_emit_bit_or, - i386_emit_bit_xor, - i386_emit_bit_not, - i386_emit_equal, - i386_emit_less_signed, - i386_emit_less_unsigned, - i386_emit_ref, - i386_emit_if_goto, - i386_emit_goto, - i386_write_goto_address, - i386_emit_const, - i386_emit_call, - i386_emit_reg, - i386_emit_pop, - i386_emit_stack_flush, - i386_emit_zero_ext, - i386_emit_swap, - i386_emit_stack_adjust, - i386_emit_int_call_1, - i386_emit_void_call_2, - i386_emit_eq_goto, - i386_emit_ne_goto, - i386_emit_lt_goto, - i386_emit_le_goto, - i386_emit_gt_goto, - i386_emit_ge_goto - }; - - -static struct emit_ops * -x86_emit_ops (void) -{ -#ifdef __x86_64__ - if (is_64bit_tdesc ()) - return &amd64_emit_ops; - else -#endif - return &i386_emit_ops; -} - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -x86_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = x86_breakpoint_len; - return x86_breakpoint; -} - -static int -x86_supports_range_stepping (void) -{ - return 1; -} - -/* Implementation of linux_target_ops method "supports_hardware_single_step". - */ - -static int -x86_supports_hardware_single_step (void) -{ - return 1; -} - -static int -x86_get_ipa_tdesc_idx (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - const struct target_desc *tdesc = regcache->tdesc; - -#ifdef __x86_64__ - return amd64_get_ipa_tdesc_idx (tdesc); -#endif - - if (tdesc == tdesc_i386_linux_no_xml) - return X86_TDESC_SSE; - - return i386_get_ipa_tdesc_idx (tdesc); -} - -/* This is initialized assuming an amd64 target. - x86_arch_setup will correct it for i386 or amd64 targets. */ - -struct linux_target_ops the_low_target = -{ - x86_arch_setup, - x86_linux_regs_info, - x86_cannot_fetch_register, - x86_cannot_store_register, - NULL, /* fetch_register */ - x86_get_pc, - x86_set_pc, - NULL, /* breakpoint_kind_from_pc */ - x86_sw_breakpoint_from_kind, - NULL, - 1, - x86_breakpoint_at, - x86_supports_z_point_type, - x86_insert_point, - x86_remove_point, - x86_stopped_by_watchpoint, - x86_stopped_data_address, - /* collect_ptrace_register/supply_ptrace_register are not needed in the - native i386 case (no registers smaller than an xfer unit), and are not - used in the biarch case (HAVE_LINUX_USRREGS is not defined). */ - NULL, - NULL, - /* need to fix up i386 siginfo if host is amd64 */ - x86_siginfo_fixup, - x86_linux_new_process, - x86_linux_delete_process, - x86_linux_new_thread, - x86_linux_delete_thread, - x86_linux_new_fork, - x86_linux_prepare_to_resume, - x86_linux_process_qsupported, - x86_supports_tracepoints, - x86_get_thread_area, - x86_install_fast_tracepoint_jump_pad, - x86_emit_ops, - x86_get_min_fast_tracepoint_insn_len, - x86_supports_range_stepping, - NULL, /* breakpoint_kind_from_current_state */ - x86_supports_hardware_single_step, - x86_get_syscall_trapinfo, - x86_get_ipa_tdesc_idx, -}; - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ -#ifdef __x86_64__ - tdesc_amd64_linux_no_xml = allocate_target_description (); - copy_target_description (tdesc_amd64_linux_no_xml, - amd64_linux_read_description (X86_XSTATE_SSE_MASK, - false)); - tdesc_amd64_linux_no_xml->xmltarget = xmltarget_amd64_linux_no_xml; -#endif - - tdesc_i386_linux_no_xml = allocate_target_description (); - copy_target_description (tdesc_i386_linux_no_xml, - i386_linux_read_description (X86_XSTATE_SSE_MASK)); - tdesc_i386_linux_no_xml->xmltarget = xmltarget_i386_linux_no_xml; - - initialize_regsets_info (&x86_regsets_info); -} diff --git a/gdb/gdbserver/linux-x86-tdesc.c b/gdb/gdbserver/linux-x86-tdesc.c deleted file mode 100644 index 96097eecc5e..00000000000 --- a/gdb/gdbserver/linux-x86-tdesc.c +++ /dev/null @@ -1,164 +0,0 @@ -/* GNU/Linux/x86-64 specific target description, for the remote server - for GDB. - Copyright (C) 2017-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "tdesc.h" -#include "linux-x86-tdesc.h" -#include "arch/i386.h" -#include "gdbsupport/x86-xstate.h" -#ifdef __x86_64__ -#include "arch/amd64.h" -#endif -#include "x86-tdesc.h" - -/* Return the right x86_linux_tdesc index for a given XCR0. Return - X86_TDESC_LAST if can't find a match. */ - -static enum x86_linux_tdesc -xcr0_to_tdesc_idx (uint64_t xcr0, bool is_x32) -{ - if (xcr0 & X86_XSTATE_PKRU) - { - if (is_x32) - { - /* No x32 MPX and PKU, fall back to avx_avx512. */ - return X86_TDESC_AVX_AVX512; - } - else - return X86_TDESC_AVX_MPX_AVX512_PKU; - } - else if (xcr0 & X86_XSTATE_AVX512) - return X86_TDESC_AVX_AVX512; - else if ((xcr0 & X86_XSTATE_AVX_MPX_MASK) == X86_XSTATE_AVX_MPX_MASK) - { - if (is_x32) /* No MPX on x32. */ - return X86_TDESC_AVX; - else - return X86_TDESC_AVX_MPX; - } - else if (xcr0 & X86_XSTATE_MPX) - { - if (is_x32) /* No MPX on x32. */ - return X86_TDESC_AVX; - else - return X86_TDESC_MPX; - } - else if (xcr0 & X86_XSTATE_AVX) - return X86_TDESC_AVX; - else if (xcr0 & X86_XSTATE_SSE) - return X86_TDESC_SSE; - else if (xcr0 & X86_XSTATE_X87) - return X86_TDESC_MMX; - else - return X86_TDESC_LAST; -} - -#if defined __i386__ || !defined IN_PROCESS_AGENT - -static struct target_desc *i386_tdescs[X86_TDESC_LAST] = { }; - -/* Return the target description according to XCR0. */ - -const struct target_desc * -i386_linux_read_description (uint64_t xcr0) -{ - enum x86_linux_tdesc idx = xcr0_to_tdesc_idx (xcr0, false); - - if (idx == X86_TDESC_LAST) - return NULL; - - struct target_desc **tdesc = &i386_tdescs[idx]; - - if (*tdesc == NULL) - { - *tdesc = i386_create_target_description (xcr0, true, false); - - init_target_desc (*tdesc, i386_expedite_regs); - } - - return *tdesc;; -} -#endif - -#ifdef __x86_64__ - -static target_desc *amd64_tdescs[X86_TDESC_LAST] = { }; -static target_desc *x32_tdescs[X86_TDESC_LAST] = { }; - -const struct target_desc * -amd64_linux_read_description (uint64_t xcr0, bool is_x32) -{ - enum x86_linux_tdesc idx = xcr0_to_tdesc_idx (xcr0, is_x32); - - if (idx == X86_TDESC_LAST) - return NULL; - - struct target_desc **tdesc = NULL; - - if (is_x32) - tdesc = &x32_tdescs[idx]; - else - tdesc = &amd64_tdescs[idx]; - - if (*tdesc == NULL) - { - *tdesc = amd64_create_target_description (xcr0, is_x32, true, true); - - init_target_desc (*tdesc, amd64_expedite_regs); - } - return *tdesc; -} - -#endif - -#ifndef IN_PROCESS_AGENT - -int -i386_get_ipa_tdesc_idx (const struct target_desc *tdesc) -{ - for (int i = 0; i < X86_TDESC_LAST; i++) - { - if (tdesc == i386_tdescs[i]) - return i; - } - - /* If none tdesc is found, return the one with minimum features. */ - return X86_TDESC_MMX; -} - -#if defined __x86_64__ -int -amd64_get_ipa_tdesc_idx (const struct target_desc *tdesc) -{ - for (int i = 0; i < X86_TDESC_LAST; i++) - { - if (tdesc == amd64_tdescs[i]) - return i; - } - for (int i = 0; i < X86_TDESC_LAST; i++) - { - if (tdesc == x32_tdescs[i]) - return i; - } - - return X86_TDESC_SSE; -} - -#endif -#endif diff --git a/gdb/gdbserver/linux-x86-tdesc.h b/gdb/gdbserver/linux-x86-tdesc.h deleted file mode 100644 index 21c8dfd3934..00000000000 --- a/gdb/gdbserver/linux-x86-tdesc.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Low level support for x86 (i386 and x86-64), shared between gdbserver - and IPA. - - Copyright (C) 2016-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LINUX_X86_TDESC_H -#define GDBSERVER_LINUX_X86_TDESC_H - -/* Note: since IPA obviously knows what ABI it's running on (i386 vs x86_64 - vs x32), it's sufficient to pass only the register set here. This, - together with the ABI known at IPA compile time, maps to a tdesc. */ - -enum x86_linux_tdesc { - X86_TDESC_MMX = 0, - X86_TDESC_SSE = 1, - X86_TDESC_AVX = 2, - X86_TDESC_MPX = 3, - X86_TDESC_AVX_MPX = 4, - X86_TDESC_AVX_AVX512 = 5, - X86_TDESC_AVX_MPX_AVX512_PKU = 6, - X86_TDESC_LAST = 7, -}; - -#if defined __i386__ || !defined IN_PROCESS_AGENT -int i386_get_ipa_tdesc_idx (const struct target_desc *tdesc); -#endif - -#if defined __x86_64__ && !defined IN_PROCESS_AGENT -int amd64_get_ipa_tdesc_idx (const struct target_desc *tdesc); -#endif - -const struct target_desc *i386_get_ipa_tdesc (int idx); - -#ifdef __x86_64__ -const struct target_desc *amd64_linux_read_description (uint64_t xcr0, - bool is_x32); -#endif - -const struct target_desc *i386_linux_read_description (uint64_t xcr0); - -#endif /* GDBSERVER_LINUX_X86_TDESC_H */ diff --git a/gdb/gdbserver/linux-xtensa-low.c b/gdb/gdbserver/linux-xtensa-low.c deleted file mode 100644 index 83af11e11dc..00000000000 --- a/gdb/gdbserver/linux-xtensa-low.c +++ /dev/null @@ -1,315 +0,0 @@ -/* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB. - Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - - -#include "server.h" -#include "linux-low.h" - -/* Defined in auto-generated file reg-xtensa.c. */ -void init_registers_xtensa (void); -extern const struct target_desc *tdesc_xtensa; - -#include -#include -#include "arch/xtensa.h" -#include "gdb_proc_service.h" - -#include "xtensa-xtregs.c" - -enum regnum { - R_PC=0, R_PS, - R_LBEG, R_LEND, R_LCOUNT, - R_SAR, - R_WS, R_WB, - R_THREADPTR, - R_A0 = 64 -}; - -static void -xtensa_fill_gregset (struct regcache *regcache, void *buf) -{ - elf_greg_t* rset = (elf_greg_t*)buf; - const struct target_desc *tdesc = regcache->tdesc; - int ar0_regnum; - char *ptr; - int i; - - /* Take care of AR registers. */ - - ar0_regnum = find_regno (tdesc, "ar0"); - ptr = (char*)&rset[R_A0]; - - for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) - { - collect_register (regcache, i, ptr); - ptr += register_size (tdesc, i); - } - - if (XSHAL_ABI == XTHAL_ABI_CALL0) - { - int a0_regnum = find_regno (tdesc, "a0"); - ptr = (char *) &rset[R_A0 + 4 * rset[R_WB]]; - - for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++) - { - if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS) - ptr = (char *) &rset[R_A0]; - collect_register (regcache, i, ptr); - ptr += register_size (tdesc, i); - } - } - - /* Loop registers, if hardware has it. */ - -#if XCHAL_HAVE_LOOPS - collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]); - collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]); - collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]); -#endif - - collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]); - collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]); - collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]); - collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]); - collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]); - -#if XCHAL_HAVE_THREADPTR - collect_register_by_name (regcache, "threadptr", - (char *) &rset[R_THREADPTR]); -#endif -} - -static void -xtensa_store_gregset (struct regcache *regcache, const void *buf) -{ - const elf_greg_t* rset = (const elf_greg_t*)buf; - const struct target_desc *tdesc = regcache->tdesc; - int ar0_regnum; - char *ptr; - int i; - - /* Take care of AR registers. */ - - ar0_regnum = find_regno (tdesc, "ar0"); - ptr = (char *)&rset[R_A0]; - - for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) - { - supply_register (regcache, i, ptr); - ptr += register_size (tdesc, i); - } - - if (XSHAL_ABI == XTHAL_ABI_CALL0) - { - int a0_regnum = find_regno (tdesc, "a0"); - ptr = (char *) &rset[R_A0 + (4 * rset[R_WB]) % XCHAL_NUM_AREGS]; - - for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++) - { - if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS) - ptr = (char *) &rset[R_A0]; - supply_register (regcache, i, ptr); - ptr += register_size (tdesc, i); - } - } - - /* Loop registers, if hardware has it. */ - -#if XCHAL_HAVE_LOOPS - supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]); - supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]); - supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]); -#endif - - supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]); - supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]); - supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]); - supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]); - supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]); - -#if XCHAL_HAVE_THREADPTR - supply_register_by_name (regcache, "threadptr", - (char *) &rset[R_THREADPTR]); -#endif -} - -/* Xtensa GNU/Linux PTRACE interface includes extended register set. */ - -static void -xtensa_fill_xtregset (struct regcache *regcache, void *buf) -{ - const xtensa_regtable_t *ptr; - - for (ptr = xtensa_regmap_table; ptr->name; ptr++) - { - collect_register_by_name (regcache, ptr->name, - (char*)buf + ptr->ptrace_offset); - } -} - -static void -xtensa_store_xtregset (struct regcache *regcache, const void *buf) -{ - const xtensa_regtable_t *ptr; - - for (ptr = xtensa_regmap_table; ptr->name; ptr++) - { - supply_register_by_name (regcache, ptr->name, - (char*)buf + ptr->ptrace_offset); - } -} - -static struct regset_info xtensa_regsets[] = { - { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), - GENERAL_REGS, - xtensa_fill_gregset, xtensa_store_gregset }, - { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE, - EXTENDED_REGS, - xtensa_fill_xtregset, xtensa_store_xtregset }, - NULL_REGSET -}; - -#if XCHAL_HAVE_BE -#define XTENSA_BREAKPOINT {0xd2,0x0f} -#else -#define XTENSA_BREAKPOINT {0x2d,0xf0} -#endif - -static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT; -#define xtensa_breakpoint_len 2 - -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -xtensa_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = xtensa_breakpoint_len; - return xtensa_breakpoint; -} - -static int -xtensa_breakpoint_at (CORE_ADDR where) -{ - unsigned long insn; - - (*the_target->read_memory) (where, (unsigned char *) &insn, - xtensa_breakpoint_len); - return memcmp((char *) &insn, - xtensa_breakpoint, xtensa_breakpoint_len) == 0; -} - -/* Called by libthread_db. */ - -ps_err_e -ps_get_thread_area (struct ps_prochandle *ph, - lwpid_t lwpid, int idx, void **base) -{ - xtensa_elf_gregset_t regs; - - if (ptrace (PTRACE_GETREGS, lwpid, NULL, ®s) != 0) - return PS_ERR; - - /* IDX is the bias from the thread pointer to the beginning of the - thread descriptor. It has to be subtracted due to implementation - quirks in libthread_db. */ - *base = (void *) ((char *) regs.threadptr - idx); - - return PS_OK; -} - -static struct regsets_info xtensa_regsets_info = - { - xtensa_regsets, /* regsets */ - 0, /* num_regsets */ - NULL, /* disabled_regsets */ - }; - -static struct regs_info regs_info = - { - NULL, /* regset_bitmap */ - NULL, /* usrregs */ - &xtensa_regsets_info - }; - -static void -xtensa_arch_setup (void) -{ - current_process ()->tdesc = tdesc_xtensa; -} - -/* Support for hardware single step. */ - -static int -xtensa_supports_hardware_single_step (void) -{ - return 1; -} - -static const struct regs_info * -xtensa_regs_info (void) -{ - return ®s_info; -} - -struct linux_target_ops the_low_target = { - xtensa_arch_setup, - xtensa_regs_info, - 0, - 0, - NULL, /* fetch_register */ - linux_get_pc_32bit, - linux_set_pc_32bit, - NULL, /* breakpoint_kind_from_pc */ - xtensa_sw_breakpoint_from_kind, - NULL, - 0, - xtensa_breakpoint_at, - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - NULL, /* siginfo_fixup */ - NULL, /* new_process */ - NULL, /* delete_process */ - NULL, /* new_thread */ - NULL, /* delete_thread */ - NULL, /* new_fork */ - NULL, /* prepare_to_resume */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* get_thread_area */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* supports_range_stepping */ - NULL, /* breakpoint_kind_from_current_state */ - xtensa_supports_hardware_single_step, -}; - - -void -initialize_low_arch (void) -{ - /* Initialize the Linux target descriptions. */ - init_registers_xtensa (); - - initialize_regsets_info (&xtensa_regsets_info); -} diff --git a/gdb/gdbserver/lynx-i386-low.c b/gdb/gdbserver/lynx-i386-low.c deleted file mode 100644 index d00e1a16771..00000000000 --- a/gdb/gdbserver/lynx-i386-low.c +++ /dev/null @@ -1,358 +0,0 @@ -/* Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "lynx-low.h" -#include -#include -#include "gdbsupport/x86-xstate.h" -#include "arch/i386.h" -#include "x86-tdesc.h" - -/* The following two typedefs are defined in a .h file which is not - in the standard include path (/sys/include/family/x86/ucontext.h), - so we just duplicate them here. - - Unfortunately for us, the definition of this structure differs between - LynxOS 5.x and LynxOS 178. Rather than duplicate the code, we use - different definitions depending on the target. */ - -#ifdef VMOS_DEV -#define LYNXOS_178 -#endif - -/* General register context */ -typedef struct usr_econtext { - - uint32_t uec_fault; - uint32_t uec_es; - uint32_t uec_ds; - uint32_t uec_edi; - uint32_t uec_esi; - uint32_t uec_ebp; - uint32_t uec_temp; - uint32_t uec_ebx; - uint32_t uec_edx; - uint32_t uec_ecx; - uint32_t uec_eax; - uint32_t uec_inum; - uint32_t uec_ecode; - uint32_t uec_eip; - uint32_t uec_cs; - uint32_t uec_eflags; - uint32_t uec_esp; - uint32_t uec_ss; - uint32_t uec_fs; - uint32_t uec_gs; -} usr_econtext_t; - -#if defined(LYNXOS_178) - -/* Floating point register context */ -typedef struct usr_fcontext { - uint32_t ufc_control; - uint32_t ufc_status; - uint32_t ufc_tag; - uint8_t *ufc_inst_off; - uint32_t ufc_inst_sel; - uint8_t *ufc_data_off; - uint32_t ufc_data_sel; - struct ufp387_real { - uint16_t umant4; - uint16_t umant3; - uint16_t umant2; - uint16_t umant1; - uint16_t us_and_e; - } ufc_reg[8]; -} usr_fcontext_t; - -#else /* This is LynxOS 5.x. */ - -/* Floating point and SIMD register context */ -typedef struct usr_fcontext { - uint16_t ufc_control; - uint16_t ufc_status; - uint16_t ufc_tag; - uint16_t ufc_opcode; - uint8_t *ufc_inst_off; - uint32_t ufc_inst_sel; - uint8_t *ufc_data_off; - uint32_t ufc_data_sel; - uint32_t usse_mxcsr; - uint32_t usse_mxcsr_mask; - struct ufp387_real { - uint16_t umant4; - uint16_t umant3; - uint16_t umant2; - uint16_t umant1; - uint16_t us_and_e; - uint16_t ureserved_1; - uint16_t ureserved_2; - uint16_t ureserved_3; - } ufc_reg[8]; - struct uxmm_register { - uint16_t uchunk_1; - uint16_t uchunk_2; - uint16_t uchunk_3; - uint16_t uchunk_4; - uint16_t uchunk_5; - uint16_t uchunk_6; - uint16_t uchunk_7; - uint16_t uchunk_8; - } uxmm_reg[8]; - char ureserved[16][14]; -} usr_fcontext_t; - -#endif - -/* The index of various registers inside the regcache. */ - -enum lynx_i386_gdb_regnum -{ - I386_EAX_REGNUM, - I386_ECX_REGNUM, - I386_EDX_REGNUM, - I386_EBX_REGNUM, - I386_ESP_REGNUM, - I386_EBP_REGNUM, - I386_ESI_REGNUM, - I386_EDI_REGNUM, - I386_EIP_REGNUM, - I386_EFLAGS_REGNUM, - I386_CS_REGNUM, - I386_SS_REGNUM, - I386_DS_REGNUM, - I386_ES_REGNUM, - I386_FS_REGNUM, - I386_GS_REGNUM, - I386_ST0_REGNUM, - I386_FCTRL_REGNUM = I386_ST0_REGNUM + 8, - I386_FSTAT_REGNUM, - I386_FTAG_REGNUM, - I386_FISEG_REGNUM, - I386_FIOFF_REGNUM, - I386_FOSEG_REGNUM, - I386_FOOFF_REGNUM, - I386_FOP_REGNUM, - I386_XMM0_REGNUM = 32, - I386_MXCSR_REGNUM = I386_XMM0_REGNUM + 8, - I386_SENTINEL_REGUM -}; - -/* The fill_function for the general-purpose register set. */ - -static void -lynx_i386_fill_gregset (struct regcache *regcache, char *buf) -{ -#define lynx_i386_collect_gp(regnum, fld) \ - collect_register (regcache, regnum, \ - buf + offsetof (usr_econtext_t, uec_##fld)) - - lynx_i386_collect_gp (I386_EAX_REGNUM, eax); - lynx_i386_collect_gp (I386_ECX_REGNUM, ecx); - lynx_i386_collect_gp (I386_EDX_REGNUM, edx); - lynx_i386_collect_gp (I386_EBX_REGNUM, ebx); - lynx_i386_collect_gp (I386_ESP_REGNUM, esp); - lynx_i386_collect_gp (I386_EBP_REGNUM, ebp); - lynx_i386_collect_gp (I386_ESI_REGNUM, esi); - lynx_i386_collect_gp (I386_EDI_REGNUM, edi); - lynx_i386_collect_gp (I386_EIP_REGNUM, eip); - lynx_i386_collect_gp (I386_EFLAGS_REGNUM, eflags); - lynx_i386_collect_gp (I386_CS_REGNUM, cs); - lynx_i386_collect_gp (I386_SS_REGNUM, ss); - lynx_i386_collect_gp (I386_DS_REGNUM, ds); - lynx_i386_collect_gp (I386_ES_REGNUM, es); - lynx_i386_collect_gp (I386_FS_REGNUM, fs); - lynx_i386_collect_gp (I386_GS_REGNUM, gs); -} - -/* The store_function for the general-purpose register set. */ - -static void -lynx_i386_store_gregset (struct regcache *regcache, const char *buf) -{ -#define lynx_i386_supply_gp(regnum, fld) \ - supply_register (regcache, regnum, \ - buf + offsetof (usr_econtext_t, uec_##fld)) - - lynx_i386_supply_gp (I386_EAX_REGNUM, eax); - lynx_i386_supply_gp (I386_ECX_REGNUM, ecx); - lynx_i386_supply_gp (I386_EDX_REGNUM, edx); - lynx_i386_supply_gp (I386_EBX_REGNUM, ebx); - lynx_i386_supply_gp (I386_ESP_REGNUM, esp); - lynx_i386_supply_gp (I386_EBP_REGNUM, ebp); - lynx_i386_supply_gp (I386_ESI_REGNUM, esi); - lynx_i386_supply_gp (I386_EDI_REGNUM, edi); - lynx_i386_supply_gp (I386_EIP_REGNUM, eip); - lynx_i386_supply_gp (I386_EFLAGS_REGNUM, eflags); - lynx_i386_supply_gp (I386_CS_REGNUM, cs); - lynx_i386_supply_gp (I386_SS_REGNUM, ss); - lynx_i386_supply_gp (I386_DS_REGNUM, ds); - lynx_i386_supply_gp (I386_ES_REGNUM, es); - lynx_i386_supply_gp (I386_FS_REGNUM, fs); - lynx_i386_supply_gp (I386_GS_REGNUM, gs); -} - -/* Extract the first 16 bits of register REGNUM in the REGCACHE, - and store these 2 bytes at DEST. - - This is useful to collect certain 16bit registers which are known - by GDBserver as 32bit registers (such as the Control Register - for instance). */ - -static void -collect_16bit_register (struct regcache *regcache, int regnum, char *dest) -{ - gdb_byte word[4]; - - collect_register (regcache, regnum, word); - memcpy (dest, word, 2); -} - -/* The fill_function for the floating-point register set. */ - -static void -lynx_i386_fill_fpregset (struct regcache *regcache, char *buf) -{ - int i; - - /* Collect %st0 .. %st7. */ - for (i = 0; i < 8; i++) - collect_register (regcache, I386_ST0_REGNUM + i, - buf + offsetof (usr_fcontext_t, ufc_reg) - + i * sizeof (struct ufp387_real)); - - /* Collect the other FPU registers. */ - collect_16bit_register (regcache, I386_FCTRL_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_control)); - collect_16bit_register (regcache, I386_FSTAT_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_status)); - collect_16bit_register (regcache, I386_FTAG_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_tag)); - collect_register (regcache, I386_FISEG_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_inst_sel)); - collect_register (regcache, I386_FIOFF_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_inst_off)); - collect_register (regcache, I386_FOSEG_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_data_sel)); - collect_register (regcache, I386_FOOFF_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_data_off)); -#if !defined(LYNXOS_178) - collect_16bit_register (regcache, I386_FOP_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_opcode)); - - /* Collect the XMM registers. */ - for (i = 0; i < 8; i++) - collect_register (regcache, I386_XMM0_REGNUM + i, - buf + offsetof (usr_fcontext_t, uxmm_reg) - + i * sizeof (struct uxmm_register)); - collect_register (regcache, I386_MXCSR_REGNUM, - buf + offsetof (usr_fcontext_t, usse_mxcsr)); -#endif -} - -/* This is the supply counterpart for collect_16bit_register: - It extracts a 2byte value from BUF, and uses that value to - set REGNUM's value in the regcache. - - This is useful to supply the value of certain 16bit registers - which are known by GDBserver as 32bit registers (such as the Control - Register for instance). */ - -static void -supply_16bit_register (struct regcache *regcache, int regnum, const char *buf) -{ - gdb_byte word[4]; - - memcpy (word, buf, 2); - memset (word + 2, 0, 2); - supply_register (regcache, regnum, word); -} - -/* The store_function for the floating-point register set. */ - -static void -lynx_i386_store_fpregset (struct regcache *regcache, const char *buf) -{ - int i; - - /* Store the %st0 .. %st7 registers. */ - for (i = 0; i < 8; i++) - supply_register (regcache, I386_ST0_REGNUM + i, - buf + offsetof (usr_fcontext_t, ufc_reg) - + i * sizeof (struct ufp387_real)); - - /* Store the other FPU registers. */ - supply_16bit_register (regcache, I386_FCTRL_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_control)); - supply_16bit_register (regcache, I386_FSTAT_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_status)); - supply_16bit_register (regcache, I386_FTAG_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_tag)); - supply_register (regcache, I386_FISEG_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_inst_sel)); - supply_register (regcache, I386_FIOFF_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_inst_off)); - supply_register (regcache, I386_FOSEG_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_data_sel)); - supply_register (regcache, I386_FOOFF_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_data_off)); -#if !defined(LYNXOS_178) - supply_16bit_register (regcache, I386_FOP_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_opcode)); - - /* Store the XMM registers. */ - for (i = 0; i < 8; i++) - supply_register (regcache, I386_XMM0_REGNUM + i, - buf + offsetof (usr_fcontext_t, uxmm_reg) - + i * sizeof (struct uxmm_register)); - supply_register (regcache, I386_MXCSR_REGNUM, - buf + offsetof (usr_fcontext_t, usse_mxcsr)); -#endif -} - -/* Implements the lynx_target_ops.arch_setup routine. */ - -static void -lynx_i386_arch_setup (void) -{ - struct target_desc *tdesc - = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); - - init_target_desc (tdesc, i386_expedite_regs); - - lynx_tdesc = tdesc; -} - -/* Description of all the x86-lynx register sets. */ - -struct lynx_regset_info lynx_target_regsets[] = { - /* General Purpose Registers. */ - {PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t), - lynx_i386_fill_gregset, lynx_i386_store_gregset}, - /* Floating Point Registers. */ - { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t), - lynx_i386_fill_fpregset, lynx_i386_store_fpregset }, - /* End of list marker. */ - {0, 0, -1, NULL, NULL } -}; - -/* The lynx_target_ops vector for x86-lynx. */ - -struct lynx_target_ops the_low_target = { - lynx_i386_arch_setup, -}; diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c deleted file mode 100644 index a5b019396fa..00000000000 --- a/gdb/gdbserver/lynx-low.c +++ /dev/null @@ -1,776 +0,0 @@ -/* Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "target.h" -#include "lynx-low.h" - -#include -#include -#include /* Provides PIDGET, TIDGET, BUILDPID, etc. */ -#include -#include -#include -#include "gdbsupport/gdb_wait.h" -#include -#include "gdbsupport/filestuff.h" -#include "gdbsupport/common-inferior.h" -#include "nat/fork-inferior.h" - -int using_threads = 1; - -const struct target_desc *lynx_tdesc; - -/* Per-process private data. */ - -struct process_info_private -{ - /* The PTID obtained from the last wait performed on this process. - Initialized to null_ptid until the first wait is performed. */ - ptid_t last_wait_event_ptid; -}; - -/* Print a debug trace on standard output if debug_threads is set. */ - -static void -lynx_debug (char *string, ...) -{ - va_list args; - - if (!debug_threads) - return; - - va_start (args, string); - fprintf (stderr, "DEBUG(lynx): "); - vfprintf (stderr, string, args); - fprintf (stderr, "\n"); - va_end (args); -} - -/* Build a ptid_t given a PID and a LynxOS TID. */ - -static ptid_t -lynx_ptid_t (int pid, long tid) -{ - /* brobecker/2010-06-21: It looks like the LWP field in ptids - should be distinct for each thread (see write_ptid where it - writes the thread ID from the LWP). So instead of storing - the LynxOS tid in the tid field of the ptid, we store it in - the lwp field. */ - return ptid_t (pid, tid, 0); -} - -/* Return the process ID of the given PTID. - - This function has little reason to exist, it's just a wrapper around - ptid_get_pid. But since we have a getter function for the lynxos - ptid, it feels cleaner to have a getter for the pid as well. */ - -static int -lynx_ptid_get_pid (ptid_t ptid) -{ - return ptid.pid (); -} - -/* Return the LynxOS tid of the given PTID. */ - -static long -lynx_ptid_get_tid (ptid_t ptid) -{ - /* See lynx_ptid_t: The LynxOS tid is stored inside the lwp field - of the ptid. */ - return ptid.lwp (); -} - -/* For a given PTID, return the associated PID as known by the LynxOS - ptrace layer. */ - -static int -lynx_ptrace_pid_from_ptid (ptid_t ptid) -{ - return BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); -} - -/* Return a string image of the ptrace REQUEST number. */ - -static char * -ptrace_request_to_str (int request) -{ -#define CASE(X) case X: return #X - switch (request) - { - CASE(PTRACE_TRACEME); - CASE(PTRACE_PEEKTEXT); - CASE(PTRACE_PEEKDATA); - CASE(PTRACE_PEEKUSER); - CASE(PTRACE_POKETEXT); - CASE(PTRACE_POKEDATA); - CASE(PTRACE_POKEUSER); - CASE(PTRACE_CONT); - CASE(PTRACE_KILL); - CASE(PTRACE_SINGLESTEP); - CASE(PTRACE_ATTACH); - CASE(PTRACE_DETACH); - CASE(PTRACE_GETREGS); - CASE(PTRACE_SETREGS); - CASE(PTRACE_GETFPREGS); - CASE(PTRACE_SETFPREGS); - CASE(PTRACE_READDATA); - CASE(PTRACE_WRITEDATA); - CASE(PTRACE_READTEXT); - CASE(PTRACE_WRITETEXT); - CASE(PTRACE_GETFPAREGS); - CASE(PTRACE_SETFPAREGS); - CASE(PTRACE_GETWINDOW); - CASE(PTRACE_SETWINDOW); - CASE(PTRACE_SYSCALL); - CASE(PTRACE_DUMPCORE); - CASE(PTRACE_SETWRBKPT); - CASE(PTRACE_SETACBKPT); - CASE(PTRACE_CLRBKPT); - CASE(PTRACE_GET_UCODE); -#ifdef PT_READ_GPR - CASE(PT_READ_GPR); -#endif -#ifdef PT_WRITE_GPR - CASE(PT_WRITE_GPR); -#endif -#ifdef PT_READ_FPR - CASE(PT_READ_FPR); -#endif -#ifdef PT_WRITE_FPR - CASE(PT_WRITE_FPR); -#endif -#ifdef PT_READ_VPR - CASE(PT_READ_VPR); -#endif -#ifdef PT_WRITE_VPR - CASE(PT_WRITE_VPR); -#endif -#ifdef PTRACE_PEEKUSP - CASE(PTRACE_PEEKUSP); -#endif -#ifdef PTRACE_POKEUSP - CASE(PTRACE_POKEUSP); -#endif - CASE(PTRACE_PEEKTHREAD); - CASE(PTRACE_THREADUSER); - CASE(PTRACE_FPREAD); - CASE(PTRACE_FPWRITE); - CASE(PTRACE_SETSIG); - CASE(PTRACE_CONT_ONE); - CASE(PTRACE_KILL_ONE); - CASE(PTRACE_SINGLESTEP_ONE); - CASE(PTRACE_GETLOADINFO); - CASE(PTRACE_GETTRACESIG); -#ifdef PTRACE_GETTHREADLIST - CASE(PTRACE_GETTHREADLIST); -#endif - } -#undef CASE - - return ""; -} - -/* A wrapper around ptrace that allows us to print debug traces of - ptrace calls if debug traces are activated. */ - -static int -lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2) -{ - int result; - const int pid = lynx_ptrace_pid_from_ptid (ptid); - int saved_errno; - - if (debug_threads) - fprintf (stderr, "PTRACE (%s, pid=%d(pid=%d, tid=%d), addr=0x%x, " - "data=0x%x, addr2=0x%x)", - ptrace_request_to_str (request), pid, PIDGET (pid), TIDGET (pid), - addr, data, addr2); - result = ptrace (request, pid, addr, data, addr2); - saved_errno = errno; - if (debug_threads) - fprintf (stderr, " -> %d (=0x%x)\n", result, result); - - errno = saved_errno; - return result; -} - -/* Call add_process with the given parameters, and initializes - the process' private data. */ - -static struct process_info * -lynx_add_process (int pid, int attached) -{ - struct process_info *proc; - - proc = add_process (pid, attached); - proc->tdesc = lynx_tdesc; - proc->priv = XCNEW (struct process_info_private); - proc->priv->last_wait_event_ptid = null_ptid; - - return proc; -} - -/* Callback used by fork_inferior to start tracing the inferior. */ - -static void -lynx_ptrace_fun () -{ - int pgrp; - - /* Switch child to its own process group so that signals won't - directly affect GDBserver. */ - pgrp = getpid(); - if (pgrp < 0) - trace_start_error_with_name ("pgrp"); - if (setpgid (0, pgrp) < 0) - trace_start_error_with_name ("setpgid"); - if (ioctl (0, TIOCSPGRP, &pgrp) < 0) - trace_start_error_with_name ("ioctl"); - if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0) - trace_start_error_with_name ("lynx_ptrace"); -} - -/* Implement the create_inferior method of the target_ops vector. */ - -static int -lynx_create_inferior (const char *program, - const std::vector &program_args) -{ - int pid; - std::string str_program_args = stringify_argv (program_args); - - lynx_debug ("lynx_create_inferior ()"); - - pid = fork_inferior (program, - str_program_args.c_str (), - get_environ ()->envp (), lynx_ptrace_fun, - NULL, NULL, NULL, NULL); - - post_fork_inferior (pid, program); - - lynx_add_process (pid, 0); - /* Do not add the process thread just yet, as we do not know its tid. - We will add it later, during the wait for the STOP event corresponding - to the lynx_ptrace (PTRACE_TRACEME) call above. */ - return pid; -} - -/* Assuming we've just attached to a running inferior whose pid is PID, - add all threads running in that process. */ - -static void -lynx_add_threads_after_attach (int pid) -{ - /* Ugh! There appears to be no way to get the list of threads - in the program we just attached to. So get the list by calling - the "ps" command. This is only needed now, as we will then - keep the thread list up to date thanks to thread creation and - exit notifications. */ - FILE *f; - char buf[256]; - int thread_pid, thread_tid; - - f = popen ("ps atx", "r"); - if (f == NULL) - perror_with_name ("Cannot get thread list"); - - while (fgets (buf, sizeof (buf), f) != NULL) - if ((sscanf (buf, "%d %d", &thread_pid, &thread_tid) == 2 - && thread_pid == pid)) - { - ptid_t thread_ptid = lynx_ptid_t (pid, thread_tid); - - if (!find_thread_ptid (thread_ptid)) - { - lynx_debug ("New thread: (pid = %d, tid = %d)", - pid, thread_tid); - add_thread (thread_ptid, NULL); - } - } - - pclose (f); -} - -/* Implement the attach target_ops method. */ - -static int -lynx_attach (unsigned long pid) -{ - ptid_t ptid = lynx_ptid_t (pid, 0); - - if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0) - error ("Cannot attach to process %lu: %s (%d)\n", pid, - safe_strerror (errno), errno); - - lynx_add_process (pid, 1); - lynx_add_threads_after_attach (pid); - - return 0; -} - -/* Implement the resume target_ops method. */ - -static void -lynx_resume (struct thread_resume *resume_info, size_t n) -{ - ptid_t ptid = resume_info[0].thread; - const int request - = (resume_info[0].kind == resume_step - ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP) - : PTRACE_CONT); - const int signal = resume_info[0].sig; - - /* If given a minus_one_ptid, then try using the current_process' - private->last_wait_event_ptid. On most LynxOS versions, - using any of the process' thread works well enough, but - LynxOS 178 is a little more sensitive, and triggers some - unexpected signals (Eg SIG61) when we resume the inferior - using a different thread. */ - if (ptid == minus_one_ptid) - ptid = current_process()->priv->last_wait_event_ptid; - - /* The ptid might still be minus_one_ptid; this can happen between - the moment we create the inferior or attach to a process, and - the moment we resume its execution for the first time. It is - fine to use the current_thread's ptid in those cases. */ - if (ptid == minus_one_ptid) - ptid = ptid_of (current_thread); - - regcache_invalidate_pid (ptid.pid ()); - - errno = 0; - lynx_ptrace (request, ptid, 1, signal, 0); - if (errno) - perror_with_name ("ptrace"); -} - -/* Resume the execution of the given PTID. */ - -static void -lynx_continue (ptid_t ptid) -{ - struct thread_resume resume_info; - - resume_info.thread = ptid; - resume_info.kind = resume_continue; - resume_info.sig = 0; - - lynx_resume (&resume_info, 1); -} - -/* A wrapper around waitpid that handles the various idiosyncrasies - of LynxOS' waitpid. */ - -static int -lynx_waitpid (int pid, int *stat_loc) -{ - int ret = 0; - - while (1) - { - ret = waitpid (pid, stat_loc, WNOHANG); - if (ret < 0) - { - /* An ECHILD error is not indicative of a real problem. - It happens for instance while waiting for the inferior - to stop after attaching to it. */ - if (errno != ECHILD) - perror_with_name ("waitpid (WNOHANG)"); - } - if (ret > 0) - break; - /* No event with WNOHANG. See if there is one with WUNTRACED. */ - ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED); - if (ret < 0) - { - /* An ECHILD error is not indicative of a real problem. - It happens for instance while waiting for the inferior - to stop after attaching to it. */ - if (errno != ECHILD) - perror_with_name ("waitpid (WNOHANG|WUNTRACED)"); - } - if (ret > 0) - break; - usleep (1000); - } - return ret; -} - -/* Implement the wait target_ops method. */ - -static ptid_t -lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options) -{ - int pid; - int ret; - int wstat; - ptid_t new_ptid; - - if (ptid == minus_one_ptid) - pid = lynx_ptid_get_pid (ptid_of (current_thread)); - else - pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); - -retry: - - ret = lynx_waitpid (pid, &wstat); - new_ptid = lynx_ptid_t (ret, ((union wait *) &wstat)->w_tid); - find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid; - - /* If this is a new thread, then add it now. The reason why we do - this here instead of when handling new-thread events is because - we need to add the thread associated to the "main" thread - even - for non-threaded applications where the new-thread events are not - generated. */ - if (!find_thread_ptid (new_ptid)) - { - lynx_debug ("New thread: (pid = %d, tid = %d)", - lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid)); - add_thread (new_ptid, NULL); - } - - if (WIFSTOPPED (wstat)) - { - status->kind = TARGET_WAITKIND_STOPPED; - status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat)); - lynx_debug ("process stopped with signal: %d", - status->value.integer); - } - else if (WIFEXITED (wstat)) - { - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = WEXITSTATUS (wstat); - lynx_debug ("process exited with code: %d", status->value.integer); - } - else if (WIFSIGNALED (wstat)) - { - status->kind = TARGET_WAITKIND_SIGNALLED; - status->value.integer = gdb_signal_from_host (WTERMSIG (wstat)); - lynx_debug ("process terminated with code: %d", - status->value.integer); - } - else - { - /* Not sure what happened if we get here, or whether we can - in fact get here. But if we do, handle the event the best - we can. */ - status->kind = TARGET_WAITKIND_STOPPED; - status->value.integer = gdb_signal_from_host (0); - lynx_debug ("unknown event ????"); - } - - /* SIGTRAP events are generated for situations other than single-step/ - breakpoint events (Eg. new-thread events). Handle those other types - of events, and resume the execution if necessary. */ - if (status->kind == TARGET_WAITKIND_STOPPED - && status->value.integer == GDB_SIGNAL_TRAP) - { - const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0); - - lynx_debug ("(realsig = %d)", realsig); - switch (realsig) - { - case SIGNEWTHREAD: - /* We just added the new thread above. No need to do anything - further. Just resume the execution again. */ - lynx_continue (new_ptid); - goto retry; - - case SIGTHREADEXIT: - remove_thread (find_thread_ptid (new_ptid)); - lynx_continue (new_ptid); - goto retry; - } - } - - return new_ptid; -} - -/* A wrapper around lynx_wait_1 that also prints debug traces when - such debug traces have been activated. */ - -static ptid_t -lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options) -{ - ptid_t new_ptid; - - lynx_debug ("lynx_wait (pid = %d, tid = %ld)", - lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); - new_ptid = lynx_wait_1 (ptid, status, options); - lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)", - lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid), - status->kind); - return new_ptid; -} - -/* Implement the kill target_ops method. */ - -static int -lynx_kill (process_info *process) -{ - ptid_t ptid = lynx_ptid_t (process->pid, 0); - struct target_waitstatus status; - - lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0); - lynx_wait (ptid, &status, 0); - the_target->mourn (process); - return 0; -} - -/* Implement the detach target_ops method. */ - -static int -lynx_detach (process_info *process) -{ - ptid_t ptid = lynx_ptid_t (process->pid, 0); - - lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0); - the_target->mourn (process); - return 0; -} - -/* Implement the mourn target_ops method. */ - -static void -lynx_mourn (struct process_info *proc) -{ - for_each_thread (proc->pid, remove_thread); - - /* Free our private data. */ - free (proc->priv); - proc->priv = NULL; - - remove_process (proc); -} - -/* Implement the join target_ops method. */ - -static void -lynx_join (int pid) -{ - /* The PTRACE_DETACH is sufficient to detach from the process. - So no need to do anything extra. */ -} - -/* Implement the thread_alive target_ops method. */ - -static int -lynx_thread_alive (ptid_t ptid) -{ - /* The list of threads is updated at the end of each wait, so it - should be up to date. No need to re-fetch it. */ - return (find_thread_ptid (ptid) != NULL); -} - -/* Implement the fetch_registers target_ops method. */ - -static void -lynx_fetch_registers (struct regcache *regcache, int regno) -{ - struct lynx_regset_info *regset = lynx_target_regsets; - ptid_t inferior_ptid = ptid_of (current_thread); - - lynx_debug ("lynx_fetch_registers (regno = %d)", regno); - - while (regset->size >= 0) - { - char *buf; - int res; - - buf = xmalloc (regset->size); - res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); - if (res < 0) - perror ("ptrace"); - regset->store_function (regcache, buf); - free (buf); - regset++; - } -} - -/* Implement the store_registers target_ops method. */ - -static void -lynx_store_registers (struct regcache *regcache, int regno) -{ - struct lynx_regset_info *regset = lynx_target_regsets; - ptid_t inferior_ptid = ptid_of (current_thread); - - lynx_debug ("lynx_store_registers (regno = %d)", regno); - - while (regset->size >= 0) - { - char *buf; - int res; - - buf = xmalloc (regset->size); - res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); - if (res == 0) - { - /* Then overlay our cached registers on that. */ - regset->fill_function (regcache, buf); - /* Only now do we write the register set. */ - res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf, - 0, 0); - } - if (res < 0) - perror ("ptrace"); - free (buf); - regset++; - } -} - -/* Implement the read_memory target_ops method. */ - -static int -lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - /* On LynxOS, memory reads needs to be performed in chunks the size - of int types, and they should also be aligned accordingly. */ - int buf; - const int xfer_size = sizeof (buf); - CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; - ptid_t inferior_ptid = ptid_of (current_thread); - - while (addr < memaddr + len) - { - int skip = 0; - int truncate = 0; - - errno = 0; - if (addr < memaddr) - skip = memaddr - addr; - if (addr + xfer_size > memaddr + len) - truncate = addr + xfer_size - memaddr - len; - buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0); - if (errno) - return errno; - memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip, - xfer_size - skip - truncate); - addr += xfer_size; - } - - return 0; -} - -/* Implement the write_memory target_ops method. */ - -static int -lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) -{ - /* On LynxOS, memory writes needs to be performed in chunks the size - of int types, and they should also be aligned accordingly. */ - int buf; - const int xfer_size = sizeof (buf); - CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; - ptid_t inferior_ptid = ptid_of (current_thread); - - while (addr < memaddr + len) - { - int skip = 0; - int truncate = 0; - - if (addr < memaddr) - skip = memaddr - addr; - if (addr + xfer_size > memaddr + len) - truncate = addr + xfer_size - memaddr - len; - if (skip > 0 || truncate > 0) - { - /* We need to read the memory at this address in order to preserve - the data that we are not overwriting. */ - lynx_read_memory (addr, (unsigned char *) &buf, xfer_size); - if (errno) - return errno; - } - memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip, - xfer_size - skip - truncate); - errno = 0; - lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0); - if (errno) - return errno; - addr += xfer_size; - } - - return 0; -} - -/* Implement the kill_request target_ops method. */ - -static void -lynx_request_interrupt (void) -{ - ptid_t inferior_ptid = ptid_of (get_first_thread ()); - - kill (lynx_ptid_get_pid (inferior_ptid), SIGINT); -} - -/* The LynxOS target_ops vector. */ - -static process_stratum_target lynx_target_ops = { - lynx_create_inferior, - NULL, /* post_create_inferior */ - lynx_attach, - lynx_kill, - lynx_detach, - lynx_mourn, - lynx_join, - lynx_thread_alive, - lynx_resume, - lynx_wait, - lynx_fetch_registers, - lynx_store_registers, - NULL, /* prepare_to_access_memory */ - NULL, /* done_accessing_memory */ - lynx_read_memory, - lynx_write_memory, - NULL, /* look_up_symbols */ - lynx_request_interrupt, - NULL, /* read_auxv */ - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_sw_breakpoint */ - NULL, /* supports_stopped_by_sw_breakpoint */ - NULL, /* stopped_by_hw_breakpoint */ - NULL, /* supports_stopped_by_hw_breakpoint */ - target_can_do_hardware_single_step, - NULL, /* stopped_by_watchpoint */ - NULL, /* stopped_data_address */ - NULL, /* read_offsets */ - NULL, /* get_tls_address */ - NULL, /* hostio_last_error */ - NULL, /* qxfer_osdata */ - NULL, /* qxfer_siginfo */ - NULL, /* supports_non_stop */ - NULL, /* async */ - NULL, /* start_non_stop */ - NULL, /* supports_multi_process */ - NULL, /* supports_fork_events */ - NULL, /* supports_vfork_events */ - NULL, /* supports_exec_events */ - NULL, /* handle_new_gdb_connection */ - NULL, /* handle_monitor_command */ -}; - -void -initialize_low (void) -{ - set_target_ops (&lynx_target_ops); - the_low_target.arch_setup (); -} - diff --git a/gdb/gdbserver/lynx-low.h b/gdb/gdbserver/lynx-low.h deleted file mode 100644 index b122298fb88..00000000000 --- a/gdb/gdbserver/lynx-low.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_LYNX_LOW_H -#define GDBSERVER_LYNX_LOW_H - -struct regcache; -struct target_desc; - -/* Some information relative to a given register set. */ - -struct lynx_regset_info -{ - /* The ptrace request needed to get/set registers of this set. */ - int get_request, set_request; - /* The size of the register set. */ - int size; - /* Fill the buffer BUF from the contents of the given REGCACHE. */ - void (*fill_function) (struct regcache *regcache, char *buf); - /* Store the register value in BUF in the given REGCACHE. */ - void (*store_function) (struct regcache *regcache, const char *buf); -}; - -/* A list of regsets for the target being debugged, terminated by an entry - where the size is negative. - - This list should be created by the target-specific code. */ - -extern struct lynx_regset_info lynx_target_regsets[]; - -/* The target-specific operations for LynxOS support. */ - -struct lynx_target_ops -{ - /* Architecture-specific setup. */ - void (*arch_setup) (void); -}; - -extern struct lynx_target_ops the_low_target; - -/* The inferior's target description. This is a global because the - LynxOS ports support neither bi-arch nor multi-process. */ -extern const struct target_desc *lynx_tdesc; - -#endif /* GDBSERVER_LYNX_LOW_H */ diff --git a/gdb/gdbserver/lynx-ppc-low.c b/gdb/gdbserver/lynx-ppc-low.c deleted file mode 100644 index f93fc1d8d87..00000000000 --- a/gdb/gdbserver/lynx-ppc-low.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "lynx-low.h" -#include -#include - -/* The following two typedefs are defined in a .h file which is not - in the standard include path (/sys/include/family/ppc/ucontext.h), - so we just duplicate them here. */ - -/* General register context */ -typedef struct usr_econtext_s -{ - uint32_t uec_iregs[32]; - uint32_t uec_inum; - uint32_t uec_srr0; - uint32_t uec_srr1; - uint32_t uec_lr; - uint32_t uec_ctr; - uint32_t uec_cr; - uint32_t uec_xer; - uint32_t uec_dar; - uint32_t uec_mq; - uint32_t uec_msr; - uint32_t uec_sregs[16]; - uint32_t uec_ss_count; - uint32_t uec_ss_addr1; - uint32_t uec_ss_addr2; - uint32_t uec_ss_code1; - uint32_t uec_ss_code2; -} usr_econtext_t; - -/* Floating point register context */ -typedef struct usr_fcontext_s -{ - uint64_t ufc_freg[32]; - uint32_t ufc_fpscr[2]; -} usr_fcontext_t; - -/* Index of for various registers inside the regcache. */ -#define R0_REGNUM 0 -#define F0_REGNUM 32 -#define PC_REGNUM 64 -#define MSR_REGNUM 65 -#define CR_REGNUM 66 -#define LR_REGNUM 67 -#define CTR_REGNUM 68 -#define XER_REGNUM 69 -#define FPSCR_REGNUM 70 - -/* Defined in auto-generated file powerpc-32.c. */ -extern void init_registers_powerpc_32 (void); -extern const struct target_desc *tdesc_powerpc_32; - -/* The fill_function for the general-purpose register set. */ - -static void -lynx_ppc_fill_gregset (struct regcache *regcache, char *buf) -{ - int i; - - /* r0 - r31 */ - for (i = 0; i < 32; i++) - collect_register (regcache, R0_REGNUM + i, - buf + offsetof (usr_econtext_t, uec_iregs[i])); - - /* The other registers provided in the GP register context. */ - collect_register (regcache, PC_REGNUM, - buf + offsetof (usr_econtext_t, uec_srr0)); - collect_register (regcache, MSR_REGNUM, - buf + offsetof (usr_econtext_t, uec_srr1)); - collect_register (regcache, CR_REGNUM, - buf + offsetof (usr_econtext_t, uec_cr)); - collect_register (regcache, LR_REGNUM, - buf + offsetof (usr_econtext_t, uec_lr)); - collect_register (regcache, CTR_REGNUM, - buf + offsetof (usr_econtext_t, uec_ctr)); - collect_register (regcache, XER_REGNUM, - buf + offsetof (usr_econtext_t, uec_xer)); -} - -/* The store_function for the general-purpose register set. */ - -static void -lynx_ppc_store_gregset (struct regcache *regcache, const char *buf) -{ - int i; - - /* r0 - r31 */ - for (i = 0; i < 32; i++) - supply_register (regcache, R0_REGNUM + i, - buf + offsetof (usr_econtext_t, uec_iregs[i])); - - /* The other registers provided in the GP register context. */ - supply_register (regcache, PC_REGNUM, - buf + offsetof (usr_econtext_t, uec_srr0)); - supply_register (regcache, MSR_REGNUM, - buf + offsetof (usr_econtext_t, uec_srr1)); - supply_register (regcache, CR_REGNUM, - buf + offsetof (usr_econtext_t, uec_cr)); - supply_register (regcache, LR_REGNUM, - buf + offsetof (usr_econtext_t, uec_lr)); - supply_register (regcache, CTR_REGNUM, - buf + offsetof (usr_econtext_t, uec_ctr)); - supply_register (regcache, XER_REGNUM, - buf + offsetof (usr_econtext_t, uec_xer)); -} - -/* The fill_function for the floating-point register set. */ - -static void -lynx_ppc_fill_fpregset (struct regcache *regcache, char *buf) -{ - int i; - - /* f0 - f31 */ - for (i = 0; i < 32; i++) - collect_register (regcache, F0_REGNUM + i, - buf + offsetof (usr_fcontext_t, ufc_freg[i])); - - /* fpscr */ - collect_register (regcache, FPSCR_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_fpscr)); -} - -/* The store_function for the floating-point register set. */ - -static void -lynx_ppc_store_fpregset (struct regcache *regcache, const char *buf) -{ - int i; - - /* f0 - f31 */ - for (i = 0; i < 32; i++) - supply_register (regcache, F0_REGNUM + i, - buf + offsetof (usr_fcontext_t, ufc_freg[i])); - - /* fpscr */ - supply_register (regcache, FPSCR_REGNUM, - buf + offsetof (usr_fcontext_t, ufc_fpscr)); -} - -/* Implements the lynx_target_ops.arch_setup routine. */ - -static void -lynx_ppc_arch_setup (void) -{ - init_registers_powerpc_32 (); - lynx_tdesc = tdesc_powerpc_32; -} - -/* Description of all the powerpc-lynx register sets. */ - -struct lynx_regset_info lynx_target_regsets[] = { - /* General Purpose Registers. */ - {PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t), - lynx_ppc_fill_gregset, lynx_ppc_store_gregset}, - /* Floating Point Registers. */ - { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t), - lynx_ppc_fill_fpregset, lynx_ppc_store_fpregset }, - /* End of list marker. */ - {0, 0, -1, NULL, NULL } -}; - -/* The lynx_target_ops vector for powerpc-lynxos. */ - -struct lynx_target_ops the_low_target = { - lynx_ppc_arch_setup, -}; diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c deleted file mode 100644 index 1b6f2365814..00000000000 --- a/gdb/gdbserver/mem-break.c +++ /dev/null @@ -1,2237 +0,0 @@ -/* Memory breakpoint operations for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#include "server.h" -#include "regcache.h" -#include "ax.h" - -#define MAX_BREAKPOINT_LEN 8 - -/* Helper macro used in loops that append multiple items to a singly-linked - list instead of inserting items at the head of the list, as, say, in the - breakpoint lists. LISTPP is a pointer to the pointer that is the head of - the new list. ITEMP is a pointer to the item to be added to the list. - TAILP must be defined to be the same type as ITEMP, and initialized to - NULL. */ - -#define APPEND_TO_LIST(listpp, itemp, tailp) \ - do \ - { \ - if ((tailp) == NULL) \ - *(listpp) = (itemp); \ - else \ - (tailp)->next = (itemp); \ - (tailp) = (itemp); \ - } \ - while (0) - -/* GDB will never try to install multiple breakpoints at the same - address. However, we can see GDB requesting to insert a breakpoint - at an address is had already inserted one previously in a few - situations. - - - The RSP documentation on Z packets says that to avoid potential - problems with duplicate packets, the operations should be - implemented in an idempotent way. - - - A breakpoint is set at ADDR, an address in a shared library. - Then the shared library is unloaded. And then another, unrelated, - breakpoint at ADDR is set. There is not breakpoint removal request - between the first and the second breakpoint. - - - When GDB wants to update the target-side breakpoint conditions or - commands, it re-inserts the breakpoint, with updated - conditions/commands associated. - - Also, we need to keep track of internal breakpoints too, so we do - need to be able to install multiple breakpoints at the same address - transparently. - - We keep track of two different, and closely related structures. A - raw breakpoint, which manages the low level, close to the metal - aspect of a breakpoint. It holds the breakpoint address, and for - software breakpoints, a buffer holding a copy of the instructions - that would be in memory had not been a breakpoint there (we call - that the shadow memory of the breakpoint). We occasionally need to - temporarilly uninsert a breakpoint without the client knowing about - it (e.g., to step over an internal breakpoint), so we keep an - `inserted' state associated with this low level breakpoint - structure. There can only be one such object for a given address. - Then, we have (a bit higher level) breakpoints. This structure - holds a callback to be called whenever a breakpoint is hit, a - high-level type, and a link to a low level raw breakpoint. There - can be many high-level breakpoints at the same address, and all of - them will point to the same raw breakpoint, which is reference - counted. */ - -/* The low level, physical, raw breakpoint. */ -struct raw_breakpoint -{ - struct raw_breakpoint *next; - - /* The low level type of the breakpoint (software breakpoint, - watchpoint, etc.) */ - enum raw_bkpt_type raw_type; - - /* A reference count. Each high level breakpoint referencing this - raw breakpoint accounts for one reference. */ - int refcount; - - /* The breakpoint's insertion address. There can only be one raw - breakpoint for a given PC. */ - CORE_ADDR pc; - - /* The breakpoint's kind. This is target specific. Most - architectures only use one specific instruction for breakpoints, while - others may use more than one. E.g., on ARM, we need to use different - breakpoint instructions on Thumb, Thumb-2, and ARM code. Likewise for - hardware breakpoints -- some architectures (including ARM) need to - setup debug registers differently depending on mode. */ - int kind; - - /* The breakpoint's shadow memory. */ - unsigned char old_data[MAX_BREAKPOINT_LEN]; - - /* Positive if this breakpoint is currently inserted in the - inferior. Negative if it was, but we've detected that it's now - gone. Zero if not inserted. */ - int inserted; -}; - -/* The type of a breakpoint. */ -enum bkpt_type - { - /* A GDB breakpoint, requested with a Z0 packet. */ - gdb_breakpoint_Z0, - - /* A GDB hardware breakpoint, requested with a Z1 packet. */ - gdb_breakpoint_Z1, - - /* A GDB write watchpoint, requested with a Z2 packet. */ - gdb_breakpoint_Z2, - - /* A GDB read watchpoint, requested with a Z3 packet. */ - gdb_breakpoint_Z3, - - /* A GDB access watchpoint, requested with a Z4 packet. */ - gdb_breakpoint_Z4, - - /* A software single-step breakpoint. */ - single_step_breakpoint, - - /* Any other breakpoint type that doesn't require specific - treatment goes here. E.g., an event breakpoint. */ - other_breakpoint, - }; - -struct point_cond_list -{ - /* Pointer to the agent expression that is the breakpoint's - conditional. */ - struct agent_expr *cond; - - /* Pointer to the next condition. */ - struct point_cond_list *next; -}; - -struct point_command_list -{ - /* Pointer to the agent expression that is the breakpoint's - commands. */ - struct agent_expr *cmd; - - /* Flag that is true if this command should run even while GDB is - disconnected. */ - int persistence; - - /* Pointer to the next command. */ - struct point_command_list *next; -}; - -/* A high level (in gdbserver's perspective) breakpoint. */ -struct breakpoint -{ - struct breakpoint *next; - - /* The breakpoint's type. */ - enum bkpt_type type; - - /* Link to this breakpoint's raw breakpoint. This is always - non-NULL. */ - struct raw_breakpoint *raw; -}; - -/* Breakpoint requested by GDB. */ - -struct gdb_breakpoint -{ - struct breakpoint base; - - /* Pointer to the condition list that should be evaluated on - the target or NULL if the breakpoint is unconditional or - if GDB doesn't want us to evaluate the conditionals on the - target's side. */ - struct point_cond_list *cond_list; - - /* Point to the list of commands to run when this is hit. */ - struct point_command_list *command_list; -}; - -/* Breakpoint used by GDBserver. */ - -struct other_breakpoint -{ - struct breakpoint base; - - /* Function to call when we hit this breakpoint. If it returns 1, - the breakpoint shall be deleted; 0 or if this callback is NULL, - it will be left inserted. */ - int (*handler) (CORE_ADDR); -}; - -/* Breakpoint for single step. */ - -struct single_step_breakpoint -{ - struct breakpoint base; - - /* Thread the reinsert breakpoint belongs to. */ - ptid_t ptid; -}; - -/* Return the breakpoint size from its kind. */ - -static int -bp_size (struct raw_breakpoint *bp) -{ - int size = 0; - - the_target->sw_breakpoint_from_kind (bp->kind, &size); - return size; -} - -/* Return the breakpoint opcode from its kind. */ - -static const gdb_byte * -bp_opcode (struct raw_breakpoint *bp) -{ - int size = 0; - - return the_target->sw_breakpoint_from_kind (bp->kind, &size); -} - -/* See mem-break.h. */ - -enum target_hw_bp_type -raw_bkpt_type_to_target_hw_bp_type (enum raw_bkpt_type raw_type) -{ - switch (raw_type) - { - case raw_bkpt_type_hw: - return hw_execute; - case raw_bkpt_type_write_wp: - return hw_write; - case raw_bkpt_type_read_wp: - return hw_read; - case raw_bkpt_type_access_wp: - return hw_access; - default: - internal_error (__FILE__, __LINE__, - "bad raw breakpoint type %d", (int) raw_type); - } -} - -/* See mem-break.h. */ - -static enum bkpt_type -Z_packet_to_bkpt_type (char z_type) -{ - gdb_assert ('0' <= z_type && z_type <= '4'); - - return (enum bkpt_type) (gdb_breakpoint_Z0 + (z_type - '0')); -} - -/* See mem-break.h. */ - -enum raw_bkpt_type -Z_packet_to_raw_bkpt_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - return raw_bkpt_type_sw; - case Z_PACKET_HW_BP: - return raw_bkpt_type_hw; - case Z_PACKET_WRITE_WP: - return raw_bkpt_type_write_wp; - case Z_PACKET_READ_WP: - return raw_bkpt_type_read_wp; - case Z_PACKET_ACCESS_WP: - return raw_bkpt_type_access_wp; - default: - gdb_assert_not_reached ("unhandled Z packet type."); - } -} - -/* Return true if breakpoint TYPE is a GDB breakpoint. */ - -static int -is_gdb_breakpoint (enum bkpt_type type) -{ - return (type == gdb_breakpoint_Z0 - || type == gdb_breakpoint_Z1 - || type == gdb_breakpoint_Z2 - || type == gdb_breakpoint_Z3 - || type == gdb_breakpoint_Z4); -} - -bool -any_persistent_commands (process_info *proc) -{ - struct breakpoint *bp; - struct point_command_list *cl; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - if (is_gdb_breakpoint (bp->type)) - { - struct gdb_breakpoint *gdb_bp = (struct gdb_breakpoint *) bp; - - for (cl = gdb_bp->command_list; cl != NULL; cl = cl->next) - if (cl->persistence) - return true; - } - } - - return false; -} - -/* Find low-level breakpoint of type TYPE at address ADDR that is not - insert-disabled. Returns NULL if not found. */ - -static struct raw_breakpoint * -find_enabled_raw_code_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->pc == addr - && bp->raw_type == type - && bp->inserted >= 0) - return bp; - - return NULL; -} - -/* Find low-level breakpoint of type TYPE at address ADDR. Returns - NULL if not found. */ - -static struct raw_breakpoint * -find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int kind) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->pc == addr && bp->raw_type == type && bp->kind == kind) - return bp; - - return NULL; -} - -/* See mem-break.h. */ - -int -insert_memory_breakpoint (struct raw_breakpoint *bp) -{ - unsigned char buf[MAX_BREAKPOINT_LEN]; - int err; - - /* Note that there can be fast tracepoint jumps installed in the - same memory range, so to get at the original memory, we need to - use read_inferior_memory, which masks those out. */ - err = read_inferior_memory (bp->pc, buf, bp_size (bp)); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to read shadow memory of" - " breakpoint at 0x%s (%s).\n", - paddress (bp->pc), safe_strerror (err)); - } - else - { - memcpy (bp->old_data, buf, bp_size (bp)); - - err = (*the_target->write_memory) (bp->pc, bp_opcode (bp), - bp_size (bp)); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to insert breakpoint at 0x%s (%s).\n", - paddress (bp->pc), safe_strerror (err)); - } - } - return err != 0 ? -1 : 0; -} - -/* See mem-break.h */ - -int -remove_memory_breakpoint (struct raw_breakpoint *bp) -{ - unsigned char buf[MAX_BREAKPOINT_LEN]; - int err; - - /* Since there can be trap breakpoints inserted in the same address - range, we use `target_write_memory', which takes care of - layering breakpoints on top of fast tracepoints, and on top of - the buffer we pass it. This works because the caller has already - either unlinked the breakpoint or marked it uninserted. Also - note that we need to pass the current shadow contents, because - target_write_memory updates any shadow memory with what we pass - here, and we want that to be a nop. */ - memcpy (buf, bp->old_data, bp_size (bp)); - err = target_write_memory (bp->pc, buf, bp_size (bp)); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to uninsert raw breakpoint " - "at 0x%s (%s) while deleting it.\n", - paddress (bp->pc), safe_strerror (err)); - } - return err != 0 ? -1 : 0; -} - -/* Set a RAW breakpoint of type TYPE and kind KIND at WHERE. On - success, a pointer to the new breakpoint is returned. On failure, - returns NULL and writes the error code to *ERR. */ - -static struct raw_breakpoint * -set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind, - int *err) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw) - { - bp = find_enabled_raw_code_breakpoint_at (where, type); - if (bp != NULL && bp->kind != kind) - { - /* A different kind than previously seen. The previous - breakpoint must be gone then. */ - if (debug_threads) - debug_printf ("Inconsistent breakpoint kind? Was %d, now %d.\n", - bp->kind, kind); - bp->inserted = -1; - bp = NULL; - } - } - else - bp = find_raw_breakpoint_at (where, type, kind); - - gdb::unique_xmalloc_ptr bp_holder; - if (bp == NULL) - { - bp_holder.reset (XCNEW (struct raw_breakpoint)); - bp = bp_holder.get (); - bp->pc = where; - bp->kind = kind; - bp->raw_type = type; - } - - if (!bp->inserted) - { - *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); - if (*err != 0) - { - if (debug_threads) - debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n", - paddress (where), *err); - - return NULL; - } - - bp->inserted = 1; - } - - /* If the breakpoint was allocated above, we know we want to keep it - now. */ - bp_holder.release (); - - /* Link the breakpoint in, if this is the first reference. */ - if (++bp->refcount == 1) - { - bp->next = proc->raw_breakpoints; - proc->raw_breakpoints = bp; - } - return bp; -} - -/* Notice that breakpoint traps are always installed on top of fast - tracepoint jumps. This is even if the fast tracepoint is installed - at a later time compared to when the breakpoint was installed. - This means that a stopping breakpoint or tracepoint has higher - "priority". In turn, this allows having fast and slow tracepoints - (and breakpoints) at the same address behave correctly. */ - - -/* A fast tracepoint jump. */ - -struct fast_tracepoint_jump -{ - struct fast_tracepoint_jump *next; - - /* A reference count. GDB can install more than one fast tracepoint - at the same address (each with its own action list, for - example). */ - int refcount; - - /* The fast tracepoint's insertion address. There can only be one - of these for a given PC. */ - CORE_ADDR pc; - - /* Non-zero if this fast tracepoint jump is currently inserted in - the inferior. */ - int inserted; - - /* The length of the jump instruction. */ - int length; - - /* A poor-man's flexible array member, holding both the jump - instruction to insert, and a copy of the instruction that would - be in memory had not been a jump there (the shadow memory of the - tracepoint jump). */ - unsigned char insn_and_shadow[0]; -}; - -/* Fast tracepoint FP's jump instruction to insert. */ -#define fast_tracepoint_jump_insn(fp) \ - ((fp)->insn_and_shadow + 0) - -/* The shadow memory of fast tracepoint jump FP. */ -#define fast_tracepoint_jump_shadow(fp) \ - ((fp)->insn_and_shadow + (fp)->length) - - -/* Return the fast tracepoint jump set at WHERE. */ - -static struct fast_tracepoint_jump * -find_fast_tracepoint_jump_at (CORE_ADDR where) -{ - struct process_info *proc = current_process (); - struct fast_tracepoint_jump *jp; - - for (jp = proc->fast_tracepoint_jumps; jp != NULL; jp = jp->next) - if (jp->pc == where) - return jp; - - return NULL; -} - -int -fast_tracepoint_jump_here (CORE_ADDR where) -{ - struct fast_tracepoint_jump *jp = find_fast_tracepoint_jump_at (where); - - return (jp != NULL); -} - -int -delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel) -{ - struct fast_tracepoint_jump *bp, **bp_link; - int ret; - struct process_info *proc = current_process (); - - bp = proc->fast_tracepoint_jumps; - bp_link = &proc->fast_tracepoint_jumps; - - while (bp) - { - if (bp == todel) - { - if (--bp->refcount == 0) - { - struct fast_tracepoint_jump *prev_bp_link = *bp_link; - unsigned char *buf; - - /* Unlink it. */ - *bp_link = bp->next; - - /* Since there can be breakpoints inserted in the same - address range, we use `target_write_memory', which - takes care of layering breakpoints on top of fast - tracepoints, and on top of the buffer we pass it. - This works because we've already unlinked the fast - tracepoint jump above. Also note that we need to - pass the current shadow contents, because - target_write_memory updates any shadow memory with - what we pass here, and we want that to be a nop. */ - buf = (unsigned char *) alloca (bp->length); - memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length); - ret = target_write_memory (bp->pc, buf, bp->length); - if (ret != 0) - { - /* Something went wrong, relink the jump. */ - *bp_link = prev_bp_link; - - if (debug_threads) - debug_printf ("Failed to uninsert fast tracepoint jump " - "at 0x%s (%s) while deleting it.\n", - paddress (bp->pc), safe_strerror (ret)); - return ret; - } - - free (bp); - } - - return 0; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - warning ("Could not find fast tracepoint jump in list."); - return ENOENT; -} - -void -inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp) -{ - jp->refcount++; -} - -struct fast_tracepoint_jump * -set_fast_tracepoint_jump (CORE_ADDR where, - unsigned char *insn, ULONGEST length) -{ - struct process_info *proc = current_process (); - struct fast_tracepoint_jump *jp; - int err; - unsigned char *buf; - - /* We refcount fast tracepoint jumps. Check if we already know - about a jump at this address. */ - jp = find_fast_tracepoint_jump_at (where); - if (jp != NULL) - { - jp->refcount++; - return jp; - } - - /* We don't, so create a new object. Double the length, because the - flexible array member holds both the jump insn, and the - shadow. */ - jp = (struct fast_tracepoint_jump *) xcalloc (1, sizeof (*jp) + (length * 2)); - jp->pc = where; - jp->length = length; - memcpy (fast_tracepoint_jump_insn (jp), insn, length); - jp->refcount = 1; - buf = (unsigned char *) alloca (length); - - /* Note that there can be trap breakpoints inserted in the same - address range. To access the original memory contents, we use - `read_inferior_memory', which masks out breakpoints. */ - err = read_inferior_memory (where, buf, length); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to read shadow memory of" - " fast tracepoint at 0x%s (%s).\n", - paddress (where), safe_strerror (err)); - free (jp); - return NULL; - } - memcpy (fast_tracepoint_jump_shadow (jp), buf, length); - - /* Link the jump in. */ - jp->inserted = 1; - jp->next = proc->fast_tracepoint_jumps; - proc->fast_tracepoint_jumps = jp; - - /* Since there can be trap breakpoints inserted in the same address - range, we use use `target_write_memory', which takes care of - layering breakpoints on top of fast tracepoints, on top of the - buffer we pass it. This works because we've already linked in - the fast tracepoint jump above. Also note that we need to pass - the current shadow contents, because target_write_memory - updates any shadow memory with what we pass here, and we want - that to be a nop. */ - err = target_write_memory (where, buf, length); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to insert fast tracepoint jump at 0x%s (%s).\n", - paddress (where), safe_strerror (err)); - - /* Unlink it. */ - proc->fast_tracepoint_jumps = jp->next; - free (jp); - - return NULL; - } - - return jp; -} - -void -uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc) -{ - struct fast_tracepoint_jump *jp; - int err; - - jp = find_fast_tracepoint_jump_at (pc); - if (jp == NULL) - { - /* This can happen when we remove all breakpoints while handling - a step-over. */ - if (debug_threads) - debug_printf ("Could not find fast tracepoint jump at 0x%s " - "in list (uninserting).\n", - paddress (pc)); - return; - } - - if (jp->inserted) - { - unsigned char *buf; - - jp->inserted = 0; - - /* Since there can be trap breakpoints inserted in the same - address range, we use use `target_write_memory', which - takes care of layering breakpoints on top of fast - tracepoints, and on top of the buffer we pass it. This works - because we've already marked the fast tracepoint fast - tracepoint jump uninserted above. Also note that we need to - pass the current shadow contents, because - target_write_memory updates any shadow memory with what we - pass here, and we want that to be a nop. */ - buf = (unsigned char *) alloca (jp->length); - memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); - err = target_write_memory (jp->pc, buf, jp->length); - if (err != 0) - { - jp->inserted = 1; - - if (debug_threads) - debug_printf ("Failed to uninsert fast tracepoint jump at" - " 0x%s (%s).\n", - paddress (pc), safe_strerror (err)); - } - } -} - -void -reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) -{ - struct fast_tracepoint_jump *jp; - int err; - unsigned char *buf; - - jp = find_fast_tracepoint_jump_at (where); - if (jp == NULL) - { - /* This can happen when we remove breakpoints when a tracepoint - hit causes a tracing stop, while handling a step-over. */ - if (debug_threads) - debug_printf ("Could not find fast tracepoint jump at 0x%s " - "in list (reinserting).\n", - paddress (where)); - return; - } - - if (jp->inserted) - error ("Jump already inserted at reinsert time."); - - jp->inserted = 1; - - /* Since there can be trap breakpoints inserted in the same address - range, we use `target_write_memory', which takes care of - layering breakpoints on top of fast tracepoints, and on top of - the buffer we pass it. This works because we've already marked - the fast tracepoint jump inserted above. Also note that we need - to pass the current shadow contents, because - target_write_memory updates any shadow memory with what we pass - here, and we want that to be a nop. */ - buf = (unsigned char *) alloca (jp->length); - memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); - err = target_write_memory (where, buf, jp->length); - if (err != 0) - { - jp->inserted = 0; - - if (debug_threads) - debug_printf ("Failed to reinsert fast tracepoint jump at" - " 0x%s (%s).\n", - paddress (where), safe_strerror (err)); - } -} - -/* Set a high-level breakpoint of type TYPE, with low level type - RAW_TYPE and kind KIND, at WHERE. On success, a pointer to the new - breakpoint is returned. On failure, returns NULL and writes the - error code to *ERR. HANDLER is called when the breakpoint is hit. - HANDLER should return 1 if the breakpoint should be deleted, 0 - otherwise. */ - -static struct breakpoint * -set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type, - CORE_ADDR where, int kind, - int (*handler) (CORE_ADDR), int *err) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - struct raw_breakpoint *raw; - - raw = set_raw_breakpoint_at (raw_type, where, kind, err); - - if (raw == NULL) - { - /* warn? */ - return NULL; - } - - if (is_gdb_breakpoint (type)) - { - struct gdb_breakpoint *gdb_bp = XCNEW (struct gdb_breakpoint); - - bp = (struct breakpoint *) gdb_bp; - gdb_assert (handler == NULL); - } - else if (type == other_breakpoint) - { - struct other_breakpoint *other_bp = XCNEW (struct other_breakpoint); - - other_bp->handler = handler; - bp = (struct breakpoint *) other_bp; - } - else if (type == single_step_breakpoint) - { - struct single_step_breakpoint *ss_bp - = XCNEW (struct single_step_breakpoint); - - bp = (struct breakpoint *) ss_bp; - } - else - gdb_assert_not_reached ("unhandled breakpoint type"); - - bp->type = type; - bp->raw = raw; - - bp->next = proc->breakpoints; - proc->breakpoints = bp; - - return bp; -} - -/* Set breakpoint of TYPE on address WHERE with handler HANDLER. */ - -static struct breakpoint * -set_breakpoint_type_at (enum bkpt_type type, CORE_ADDR where, - int (*handler) (CORE_ADDR)) -{ - int err_ignored; - CORE_ADDR placed_address = where; - int breakpoint_kind = target_breakpoint_kind_from_pc (&placed_address); - - return set_breakpoint (type, raw_bkpt_type_sw, - placed_address, breakpoint_kind, handler, - &err_ignored); -} - -/* See mem-break.h */ - -struct breakpoint * -set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) -{ - return set_breakpoint_type_at (other_breakpoint, where, handler); -} - - -static int -delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) -{ - struct raw_breakpoint *bp, **bp_link; - int ret; - - bp = proc->raw_breakpoints; - bp_link = &proc->raw_breakpoints; - - while (bp) - { - if (bp == todel) - { - if (bp->inserted > 0) - { - struct raw_breakpoint *prev_bp_link = *bp_link; - - *bp_link = bp->next; - - ret = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, - bp); - if (ret != 0) - { - /* Something went wrong, relink the breakpoint. */ - *bp_link = prev_bp_link; - - if (debug_threads) - debug_printf ("Failed to uninsert raw breakpoint " - "at 0x%s while deleting it.\n", - paddress (bp->pc)); - return ret; - } - } - else - *bp_link = bp->next; - - free (bp); - return 0; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - warning ("Could not find raw breakpoint in list."); - return ENOENT; -} - -static int -release_breakpoint (struct process_info *proc, struct breakpoint *bp) -{ - int newrefcount; - int ret; - - newrefcount = bp->raw->refcount - 1; - if (newrefcount == 0) - { - ret = delete_raw_breakpoint (proc, bp->raw); - if (ret != 0) - return ret; - } - else - bp->raw->refcount = newrefcount; - - free (bp); - - return 0; -} - -static int -delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel) -{ - struct breakpoint *bp, **bp_link; - int err; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - if (bp == todel) - { - *bp_link = bp->next; - - err = release_breakpoint (proc, bp); - if (err != 0) - return err; - - bp = *bp_link; - return 0; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - warning ("Could not find breakpoint in list."); - return ENOENT; -} - -int -delete_breakpoint (struct breakpoint *todel) -{ - struct process_info *proc = current_process (); - return delete_breakpoint_1 (proc, todel); -} - -/* Locate a GDB breakpoint of type Z_TYPE and kind KIND placed at - address ADDR and return a pointer to its structure. If KIND is -1, - the breakpoint's kind is ignored. */ - -static struct gdb_breakpoint * -find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - enum bkpt_type type = Z_packet_to_bkpt_type (z_type); - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - if (bp->type == type && bp->raw->pc == addr - && (kind == -1 || bp->raw->kind == kind)) - return (struct gdb_breakpoint *) bp; - - return NULL; -} - -static int -z_type_supported (char z_type) -{ - return (z_type >= '0' && z_type <= '4' - && the_target->supports_z_point_type != NULL - && the_target->supports_z_point_type (z_type)); -} - -/* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND. - Returns a pointer to the newly created breakpoint on success. On - failure returns NULL and sets *ERR to either -1 for error, or 1 if - Z_TYPE breakpoints are not supported on this target. */ - -static struct gdb_breakpoint * -set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err) -{ - struct gdb_breakpoint *bp; - enum bkpt_type type; - enum raw_bkpt_type raw_type; - - /* If we see GDB inserting a second code breakpoint at the same - address, then either: GDB is updating the breakpoint's conditions - or commands; or, the first breakpoint must have disappeared due - to a shared library unload. On targets where the shared - libraries are handled by userspace, like SVR4, for example, - GDBserver can't tell if a library was loaded or unloaded. Since - we refcount raw breakpoints, we must be careful to make sure GDB - breakpoints never contribute more than one reference. if we - didn't do this, in case the previous breakpoint is gone due to a - shared library unload, we'd just increase the refcount of the - previous breakpoint at this address, but the trap was not planted - in the inferior anymore, thus the breakpoint would never be hit. - Note this must be careful to not create a window where - breakpoints are removed from the target, for non-stop, in case - the target can poke at memory while the program is running. */ - if (z_type == Z_PACKET_SW_BP - || z_type == Z_PACKET_HW_BP) - { - bp = find_gdb_breakpoint (z_type, addr, -1); - - if (bp != NULL) - { - if (bp->base.raw->kind != kind) - { - /* A different kind than previously seen. The previous - breakpoint must be gone then. */ - bp->base.raw->inserted = -1; - delete_breakpoint ((struct breakpoint *) bp); - bp = NULL; - } - else if (z_type == Z_PACKET_SW_BP) - { - /* Check if the breakpoint is actually gone from the - target, due to an solib unload, for example. Might - as well validate _all_ breakpoints. */ - validate_breakpoints (); - - /* Breakpoints that don't pass validation are - deleted. */ - bp = find_gdb_breakpoint (z_type, addr, -1); - } - } - } - else - { - /* Data breakpoints for the same address but different kind are - expected. GDB doesn't merge these. The backend gets to do - that if it wants/can. */ - bp = find_gdb_breakpoint (z_type, addr, kind); - } - - if (bp != NULL) - { - /* We already know about this breakpoint, there's nothing else - to do - GDB's reference is already accounted for. Note that - whether the breakpoint inserted is left as is - we may be - stepping over it, for example, in which case we don't want to - force-reinsert it. */ - return bp; - } - - raw_type = Z_packet_to_raw_bkpt_type (z_type); - type = Z_packet_to_bkpt_type (z_type); - return (struct gdb_breakpoint *) set_breakpoint (type, raw_type, addr, - kind, NULL, err); -} - -static int -check_gdb_bp_preconditions (char z_type, int *err) -{ - /* As software/memory breakpoints work by poking at memory, we need - to prepare to access memory. If that operation fails, we need to - return error. Seeing an error, if this is the first breakpoint - of that type that GDB tries to insert, GDB would then assume the - breakpoint type is supported, but it may actually not be. So we - need to check whether the type is supported at all before - preparing to access memory. */ - if (!z_type_supported (z_type)) - { - *err = 1; - return 0; - } - - return 1; -} - -/* See mem-break.h. This is a wrapper for set_gdb_breakpoint_1 that - knows to prepare to access memory for Z0 breakpoints. */ - -struct gdb_breakpoint * -set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err) -{ - struct gdb_breakpoint *bp; - - if (!check_gdb_bp_preconditions (z_type, err)) - return NULL; - - /* If inserting a software/memory breakpoint, need to prepare to - access memory. */ - if (z_type == Z_PACKET_SW_BP) - { - if (prepare_to_access_memory () != 0) - { - *err = -1; - return NULL; - } - } - - bp = set_gdb_breakpoint_1 (z_type, addr, kind, err); - - if (z_type == Z_PACKET_SW_BP) - done_accessing_memory (); - - return bp; -} - -/* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously - inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success, - -1 on error, and 1 if Z_TYPE breakpoints are not supported on this - target. */ - -static int -delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind) -{ - struct gdb_breakpoint *bp; - int err; - - bp = find_gdb_breakpoint (z_type, addr, kind); - if (bp == NULL) - return -1; - - /* Before deleting the breakpoint, make sure to free its condition - and command lists. */ - clear_breakpoint_conditions_and_commands (bp); - err = delete_breakpoint ((struct breakpoint *) bp); - if (err != 0) - return -1; - - return 0; -} - -/* See mem-break.h. This is a wrapper for delete_gdb_breakpoint that - knows to prepare to access memory for Z0 breakpoints. */ - -int -delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) -{ - int ret; - - if (!check_gdb_bp_preconditions (z_type, &ret)) - return ret; - - /* If inserting a software/memory breakpoint, need to prepare to - access memory. */ - if (z_type == Z_PACKET_SW_BP) - { - int err; - - err = prepare_to_access_memory (); - if (err != 0) - return -1; - } - - ret = delete_gdb_breakpoint_1 (z_type, addr, kind); - - if (z_type == Z_PACKET_SW_BP) - done_accessing_memory (); - - return ret; -} - -/* Clear all conditions associated with a breakpoint. */ - -static void -clear_breakpoint_conditions (struct gdb_breakpoint *bp) -{ - struct point_cond_list *cond; - - if (bp->cond_list == NULL) - return; - - cond = bp->cond_list; - - while (cond != NULL) - { - struct point_cond_list *cond_next; - - cond_next = cond->next; - gdb_free_agent_expr (cond->cond); - free (cond); - cond = cond_next; - } - - bp->cond_list = NULL; -} - -/* Clear all commands associated with a breakpoint. */ - -static void -clear_breakpoint_commands (struct gdb_breakpoint *bp) -{ - struct point_command_list *cmd; - - if (bp->command_list == NULL) - return; - - cmd = bp->command_list; - - while (cmd != NULL) - { - struct point_command_list *cmd_next; - - cmd_next = cmd->next; - gdb_free_agent_expr (cmd->cmd); - free (cmd); - cmd = cmd_next; - } - - bp->command_list = NULL; -} - -void -clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp) -{ - clear_breakpoint_conditions (bp); - clear_breakpoint_commands (bp); -} - -/* Add condition CONDITION to GDBserver's breakpoint BP. */ - -static void -add_condition_to_breakpoint (struct gdb_breakpoint *bp, - struct agent_expr *condition) -{ - struct point_cond_list *new_cond; - - /* Create new condition. */ - new_cond = XCNEW (struct point_cond_list); - new_cond->cond = condition; - - /* Add condition to the list. */ - new_cond->next = bp->cond_list; - bp->cond_list = new_cond; -} - -/* Add a target-side condition CONDITION to a breakpoint. */ - -int -add_breakpoint_condition (struct gdb_breakpoint *bp, const char **condition) -{ - const char *actparm = *condition; - struct agent_expr *cond; - - if (condition == NULL) - return 1; - - if (bp == NULL) - return 0; - - cond = gdb_parse_agent_expr (&actparm); - - if (cond == NULL) - { - warning ("Condition evaluation failed. Assuming unconditional."); - return 0; - } - - add_condition_to_breakpoint (bp, cond); - - *condition = actparm; - - return 1; -} - -/* Evaluate condition (if any) at breakpoint BP. Return 1 if - true and 0 otherwise. */ - -static int -gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr) -{ - /* Fetch registers for the current inferior. */ - struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); - ULONGEST value = 0; - struct point_cond_list *cl; - int err = 0; - struct eval_agent_expr_context ctx; - - if (bp == NULL) - return 0; - - /* Check if the breakpoint is unconditional. If it is, - the condition always evaluates to TRUE. */ - if (bp->cond_list == NULL) - return 1; - - ctx.regcache = get_thread_regcache (current_thread, 1); - ctx.tframe = NULL; - ctx.tpoint = NULL; - - /* Evaluate each condition in the breakpoint's list of conditions. - Return true if any of the conditions evaluates to TRUE. - - If we failed to evaluate the expression, TRUE is returned. This - forces GDB to reevaluate the conditions. */ - for (cl = bp->cond_list; - cl && !value && !err; cl = cl->next) - { - /* Evaluate the condition. */ - err = gdb_eval_agent_expr (&ctx, cl->cond, &value); - } - - if (err) - return 1; - - return (value != 0); -} - -int -gdb_condition_true_at_breakpoint (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. */ - return (gdb_condition_true_at_breakpoint_z_type (Z_PACKET_SW_BP, where) - || gdb_condition_true_at_breakpoint_z_type (Z_PACKET_HW_BP, where)); -} - -/* Add commands COMMANDS to GDBserver's breakpoint BP. */ - -static void -add_commands_to_breakpoint (struct gdb_breakpoint *bp, - struct agent_expr *commands, int persist) -{ - struct point_command_list *new_cmd; - - /* Create new command. */ - new_cmd = XCNEW (struct point_command_list); - new_cmd->cmd = commands; - new_cmd->persistence = persist; - - /* Add commands to the list. */ - new_cmd->next = bp->command_list; - bp->command_list = new_cmd; -} - -/* Add a target-side command COMMAND to the breakpoint at ADDR. */ - -int -add_breakpoint_commands (struct gdb_breakpoint *bp, const char **command, - int persist) -{ - const char *actparm = *command; - struct agent_expr *cmd; - - if (command == NULL) - return 1; - - if (bp == NULL) - return 0; - - cmd = gdb_parse_agent_expr (&actparm); - - if (cmd == NULL) - { - warning ("Command evaluation failed. Disabling."); - return 0; - } - - add_commands_to_breakpoint (bp, cmd, persist); - - *command = actparm; - - return 1; -} - -/* Return true if there are no commands to run at this location, - which likely means we want to report back to GDB. */ - -static int -gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr) -{ - struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); - - if (bp == NULL) - return 1; - - if (debug_threads) - debug_printf ("at 0x%s, type Z%c, bp command_list is 0x%s\n", - paddress (addr), z_type, - phex_nz ((uintptr_t) bp->command_list, 0)); - return (bp->command_list == NULL); -} - -/* Return true if there are no commands to run at this location, - which likely means we want to report back to GDB. */ - -int -gdb_no_commands_at_breakpoint (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. */ - return (gdb_no_commands_at_breakpoint_z_type (Z_PACKET_SW_BP, where) - && gdb_no_commands_at_breakpoint_z_type (Z_PACKET_HW_BP, where)); -} - -/* Run a breakpoint's commands. Returns 0 if there was a problem - running any command, 1 otherwise. */ - -static int -run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr) -{ - /* Fetch registers for the current inferior. */ - struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); - ULONGEST value = 0; - struct point_command_list *cl; - int err = 0; - struct eval_agent_expr_context ctx; - - if (bp == NULL) - return 1; - - ctx.regcache = get_thread_regcache (current_thread, 1); - ctx.tframe = NULL; - ctx.tpoint = NULL; - - for (cl = bp->command_list; - cl && !value && !err; cl = cl->next) - { - /* Run the command. */ - err = gdb_eval_agent_expr (&ctx, cl->cmd, &value); - - /* If one command has a problem, stop digging the hole deeper. */ - if (err) - return 0; - } - - return 1; -} - -void -run_breakpoint_commands (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. If one - command has a problem, stop digging the hole deeper. */ - if (run_breakpoint_commands_z_type (Z_PACKET_SW_BP, where)) - run_breakpoint_commands_z_type (Z_PACKET_HW_BP, where); -} - -/* See mem-break.h. */ - -int -gdb_breakpoint_here (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. */ - return (find_gdb_breakpoint (Z_PACKET_SW_BP, where, -1) != NULL - || find_gdb_breakpoint (Z_PACKET_HW_BP, where, -1) != NULL); -} - -void -set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid) -{ - struct single_step_breakpoint *bp; - - gdb_assert (current_ptid.pid () == ptid.pid ()); - - bp = (struct single_step_breakpoint *) set_breakpoint_type_at (single_step_breakpoint, - stop_at, NULL); - bp->ptid = ptid; -} - -void -delete_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp, **bp_link; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - *bp_link = bp->next; - release_breakpoint (proc, bp); - bp = *bp_link; - current_thread = saved_thread; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } -} - -static void -uninsert_raw_breakpoint (struct raw_breakpoint *bp) -{ - if (bp->inserted < 0) - { - if (debug_threads) - debug_printf ("Breakpoint at %s is marked insert-disabled.\n", - paddress (bp->pc)); - } - else if (bp->inserted > 0) - { - int err; - - bp->inserted = 0; - - err = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp); - if (err != 0) - { - bp->inserted = 1; - - if (debug_threads) - debug_printf ("Failed to uninsert raw breakpoint at 0x%s.\n", - paddress (bp->pc)); - } - } -} - -void -uninsert_breakpoints_at (CORE_ADDR pc) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - int found = 0; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == pc) - { - found = 1; - - if (bp->inserted) - uninsert_raw_breakpoint (bp); - } - - if (!found) - { - /* This can happen when we remove all breakpoints while handling - a step-over. */ - if (debug_threads) - debug_printf ("Could not find breakpoint at 0x%s " - "in list (uninserting).\n", - paddress (pc)); - } -} - -void -uninsert_all_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->inserted) - uninsert_raw_breakpoint (bp); -} - -void -uninsert_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - { - gdb_assert (bp->raw->inserted > 0); - - /* Only uninsert the raw breakpoint if it only belongs to a - reinsert breakpoint. */ - if (bp->raw->refcount == 1) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - uninsert_raw_breakpoint (bp->raw); - current_thread = saved_thread; - } - } - } -} - -static void -reinsert_raw_breakpoint (struct raw_breakpoint *bp) -{ - int err; - - if (bp->inserted) - return; - - err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); - if (err == 0) - bp->inserted = 1; - else if (debug_threads) - debug_printf ("Failed to reinsert breakpoint at 0x%s (%d).\n", - paddress (bp->pc), err); -} - -void -reinsert_breakpoints_at (CORE_ADDR pc) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - int found = 0; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == pc) - { - found = 1; - - reinsert_raw_breakpoint (bp); - } - - if (!found) - { - /* This can happen when we remove all breakpoints while handling - a step-over. */ - if (debug_threads) - debug_printf ("Could not find raw breakpoint at 0x%s " - "in list (reinserting).\n", - paddress (pc)); - } -} - -int -has_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp, **bp_link; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - return 1; - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - return 0; -} - -void -reinsert_all_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && !bp->inserted) - reinsert_raw_breakpoint (bp); -} - -void -reinsert_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - { - gdb_assert (bp->raw->inserted > 0); - - if (bp->raw->refcount == 1) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - reinsert_raw_breakpoint (bp->raw); - current_thread = saved_thread; - } - } - } -} - -void -check_breakpoints (CORE_ADDR stop_pc) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp, **bp_link; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - struct raw_breakpoint *raw = bp->raw; - - if ((raw->raw_type == raw_bkpt_type_sw - || raw->raw_type == raw_bkpt_type_hw) - && raw->pc == stop_pc) - { - if (!raw->inserted) - { - warning ("Hit a removed breakpoint?"); - return; - } - - if (bp->type == other_breakpoint) - { - struct other_breakpoint *other_bp - = (struct other_breakpoint *) bp; - - if (other_bp->handler != NULL && (*other_bp->handler) (stop_pc)) - { - *bp_link = bp->next; - - release_breakpoint (proc, bp); - - bp = *bp_link; - continue; - } - } - } - - bp_link = &bp->next; - bp = *bp_link; - } -} - -int -breakpoint_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == addr) - return 1; - - return 0; -} - -int -breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == addr - && bp->inserted) - return 1; - - return 0; -} - -/* See mem-break.h. */ - -int -software_breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->raw_type == raw_bkpt_type_sw - && bp->pc == addr - && bp->inserted) - return 1; - - return 0; -} - -/* See mem-break.h. */ - -int -hardware_breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->raw_type == raw_bkpt_type_hw - && bp->pc == addr - && bp->inserted) - return 1; - - return 0; -} - -/* See mem-break.h. */ - -int -single_step_breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - if (bp->type == single_step_breakpoint - && bp->raw->pc == addr - && bp->raw->inserted) - return 1; - - return 0; -} - -static int -validate_inserted_breakpoint (struct raw_breakpoint *bp) -{ - unsigned char *buf; - int err; - - gdb_assert (bp->inserted); - gdb_assert (bp->raw_type == raw_bkpt_type_sw); - - buf = (unsigned char *) alloca (bp_size (bp)); - err = (*the_target->read_memory) (bp->pc, buf, bp_size (bp)); - if (err || memcmp (buf, bp_opcode (bp), bp_size (bp)) != 0) - { - /* Tag it as gone. */ - bp->inserted = -1; - return 0; - } - - return 1; -} - -static void -delete_disabled_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp, *next; - - for (bp = proc->breakpoints; bp != NULL; bp = next) - { - next = bp->next; - if (bp->raw->inserted < 0) - { - /* If single_step_breakpoints become disabled, that means the - manipulations (insertion and removal) of them are wrong. */ - gdb_assert (bp->type != single_step_breakpoint); - delete_breakpoint_1 (proc, bp); - } - } -} - -/* Check if breakpoints we inserted still appear to be inserted. They - may disappear due to a shared library unload, and worse, a new - shared library may be reloaded at the same address as the - previously unloaded one. If that happens, we should make sure that - the shadow memory of the old breakpoints isn't used when reading or - writing memory. */ - -void -validate_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - struct raw_breakpoint *raw = bp->raw; - - if (raw->raw_type == raw_bkpt_type_sw && raw->inserted > 0) - validate_inserted_breakpoint (raw); - } - - delete_disabled_breakpoints (); -} - -void -check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp = proc->raw_breakpoints; - struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; - CORE_ADDR mem_end = mem_addr + mem_len; - int disabled_one = 0; - - for (; jp != NULL; jp = jp->next) - { - CORE_ADDR bp_end = jp->pc + jp->length; - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - gdb_assert (fast_tracepoint_jump_shadow (jp) >= buf + mem_len - || buf >= fast_tracepoint_jump_shadow (jp) + (jp)->length); - - if (mem_addr >= bp_end) - continue; - if (jp->pc >= mem_end) - continue; - - start = jp->pc; - if (mem_addr > start) - start = mem_addr; - - end = bp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - jp->pc; - buf_offset = start - mem_addr; - - if (jp->inserted) - memcpy (buf + buf_offset, - fast_tracepoint_jump_shadow (jp) + copy_offset, - copy_len); - } - - for (; bp != NULL; bp = bp->next) - { - CORE_ADDR bp_end = bp->pc + bp_size (bp); - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - if (bp->raw_type != raw_bkpt_type_sw) - continue; - - gdb_assert (bp->old_data >= buf + mem_len - || buf >= &bp->old_data[sizeof (bp->old_data)]); - - if (mem_addr >= bp_end) - continue; - if (bp->pc >= mem_end) - continue; - - start = bp->pc; - if (mem_addr > start) - start = mem_addr; - - end = bp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - bp->pc; - buf_offset = start - mem_addr; - - if (bp->inserted > 0) - { - if (validate_inserted_breakpoint (bp)) - memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len); - else - disabled_one = 1; - } - } - - if (disabled_one) - delete_disabled_breakpoints (); -} - -void -check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, - const unsigned char *myaddr, int mem_len) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp = proc->raw_breakpoints; - struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; - CORE_ADDR mem_end = mem_addr + mem_len; - int disabled_one = 0; - - /* First fast tracepoint jumps, then breakpoint traps on top. */ - - for (; jp != NULL; jp = jp->next) - { - CORE_ADDR jp_end = jp->pc + jp->length; - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - gdb_assert (fast_tracepoint_jump_shadow (jp) >= myaddr + mem_len - || myaddr >= fast_tracepoint_jump_shadow (jp) + (jp)->length); - gdb_assert (fast_tracepoint_jump_insn (jp) >= buf + mem_len - || buf >= fast_tracepoint_jump_insn (jp) + (jp)->length); - - if (mem_addr >= jp_end) - continue; - if (jp->pc >= mem_end) - continue; - - start = jp->pc; - if (mem_addr > start) - start = mem_addr; - - end = jp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - jp->pc; - buf_offset = start - mem_addr; - - memcpy (fast_tracepoint_jump_shadow (jp) + copy_offset, - myaddr + buf_offset, copy_len); - if (jp->inserted) - memcpy (buf + buf_offset, - fast_tracepoint_jump_insn (jp) + copy_offset, copy_len); - } - - for (; bp != NULL; bp = bp->next) - { - CORE_ADDR bp_end = bp->pc + bp_size (bp); - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - if (bp->raw_type != raw_bkpt_type_sw) - continue; - - gdb_assert (bp->old_data >= myaddr + mem_len - || myaddr >= &bp->old_data[sizeof (bp->old_data)]); - - if (mem_addr >= bp_end) - continue; - if (bp->pc >= mem_end) - continue; - - start = bp->pc; - if (mem_addr > start) - start = mem_addr; - - end = bp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - bp->pc; - buf_offset = start - mem_addr; - - memcpy (bp->old_data + copy_offset, myaddr + buf_offset, copy_len); - if (bp->inserted > 0) - { - if (validate_inserted_breakpoint (bp)) - memcpy (buf + buf_offset, bp_opcode (bp) + copy_offset, copy_len); - else - disabled_one = 1; - } - } - - if (disabled_one) - delete_disabled_breakpoints (); -} - -/* Delete all breakpoints, and un-insert them from the inferior. */ - -void -delete_all_breakpoints (void) -{ - struct process_info *proc = current_process (); - - while (proc->breakpoints) - delete_breakpoint_1 (proc, proc->breakpoints); -} - -/* Clear the "inserted" flag in all breakpoints. */ - -void -mark_breakpoints_out (struct process_info *proc) -{ - struct raw_breakpoint *raw_bp; - - for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next) - raw_bp->inserted = 0; -} - -/* Release all breakpoints, but do not try to un-insert them from the - inferior. */ - -void -free_all_breakpoints (struct process_info *proc) -{ - mark_breakpoints_out (proc); - - /* Note: use PROC explicitly instead of deferring to - delete_all_breakpoints --- CURRENT_INFERIOR may already have been - released when we get here. There should be no call to - current_process from here on. */ - while (proc->breakpoints) - delete_breakpoint_1 (proc, proc->breakpoints); -} - -/* Clone an agent expression. */ - -static struct agent_expr * -clone_agent_expr (const struct agent_expr *src_ax) -{ - struct agent_expr *ax; - - ax = XCNEW (struct agent_expr); - ax->length = src_ax->length; - ax->bytes = (unsigned char *) xcalloc (ax->length, 1); - memcpy (ax->bytes, src_ax->bytes, ax->length); - return ax; -} - -/* Deep-copy the contents of one breakpoint to another. */ - -static struct breakpoint * -clone_one_breakpoint (const struct breakpoint *src, ptid_t ptid) -{ - struct breakpoint *dest; - struct raw_breakpoint *dest_raw; - - /* Clone the raw breakpoint. */ - dest_raw = XCNEW (struct raw_breakpoint); - dest_raw->raw_type = src->raw->raw_type; - dest_raw->refcount = src->raw->refcount; - dest_raw->pc = src->raw->pc; - dest_raw->kind = src->raw->kind; - memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN); - dest_raw->inserted = src->raw->inserted; - - /* Clone the high-level breakpoint. */ - if (is_gdb_breakpoint (src->type)) - { - struct gdb_breakpoint *gdb_dest = XCNEW (struct gdb_breakpoint); - struct point_cond_list *current_cond; - struct point_cond_list *new_cond; - struct point_cond_list *cond_tail = NULL; - struct point_command_list *current_cmd; - struct point_command_list *new_cmd; - struct point_command_list *cmd_tail = NULL; - - /* Clone the condition list. */ - for (current_cond = ((struct gdb_breakpoint *) src)->cond_list; - current_cond != NULL; - current_cond = current_cond->next) - { - new_cond = XCNEW (struct point_cond_list); - new_cond->cond = clone_agent_expr (current_cond->cond); - APPEND_TO_LIST (&gdb_dest->cond_list, new_cond, cond_tail); - } - - /* Clone the command list. */ - for (current_cmd = ((struct gdb_breakpoint *) src)->command_list; - current_cmd != NULL; - current_cmd = current_cmd->next) - { - new_cmd = XCNEW (struct point_command_list); - new_cmd->cmd = clone_agent_expr (current_cmd->cmd); - new_cmd->persistence = current_cmd->persistence; - APPEND_TO_LIST (&gdb_dest->command_list, new_cmd, cmd_tail); - } - - dest = (struct breakpoint *) gdb_dest; - } - else if (src->type == other_breakpoint) - { - struct other_breakpoint *other_dest = XCNEW (struct other_breakpoint); - - other_dest->handler = ((struct other_breakpoint *) src)->handler; - dest = (struct breakpoint *) other_dest; - } - else if (src->type == single_step_breakpoint) - { - struct single_step_breakpoint *ss_dest - = XCNEW (struct single_step_breakpoint); - - dest = (struct breakpoint *) ss_dest; - /* Since single-step breakpoint is thread specific, don't copy - thread id from SRC, use ID instead. */ - ss_dest->ptid = ptid; - } - else - gdb_assert_not_reached ("unhandled breakpoint type"); - - dest->type = src->type; - dest->raw = dest_raw; - - return dest; -} - -/* See mem-break.h. */ - -void -clone_all_breakpoints (struct thread_info *child_thread, - const struct thread_info *parent_thread) -{ - const struct breakpoint *bp; - struct breakpoint *new_bkpt; - struct breakpoint *bkpt_tail = NULL; - struct raw_breakpoint *raw_bkpt_tail = NULL; - struct process_info *child_proc = get_thread_process (child_thread); - struct process_info *parent_proc = get_thread_process (parent_thread); - struct breakpoint **new_list = &child_proc->breakpoints; - struct raw_breakpoint **new_raw_list = &child_proc->raw_breakpoints; - - for (bp = parent_proc->breakpoints; bp != NULL; bp = bp->next) - { - new_bkpt = clone_one_breakpoint (bp, ptid_of (child_thread)); - APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail); - APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail); - } -} diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h deleted file mode 100644 index bbe1ff1a5fb..00000000000 --- a/gdb/gdbserver/mem-break.h +++ /dev/null @@ -1,279 +0,0 @@ -/* Memory breakpoint interfaces for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#ifndef GDBSERVER_MEM_BREAK_H -#define GDBSERVER_MEM_BREAK_H - -#include "gdbsupport/break-common.h" - -/* Breakpoints are opaque. */ -struct breakpoint; -struct gdb_breakpoint; -struct fast_tracepoint_jump; -struct raw_breakpoint; -struct process_info; - -#define Z_PACKET_SW_BP '0' -#define Z_PACKET_HW_BP '1' -#define Z_PACKET_WRITE_WP '2' -#define Z_PACKET_READ_WP '3' -#define Z_PACKET_ACCESS_WP '4' - -/* The low level breakpoint types. */ - -enum raw_bkpt_type - { - /* Software/memory breakpoint. */ - raw_bkpt_type_sw, - - /* Hardware-assisted breakpoint. */ - raw_bkpt_type_hw, - - /* Hardware-assisted write watchpoint. */ - raw_bkpt_type_write_wp, - - /* Hardware-assisted read watchpoint. */ - raw_bkpt_type_read_wp, - - /* Hardware-assisted access watchpoint. */ - raw_bkpt_type_access_wp - }; - -/* Map the protocol breakpoint/watchpoint type Z_TYPE to the internal - raw breakpoint type. */ - -enum raw_bkpt_type Z_packet_to_raw_bkpt_type (char z_type); - -/* Map a raw breakpoint type to an enum target_hw_bp_type. */ - -enum target_hw_bp_type raw_bkpt_type_to_target_hw_bp_type - (enum raw_bkpt_type raw_type); - -/* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND. - Returns a pointer to the newly created breakpoint on success. On - failure returns NULL and sets *ERR to either -1 for error, or 1 if - Z_TYPE breakpoints are not supported on this target. */ - -struct gdb_breakpoint *set_gdb_breakpoint (char z_type, CORE_ADDR addr, - int kind, int *err); - -/* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously - inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success, - -1 on error, and 1 if Z_TYPE breakpoints are not supported on this - target. */ - -int delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind); - -/* Returns TRUE if there's a software or hardware (code) breakpoint at - ADDR in our tables, inserted, or not. */ - -int breakpoint_here (CORE_ADDR addr); - -/* Returns TRUE if there's any inserted software or hardware (code) - breakpoint set at ADDR. */ - -int breakpoint_inserted_here (CORE_ADDR addr); - -/* Returns TRUE if there's any inserted software breakpoint at - ADDR. */ - -int software_breakpoint_inserted_here (CORE_ADDR addr); - -/* Returns TRUE if there's any inserted hardware (code) breakpoint at - ADDR. */ - -int hardware_breakpoint_inserted_here (CORE_ADDR addr); - -/* Returns TRUE if there's any single-step breakpoint at ADDR. */ - -int single_step_breakpoint_inserted_here (CORE_ADDR addr); - -/* Clear all breakpoint conditions and commands associated with a - breakpoint. */ - -void clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp); - -/* Set target-side condition CONDITION to the breakpoint at ADDR. - Returns false on failure. On success, advances CONDITION pointer - past the condition and returns true. */ - -int add_breakpoint_condition (struct gdb_breakpoint *bp, - const char **condition); - -/* Set target-side commands COMMANDS to the breakpoint at ADDR. - Returns false on failure. On success, advances COMMANDS past the - commands and returns true. If PERSIST, the commands should run - even while GDB is disconnected. */ - -int add_breakpoint_commands (struct gdb_breakpoint *bp, const char **commands, - int persist); - -/* Return true if PROC has any persistent command. */ -bool any_persistent_commands (process_info *proc); - -/* Evaluation condition (if any) at breakpoint BP. Return 1 if - true and 0 otherwise. */ - -int gdb_condition_true_at_breakpoint (CORE_ADDR where); - -int gdb_no_commands_at_breakpoint (CORE_ADDR where); - -void run_breakpoint_commands (CORE_ADDR where); - -/* Returns TRUE if there's a GDB breakpoint (Z0 or Z1) set at - WHERE. */ - -int gdb_breakpoint_here (CORE_ADDR where); - -/* Create a new breakpoint at WHERE, and call HANDLER when - it is hit. HANDLER should return 1 if the breakpoint - should be deleted, 0 otherwise. The type of the created - breakpoint is other_breakpoint. */ - -struct breakpoint *set_breakpoint_at (CORE_ADDR where, - int (*handler) (CORE_ADDR)); - -/* Delete a breakpoint. */ - -int delete_breakpoint (struct breakpoint *bkpt); - -/* Set a single-step breakpoint at STOP_AT for thread represented by - PTID. */ - -void set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid); - -/* Delete all single-step breakpoints of THREAD. */ - -void delete_single_step_breakpoints (struct thread_info *thread); - -/* Reinsert all single-step breakpoints of THREAD. */ - -void reinsert_single_step_breakpoints (struct thread_info *thread); - -/* Uninsert all single-step breakpoints of THREAD. This still leaves - the single-step breakpoints in the table. */ - -void uninsert_single_step_breakpoints (struct thread_info *thread); - -/* Reinsert breakpoints at WHERE (and change their status to - inserted). */ - -void reinsert_breakpoints_at (CORE_ADDR where); - -/* The THREAD has single-step breakpoints or not. */ - -int has_single_step_breakpoints (struct thread_info *thread); - -/* Uninsert breakpoints at WHERE (and change their status to - uninserted). This still leaves the breakpoints in the table. */ - -void uninsert_breakpoints_at (CORE_ADDR where); - -/* Reinsert all breakpoints of the current process (and change their - status to inserted). */ - -void reinsert_all_breakpoints (void); - -/* Uninsert all breakpoints of the current process (and change their - status to uninserted). This still leaves the breakpoints in the - table. */ - -void uninsert_all_breakpoints (void); - -/* See if any breakpoint claims ownership of STOP_PC. Call the handler for - the breakpoint, if found. */ - -void check_breakpoints (CORE_ADDR stop_pc); - -/* See if any breakpoints shadow the target memory area from MEM_ADDR - to MEM_ADDR + MEM_LEN. Update the data already read from the target - (in BUF) if necessary. */ - -void check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len); - -/* See if any breakpoints shadow the target memory area from MEM_ADDR - to MEM_ADDR + MEM_LEN. Update the data to be written to the target - (in BUF, a copy of MYADDR on entry) if necessary, as well as the - original data for any breakpoints. */ - -void check_mem_write (CORE_ADDR mem_addr, - unsigned char *buf, const unsigned char *myaddr, int mem_len); - -/* Delete all breakpoints. */ - -void delete_all_breakpoints (void); - -/* Clear the "inserted" flag in all breakpoints of PROC. */ - -void mark_breakpoints_out (struct process_info *proc); - -/* Delete all breakpoints, but do not try to un-insert them from the - inferior. */ - -void free_all_breakpoints (struct process_info *proc); - -/* Check if breakpoints still seem to be inserted in the inferior. */ - -void validate_breakpoints (void); - -/* Insert a fast tracepoint jump at WHERE, using instruction INSN, of - LENGTH bytes. */ - -struct fast_tracepoint_jump *set_fast_tracepoint_jump (CORE_ADDR where, - unsigned char *insn, - ULONGEST length); - -/* Increment reference counter of JP. */ -void inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp); - -/* Delete fast tracepoint jump TODEL from our tables, and uninsert if - from memory. */ - -int delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel); - -/* Returns true if there's fast tracepoint jump set at WHERE. */ - -int fast_tracepoint_jump_here (CORE_ADDR); - -/* Uninsert fast tracepoint jumps at WHERE (and change their status to - uninserted). This still leaves the tracepoints in the table. */ - -void uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc); - -/* Reinsert fast tracepoint jumps at WHERE (and change their status to - inserted). */ - -void reinsert_fast_tracepoint_jumps_at (CORE_ADDR where); - -/* Insert a memory breakpoint. */ - -int insert_memory_breakpoint (struct raw_breakpoint *bp); - -/* Remove a previously inserted memory breakpoint. */ - -int remove_memory_breakpoint (struct raw_breakpoint *bp); - -/* Create a new breakpoint list in CHILD_THREAD's process that is a - copy of breakpoint list in PARENT_THREAD's process. */ - -void clone_all_breakpoints (struct thread_info *child_thread, - const struct thread_info *parent_thread); - -#endif /* GDBSERVER_MEM_BREAK_H */ diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c deleted file mode 100644 index e18cecde53b..00000000000 --- a/gdb/gdbserver/notif.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Notification to GDB. - Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -/* Async notifications to GDB. When the state of remote target is - changed or something interesting to GDB happened, async - notifications are used to tell GDB. - - Each type of notification is represented by an object - 'struct notif_server', in which there is a queue for events to GDB - represented by 'struct notif_event'. GDBserver writes (by means of - 'write' field) each event in the queue into the buffer and send the - contents in buffer to GDB. The contents in buffer is specified in - RSP. See more in the comments to field 'queue' of - 'struct notif_server'. - - Here is the workflow of sending events and managing queue: - 1. At any time, when something interesting FOO happens, a object - of 'struct notif_event' or its sub-class EVENT is created for FOO. - - 2. Enque EVENT to the 'queue' field of 'struct notif_server' for - FOO and send corresponding notification packet to GDB if EVENT is - the first one. - #1 and #2 are done by function 'notif_push'. - - 3. EVENT is not deque'ed until the ack of FOO from GDB arrives. - Before ack of FOO arrives, FOO happens again, a new object of - EVENT is created and enque EVENT silently. - Once GDB has a chance to ack to FOO, it sends an ack to GDBserver, - and GDBserver repeatedly sends events to GDB and gets ack of FOO, - until queue is empty. Then, GDBserver sends 'OK' to GDB that all - queued notification events are done. - - # 3 is done by function 'handle_notif_ack'. */ - -#include "server.h" -#include "notif.h" - -static struct notif_server *notifs[] = -{ - ¬if_stop, -}; - -/* Write another event or an OK, if there are no more left, to - OWN_BUF. */ - -void -notif_write_event (struct notif_server *notif, char *own_buf) -{ - if (!notif->queue.empty ()) - { - struct notif_event *event = notif->queue.front (); - - notif->write (event, own_buf); - } - else - write_ok (own_buf); -} - -/* Handle the ack in buffer OWN_BUF,and packet length is PACKET_LEN. - Return 1 if the ack is handled, and return 0 if the contents - in OWN_BUF is not a ack. */ - -int -handle_notif_ack (char *own_buf, int packet_len) -{ - size_t i; - struct notif_server *np; - - for (i = 0; i < ARRAY_SIZE (notifs); i++) - { - const char *ack_name = notifs[i]->ack_name; - - if (startswith (own_buf, ack_name) - && packet_len == strlen (ack_name)) - break; - } - - if (i == ARRAY_SIZE (notifs)) - return 0; - - np = notifs[i]; - - /* If we're waiting for GDB to acknowledge a pending event, - consider that done. */ - if (!np->queue.empty ()) - { - struct notif_event *head = np->queue.front (); - np->queue.pop_front (); - - if (remote_debug) - debug_printf ("%s: acking %d\n", np->ack_name, - (int) np->queue.size ()); - - delete head; - } - - notif_write_event (np, own_buf); - - return 1; -} - -/* Put EVENT to the queue of NOTIF. */ - -void -notif_event_enque (struct notif_server *notif, - struct notif_event *event) -{ - notif->queue.push_back (event); - - if (remote_debug) - debug_printf ("pending events: %s %d\n", notif->notif_name, - (int) notif->queue.size ()); - -} - -/* Push one event NEW_EVENT of notification NP into NP->queue. */ - -void -notif_push (struct notif_server *np, struct notif_event *new_event) -{ - bool is_first_event = np->queue.empty (); - - /* Something interesting. Tell GDB about it. */ - notif_event_enque (np, new_event); - - /* If this is the first stop reply in the queue, then inform GDB - about it, by sending a corresponding notification. */ - if (is_first_event) - { - char buf[PBUFSIZ]; - char *p = buf; - - xsnprintf (p, PBUFSIZ, "%s:", np->notif_name); - p += strlen (p); - - np->write (new_event, p); - putpkt_notif (buf); - } -} diff --git a/gdb/gdbserver/notif.h b/gdb/gdbserver/notif.h deleted file mode 100644 index c5d48c0f3b6..00000000000 --- a/gdb/gdbserver/notif.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Notification to GDB. - Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_NOTIF_H -#define GDBSERVER_NOTIF_H - -#include "target.h" -#include - -/* Structure holding information related to a single event. We - keep a queue of these to push to GDB. It can be extended if - the event of given notification contains more information. */ - -struct notif_event -{ - virtual ~notif_event () - { - } - - /* No payload needed. */ -}; - -/* A type notification to GDB. An object of 'struct notif_server' - represents a type of notification. */ - -typedef struct notif_server -{ - /* The name of ack packet, for example, 'vStopped'. */ - const char *ack_name; - - /* The notification packet, for example, '%Stop'. Note that '%' is - not in 'notif_name'. */ - const char *notif_name; - - /* A queue of events to GDB. A new notif_event can be enque'ed - into QUEUE at any appropriate time, and the notif_reply is - deque'ed only when the ack from GDB arrives. */ - std::list queue; - - /* Write event EVENT to OWN_BUF. */ - void (*write) (struct notif_event *event, char *own_buf); -} *notif_server_p; - -extern struct notif_server notif_stop; - -int handle_notif_ack (char *own_buf, int packet_len); -void notif_write_event (struct notif_server *notif, char *own_buf); - -void notif_push (struct notif_server *np, struct notif_event *event); -void notif_event_enque (struct notif_server *notif, - struct notif_event *event); - -#endif /* GDBSERVER_NOTIF_H */ diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c deleted file mode 100644 index b4dea479b9c..00000000000 --- a/gdb/gdbserver/nto-low.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* QNX Neutrino specific low level interface, for the remote server - for GDB. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - - -#include "server.h" -#include "gdbthread.h" -#include "nto-low.h" -#include "hostio.h" -#include "debug.h" - -#include -#include -#include -#include -#include -#include -#include - - -int using_threads = 1; - -const struct target_desc *nto_tdesc; - -static void -nto_trace (const char *fmt, ...) -{ - va_list arg_list; - - if (debug_threads == 0) - return; - fprintf (stderr, "nto:"); - va_start (arg_list, fmt); - vfprintf (stderr, fmt, arg_list); - va_end (arg_list); -} - -#define TRACE nto_trace - -/* Structure holding neutrino specific information about - inferior. */ - -struct nto_inferior -{ - char nto_procfs_path[PATH_MAX]; - int ctl_fd; - pid_t pid; - int exit_signo; /* For tracking exit status. */ -}; - -static struct nto_inferior nto_inferior; - -static void -init_nto_inferior (struct nto_inferior *nto_inferior) -{ - memset (nto_inferior, 0, sizeof (struct nto_inferior)); - nto_inferior->ctl_fd = -1; - nto_inferior->pid = -1; -} - -static void -do_detach (void) -{ - if (nto_inferior.ctl_fd != -1) - { - nto_trace ("Closing fd\n"); - close (nto_inferior.ctl_fd); - init_nto_inferior (&nto_inferior); - } -} - -/* Set current thread. Return 1 on success, 0 otherwise. */ - -static int -nto_set_thread (ptid_t ptid) -{ - int res = 0; - - TRACE ("%s pid: %d tid: %ld\n", __func__, ptid.pid (), - ptid.lwp ()); - if (nto_inferior.ctl_fd != -1 - && ptid != null_ptid - && ptid != minus_one_ptid) - { - pthread_t tid = ptid.lwp (); - - if (EOK == devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid, - sizeof (tid), 0)) - res = 1; - else - TRACE ("%s: Error: failed to set current thread\n", __func__); - } - return res; -} - -/* This function will determine all alive threads. Note that we do not list - dead but unjoined threads even though they are still in the process' thread - list. - - NTO_INFERIOR must not be NULL. */ - -static void -nto_find_new_threads (struct nto_inferior *nto_inferior) -{ - pthread_t tid; - - TRACE ("%s pid:%d\n", __func__, nto_inferior->pid); - - if (nto_inferior->ctl_fd == -1) - return; - - for (tid = 1;; ++tid) - { - procfs_status status; - ptid_t ptid; - int err; - - status.tid = tid; - err = devctl (nto_inferior->ctl_fd, DCMD_PROC_TIDSTATUS, &status, - sizeof (status), 0); - - if (err != EOK || status.tid == 0) - break; - - /* All threads in between are gone. */ - while (tid != status.tid || status.state == STATE_DEAD) - { - struct thread_info *ti; - - ptid = ptid_t (nto_inferior->pid, tid, 0); - ti = find_thread_ptid (ptid); - if (ti != NULL) - { - TRACE ("Removing thread %d\n", tid); - remove_thread (ti); - } - if (tid == status.tid) - break; - ++tid; - } - - if (status.state != STATE_DEAD) - { - TRACE ("Adding thread %d\n", tid); - ptid = ptid_t (nto_inferior->pid, tid, 0); - if (!find_thread_ptid (ptid)) - add_thread (ptid, NULL); - } - } -} - -/* Given pid, open procfs path. */ - -static pid_t -do_attach (pid_t pid) -{ - procfs_status status; - struct sigevent event; - - if (nto_inferior.ctl_fd != -1) - { - close (nto_inferior.ctl_fd); - init_nto_inferior (&nto_inferior); - } - xsnprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", pid); - nto_inferior.ctl_fd = open (nto_inferior.nto_procfs_path, O_RDWR); - if (nto_inferior.ctl_fd == -1) - { - TRACE ("Failed to open %s\n", nto_inferior.nto_procfs_path); - init_nto_inferior (&nto_inferior); - return -1; - } - if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) - != EOK) - { - do_detach (); - return -1; - } - nto_inferior.pid = pid; - /* Define a sigevent for process stopped notification. */ - event.sigev_notify = SIGEV_SIGNAL_THREAD; - event.sigev_signo = SIGUSR1; - event.sigev_code = 0; - event.sigev_value.sival_ptr = NULL; - event.sigev_priority = -1; - devctl (nto_inferior.ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0); - - if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), - 0) == EOK - && (status.flags & _DEBUG_FLAG_STOPPED)) - { - ptid_t ptid; - struct process_info *proc; - - kill (pid, SIGCONT); - ptid = ptid_t (status.pid, status.tid, 0); - the_low_target.arch_setup (); - proc = add_process (status.pid, 1); - proc->tdesc = nto_tdesc; - TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid, - ptid.lwp ()); - nto_find_new_threads (&nto_inferior); - } - else - { - do_detach (); - return -1; - } - - return pid; -} - -/* Read or write LEN bytes from/to inferior's MEMADDR memory address - into gdbservers's MYADDR buffer. Return number of bytes actually - transfered. */ - -static int -nto_xfer_memory (off_t memaddr, unsigned char *myaddr, int len, - int dowrite) -{ - int nbytes = 0; - - if (lseek (nto_inferior.ctl_fd, memaddr, SEEK_SET) == memaddr) - { - if (dowrite) - nbytes = write (nto_inferior.ctl_fd, myaddr, len); - else - nbytes = read (nto_inferior.ctl_fd, myaddr, len); - if (nbytes < 0) - nbytes = 0; - } - if (nbytes == 0) - { - int e = errno; - TRACE ("Error in %s : errno=%d (%s)\n", __func__, e, safe_strerror (e)); - } - return nbytes; -} - -/* Insert or remove breakpoint or watchpoint at address ADDR. - TYPE can be one of Neutrino breakpoint types. SIZE must be 0 for - inserting the point, -1 for removing it. - - Return 0 on success, 1 otherwise. */ - -static int -nto_breakpoint (CORE_ADDR addr, int type, int size) -{ - procfs_break brk; - - brk.type = type; - brk.addr = addr; - brk.size = size; - if (devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0) - != EOK) - return 1; - return 0; -} - -/* Read auxiliary vector from inferior's initial stack into gdbserver's - MYADDR buffer, up to LEN bytes. - - Return number of bytes read. */ - -static int -nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack, - unsigned char *myaddr, - unsigned int len) -{ - int data_ofs = 0; - int anint; - unsigned int len_read = 0; - - /* Skip over argc, argv and envp... Comment from ldd.c: - - The startup frame is set-up so that we have: - auxv - NULL - ... - envp2 - envp1 <----- void *frame + (argc + 2) * sizeof(char *) - NULL - ... - argv2 - argv1 - argc <------ void * frame - - On entry to ldd, frame gives the address of argc on the stack. */ - if (nto_xfer_memory (initial_stack, (unsigned char *)&anint, - sizeof (anint), 0) != sizeof (anint)) - return 0; - - /* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */ - data_ofs += (anint + 2) * sizeof (void *); /* + 2 comes from argc itself and - NULL terminating pointer in - argv. */ - - /* Now loop over env table: */ - while (nto_xfer_memory (initial_stack + data_ofs, - (unsigned char *)&anint, sizeof (anint), 0) - == sizeof (anint)) - { - data_ofs += sizeof (anint); - if (anint == 0) - break; - } - initial_stack += data_ofs; - - memset (myaddr, 0, len); - while (len_read <= len - sizeof (auxv_t)) - { - auxv_t *auxv = (auxv_t *)myaddr; - - /* Search backwards until we have read AT_PHDR (num. 3), - AT_PHENT (num 4), AT_PHNUM (num 5) */ - if (nto_xfer_memory (initial_stack, (unsigned char *)auxv, - sizeof (auxv_t), 0) == sizeof (auxv_t)) - { - if (auxv->a_type != AT_NULL) - { - auxv++; - len_read += sizeof (auxv_t); - } - if (auxv->a_type == AT_PHNUM) /* That's all we need. */ - break; - initial_stack += sizeof (auxv_t); - } - else - break; - } - TRACE ("auxv: len_read: %d\n", len_read); - return len_read; -} - -/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its - arguments. */ - -static int -nto_create_inferior (const char *program, - const std::vector &program_args) -{ - struct inheritance inherit; - pid_t pid; - sigset_t set; - std::string str_program_args = stringify_argv (program_args); - - TRACE ("%s %s\n", __func__, program); - /* Clear any pending SIGUSR1's but keep the behavior the same. */ - signal (SIGUSR1, signal (SIGUSR1, SIG_IGN)); - - sigemptyset (&set); - sigaddset (&set, SIGUSR1); - sigprocmask (SIG_UNBLOCK, &set, NULL); - - memset (&inherit, 0, sizeof (inherit)); - inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD; - inherit.pgroup = SPAWN_NEWPGROUP; - pid = spawnp (program, 0, NULL, &inherit, - (char *) str_program_args.c_str (), 0); - sigprocmask (SIG_BLOCK, &set, NULL); - - if (pid == -1) - return -1; - - if (do_attach (pid) != pid) - return -1; - - return pid; -} - -/* Attach to process PID. */ - -static int -nto_attach (unsigned long pid) -{ - TRACE ("%s %ld\n", __func__, pid); - if (do_attach (pid) != pid) - error ("Unable to attach to %ld\n", pid); - return 0; -} - -/* Send signal to process PID. */ - -static int -nto_kill (process_info *proc) -{ - int pid = proc->pid; - - TRACE ("%s %d\n", __func__, pid); - kill (pid, SIGKILL); - do_detach (); - return 0; -} - -/* Detach from process PID. */ - -static int -nto_detach (process_info *proc) -{ - TRACE ("%s %d\n", __func__, proc->pid); - do_detach (); - return 0; -} - -static void -nto_mourn (struct process_info *process) -{ - remove_process (process); -} - -/* Check if the given thread is alive. - - Return 1 if alive, 0 otherwise. */ - -static int -nto_thread_alive (ptid_t ptid) -{ - int res; - - TRACE ("%s pid:%d tid:%d\n", __func__, ptid.pid (), - ptid.lwp ()); - if (SignalKill (0, ptid.pid (), ptid.lwp (), - 0, 0, 0) == -1) - res = 0; - else - res = 1; - TRACE ("%s: %s\n", __func__, res ? "yes" : "no"); - return res; -} - -/* Resume inferior's execution. */ - -static void -nto_resume (struct thread_resume *resume_info, size_t n) -{ - /* We can only work in all-stop mode. */ - procfs_status status; - procfs_run run; - int err; - - TRACE ("%s\n", __func__); - /* Workaround for aliasing rules violation. */ - sigset_t *run_fault = (sigset_t *) (void *) &run.fault; - - nto_set_thread (resume_info->thread); - - run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE; - if (resume_info->kind == resume_step) - run.flags |= _DEBUG_RUN_STEP; - run.flags |= _DEBUG_RUN_ARM; - - sigemptyset (run_fault); - sigaddset (run_fault, FLTBPT); - sigaddset (run_fault, FLTTRACE); - sigaddset (run_fault, FLTILL); - sigaddset (run_fault, FLTPRIV); - sigaddset (run_fault, FLTBOUNDS); - sigaddset (run_fault, FLTIOVF); - sigaddset (run_fault, FLTIZDIV); - sigaddset (run_fault, FLTFPE); - sigaddset (run_fault, FLTPAGE); - sigaddset (run_fault, FLTSTACK); - sigaddset (run_fault, FLTACCESS); - - sigemptyset (&run.trace); - if (resume_info->sig) - { - int signal_to_pass; - - devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), - 0); - signal_to_pass = resume_info->sig; - if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED)) - { - if (signal_to_pass != status.info.si_signo) - { - kill (status.pid, signal_to_pass); - run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG; - } - else /* Let it kill the program without telling us. */ - sigdelset (&run.trace, signal_to_pass); - } - } - else - run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT; - - sigfillset (&run.trace); - - regcache_invalidate (); - - err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0); - if (err != EOK) - TRACE ("Error: %d \"%s\"\n", err, safe_strerror (err)); -} - -/* Wait for inferior's event. - - Return ptid of thread that caused the event. */ - -static ptid_t -nto_wait (ptid_t ptid, - struct target_waitstatus *ourstatus, int target_options) -{ - sigset_t set; - siginfo_t info; - procfs_status status; - const int trace_mask = (_DEBUG_FLAG_TRACE_EXEC | _DEBUG_FLAG_TRACE_RD - | _DEBUG_FLAG_TRACE_WR | _DEBUG_FLAG_TRACE_MODIFY); - - TRACE ("%s\n", __func__); - - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - - sigemptyset (&set); - sigaddset (&set, SIGUSR1); - - devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); - while (!(status.flags & _DEBUG_FLAG_ISTOP)) - { - sigwaitinfo (&set, &info); - devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), - 0); - } - nto_find_new_threads (&nto_inferior); - - if (status.flags & _DEBUG_FLAG_SSTEP) - { - TRACE ("SSTEP\n"); - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = GDB_SIGNAL_TRAP; - } - /* Was it a breakpoint? */ - else if (status.flags & trace_mask) - { - TRACE ("STOPPED\n"); - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = GDB_SIGNAL_TRAP; - } - else if (status.flags & _DEBUG_FLAG_ISTOP) - { - TRACE ("ISTOP\n"); - switch (status.why) - { - case _DEBUG_WHY_SIGNALLED: - TRACE (" SIGNALLED\n"); - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = - gdb_signal_from_host (status.info.si_signo); - nto_inferior.exit_signo = ourstatus->value.sig; - break; - case _DEBUG_WHY_FAULTED: - TRACE (" FAULTED\n"); - ourstatus->kind = TARGET_WAITKIND_STOPPED; - if (status.info.si_signo == SIGTRAP) - { - ourstatus->value.sig = 0; - nto_inferior.exit_signo = 0; - } - else - { - ourstatus->value.sig = - gdb_signal_from_host (status.info.si_signo); - nto_inferior.exit_signo = ourstatus->value.sig; - } - break; - - case _DEBUG_WHY_TERMINATED: - { - int waitval = 0; - - TRACE (" TERMINATED\n"); - waitpid (ptid.pid (), &waitval, WNOHANG); - if (nto_inferior.exit_signo) - { - /* Abnormal death. */ - ourstatus->kind = TARGET_WAITKIND_SIGNALLED; - ourstatus->value.sig = nto_inferior.exit_signo; - } - else - { - /* Normal death. */ - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = WEXITSTATUS (waitval); - } - nto_inferior.exit_signo = 0; - break; - } - - case _DEBUG_WHY_REQUESTED: - TRACE ("REQUESTED\n"); - /* We are assuming a requested stop is due to a SIGINT. */ - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = GDB_SIGNAL_INT; - nto_inferior.exit_signo = 0; - break; - } - } - - return ptid_t (status.pid, status.tid, 0); -} - -/* Fetch inferior's registers for currently selected thread (CURRENT_INFERIOR). - If REGNO is -1, fetch all registers, or REGNO register only otherwise. */ - -static void -nto_fetch_registers (struct regcache *regcache, int regno) -{ - int regsize; - procfs_greg greg; - - TRACE ("%s (regno=%d)\n", __func__, regno); - if (regno >= the_low_target.num_regs) - return; - - if (current_thread == NULL) - { - TRACE ("current_thread is NULL\n"); - return; - } - ptid_t ptid = ptid_of (current_thread); - if (!nto_set_thread (ptid)) - return; - - if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg), - ®size) == EOK) - { - if (regno == -1) /* All registers. */ - { - for (regno = 0; regno != the_low_target.num_regs; ++regno) - { - const unsigned int registeroffset - = the_low_target.register_offset (regno); - supply_register (regcache, regno, - ((char *)&greg) + registeroffset); - } - } - else - { - const unsigned int registeroffset - = the_low_target.register_offset (regno); - if (registeroffset == -1) - return; - supply_register (regcache, regno, ((char *)&greg) + registeroffset); - } - } - else - TRACE ("ERROR reading registers from inferior.\n"); -} - -/* Store registers for currently selected thread (CURRENT_INFERIOR). - We always store all registers, regardless of REGNO. */ - -static void -nto_store_registers (struct regcache *regcache, int regno) -{ - procfs_greg greg; - int err; - - TRACE ("%s (regno:%d)\n", __func__, regno); - - if (current_thread == NULL) - { - TRACE ("current_thread is NULL\n"); - return; - } - ptid_t ptid = ptid_of (current_thread); - if (!nto_set_thread (ptid)) - return; - - memset (&greg, 0, sizeof (greg)); - for (regno = 0; regno != the_low_target.num_regs; ++regno) - { - const unsigned int regoffset - = the_low_target.register_offset (regno); - collect_register (regcache, regno, ((char *)&greg) + regoffset); - } - err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg), - 0); - if (err != EOK) - TRACE ("Error: setting registers.\n"); -} - -/* Read LEN bytes from inferior's memory address MEMADDR into - gdbserver's MYADDR buffer. - - Return 0 on success -1 otherwise. */ - -static int -nto_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - TRACE ("%s memaddr:0x%08lx, len:%d\n", __func__, memaddr, len); - - if (nto_xfer_memory (memaddr, myaddr, len, 0) != len) - { - TRACE ("Failed to read memory\n"); - return -1; - } - - return 0; -} - -/* Write LEN bytes from gdbserver's buffer MYADDR into inferior's - memory at address MEMADDR. - - Return 0 on success -1 otherwise. */ - -static int -nto_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) -{ - int len_written; - - TRACE ("%s memaddr: 0x%08llx len: %d\n", __func__, memaddr, len); - if ((len_written = nto_xfer_memory (memaddr, (unsigned char *)myaddr, len, - 1)) - != len) - { - TRACE ("Wanted to write: %d but written: %d\n", len, len_written); - return -1; - } - - return 0; -} - -/* Stop inferior. We always stop all threads. */ - -static void -nto_request_interrupt (void) -{ - TRACE ("%s\n", __func__); - nto_set_thread (ptid_t (nto_inferior.pid, 1, 0)); - if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0)) - TRACE ("Error stopping inferior.\n"); -} - -/* Read auxiliary vector from inferior's memory into gdbserver's buffer - MYADDR. We always read whole auxv. - - Return number of bytes stored in MYADDR buffer, 0 if OFFSET > 0 - or -1 on error. */ - -static int -nto_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len) -{ - int err; - CORE_ADDR initial_stack; - procfs_info procinfo; - - TRACE ("%s\n", __func__); - if (offset > 0) - return 0; - - err = devctl (nto_inferior.ctl_fd, DCMD_PROC_INFO, &procinfo, - sizeof procinfo, 0); - if (err != EOK) - return -1; - - initial_stack = procinfo.initial_stack; - - return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len); -} - -static int -nto_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - case Z_PACKET_HW_BP: - case Z_PACKET_WRITE_WP: - case Z_PACKET_READ_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - return 0; - } -} - -/* Insert {break/watch}point at address ADDR. SIZE is not used. */ - -static int -nto_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - int wtype = _DEBUG_BREAK_HW; /* Always request HW. */ - - TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, size); - switch (type) - { - case raw_bkpt_type_sw: - wtype = _DEBUG_BREAK_EXEC; - break; - case raw_bkpt_type_hw: - wtype |= _DEBUG_BREAK_EXEC; - break; - case raw_bkpt_type_write_wp: - wtype |= _DEBUG_BREAK_RW; - break; - case raw_bkpt_type_read_wp: - wtype |= _DEBUG_BREAK_RD; - break; - case raw_bkpt_type_access_wp: - wtype |= _DEBUG_BREAK_RW; - break; - default: - return 1; /* Not supported. */ - } - return nto_breakpoint (addr, wtype, 0); -} - -/* Remove {break/watch}point at address ADDR. SIZE is not used. */ - -static int -nto_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - int wtype = _DEBUG_BREAK_HW; /* Always request HW. */ - - TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, size); - switch (type) - { - case raw_bkpt_type_sw: - wtype = _DEBUG_BREAK_EXEC; - break; - case raw_bkpt_type_hw: - wtype |= _DEBUG_BREAK_EXEC; - break; - case raw_bkpt_type_write_wp: - wtype |= _DEBUG_BREAK_RW; - break; - case raw_bkpt_type_read_wp: - wtype |= _DEBUG_BREAK_RD; - break; - case raw_bkpt_type_access_wp: - wtype |= _DEBUG_BREAK_RW; - break; - default: - return 1; /* Not supported. */ - } - return nto_breakpoint (addr, wtype, -1); -} - -/* Check if the reason of stop for current thread (CURRENT_INFERIOR) is - a watchpoint. - - Return 1 if stopped by watchpoint, 0 otherwise. */ - -static int -nto_stopped_by_watchpoint (void) -{ - int ret = 0; - - TRACE ("%s\n", __func__); - if (nto_inferior.ctl_fd != -1 && current_thread != NULL) - { - ptid_t ptid = ptid_of (current_thread); - if (nto_set_thread (ptid)) - { - const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR - | _DEBUG_FLAG_TRACE_MODIFY; - procfs_status status; - int err; - - err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, - sizeof (status), 0); - if (err == EOK && (status.flags & watchmask)) - ret = 1; - } - } - TRACE ("%s: %s\n", __func__, ret ? "yes" : "no"); - return ret; -} - -/* Get instruction pointer for CURRENT_INFERIOR thread. - - Return inferior's instruction pointer value, or 0 on error. */ - -static CORE_ADDR -nto_stopped_data_address (void) -{ - CORE_ADDR ret = (CORE_ADDR)0; - - TRACE ("%s\n", __func__); - if (nto_inferior.ctl_fd != -1 && current_thread != NULL) - { - ptid_t ptid = ptid_of (current_thread); - - if (nto_set_thread (ptid)) - { - procfs_status status; - - if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, - sizeof (status), 0) == EOK) - ret = status.ip; - } - } - TRACE ("%s: 0x%08lx\n", __func__, ret); - return ret; -} - -/* We do not currently support non-stop. */ - -static int -nto_supports_non_stop (void) -{ - TRACE ("%s\n", __func__); - return 0; -} - -/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -nto_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = the_low_target.breakpoint_len; - return the_low_target.breakpoint; -} - - -static process_stratum_target nto_target_ops = { - nto_create_inferior, - NULL, /* post_create_inferior */ - nto_attach, - nto_kill, - nto_detach, - nto_mourn, - NULL, /* nto_join */ - nto_thread_alive, - nto_resume, - nto_wait, - nto_fetch_registers, - nto_store_registers, - NULL, /* prepare_to_access_memory */ - NULL, /* done_accessing_memory */ - nto_read_memory, - nto_write_memory, - NULL, /* nto_look_up_symbols */ - nto_request_interrupt, - nto_read_auxv, - nto_supports_z_point_type, - nto_insert_point, - nto_remove_point, - NULL, /* stopped_by_sw_breakpoint */ - NULL, /* supports_stopped_by_sw_breakpoint */ - NULL, /* stopped_by_hw_breakpoint */ - NULL, /* supports_stopped_by_hw_breakpoint */ - target_can_do_hardware_single_step, - nto_stopped_by_watchpoint, - nto_stopped_data_address, - NULL, /* nto_read_offsets */ - NULL, /* thread_db_set_tls_address */ - hostio_last_error_from_errno, - NULL, /* nto_qxfer_osdata */ - NULL, /* xfer_siginfo */ - nto_supports_non_stop, - NULL, /* async */ - NULL, /* start_non_stop */ - NULL, /* supports_multi_process */ - NULL, /* supports_fork_events */ - NULL, /* supports_vfork_events */ - NULL, /* supports_exec_events */ - NULL, /* handle_new_gdb_connection */ - NULL, /* handle_monitor_command */ - NULL, /* core_of_thread */ - NULL, /* read_loadmap */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* read_pc */ - NULL, /* write_pc */ - NULL, /* thread_stopped */ - NULL, /* get_tib_address */ - NULL, /* pause_all */ - NULL, /* unpause_all */ - NULL, /* stabilize_threads */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* supports_disable_randomization */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* qxfer_libraries_svr4 */ - NULL, /* support_agent */ - NULL, /* enable_btrace */ - NULL, /* disable_btrace */ - NULL, /* read_btrace */ - NULL, /* read_btrace_conf */ - NULL, /* supports_range_stepping */ - NULL, /* pid_to_exec_file */ - NULL, /* multifs_open */ - NULL, /* multifs_unlink */ - NULL, /* multifs_readlink */ - NULL, /* breakpoint_kind_from_pc */ - nto_sw_breakpoint_from_kind, -}; - - -/* Global function called by server.c. Initializes QNX Neutrino - gdbserver. */ - -void -initialize_low (void) -{ - sigset_t set; - - TRACE ("%s\n", __func__); - set_target_ops (&nto_target_ops); - - /* We use SIGUSR1 to gain control after we block waiting for a process. - We use sigwaitevent to wait. */ - sigemptyset (&set); - sigaddset (&set, SIGUSR1); - sigprocmask (SIG_BLOCK, &set, NULL); -} - diff --git a/gdb/gdbserver/nto-low.h b/gdb/gdbserver/nto-low.h deleted file mode 100644 index 393b8a98695..00000000000 --- a/gdb/gdbserver/nto-low.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Internal interfaces for the QNX Neutrino specific target code for gdbserver. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_NTO_LOW_H -#define GDBSERVER_NTO_LOW_H - -struct target_desc; - -enum regset_type -{ - NTO_REG_GENERAL, - NTO_REG_FLOAT, - NTO_REG_SYSTEM, - NTO_REG_ALT, - NTO_REG_END -}; - -struct nto_target_ops -{ - /* Architecture specific setup. */ - void (*arch_setup) (void); - int num_regs; - int (*register_offset) (int gdbregno); - const unsigned char *breakpoint; - int breakpoint_len; -}; - -extern struct nto_target_ops the_low_target; - -/* The inferior's target description. This is a global because the - LynxOS ports support neither bi-arch nor multi-process. */ -extern const struct target_desc *nto_tdesc; - -#endif /* GDBSERVER_NTO_LOW_H */ diff --git a/gdb/gdbserver/nto-x86-low.c b/gdb/gdbserver/nto-x86-low.c deleted file mode 100644 index efee9573622..00000000000 --- a/gdb/gdbserver/nto-x86-low.c +++ /dev/null @@ -1,109 +0,0 @@ -/* QNX Neutrino specific low level interface, for the remote server - for GDB. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "nto-low.h" -#include "regdef.h" -#include "regcache.h" - -#include -#include "gdbsupport/x86-xstate.h" -#include "arch/i386.h" -#include "x86-tdesc.h" - -const unsigned char x86_breakpoint[] = { 0xCC }; -#define x86_breakpoint_len 1 - -/* Returns offset in appropriate Neutrino's context structure. - Defined in x86/context.h. - GDBREGNO is index into regs_i386 array. It is autogenerated and - hopefully doesn't change. */ -static int -nto_x86_register_offset (int gdbregno) -{ - if (gdbregno >= 0 && gdbregno < 16) - { - X86_CPU_REGISTERS *dummy = (void*)0; - /* GPRs */ - switch (gdbregno) - { - case 0: - return (int)&(dummy->eax); - case 1: - return (int)&(dummy->ecx); - case 2: - return (int)&(dummy->edx); - case 3: - return (int)&(dummy->ebx); - case 4: - return (int)&(dummy->esp); - case 5: - return (int)&(dummy->ebp); - case 6: - return (int)&(dummy->esi); - case 7: - return (int)&(dummy->edi); - case 8: - return (int)&(dummy->eip); - case 9: - return (int)&(dummy->efl); - case 10: - return (int)&(dummy->cs); - case 11: - return (int)&(dummy->ss); -#ifdef __SEGMENTS__ - case 12: - return (int)&(dummy->ds); - case 13: - return (int)&(dummy->es); - case 14: - return (int)&(dummy->fs); - case 15: - return (int)&(dummy->gs); -#endif - default: - return -1; - } - } - return -1; -} - -static void -nto_x86_arch_setup (void) -{ - the_low_target.num_regs = 16; - struct target_desc *tdesc - = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); - - init_target_desc (tdesc, i386_expedite_regs); - - nto_tdesc = tdesc; -} - -struct nto_target_ops the_low_target = -{ - nto_x86_arch_setup, - 0, /* num_regs */ - nto_x86_register_offset, - x86_breakpoint, - x86_breakpoint_len -}; - - - diff --git a/gdb/gdbserver/proc-service.c b/gdb/gdbserver/proc-service.c deleted file mode 100644 index 9c8885ea912..00000000000 --- a/gdb/gdbserver/proc-service.c +++ /dev/null @@ -1,165 +0,0 @@ -/* libthread_db helper functions for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#include "server.h" - -/* This file is currently tied to GNU/Linux. It should scale well to - another libthread_db implementation, with the appropriate gdbserver - hooks, but for now this means we can use GNU/Linux's target data. */ - -#include "linux-low.h" - -#include "gdb_proc_service.h" - -typedef struct ps_prochandle *gdb_ps_prochandle_t; -typedef void *gdb_ps_read_buf_t; -typedef const void *gdb_ps_write_buf_t; -typedef size_t gdb_ps_size_t; - -#ifdef HAVE_LINUX_REGSETS -#define HAVE_REGSETS -#endif - -#ifdef HAVE_REGSETS -static struct regset_info * -gregset_info (void) -{ - int i = 0; - const struct regs_info *regs_info = (*the_low_target.regs_info) (); - struct regsets_info *regsets_info = regs_info->regsets_info; - - while (regsets_info->regsets[i].size != -1) - { - if (regsets_info->regsets[i].type == GENERAL_REGS) - break; - i++; - } - - return ®sets_info->regsets[i]; -} -#endif - -/* Search for the symbol named NAME within the object named OBJ within - the target process PH. If the symbol is found the address of the - symbol is stored in SYM_ADDR. */ - -ps_err_e -ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj, - const char *name, psaddr_t *sym_addr) -{ - CORE_ADDR addr; - - if (thread_db_look_up_one_symbol (name, &addr) == 0) - return PS_NOSYM; - - *sym_addr = (psaddr_t) (unsigned long) addr; - return PS_OK; -} - -/* Read SIZE bytes from the target process PH at address ADDR and copy - them into BUF. */ - -ps_err_e -ps_pdread (gdb_ps_prochandle_t ph, psaddr_t addr, - gdb_ps_read_buf_t buf, gdb_ps_size_t size) -{ - if (read_inferior_memory ((uintptr_t) addr, (gdb_byte *) buf, size) != 0) - return PS_ERR; - return PS_OK; -} - -/* Write SIZE bytes from BUF into the target process PH at address ADDR. */ - -ps_err_e -ps_pdwrite (gdb_ps_prochandle_t ph, psaddr_t addr, - gdb_ps_write_buf_t buf, gdb_ps_size_t size) -{ - if (target_write_memory ((uintptr_t) addr, (const gdb_byte *) buf, size) - != 0) - return PS_ERR; - return PS_OK; -} - -/* Get the general registers of LWP LWPID within the target process PH - and store them in GREGSET. */ - -ps_err_e -ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset) -{ -#ifdef HAVE_REGSETS - struct lwp_info *lwp; - struct thread_info *reg_thread, *saved_thread; - struct regcache *regcache; - - lwp = find_lwp_pid (ptid_t (lwpid)); - if (lwp == NULL) - return PS_ERR; - - reg_thread = get_lwp_thread (lwp); - saved_thread = current_thread; - current_thread = reg_thread; - regcache = get_thread_regcache (current_thread, 1); - gregset_info ()->fill_function (regcache, gregset); - - current_thread = saved_thread; - return PS_OK; -#else - return PS_ERR; -#endif -} - -/* Set the general registers of LWP LWPID within the target process PH - from GREGSET. */ - -ps_err_e -ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset) -{ - /* Unneeded. */ - return PS_ERR; -} - -/* Get the floating-point registers of LWP LWPID within the target - process PH and store them in FPREGSET. */ - -ps_err_e -ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prfpregset_t *fpregset) -{ - /* Unneeded. */ - return PS_ERR; -} - -/* Set the floating-point registers of LWP LWPID within the target - process PH from FPREGSET. */ - -ps_err_e -ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prfpregset_t *fpregset) -{ - /* Unneeded. */ - return PS_ERR; -} - -/* Return overall process id of the target PH. Special for GNU/Linux - -- not used on Solaris. */ - -pid_t -ps_getpid (gdb_ps_prochandle_t ph) -{ - return pid_of (current_thread); -} diff --git a/gdb/gdbserver/proc-service.list b/gdb/gdbserver/proc-service.list deleted file mode 100644 index 61330453885..00000000000 --- a/gdb/gdbserver/proc-service.list +++ /dev/null @@ -1,30 +0,0 @@ -/* -Wl,--dynamic-list symbols exported for libthread_db. - - Copyright (C) 2010-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -{ - ps_get_thread_area; - ps_getpid; - ps_lgetfpregs; - ps_lgetregs; - ps_lsetfpregs; - ps_lsetregs; - ps_pdread; - ps_pdwrite; - ps_pglobal_lookup; -}; diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c deleted file mode 100644 index f63463344af..00000000000 --- a/gdb/gdbserver/regcache.c +++ /dev/null @@ -1,528 +0,0 @@ -/* Register support routines for the remote server for GDB. - Copyright (C) 2001-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "regdef.h" -#include "gdbthread.h" -#include "tdesc.h" -#include "gdbsupport/rsp-low.h" -#ifndef IN_PROCESS_AGENT - -struct regcache * -get_thread_regcache (struct thread_info *thread, int fetch) -{ - struct regcache *regcache; - - regcache = thread_regcache_data (thread); - - /* Threads' regcaches are created lazily, because biarch targets add - the main thread/lwp before seeing it stop for the first time, and - it is only after the target sees the thread stop for the first - time that the target has a chance of determining the process's - architecture. IOW, when we first add the process's main thread - we don't know which architecture/tdesc its regcache should - have. */ - if (regcache == NULL) - { - struct process_info *proc = get_thread_process (thread); - - gdb_assert (proc->tdesc != NULL); - - regcache = new_register_cache (proc->tdesc); - set_thread_regcache_data (thread, regcache); - } - - if (fetch && regcache->registers_valid == 0) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - /* Invalidate all registers, to prevent stale left-overs. */ - memset (regcache->register_status, REG_UNAVAILABLE, - regcache->tdesc->reg_defs.size ()); - fetch_inferior_registers (regcache, -1); - current_thread = saved_thread; - regcache->registers_valid = 1; - } - - return regcache; -} - -/* See gdbsupport/common-regcache.h. */ - -struct regcache * -get_thread_regcache_for_ptid (ptid_t ptid) -{ - return get_thread_regcache (find_thread_ptid (ptid), 1); -} - -void -regcache_invalidate_thread (struct thread_info *thread) -{ - struct regcache *regcache; - - regcache = thread_regcache_data (thread); - - if (regcache == NULL) - return; - - if (regcache->registers_valid) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - store_inferior_registers (regcache, -1); - current_thread = saved_thread; - } - - regcache->registers_valid = 0; -} - -/* See regcache.h. */ - -void -regcache_invalidate_pid (int pid) -{ - /* Only invalidate the regcaches of threads of this process. */ - for_each_thread (pid, regcache_invalidate_thread); -} - -/* See regcache.h. */ - -void -regcache_invalidate (void) -{ - /* Only update the threads of the current process. */ - int pid = current_thread->id.pid (); - - regcache_invalidate_pid (pid); -} - -#endif - -struct regcache * -init_register_cache (struct regcache *regcache, - const struct target_desc *tdesc, - unsigned char *regbuf) -{ - if (regbuf == NULL) - { -#ifndef IN_PROCESS_AGENT - /* Make sure to zero-initialize the register cache when it is - created, in case there are registers the target never - fetches. This way they'll read as zero instead of - garbage. */ - regcache->tdesc = tdesc; - regcache->registers - = (unsigned char *) xcalloc (1, tdesc->registers_size); - regcache->registers_owned = 1; - regcache->register_status - = (unsigned char *) xmalloc (tdesc->reg_defs.size ()); - memset ((void *) regcache->register_status, REG_UNAVAILABLE, - tdesc->reg_defs.size ()); -#else - gdb_assert_not_reached ("can't allocate memory from the heap"); -#endif - } - else - { - regcache->tdesc = tdesc; - regcache->registers = regbuf; - regcache->registers_owned = 0; -#ifndef IN_PROCESS_AGENT - regcache->register_status = NULL; -#endif - } - - regcache->registers_valid = 0; - - return regcache; -} - -#ifndef IN_PROCESS_AGENT - -struct regcache * -new_register_cache (const struct target_desc *tdesc) -{ - struct regcache *regcache = new struct regcache; - - gdb_assert (tdesc->registers_size != 0); - - return init_register_cache (regcache, tdesc, NULL); -} - -void -free_register_cache (struct regcache *regcache) -{ - if (regcache) - { - if (regcache->registers_owned) - free (regcache->registers); - free (regcache->register_status); - delete regcache; - } -} - -#endif - -void -regcache_cpy (struct regcache *dst, struct regcache *src) -{ - gdb_assert (src != NULL && dst != NULL); - gdb_assert (src->tdesc == dst->tdesc); - gdb_assert (src != dst); - - memcpy (dst->registers, src->registers, src->tdesc->registers_size); -#ifndef IN_PROCESS_AGENT - if (dst->register_status != NULL && src->register_status != NULL) - memcpy (dst->register_status, src->register_status, - src->tdesc->reg_defs.size ()); -#endif - dst->registers_valid = src->registers_valid; -} - -/* Return a reference to the description of register N. */ - -static const struct reg & -find_register_by_number (const struct target_desc *tdesc, int n) -{ - return tdesc->reg_defs[n]; -} - -#ifndef IN_PROCESS_AGENT - -void -registers_to_string (struct regcache *regcache, char *buf) -{ - unsigned char *registers = regcache->registers; - const struct target_desc *tdesc = regcache->tdesc; - - for (int i = 0; i < tdesc->reg_defs.size (); ++i) - { - if (regcache->register_status[i] == REG_VALID) - { - bin2hex (registers, buf, register_size (tdesc, i)); - buf += register_size (tdesc, i) * 2; - } - else - { - memset (buf, 'x', register_size (tdesc, i) * 2); - buf += register_size (tdesc, i) * 2; - } - registers += register_size (tdesc, i); - } - *buf = '\0'; -} - -void -registers_from_string (struct regcache *regcache, char *buf) -{ - int len = strlen (buf); - unsigned char *registers = regcache->registers; - const struct target_desc *tdesc = regcache->tdesc; - - if (len != tdesc->registers_size * 2) - { - warning ("Wrong sized register packet (expected %d bytes, got %d)", - 2 * tdesc->registers_size, len); - if (len > tdesc->registers_size * 2) - len = tdesc->registers_size * 2; - } - hex2bin (buf, registers, len / 2); -} - -int -find_regno (const struct target_desc *tdesc, const char *name) -{ - for (int i = 0; i < tdesc->reg_defs.size (); ++i) - { - if (strcmp (name, find_register_by_number (tdesc, i).name) == 0) - return i; - } - internal_error (__FILE__, __LINE__, "Unknown register %s requested", - name); -} - -static void -free_register_cache_thread (struct thread_info *thread) -{ - struct regcache *regcache = thread_regcache_data (thread); - - if (regcache != NULL) - { - regcache_invalidate_thread (thread); - free_register_cache (regcache); - set_thread_regcache_data (thread, NULL); - } -} - -void -regcache_release (void) -{ - /* Flush and release all pre-existing register caches. */ - for_each_thread (free_register_cache_thread); -} -#endif - -int -register_cache_size (const struct target_desc *tdesc) -{ - return tdesc->registers_size; -} - -int -register_size (const struct target_desc *tdesc, int n) -{ - return find_register_by_number (tdesc, n).size / 8; -} - -/* See gdbsupport/common-regcache.h. */ - -int -regcache_register_size (const struct regcache *regcache, int n) -{ - return register_size (regcache->tdesc, n); -} - -static unsigned char * -register_data (const struct regcache *regcache, int n, int fetch) -{ - return (regcache->registers - + find_register_by_number (regcache->tdesc, n).offset / 8); -} - -void -supply_register (struct regcache *regcache, int n, const void *buf) -{ - return regcache->raw_supply (n, buf); -} - -/* See gdbsupport/common-regcache.h. */ - -void -regcache::raw_supply (int n, const void *buf) -{ - if (buf) - { - memcpy (register_data (this, n, 0), buf, register_size (tdesc, n)); -#ifndef IN_PROCESS_AGENT - if (register_status != NULL) - register_status[n] = REG_VALID; -#endif - } - else - { - memset (register_data (this, n, 0), 0, register_size (tdesc, n)); -#ifndef IN_PROCESS_AGENT - if (register_status != NULL) - register_status[n] = REG_UNAVAILABLE; -#endif - } -} - -/* Supply register N with value zero to REGCACHE. */ - -void -supply_register_zeroed (struct regcache *regcache, int n) -{ - memset (register_data (regcache, n, 0), 0, - register_size (regcache->tdesc, n)); -#ifndef IN_PROCESS_AGENT - if (regcache->register_status != NULL) - regcache->register_status[n] = REG_VALID; -#endif -} - -#ifndef IN_PROCESS_AGENT - -/* Supply register called NAME with value zero to REGCACHE. */ - -void -supply_register_by_name_zeroed (struct regcache *regcache, - const char *name) -{ - supply_register_zeroed (regcache, find_regno (regcache->tdesc, name)); -} - -#endif - -/* Supply the whole register set whose contents are stored in BUF, to - REGCACHE. If BUF is NULL, all the registers' values are recorded - as unavailable. */ - -void -supply_regblock (struct regcache *regcache, const void *buf) -{ - if (buf) - { - const struct target_desc *tdesc = regcache->tdesc; - - memcpy (regcache->registers, buf, tdesc->registers_size); -#ifndef IN_PROCESS_AGENT - { - int i; - - for (i = 0; i < tdesc->reg_defs.size (); i++) - regcache->register_status[i] = REG_VALID; - } -#endif - } - else - { - const struct target_desc *tdesc = regcache->tdesc; - - memset (regcache->registers, 0, tdesc->registers_size); -#ifndef IN_PROCESS_AGENT - { - int i; - - for (i = 0; i < tdesc->reg_defs.size (); i++) - regcache->register_status[i] = REG_UNAVAILABLE; - } -#endif - } -} - -#ifndef IN_PROCESS_AGENT - -void -supply_register_by_name (struct regcache *regcache, - const char *name, const void *buf) -{ - supply_register (regcache, find_regno (regcache->tdesc, name), buf); -} - -#endif - -void -collect_register (struct regcache *regcache, int n, void *buf) -{ - regcache->raw_collect (n, buf); -} - -/* See gdbsupport/common-regcache.h. */ - -void -regcache::raw_collect (int n, void *buf) const -{ - memcpy (buf, register_data (this, n, 1), register_size (tdesc, n)); -} - -enum register_status -regcache_raw_read_unsigned (struct regcache *regcache, int regnum, - ULONGEST *val) -{ - int size; - - gdb_assert (regcache != NULL); - gdb_assert (regnum >= 0 - && regnum < regcache->tdesc->reg_defs.size ()); - - size = register_size (regcache->tdesc, regnum); - - if (size > (int) sizeof (ULONGEST)) - error (_("That operation is not available on integers of more than" - "%d bytes."), - (int) sizeof (ULONGEST)); - - *val = 0; - collect_register (regcache, regnum, val); - - return REG_VALID; -} - -#ifndef IN_PROCESS_AGENT - -/* See regcache.h. */ - -ULONGEST -regcache_raw_get_unsigned_by_name (struct regcache *regcache, - const char *name) -{ - return regcache_raw_get_unsigned (regcache, - find_regno (regcache->tdesc, name)); -} - -void -collect_register_as_string (struct regcache *regcache, int n, char *buf) -{ - bin2hex (register_data (regcache, n, 1), buf, - register_size (regcache->tdesc, n)); -} - -void -collect_register_by_name (struct regcache *regcache, - const char *name, void *buf) -{ - collect_register (regcache, find_regno (regcache->tdesc, name), buf); -} - -/* Special handling for register PC. */ - -CORE_ADDR -regcache_read_pc (struct regcache *regcache) -{ - CORE_ADDR pc_val; - - if (the_target->read_pc) - pc_val = the_target->read_pc (regcache); - else - internal_error (__FILE__, __LINE__, - "regcache_read_pc: Unable to find PC"); - - return pc_val; -} - -void -regcache_write_pc (struct regcache *regcache, CORE_ADDR pc) -{ - if (the_target->write_pc) - the_target->write_pc (regcache, pc); - else - internal_error (__FILE__, __LINE__, - "regcache_write_pc: Unable to update PC"); -} - -#endif - -/* See gdbsupport/common-regcache.h. */ - -enum register_status -regcache::get_register_status (int regnum) const -{ -#ifndef IN_PROCESS_AGENT - gdb_assert (regnum >= 0 && regnum < tdesc->reg_defs.size ()); - return (enum register_status) (register_status[regnum]); -#else - return REG_VALID; -#endif -} - -/* See gdbsupport/common-regcache.h. */ - -bool -regcache::raw_compare (int regnum, const void *buf, int offset) const -{ - gdb_assert (buf != NULL); - - const unsigned char *regbuf = register_data (this, regnum, 1); - int size = register_size (tdesc, regnum); - gdb_assert (size >= offset); - - return (memcmp (buf, regbuf + offset, size - offset) == 0); -} diff --git a/gdb/gdbserver/regcache.h b/gdb/gdbserver/regcache.h deleted file mode 100644 index 8725707c685..00000000000 --- a/gdb/gdbserver/regcache.h +++ /dev/null @@ -1,141 +0,0 @@ -/* Register support routines for the remote server for GDB. - Copyright (C) 2001-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_REGCACHE_H -#define GDBSERVER_REGCACHE_H - -#include "gdbsupport/common-regcache.h" - -struct thread_info; -struct target_desc; - -/* The data for the register cache. Note that we have one per - inferior; this is primarily for simplicity, as the performance - benefit is minimal. */ - -struct regcache : public reg_buffer_common -{ - /* The regcache's target description. */ - const struct target_desc *tdesc = nullptr; - - /* Whether the REGISTERS buffer's contents are valid. If false, we - haven't fetched the registers from the target yet. Not that this - register cache is _not_ pass-through, unlike GDB's. Note that - "valid" here is unrelated to whether the registers are available - in a traceframe. For that, check REGISTER_STATUS below. */ - int registers_valid = 0; - int registers_owned = 0; - unsigned char *registers = nullptr; -#ifndef IN_PROCESS_AGENT - /* One of REG_UNAVAILABLE or REG_VALID. */ - unsigned char *register_status = nullptr; -#endif - - /* See gdbsupport/common-regcache.h. */ - enum register_status get_register_status (int regnum) const override; - - /* See gdbsupport/common-regcache.h. */ - void raw_supply (int regnum, const void *buf) override; - - /* See gdbsupport/common-regcache.h. */ - void raw_collect (int regnum, void *buf) const override; - - /* See gdbsupport/common-regcache.h. */ - bool raw_compare (int regnum, const void *buf, int offset) const override; -}; - -struct regcache *init_register_cache (struct regcache *regcache, - const struct target_desc *tdesc, - unsigned char *regbuf); - -void regcache_cpy (struct regcache *dst, struct regcache *src); - -/* Create a new register cache for INFERIOR. */ - -struct regcache *new_register_cache (const struct target_desc *tdesc); - -struct regcache *get_thread_regcache (struct thread_info *thread, int fetch); - -/* Release all memory associated with the register cache for INFERIOR. */ - -void free_register_cache (struct regcache *regcache); - -/* Invalidate cached registers for one thread. */ - -void regcache_invalidate_thread (struct thread_info *); - -/* Invalidate cached registers for all threads of the given process. */ - -void regcache_invalidate_pid (int pid); - -/* Invalidate cached registers for all threads of the current - process. */ - -void regcache_invalidate (void); - -/* Invalidate and release the register cache of all threads of the - current process. */ - -void regcache_release (void); - -/* Convert all registers to a string in the currently specified remote - format. */ - -void registers_to_string (struct regcache *regcache, char *buf); - -/* Convert a string to register values and fill our register cache. */ - -void registers_from_string (struct regcache *regcache, char *buf); - -/* For regcache_read_pc see gdbsupport/common-regcache.h. */ - -void regcache_write_pc (struct regcache *regcache, CORE_ADDR pc); - -int register_cache_size (const struct target_desc *tdesc); - -int register_size (const struct target_desc *tdesc, int n); - -int find_regno (const struct target_desc *tdesc, const char *name); - -void supply_register (struct regcache *regcache, int n, const void *buf); - -void supply_register_zeroed (struct regcache *regcache, int n); - -void supply_register_by_name (struct regcache *regcache, - const char *name, const void *buf); - -void supply_register_by_name_zeroed (struct regcache *regcache, - const char *name); - -void supply_regblock (struct regcache *regcache, const void *buf); - -void collect_register (struct regcache *regcache, int n, void *buf); - -void collect_register_as_string (struct regcache *regcache, int n, char *buf); - -void collect_register_by_name (struct regcache *regcache, - const char *name, void *buf); - -/* Read a raw register as an unsigned integer. Convenience wrapper - around regcache_raw_get_unsigned that takes a register name instead - of a register number. */ - -ULONGEST regcache_raw_get_unsigned_by_name (struct regcache *regcache, - const char *name); - -#endif /* GDBSERVER_REGCACHE_H */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c deleted file mode 100644 index b8a8c6576f9..00000000000 --- a/gdb/gdbserver/remote-utils.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* Remote utility routines for the remote server for GDB. - Copyright (C) 1986-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#if HAVE_TERMIOS_H -#include -#endif -#include "target.h" -#include "gdbthread.h" -#include "tdesc.h" -#include "debug.h" -#include "dll.h" -#include "gdbsupport/rsp-low.h" -#include "gdbsupport/netstuff.h" -#include "gdbsupport/filestuff.h" -#include "gdbsupport/gdb-sigmask.h" -#include -#if HAVE_SYS_IOCTL_H -#include -#endif -#if HAVE_SYS_FILE_H -#include -#endif -#if HAVE_NETINET_IN_H -#include -#endif -#if HAVE_SYS_SOCKET_H -#include -#endif -#if HAVE_NETDB_H -#include -#endif -#if HAVE_NETINET_TCP_H -#include -#endif -#if HAVE_SYS_IOCTL_H -#include -#endif -#if HAVE_SIGNAL_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#include "gdbsupport/gdb_sys_time.h" -#include -#if HAVE_ARPA_INET_H -#include -#endif -#include - -#if USE_WIN32API -#include -#endif - -#if __QNX__ -#include -#endif /* __QNX__ */ - -#ifndef HAVE_SOCKLEN_T -typedef int socklen_t; -#endif - -#ifndef IN_PROCESS_AGENT - -#if USE_WIN32API -# define INVALID_DESCRIPTOR INVALID_SOCKET -#else -# define INVALID_DESCRIPTOR -1 -#endif - -/* Extra value for readchar_callback. */ -enum { - /* The callback is currently not scheduled. */ - NOT_SCHEDULED = -1 -}; - -/* Status of the readchar callback. - Either NOT_SCHEDULED or the callback id. */ -static int readchar_callback = NOT_SCHEDULED; - -static int readchar (void); -static void reset_readchar (void); -static void reschedule (void); - -/* A cache entry for a successfully looked-up symbol. */ -struct sym_cache -{ - char *name; - CORE_ADDR addr; - struct sym_cache *next; -}; - -static int remote_is_stdio = 0; - -static gdb_fildes_t remote_desc = INVALID_DESCRIPTOR; -static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR; - -#ifdef USE_WIN32API -# define read(fd, buf, len) recv (fd, (char *) buf, len, 0) -# define write(fd, buf, len) send (fd, (char *) buf, len, 0) -#endif - -int -gdb_connected (void) -{ - return remote_desc != INVALID_DESCRIPTOR; -} - -/* Return true if the remote connection is over stdio. */ - -int -remote_connection_is_stdio (void) -{ - return remote_is_stdio; -} - -static void -enable_async_notification (int fd) -{ -#if defined(F_SETFL) && defined (FASYNC) - int save_fcntl_flags; - - save_fcntl_flags = fcntl (fd, F_GETFL, 0); - fcntl (fd, F_SETFL, save_fcntl_flags | FASYNC); -#if defined (F_SETOWN) - fcntl (fd, F_SETOWN, getpid ()); -#endif -#endif -} - -static int -handle_accept_event (int err, gdb_client_data client_data) -{ - struct sockaddr_storage sockaddr; - socklen_t len = sizeof (sockaddr); - - if (debug_threads) - debug_printf ("handling possible accept event\n"); - - remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &len); - if (remote_desc == -1) - perror_with_name ("Accept failed"); - - /* Enable TCP keep alive process. */ - socklen_t tmp = 1; - setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE, - (char *) &tmp, sizeof (tmp)); - - /* Tell TCP not to delay small packets. This greatly speeds up - interactive response. */ - tmp = 1; - setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, - (char *) &tmp, sizeof (tmp)); - -#ifndef USE_WIN32API - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply - exits when the remote side dies. */ -#endif - - if (run_once) - { -#ifndef USE_WIN32API - close (listen_desc); /* No longer need this */ -#else - closesocket (listen_desc); /* No longer need this */ -#endif - } - - /* Even if !RUN_ONCE no longer notice new connections. Still keep the - descriptor open for add_file_handler to wait for a new connection. */ - delete_file_handler (listen_desc); - - /* Convert IP address to string. */ - char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT]; - - int r = getnameinfo ((struct sockaddr *) &sockaddr, len, - orig_host, sizeof (orig_host), - orig_port, sizeof (orig_port), - NI_NUMERICHOST | NI_NUMERICSERV); - - if (r != 0) - fprintf (stderr, _("Could not obtain remote address: %s\n"), - gai_strerror (r)); - else - fprintf (stderr, _("Remote debugging from host %s, port %s\n"), - orig_host, orig_port); - - enable_async_notification (remote_desc); - - /* Register the event loop handler. */ - add_file_handler (remote_desc, handle_serial_event, NULL); - - /* We have a new GDB connection now. If we were disconnected - tracing, there's a window where the target could report a stop - event to the event loop, and since we have a connection now, we'd - try to send vStopped notifications to GDB. But, don't do that - until GDB as selected all-stop/non-stop, and has queried the - threads' status ('?'). */ - target_async (0); - - return 0; -} - -/* Prepare for a later connection to a remote debugger. - NAME is the filename used for communication. */ - -void -remote_prepare (const char *name) -{ - client_state &cs = get_client_state (); -#ifdef USE_WIN32API - static int winsock_initialized; -#endif - socklen_t tmp; - - remote_is_stdio = 0; - if (strcmp (name, STDIO_CONNECTION_NAME) == 0) - { - /* We need to record fact that we're using stdio sooner than the - call to remote_open so start_inferior knows the connection is - via stdio. */ - remote_is_stdio = 1; - cs.transport_is_reliable = 1; - return; - } - - struct addrinfo hint; - struct addrinfo *ainfo; - - memset (&hint, 0, sizeof (hint)); - /* Assume no prefix will be passed, therefore we should use - AF_UNSPEC. */ - hint.ai_family = AF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - hint.ai_protocol = IPPROTO_TCP; - - parsed_connection_spec parsed - = parse_connection_spec_without_prefix (name, &hint); - - if (parsed.port_str.empty ()) - { - cs.transport_is_reliable = 0; - return; - } - -#ifdef USE_WIN32API - if (!winsock_initialized) - { - WSADATA wsad; - - WSAStartup (MAKEWORD (1, 0), &wsad); - winsock_initialized = 1; - } -#endif - - int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (), - &hint, &ainfo); - - if (r != 0) - error (_("%s: cannot resolve name: %s"), name, gai_strerror (r)); - - scoped_free_addrinfo freeaddrinfo (ainfo); - - struct addrinfo *iter; - - for (iter = ainfo; iter != NULL; iter = iter->ai_next) - { - listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype, - iter->ai_protocol); - - if (listen_desc >= 0) - break; - } - - if (iter == NULL) - perror_with_name ("Can't open socket"); - - /* Allow rapid reuse of this port. */ - tmp = 1; - setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, - sizeof (tmp)); - - switch (iter->ai_family) - { - case AF_INET: - ((struct sockaddr_in *) iter->ai_addr)->sin_addr.s_addr = INADDR_ANY; - break; - case AF_INET6: - ((struct sockaddr_in6 *) iter->ai_addr)->sin6_addr = in6addr_any; - break; - default: - internal_error (__FILE__, __LINE__, - _("Invalid 'ai_family' %d\n"), iter->ai_family); - } - - if (bind (listen_desc, iter->ai_addr, iter->ai_addrlen) != 0) - perror_with_name ("Can't bind address"); - - if (listen (listen_desc, 1) != 0) - perror_with_name ("Can't listen on socket"); - - cs.transport_is_reliable = 1; -} - -/* Open a connection to a remote debugger. - NAME is the filename used for communication. */ - -void -remote_open (const char *name) -{ - const char *port_str; - - port_str = strchr (name, ':'); -#ifdef USE_WIN32API - if (port_str == NULL) - error ("Only HOST:PORT is supported on this platform."); -#endif - - if (strcmp (name, STDIO_CONNECTION_NAME) == 0) - { - fprintf (stderr, "Remote debugging using stdio\n"); - - /* Use stdin as the handle of the connection. - We only select on reads, for example. */ - remote_desc = fileno (stdin); - - enable_async_notification (remote_desc); - - /* Register the event loop handler. */ - add_file_handler (remote_desc, handle_serial_event, NULL); - } -#ifndef USE_WIN32API - else if (port_str == NULL) - { - struct stat statbuf; - - if (stat (name, &statbuf) == 0 - && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))) - remote_desc = open (name, O_RDWR); - else - { - errno = EINVAL; - remote_desc = -1; - } - - if (remote_desc < 0) - perror_with_name ("Could not open remote device"); - -#if HAVE_TERMIOS_H - { - struct termios termios; - tcgetattr (remote_desc, &termios); - - termios.c_iflag = 0; - termios.c_oflag = 0; - termios.c_lflag = 0; - termios.c_cflag &= ~(CSIZE | PARENB); - termios.c_cflag |= CLOCAL | CS8; - termios.c_cc[VMIN] = 1; - termios.c_cc[VTIME] = 0; - - tcsetattr (remote_desc, TCSANOW, &termios); - } -#endif - - fprintf (stderr, "Remote debugging using %s\n", name); - - enable_async_notification (remote_desc); - - /* Register the event loop handler. */ - add_file_handler (remote_desc, handle_serial_event, NULL); - } -#endif /* USE_WIN32API */ - else - { - char listen_port[GDB_NI_MAX_PORT]; - struct sockaddr_storage sockaddr; - socklen_t len = sizeof (sockaddr); - - if (getsockname (listen_desc, (struct sockaddr *) &sockaddr, &len) < 0) - perror_with_name ("Can't determine port"); - - int r = getnameinfo ((struct sockaddr *) &sockaddr, len, - NULL, 0, - listen_port, sizeof (listen_port), - NI_NUMERICSERV); - - if (r != 0) - fprintf (stderr, _("Can't obtain port where we are listening: %s"), - gai_strerror (r)); - else - fprintf (stderr, _("Listening on port %s\n"), listen_port); - - fflush (stderr); - - /* Register the event loop handler. */ - add_file_handler (listen_desc, handle_accept_event, NULL); - } -} - -void -remote_close (void) -{ - delete_file_handler (remote_desc); - - disable_async_io (); - -#ifdef USE_WIN32API - closesocket (remote_desc); -#else - if (! remote_connection_is_stdio ()) - close (remote_desc); -#endif - remote_desc = INVALID_DESCRIPTOR; - - reset_readchar (); -} - -#endif - -#ifndef IN_PROCESS_AGENT - -void -decode_address (CORE_ADDR *addrp, const char *start, int len) -{ - CORE_ADDR addr; - char ch; - int i; - - addr = 0; - for (i = 0; i < len; i++) - { - ch = start[i]; - addr = addr << 4; - addr = addr | (fromhex (ch) & 0x0f); - } - *addrp = addr; -} - -const char * -decode_address_to_semicolon (CORE_ADDR *addrp, const char *start) -{ - const char *end; - - end = start; - while (*end != '\0' && *end != ';') - end++; - - decode_address (addrp, start, end - start); - - if (*end == ';') - end++; - return end; -} - -#endif - -#ifndef IN_PROCESS_AGENT - -/* Look for a sequence of characters which can be run-length encoded. - If there are any, update *CSUM and *P. Otherwise, output the - single character. Return the number of characters consumed. */ - -static int -try_rle (char *buf, int remaining, unsigned char *csum, char **p) -{ - int n; - - /* Always output the character. */ - *csum += buf[0]; - *(*p)++ = buf[0]; - - /* Don't go past '~'. */ - if (remaining > 97) - remaining = 97; - - for (n = 1; n < remaining; n++) - if (buf[n] != buf[0]) - break; - - /* N is the index of the first character not the same as buf[0]. - buf[0] is counted twice, so by decrementing N, we get the number - of characters the RLE sequence will replace. */ - n--; - - if (n < 3) - return 1; - - /* Skip the frame characters. The manual says to skip '+' and '-' - also, but there's no reason to. Unfortunately these two unusable - characters double the encoded length of a four byte zero - value. */ - while (n + 29 == '$' || n + 29 == '#') - n--; - - *csum += '*'; - *(*p)++ = '*'; - *csum += n + 29; - *(*p)++ = n + 29; - - return n + 1; -} - -#endif - -#ifndef IN_PROCESS_AGENT - -/* Write a PTID to BUF. Returns BUF+CHARACTERS_WRITTEN. */ - -char * -write_ptid (char *buf, ptid_t ptid) -{ - client_state &cs = get_client_state (); - int pid, tid; - - if (cs.multi_process) - { - pid = ptid.pid (); - if (pid < 0) - buf += sprintf (buf, "p-%x.", -pid); - else - buf += sprintf (buf, "p%x.", pid); - } - tid = ptid.lwp (); - if (tid < 0) - buf += sprintf (buf, "-%x", -tid); - else - buf += sprintf (buf, "%x", tid); - - return buf; -} - -static ULONGEST -hex_or_minus_one (const char *buf, const char **obuf) -{ - ULONGEST ret; - - if (startswith (buf, "-1")) - { - ret = (ULONGEST) -1; - buf += 2; - } - else - buf = unpack_varlen_hex (buf, &ret); - - if (obuf) - *obuf = buf; - - return ret; -} - -/* Extract a PTID from BUF. If non-null, OBUF is set to the to one - passed the last parsed char. Returns null_ptid on error. */ -ptid_t -read_ptid (const char *buf, const char **obuf) -{ - const char *p = buf; - const char *pp; - ULONGEST pid = 0, tid = 0; - - if (*p == 'p') - { - /* Multi-process ptid. */ - pp = unpack_varlen_hex (p + 1, &pid); - if (*pp != '.') - error ("invalid remote ptid: %s\n", p); - - p = pp + 1; - - tid = hex_or_minus_one (p, &pp); - - if (obuf) - *obuf = pp; - return ptid_t (pid, tid, 0); - } - - /* No multi-process. Just a tid. */ - tid = hex_or_minus_one (p, &pp); - - /* Since GDB is not sending a process id (multi-process extensions - are off), then there's only one process. Default to the first in - the list. */ - pid = pid_of (get_first_process ()); - - if (obuf) - *obuf = pp; - return ptid_t (pid, tid, 0); -} - -/* Write COUNT bytes in BUF to the client. - The result is the number of bytes written or -1 if error. - This may return less than COUNT. */ - -static int -write_prim (const void *buf, int count) -{ - if (remote_connection_is_stdio ()) - return write (fileno (stdout), buf, count); - else - return write (remote_desc, buf, count); -} - -/* Read COUNT bytes from the client and store in BUF. - The result is the number of bytes read or -1 if error. - This may return less than COUNT. */ - -static int -read_prim (void *buf, int count) -{ - if (remote_connection_is_stdio ()) - return read (fileno (stdin), buf, count); - else - return read (remote_desc, buf, count); -} - -/* Send a packet to the remote machine, with error checking. - The data of the packet is in BUF, and the length of the - packet is in CNT. Returns >= 0 on success, -1 otherwise. */ - -static int -putpkt_binary_1 (char *buf, int cnt, int is_notif) -{ - client_state &cs = get_client_state (); - int i; - unsigned char csum = 0; - char *buf2; - char *p; - int cc; - - buf2 = (char *) xmalloc (strlen ("$") + cnt + strlen ("#nn") + 1); - - /* Copy the packet into buffer BUF2, encapsulating it - and giving it a checksum. */ - - p = buf2; - if (is_notif) - *p++ = '%'; - else - *p++ = '$'; - - for (i = 0; i < cnt;) - i += try_rle (buf + i, cnt - i, &csum, &p); - - *p++ = '#'; - *p++ = tohex ((csum >> 4) & 0xf); - *p++ = tohex (csum & 0xf); - - *p = '\0'; - - /* Send it over and over until we get a positive ack. */ - - do - { - if (write_prim (buf2, p - buf2) != p - buf2) - { - perror ("putpkt(write)"); - free (buf2); - return -1; - } - - if (cs.noack_mode || is_notif) - { - /* Don't expect an ack then. */ - if (remote_debug) - { - if (is_notif) - debug_printf ("putpkt (\"%s\"); [notif]\n", buf2); - else - debug_printf ("putpkt (\"%s\"); [noack mode]\n", buf2); - debug_flush (); - } - break; - } - - if (remote_debug) - { - debug_printf ("putpkt (\"%s\"); [looking for ack]\n", buf2); - debug_flush (); - } - - cc = readchar (); - - if (cc < 0) - { - free (buf2); - return -1; - } - - if (remote_debug) - { - debug_printf ("[received '%c' (0x%x)]\n", cc, cc); - debug_flush (); - } - - /* Check for an input interrupt while we're here. */ - if (cc == '\003' && current_thread != NULL) - (*the_target->request_interrupt) (); - } - while (cc != '+'); - - free (buf2); - return 1; /* Success! */ -} - -int -putpkt_binary (char *buf, int cnt) -{ - return putpkt_binary_1 (buf, cnt, 0); -} - -/* Send a packet to the remote machine, with error checking. The data - of the packet is in BUF, and the packet should be a NUL-terminated - string. Returns >= 0 on success, -1 otherwise. */ - -int -putpkt (char *buf) -{ - return putpkt_binary (buf, strlen (buf)); -} - -int -putpkt_notif (char *buf) -{ - return putpkt_binary_1 (buf, strlen (buf), 1); -} - -/* Come here when we get an input interrupt from the remote side. This - interrupt should only be active while we are waiting for the child to do - something. Thus this assumes readchar:bufcnt is 0. - About the only thing that should come through is a ^C, which - will cause us to request child interruption. */ - -static void -input_interrupt (int unused) -{ - fd_set readset; - struct timeval immediate = { 0, 0 }; - - /* Protect against spurious interrupts. This has been observed to - be a problem under NetBSD 1.4 and 1.5. */ - - FD_ZERO (&readset); - FD_SET (remote_desc, &readset); - if (select (remote_desc + 1, &readset, 0, 0, &immediate) > 0) - { - int cc; - char c = 0; - - cc = read_prim (&c, 1); - - if (cc == 0) - { - fprintf (stderr, "client connection closed\n"); - return; - } - else if (cc != 1 || c != '\003') - { - fprintf (stderr, "input_interrupt, count = %d c = %d ", cc, c); - if (isprint (c)) - fprintf (stderr, "('%c')\n", c); - else - fprintf (stderr, "('\\x%02x')\n", c & 0xff); - return; - } - - (*the_target->request_interrupt) (); - } -} - -/* Check if the remote side sent us an interrupt request (^C). */ -void -check_remote_input_interrupt_request (void) -{ - /* This function may be called before establishing communications, - therefore we need to validate the remote descriptor. */ - - if (remote_desc == INVALID_DESCRIPTOR) - return; - - input_interrupt (0); -} - -/* Asynchronous I/O support. SIGIO must be unblocked when waiting, - in order to accept Control-C from the client, and must be blocked - when talking to the client. */ - -static void -block_unblock_async_io (int block) -{ -#ifndef USE_WIN32API - sigset_t sigio_set; - - sigemptyset (&sigio_set); - sigaddset (&sigio_set, SIGIO); - gdb_sigmask (block ? SIG_BLOCK : SIG_UNBLOCK, &sigio_set, NULL); -#endif -} - -#ifdef __QNX__ -static void -nto_comctrl (int enable) -{ - struct sigevent event; - - if (enable) - { - event.sigev_notify = SIGEV_SIGNAL_THREAD; - event.sigev_signo = SIGIO; - event.sigev_code = 0; - event.sigev_value.sival_ptr = NULL; - event.sigev_priority = -1; - ionotify (remote_desc, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT, - &event); - } - else - ionotify (remote_desc, _NOTIFY_ACTION_POLL, _NOTIFY_COND_INPUT, NULL); -} -#endif /* __QNX__ */ - - -/* Current state of asynchronous I/O. */ -static int async_io_enabled; - -/* Enable asynchronous I/O. */ -void -enable_async_io (void) -{ - if (async_io_enabled) - return; - - block_unblock_async_io (0); - - async_io_enabled = 1; -#ifdef __QNX__ - nto_comctrl (1); -#endif /* __QNX__ */ -} - -/* Disable asynchronous I/O. */ -void -disable_async_io (void) -{ - if (!async_io_enabled) - return; - - block_unblock_async_io (1); - - async_io_enabled = 0; -#ifdef __QNX__ - nto_comctrl (0); -#endif /* __QNX__ */ - -} - -void -initialize_async_io (void) -{ - /* Make sure that async I/O starts blocked. */ - async_io_enabled = 1; - disable_async_io (); - - /* Install the signal handler. */ -#ifndef USE_WIN32API - signal (SIGIO, input_interrupt); -#endif -} - -/* Internal buffer used by readchar. - These are global to readchar because reschedule_remote needs to be - able to tell whether the buffer is empty. */ - -static unsigned char readchar_buf[BUFSIZ]; -static int readchar_bufcnt = 0; -static unsigned char *readchar_bufp; - -/* Returns next char from remote GDB. -1 if error. */ - -static int -readchar (void) -{ - int ch; - - if (readchar_bufcnt == 0) - { - readchar_bufcnt = read_prim (readchar_buf, sizeof (readchar_buf)); - - if (readchar_bufcnt <= 0) - { - if (readchar_bufcnt == 0) - { - if (remote_debug) - debug_printf ("readchar: Got EOF\n"); - } - else - perror ("readchar"); - - return -1; - } - - readchar_bufp = readchar_buf; - } - - readchar_bufcnt--; - ch = *readchar_bufp++; - reschedule (); - return ch; -} - -/* Reset the readchar state machine. */ - -static void -reset_readchar (void) -{ - readchar_bufcnt = 0; - if (readchar_callback != NOT_SCHEDULED) - { - delete_callback_event (readchar_callback); - readchar_callback = NOT_SCHEDULED; - } -} - -/* Process remaining data in readchar_buf. */ - -static int -process_remaining (void *context) -{ - int res; - - /* This is a one-shot event. */ - readchar_callback = NOT_SCHEDULED; - - if (readchar_bufcnt > 0) - res = handle_serial_event (0, NULL); - else - res = 0; - - return res; -} - -/* If there is still data in the buffer, queue another event to process it, - we can't sleep in select yet. */ - -static void -reschedule (void) -{ - if (readchar_bufcnt > 0 && readchar_callback == NOT_SCHEDULED) - readchar_callback = append_callback_event (process_remaining, NULL); -} - -/* Read a packet from the remote machine, with error checking, - and store it in BUF. Returns length of packet, or negative if error. */ - -int -getpkt (char *buf) -{ - client_state &cs = get_client_state (); - char *bp; - unsigned char csum, c1, c2; - int c; - - while (1) - { - csum = 0; - - while (1) - { - c = readchar (); - - /* The '\003' may appear before or after each packet, so - check for an input interrupt. */ - if (c == '\003') - { - (*the_target->request_interrupt) (); - continue; - } - - if (c == '$') - break; - if (remote_debug) - { - debug_printf ("[getpkt: discarding char '%c']\n", c); - debug_flush (); - } - - if (c < 0) - return -1; - } - - bp = buf; - while (1) - { - c = readchar (); - if (c < 0) - return -1; - if (c == '#') - break; - *bp++ = c; - csum += c; - } - *bp = 0; - - c1 = fromhex (readchar ()); - c2 = fromhex (readchar ()); - - if (csum == (c1 << 4) + c2) - break; - - if (cs.noack_mode) - { - fprintf (stderr, - "Bad checksum, sentsum=0x%x, csum=0x%x, " - "buf=%s [no-ack-mode, Bad medium?]\n", - (c1 << 4) + c2, csum, buf); - /* Not much we can do, GDB wasn't expecting an ack/nac. */ - break; - } - - fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", - (c1 << 4) + c2, csum, buf); - if (write_prim ("-", 1) != 1) - return -1; - } - - if (!cs.noack_mode) - { - if (remote_debug) - { - debug_printf ("getpkt (\"%s\"); [sending ack] \n", buf); - debug_flush (); - } - - if (write_prim ("+", 1) != 1) - return -1; - - if (remote_debug) - { - debug_printf ("[sent ack]\n"); - debug_flush (); - } - } - else - { - if (remote_debug) - { - debug_printf ("getpkt (\"%s\"); [no ack sent] \n", buf); - debug_flush (); - } - } - - /* The readchar above may have already read a '\003' out of the socket - and moved it to the local buffer. For example, when GDB sends - vCont;c immediately followed by interrupt (see - gdb.base/interrupt-noterm.exp). As soon as we see the vCont;c, we'll - resume the inferior and wait. Since we've already moved the '\003' - to the local buffer, SIGIO won't help. In that case, if we don't - check for interrupt after the vCont;c packet, the interrupt character - would stay in the buffer unattended until after the next (unrelated) - stop. */ - while (readchar_bufcnt > 0 && *readchar_bufp == '\003') - { - /* Consume the interrupt character in the buffer. */ - readchar (); - (*the_target->request_interrupt) (); - } - - return bp - buf; -} - -void -write_ok (char *buf) -{ - buf[0] = 'O'; - buf[1] = 'K'; - buf[2] = '\0'; -} - -void -write_enn (char *buf) -{ - /* Some day, we should define the meanings of the error codes... */ - buf[0] = 'E'; - buf[1] = '0'; - buf[2] = '1'; - buf[3] = '\0'; -} - -#endif - -#ifndef IN_PROCESS_AGENT - -static char * -outreg (struct regcache *regcache, int regno, char *buf) -{ - if ((regno >> 12) != 0) - *buf++ = tohex ((regno >> 12) & 0xf); - if ((regno >> 8) != 0) - *buf++ = tohex ((regno >> 8) & 0xf); - *buf++ = tohex ((regno >> 4) & 0xf); - *buf++ = tohex (regno & 0xf); - *buf++ = ':'; - collect_register_as_string (regcache, regno, buf); - buf += 2 * register_size (regcache->tdesc, regno); - *buf++ = ';'; - - return buf; -} - -void -prepare_resume_reply (char *buf, ptid_t ptid, - struct target_waitstatus *status) -{ - client_state &cs = get_client_state (); - if (debug_threads) - debug_printf ("Writing resume reply for %s:%d\n", - target_pid_to_str (ptid), status->kind); - - switch (status->kind) - { - case TARGET_WAITKIND_STOPPED: - case TARGET_WAITKIND_FORKED: - case TARGET_WAITKIND_VFORKED: - case TARGET_WAITKIND_VFORK_DONE: - case TARGET_WAITKIND_EXECD: - case TARGET_WAITKIND_THREAD_CREATED: - case TARGET_WAITKIND_SYSCALL_ENTRY: - case TARGET_WAITKIND_SYSCALL_RETURN: - { - struct thread_info *saved_thread; - const char **regp; - struct regcache *regcache; - - if ((status->kind == TARGET_WAITKIND_FORKED && cs.report_fork_events) - || (status->kind == TARGET_WAITKIND_VFORKED - && cs.report_vfork_events)) - { - enum gdb_signal signal = GDB_SIGNAL_TRAP; - const char *event = (status->kind == TARGET_WAITKIND_FORKED - ? "fork" : "vfork"); - - sprintf (buf, "T%02x%s:", signal, event); - buf += strlen (buf); - buf = write_ptid (buf, status->value.related_pid); - strcat (buf, ";"); - } - else if (status->kind == TARGET_WAITKIND_VFORK_DONE - && cs.report_vfork_events) - { - enum gdb_signal signal = GDB_SIGNAL_TRAP; - - sprintf (buf, "T%02xvforkdone:;", signal); - } - else if (status->kind == TARGET_WAITKIND_EXECD && cs.report_exec_events) - { - enum gdb_signal signal = GDB_SIGNAL_TRAP; - const char *event = "exec"; - char hexified_pathname[PATH_MAX * 2]; - - sprintf (buf, "T%02x%s:", signal, event); - buf += strlen (buf); - - /* Encode pathname to hexified format. */ - bin2hex ((const gdb_byte *) status->value.execd_pathname, - hexified_pathname, - strlen (status->value.execd_pathname)); - - sprintf (buf, "%s;", hexified_pathname); - xfree (status->value.execd_pathname); - status->value.execd_pathname = NULL; - buf += strlen (buf); - } - else if (status->kind == TARGET_WAITKIND_THREAD_CREATED - && cs.report_thread_events) - { - enum gdb_signal signal = GDB_SIGNAL_TRAP; - - sprintf (buf, "T%02xcreate:;", signal); - } - else if (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY - || status->kind == TARGET_WAITKIND_SYSCALL_RETURN) - { - enum gdb_signal signal = GDB_SIGNAL_TRAP; - const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY - ? "syscall_entry" : "syscall_return"); - - sprintf (buf, "T%02x%s:%x;", signal, event, - status->value.syscall_number); - } - else - sprintf (buf, "T%02x", status->value.sig); - - buf += strlen (buf); - - saved_thread = current_thread; - - switch_to_thread (the_target, ptid); - - regp = current_target_desc ()->expedite_regs; - - regcache = get_thread_regcache (current_thread, 1); - - if (the_target->stopped_by_watchpoint != NULL - && (*the_target->stopped_by_watchpoint) ()) - { - CORE_ADDR addr; - int i; - - memcpy (buf, "watch:", 6); - buf += 6; - - addr = (*the_target->stopped_data_address) (); - - /* Convert each byte of the address into two hexadecimal - chars. Note that we take sizeof (void *) instead of - sizeof (addr); this is to avoid sending a 64-bit - address to a 32-bit GDB. */ - for (i = sizeof (void *) * 2; i > 0; i--) - *buf++ = tohex ((addr >> (i - 1) * 4) & 0xf); - *buf++ = ';'; - } - else if (cs.swbreak_feature && target_stopped_by_sw_breakpoint ()) - { - sprintf (buf, "swbreak:;"); - buf += strlen (buf); - } - else if (cs.hwbreak_feature && target_stopped_by_hw_breakpoint ()) - { - sprintf (buf, "hwbreak:;"); - buf += strlen (buf); - } - - while (*regp) - { - buf = outreg (regcache, find_regno (regcache->tdesc, *regp), buf); - regp ++; - } - *buf = '\0'; - - /* Formerly, if the debugger had not used any thread features - we would not burden it with a thread status response. This - was for the benefit of GDB 4.13 and older. However, in - recent GDB versions the check (``if (cont_thread != 0)'') - does not have the desired effect because of sillyness in - the way that the remote protocol handles specifying a - thread. Since thread support relies on qSymbol support - anyway, assume GDB can handle threads. */ - - if (using_threads && !disable_packet_Tthread) - { - /* This if (1) ought to be unnecessary. But remote_wait - in GDB will claim this event belongs to inferior_ptid - if we do not specify a thread, and there's no way for - gdbserver to know what inferior_ptid is. */ - if (1 || cs.general_thread != ptid) - { - int core = -1; - /* In non-stop, don't change the general thread behind - GDB's back. */ - if (!non_stop) - cs.general_thread = ptid; - sprintf (buf, "thread:"); - buf += strlen (buf); - buf = write_ptid (buf, ptid); - strcat (buf, ";"); - buf += strlen (buf); - - core = target_core_of_thread (ptid); - - if (core != -1) - { - sprintf (buf, "core:"); - buf += strlen (buf); - sprintf (buf, "%x", core); - strcat (buf, ";"); - buf += strlen (buf); - } - } - } - - if (dlls_changed) - { - strcpy (buf, "library:;"); - buf += strlen (buf); - dlls_changed = 0; - } - - current_thread = saved_thread; - } - break; - case TARGET_WAITKIND_EXITED: - if (cs.multi_process) - sprintf (buf, "W%x;process:%x", - status->value.integer, ptid.pid ()); - else - sprintf (buf, "W%02x", status->value.integer); - break; - case TARGET_WAITKIND_SIGNALLED: - if (cs.multi_process) - sprintf (buf, "X%x;process:%x", - status->value.sig, ptid.pid ()); - else - sprintf (buf, "X%02x", status->value.sig); - break; - case TARGET_WAITKIND_THREAD_EXITED: - sprintf (buf, "w%x;", status->value.integer); - buf += strlen (buf); - buf = write_ptid (buf, ptid); - break; - case TARGET_WAITKIND_NO_RESUMED: - sprintf (buf, "N"); - break; - default: - error ("unhandled waitkind"); - break; - } -} - -void -decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr) -{ - int i = 0, j = 0; - char ch; - *mem_addr_ptr = *len_ptr = 0; - - while ((ch = from[i++]) != ',') - { - *mem_addr_ptr = *mem_addr_ptr << 4; - *mem_addr_ptr |= fromhex (ch) & 0x0f; - } - - for (j = 0; j < 4; j++) - { - if ((ch = from[i++]) == 0) - break; - *len_ptr = *len_ptr << 4; - *len_ptr |= fromhex (ch) & 0x0f; - } -} - -void -decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, - unsigned char **to_p) -{ - int i = 0; - char ch; - *mem_addr_ptr = *len_ptr = 0; - - while ((ch = from[i++]) != ',') - { - *mem_addr_ptr = *mem_addr_ptr << 4; - *mem_addr_ptr |= fromhex (ch) & 0x0f; - } - - while ((ch = from[i++]) != ':') - { - *len_ptr = *len_ptr << 4; - *len_ptr |= fromhex (ch) & 0x0f; - } - - if (*to_p == NULL) - *to_p = (unsigned char *) xmalloc (*len_ptr); - - hex2bin (&from[i++], *to_p, *len_ptr); -} - -int -decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr, - unsigned int *len_ptr, unsigned char **to_p) -{ - int i = 0; - char ch; - *mem_addr_ptr = *len_ptr = 0; - - while ((ch = from[i++]) != ',') - { - *mem_addr_ptr = *mem_addr_ptr << 4; - *mem_addr_ptr |= fromhex (ch) & 0x0f; - } - - while ((ch = from[i++]) != ':') - { - *len_ptr = *len_ptr << 4; - *len_ptr |= fromhex (ch) & 0x0f; - } - - if (*to_p == NULL) - *to_p = (unsigned char *) xmalloc (*len_ptr); - - if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i, - *to_p, *len_ptr) != *len_ptr) - return -1; - - return 0; -} - -/* Decode a qXfer write request. */ - -int -decode_xfer_write (char *buf, int packet_len, CORE_ADDR *offset, - unsigned int *len, unsigned char *data) -{ - char ch; - char *b = buf; - - /* Extract the offset. */ - *offset = 0; - while ((ch = *buf++) != ':') - { - *offset = *offset << 4; - *offset |= fromhex (ch) & 0x0f; - } - - /* Get encoded data. */ - packet_len -= buf - b; - *len = remote_unescape_input ((const gdb_byte *) buf, packet_len, - data, packet_len); - return 0; -} - -/* Decode the parameters of a qSearch:memory packet. */ - -int -decode_search_memory_packet (const char *buf, int packet_len, - CORE_ADDR *start_addrp, - CORE_ADDR *search_space_lenp, - gdb_byte *pattern, unsigned int *pattern_lenp) -{ - const char *p = buf; - - p = decode_address_to_semicolon (start_addrp, p); - p = decode_address_to_semicolon (search_space_lenp, p); - packet_len -= p - buf; - *pattern_lenp = remote_unescape_input ((const gdb_byte *) p, packet_len, - pattern, packet_len); - return 0; -} - -static void -free_sym_cache (struct sym_cache *sym) -{ - if (sym != NULL) - { - free (sym->name); - free (sym); - } -} - -void -clear_symbol_cache (struct sym_cache **symcache_p) -{ - struct sym_cache *sym, *next; - - /* Check the cache first. */ - for (sym = *symcache_p; sym; sym = next) - { - next = sym->next; - free_sym_cache (sym); - } - - *symcache_p = NULL; -} - -/* Get the address of NAME, and return it in ADDRP if found. if - MAY_ASK_GDB is false, assume symbol cache misses are failures. - Returns 1 if the symbol is found, 0 if it is not, -1 on error. */ - -int -look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb) -{ - client_state &cs = get_client_state (); - char *p, *q; - int len; - struct sym_cache *sym; - struct process_info *proc; - - proc = current_process (); - - /* Check the cache first. */ - for (sym = proc->symbol_cache; sym; sym = sym->next) - if (strcmp (name, sym->name) == 0) - { - *addrp = sym->addr; - return 1; - } - - /* It might not be an appropriate time to look up a symbol, - e.g. while we're trying to fetch registers. */ - if (!may_ask_gdb) - return 0; - - /* Send the request. */ - strcpy (cs.own_buf, "qSymbol:"); - bin2hex ((const gdb_byte *) name, cs.own_buf + strlen ("qSymbol:"), - strlen (name)); - if (putpkt (cs.own_buf) < 0) - return -1; - - /* FIXME: Eventually add buffer overflow checking (to getpkt?) */ - len = getpkt (cs.own_buf); - if (len < 0) - return -1; - - /* We ought to handle pretty much any packet at this point while we - wait for the qSymbol "response". That requires re-entering the - main loop. For now, this is an adequate approximation; allow - GDB to read from memory and handle 'v' packets (for vFile transfers) - while it figures out the address of the symbol. */ - while (1) - { - if (cs.own_buf[0] == 'm') - { - CORE_ADDR mem_addr; - unsigned char *mem_buf; - unsigned int mem_len; - - decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len); - mem_buf = (unsigned char *) xmalloc (mem_len); - if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0) - bin2hex (mem_buf, cs.own_buf, mem_len); - else - write_enn (cs.own_buf); - free (mem_buf); - if (putpkt (cs.own_buf) < 0) - return -1; - } - else if (cs.own_buf[0] == 'v') - { - int new_len = -1; - handle_v_requests (cs.own_buf, len, &new_len); - if (new_len != -1) - putpkt_binary (cs.own_buf, new_len); - else - putpkt (cs.own_buf); - } - else - break; - len = getpkt (cs.own_buf); - if (len < 0) - return -1; - } - - if (!startswith (cs.own_buf, "qSymbol:")) - { - warning ("Malformed response to qSymbol, ignoring: %s", cs.own_buf); - return -1; - } - - p = cs.own_buf + strlen ("qSymbol:"); - q = p; - while (*q && *q != ':') - q++; - - /* Make sure we found a value for the symbol. */ - if (p == q || *q == '\0') - return 0; - - decode_address (addrp, p, q - p); - - /* Save the symbol in our cache. */ - sym = XNEW (struct sym_cache); - sym->name = xstrdup (name); - sym->addr = *addrp; - sym->next = proc->symbol_cache; - proc->symbol_cache = sym; - - return 1; -} - -/* Relocate an instruction to execute at a different address. OLDLOC - is the address in the inferior memory where the instruction to - relocate is currently at. On input, TO points to the destination - where we want the instruction to be copied (and possibly adjusted) - to. On output, it points to one past the end of the resulting - instruction(s). The effect of executing the instruction at TO - shall be the same as if executing it at OLDLOC. For example, call - instructions that implicitly push the return address on the stack - should be adjusted to return to the instruction after OLDLOC; - relative branches, and other PC-relative instructions need the - offset adjusted; etc. Returns 0 on success, -1 on failure. */ - -int -relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc) -{ - client_state &cs = get_client_state (); - int len; - ULONGEST written = 0; - - /* Send the request. */ - sprintf (cs.own_buf, "qRelocInsn:%s;%s", paddress (oldloc), - paddress (*to)); - if (putpkt (cs.own_buf) < 0) - return -1; - - /* FIXME: Eventually add buffer overflow checking (to getpkt?) */ - len = getpkt (cs.own_buf); - if (len < 0) - return -1; - - /* We ought to handle pretty much any packet at this point while we - wait for the qRelocInsn "response". That requires re-entering - the main loop. For now, this is an adequate approximation; allow - GDB to access memory. */ - while (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'M' || cs.own_buf[0] == 'X') - { - CORE_ADDR mem_addr; - unsigned char *mem_buf = NULL; - unsigned int mem_len; - - if (cs.own_buf[0] == 'm') - { - decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len); - mem_buf = (unsigned char *) xmalloc (mem_len); - if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0) - bin2hex (mem_buf, cs.own_buf, mem_len); - else - write_enn (cs.own_buf); - } - else if (cs.own_buf[0] == 'X') - { - if (decode_X_packet (&cs.own_buf[1], len - 1, &mem_addr, - &mem_len, &mem_buf) < 0 - || target_write_memory (mem_addr, mem_buf, mem_len) != 0) - write_enn (cs.own_buf); - else - write_ok (cs.own_buf); - } - else - { - decode_M_packet (&cs.own_buf[1], &mem_addr, &mem_len, &mem_buf); - if (target_write_memory (mem_addr, mem_buf, mem_len) == 0) - write_ok (cs.own_buf); - else - write_enn (cs.own_buf); - } - free (mem_buf); - if (putpkt (cs.own_buf) < 0) - return -1; - len = getpkt (cs.own_buf); - if (len < 0) - return -1; - } - - if (cs.own_buf[0] == 'E') - { - warning ("An error occurred while relocating an instruction: %s", - cs.own_buf); - return -1; - } - - if (!startswith (cs.own_buf, "qRelocInsn:")) - { - warning ("Malformed response to qRelocInsn, ignoring: %s", - cs.own_buf); - return -1; - } - - unpack_varlen_hex (cs.own_buf + strlen ("qRelocInsn:"), &written); - - *to += written; - return 0; -} - -void -monitor_output (const char *msg) -{ - int len = strlen (msg); - char *buf = (char *) xmalloc (len * 2 + 2); - - buf[0] = 'O'; - bin2hex ((const gdb_byte *) msg, buf + 1, len); - - putpkt (buf); - free (buf); -} - -#endif diff --git a/gdb/gdbserver/remote-utils.h b/gdb/gdbserver/remote-utils.h deleted file mode 100644 index 1b31456798b..00000000000 --- a/gdb/gdbserver/remote-utils.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Remote utility routines for the remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_REMOTE_UTILS_H -#define GDBSERVER_REMOTE_UTILS_H - -int gdb_connected (void); - -#define STDIO_CONNECTION_NAME "stdio" -int remote_connection_is_stdio (void); - -ptid_t read_ptid (const char *buf, const char **obuf); -char *write_ptid (char *buf, ptid_t ptid); - -int putpkt (char *buf); -int putpkt_binary (char *buf, int len); -int putpkt_notif (char *buf); -int getpkt (char *buf); -void remote_prepare (const char *name); -void remote_open (const char *name); -void remote_close (void); -void write_ok (char *buf); -void write_enn (char *buf); -void initialize_async_io (void); -void enable_async_io (void); -void disable_async_io (void); -void check_remote_input_interrupt_request (void); -void prepare_resume_reply (char *buf, ptid_t ptid, - struct target_waitstatus *status); - -const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start); -void decode_address (CORE_ADDR *addrp, const char *start, int len); -void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr, - unsigned int *len_ptr); -void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr, - unsigned int *len_ptr, unsigned char **to_p); -int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr, - unsigned int *len_ptr, unsigned char **to_p); -int decode_xfer_write (char *buf, int packet_len, - CORE_ADDR *offset, unsigned int *len, - unsigned char *data); -int decode_search_memory_packet (const char *buf, int packet_len, - CORE_ADDR *start_addrp, - CORE_ADDR *search_space_lenp, - gdb_byte *pattern, - unsigned int *pattern_lenp); - -void clear_symbol_cache (struct sym_cache **symcache_p); -int look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb); - -int relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc); - -void monitor_output (const char *msg); - -#endif /* GDBSERVER_REMOTE_UTILS_H */ diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c deleted file mode 100644 index 3fc026f78eb..00000000000 --- a/gdb/gdbserver/server.c +++ /dev/null @@ -1,4485 +0,0 @@ -/* Main code for remote server for GDB. - Copyright (C) 1989-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "gdbthread.h" -#include "gdbsupport/agent.h" -#include "notif.h" -#include "tdesc.h" -#include "gdbsupport/rsp-low.h" -#include "gdbsupport/signals-state-save-restore.h" -#include -#include -#if HAVE_SIGNAL_H -#include -#endif -#include "gdbsupport/gdb_vecs.h" -#include "gdbsupport/gdb_wait.h" -#include "gdbsupport/btrace-common.h" -#include "gdbsupport/filestuff.h" -#include "tracepoint.h" -#include "dll.h" -#include "hostio.h" -#include -#include "gdbsupport/common-inferior.h" -#include "gdbsupport/job-control.h" -#include "gdbsupport/environ.h" -#include "filenames.h" -#include "gdbsupport/pathstuff.h" -#ifdef USE_XML -#include "xml-builtin.h" -#endif - -#include "gdbsupport/selftest.h" -#include "gdbsupport/scope-exit.h" - -#define require_running_or_return(BUF) \ - if (!target_running ()) \ - { \ - write_enn (BUF); \ - return; \ - } - -#define require_running_or_break(BUF) \ - if (!target_running ()) \ - { \ - write_enn (BUF); \ - break; \ - } - -/* String containing the current directory (what getwd would return). */ - -char *current_directory; - -/* The environment to pass to the inferior when creating it. */ - -static gdb_environ our_environ; - -bool server_waiting; - -static bool extended_protocol; -static bool response_needed; -static bool exit_requested; - -/* --once: Exit after the first connection has closed. */ -bool run_once; - -/* Whether to report TARGET_WAITKIND_NO_RESUMED events. */ -static bool report_no_resumed; - -bool non_stop; - -static struct { - /* Set the PROGRAM_PATH. Here we adjust the path of the provided - binary if needed. */ - void set (gdb::unique_xmalloc_ptr &&path) - { - m_path = std::move (path); - - /* Make sure we're using the absolute path of the inferior when - creating it. */ - if (!contains_dir_separator (m_path.get ())) - { - int reg_file_errno; - - /* Check if the file is in our CWD. If it is, then we prefix - its name with CURRENT_DIRECTORY. Otherwise, we leave the - name as-is because we'll try searching for it in $PATH. */ - if (is_regular_file (m_path.get (), ®_file_errno)) - m_path = gdb_abspath (m_path.get ()); - } - } - - /* Return the PROGRAM_PATH. */ - char *get () - { return m_path.get (); } - -private: - /* The program name, adjusted if needed. */ - gdb::unique_xmalloc_ptr m_path; -} program_path; -static std::vector program_args; -static std::string wrapper_argv; - -/* The PID of the originally created or attached inferior. Used to - send signals to the process when GDB sends us an asynchronous interrupt - (user hitting Control-C in the client), and to wait for the child to exit - when no longer debugging it. */ - -unsigned long signal_pid; - -/* Set if you want to disable optional thread related packets support - in gdbserver, for the sake of testing GDB against stubs that don't - support them. */ -bool disable_packet_vCont; -bool disable_packet_Tthread; -bool disable_packet_qC; -bool disable_packet_qfThreadInfo; - -static unsigned char *mem_buf; - -/* A sub-class of 'struct notif_event' for stop, holding information - relative to a single stop reply. We keep a queue of these to - push to GDB in non-stop mode. */ - -struct vstop_notif : public notif_event -{ - /* Thread or process that got the event. */ - ptid_t ptid; - - /* Event info. */ - struct target_waitstatus status; -}; - -/* The current btrace configuration. This is gdbserver's mirror of GDB's - btrace configuration. */ -static struct btrace_config current_btrace_conf; - -/* The client remote protocol state. */ - -static client_state g_client_state; - -client_state & -get_client_state () -{ - client_state &cs = g_client_state; - return cs; -} - - -/* Put a stop reply to the stop reply queue. */ - -static void -queue_stop_reply (ptid_t ptid, struct target_waitstatus *status) -{ - struct vstop_notif *new_notif = new struct vstop_notif; - - new_notif->ptid = ptid; - new_notif->status = *status; - - notif_event_enque (¬if_stop, new_notif); -} - -static bool -remove_all_on_match_ptid (struct notif_event *event, ptid_t filter_ptid) -{ - struct vstop_notif *vstop_event = (struct vstop_notif *) event; - - return vstop_event->ptid.matches (filter_ptid); -} - -/* See server.h. */ - -void -discard_queued_stop_replies (ptid_t ptid) -{ - std::list::iterator iter, next, end; - end = notif_stop.queue.end (); - for (iter = notif_stop.queue.begin (); iter != end; iter = next) - { - next = iter; - ++next; - - if (remove_all_on_match_ptid (*iter, ptid)) - { - delete *iter; - notif_stop.queue.erase (iter); - } - } -} - -static void -vstop_notif_reply (struct notif_event *event, char *own_buf) -{ - struct vstop_notif *vstop = (struct vstop_notif *) event; - - prepare_resume_reply (own_buf, vstop->ptid, &vstop->status); -} - -/* Helper for in_queued_stop_replies. */ - -static bool -in_queued_stop_replies_ptid (struct notif_event *event, ptid_t filter_ptid) -{ - struct vstop_notif *vstop_event = (struct vstop_notif *) event; - - if (vstop_event->ptid.matches (filter_ptid)) - return true; - - /* Don't resume fork children that GDB does not know about yet. */ - if ((vstop_event->status.kind == TARGET_WAITKIND_FORKED - || vstop_event->status.kind == TARGET_WAITKIND_VFORKED) - && vstop_event->status.value.related_pid.matches (filter_ptid)) - return true; - - return false; -} - -/* See server.h. */ - -int -in_queued_stop_replies (ptid_t ptid) -{ - for (notif_event *event : notif_stop.queue) - { - if (in_queued_stop_replies_ptid (event, ptid)) - return true; - } - - return false; -} - -struct notif_server notif_stop = -{ - "vStopped", "Stop", {}, vstop_notif_reply, -}; - -static int -target_running (void) -{ - return get_first_thread () != NULL; -} - -/* See gdbsupport/common-inferior.h. */ - -const char * -get_exec_wrapper () -{ - return !wrapper_argv.empty () ? wrapper_argv.c_str () : NULL; -} - -/* See gdbsupport/common-inferior.h. */ - -const char * -get_exec_file (int err) -{ - if (err && program_path.get () == NULL) - error (_("No executable file specified.")); - - return program_path.get (); -} - -/* See server.h. */ - -gdb_environ * -get_environ () -{ - return &our_environ; -} - -static int -attach_inferior (int pid) -{ - client_state &cs = get_client_state (); - /* myattach should return -1 if attaching is unsupported, - 0 if it succeeded, and call error() otherwise. */ - - if (find_process_pid (pid) != nullptr) - error ("Already attached to process %d\n", pid); - - if (myattach (pid) != 0) - return -1; - - fprintf (stderr, "Attached; pid = %d\n", pid); - fflush (stderr); - - /* FIXME - It may be that we should get the SIGNAL_PID from the - attach function, so that it can be the main thread instead of - whichever we were told to attach to. */ - signal_pid = pid; - - if (!non_stop) - { - cs.last_ptid = mywait (ptid_t (pid), &cs.last_status, 0, 0); - - /* GDB knows to ignore the first SIGSTOP after attaching to a running - process using the "attach" command, but this is different; it's - just using "target remote". Pretend it's just starting up. */ - if (cs.last_status.kind == TARGET_WAITKIND_STOPPED - && cs.last_status.value.sig == GDB_SIGNAL_STOP) - cs.last_status.value.sig = GDB_SIGNAL_TRAP; - - current_thread->last_resume_kind = resume_stop; - current_thread->last_status = cs.last_status; - } - - return 0; -} - -/* Decode a qXfer read request. Return 0 if everything looks OK, - or -1 otherwise. */ - -static int -decode_xfer_read (char *buf, CORE_ADDR *ofs, unsigned int *len) -{ - /* After the read marker and annex, qXfer looks like a - traditional 'm' packet. */ - decode_m_packet (buf, ofs, len); - - return 0; -} - -static int -decode_xfer (char *buf, char **object, char **rw, char **annex, char **offset) -{ - /* Extract and NUL-terminate the object. */ - *object = buf; - while (*buf && *buf != ':') - buf++; - if (*buf == '\0') - return -1; - *buf++ = 0; - - /* Extract and NUL-terminate the read/write action. */ - *rw = buf; - while (*buf && *buf != ':') - buf++; - if (*buf == '\0') - return -1; - *buf++ = 0; - - /* Extract and NUL-terminate the annex. */ - *annex = buf; - while (*buf && *buf != ':') - buf++; - if (*buf == '\0') - return -1; - *buf++ = 0; - - *offset = buf; - return 0; -} - -/* Write the response to a successful qXfer read. Returns the - length of the (binary) data stored in BUF, corresponding - to as much of DATA/LEN as we could fit. IS_MORE controls - the first character of the response. */ -static int -write_qxfer_response (char *buf, const gdb_byte *data, int len, int is_more) -{ - int out_len; - - if (is_more) - buf[0] = 'm'; - else - buf[0] = 'l'; - - return remote_escape_output (data, len, 1, (unsigned char *) buf + 1, - &out_len, PBUFSIZ - 2) + 1; -} - -/* Handle btrace enabling in BTS format. */ - -static void -handle_btrace_enable_bts (struct thread_info *thread) -{ - if (thread->btrace != NULL) - error (_("Btrace already enabled.")); - - current_btrace_conf.format = BTRACE_FORMAT_BTS; - thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf); -} - -/* Handle btrace enabling in Intel Processor Trace format. */ - -static void -handle_btrace_enable_pt (struct thread_info *thread) -{ - if (thread->btrace != NULL) - error (_("Btrace already enabled.")); - - current_btrace_conf.format = BTRACE_FORMAT_PT; - thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf); -} - -/* Handle btrace disabling. */ - -static void -handle_btrace_disable (struct thread_info *thread) -{ - - if (thread->btrace == NULL) - error (_("Branch tracing not enabled.")); - - if (target_disable_btrace (thread->btrace) != 0) - error (_("Could not disable branch tracing.")); - - thread->btrace = NULL; -} - -/* Handle the "Qbtrace" packet. */ - -static int -handle_btrace_general_set (char *own_buf) -{ - client_state &cs = get_client_state (); - struct thread_info *thread; - char *op; - - if (!startswith (own_buf, "Qbtrace:")) - return 0; - - op = own_buf + strlen ("Qbtrace:"); - - if (cs.general_thread == null_ptid - || cs.general_thread == minus_one_ptid) - { - strcpy (own_buf, "E.Must select a single thread."); - return -1; - } - - thread = find_thread_ptid (cs.general_thread); - if (thread == NULL) - { - strcpy (own_buf, "E.No such thread."); - return -1; - } - - try - { - if (strcmp (op, "bts") == 0) - handle_btrace_enable_bts (thread); - else if (strcmp (op, "pt") == 0) - handle_btrace_enable_pt (thread); - else if (strcmp (op, "off") == 0) - handle_btrace_disable (thread); - else - error (_("Bad Qbtrace operation. Use bts, pt, or off.")); - - write_ok (own_buf); - } - catch (const gdb_exception_error &exception) - { - sprintf (own_buf, "E.%s", exception.what ()); - } - - return 1; -} - -/* Handle the "Qbtrace-conf" packet. */ - -static int -handle_btrace_conf_general_set (char *own_buf) -{ - client_state &cs = get_client_state (); - struct thread_info *thread; - char *op; - - if (!startswith (own_buf, "Qbtrace-conf:")) - return 0; - - op = own_buf + strlen ("Qbtrace-conf:"); - - if (cs.general_thread == null_ptid - || cs.general_thread == minus_one_ptid) - { - strcpy (own_buf, "E.Must select a single thread."); - return -1; - } - - thread = find_thread_ptid (cs.general_thread); - if (thread == NULL) - { - strcpy (own_buf, "E.No such thread."); - return -1; - } - - if (startswith (op, "bts:size=")) - { - unsigned long size; - char *endp = NULL; - - errno = 0; - size = strtoul (op + strlen ("bts:size="), &endp, 16); - if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX) - { - strcpy (own_buf, "E.Bad size value."); - return -1; - } - - current_btrace_conf.bts.size = (unsigned int) size; - } - else if (strncmp (op, "pt:size=", strlen ("pt:size=")) == 0) - { - unsigned long size; - char *endp = NULL; - - errno = 0; - size = strtoul (op + strlen ("pt:size="), &endp, 16); - if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX) - { - strcpy (own_buf, "E.Bad size value."); - return -1; - } - - current_btrace_conf.pt.size = (unsigned int) size; - } - else - { - strcpy (own_buf, "E.Bad Qbtrace configuration option."); - return -1; - } - - write_ok (own_buf); - return 1; -} - -/* Handle all of the extended 'Q' packets. */ - -static void -handle_general_set (char *own_buf) -{ - client_state &cs = get_client_state (); - if (startswith (own_buf, "QPassSignals:")) - { - int numsigs = (int) GDB_SIGNAL_LAST, i; - const char *p = own_buf + strlen ("QPassSignals:"); - CORE_ADDR cursig; - - p = decode_address_to_semicolon (&cursig, p); - for (i = 0; i < numsigs; i++) - { - if (i == cursig) - { - cs.pass_signals[i] = 1; - if (*p == '\0') - /* Keep looping, to clear the remaining signals. */ - cursig = -1; - else - p = decode_address_to_semicolon (&cursig, p); - } - else - cs.pass_signals[i] = 0; - } - strcpy (own_buf, "OK"); - return; - } - - if (startswith (own_buf, "QProgramSignals:")) - { - int numsigs = (int) GDB_SIGNAL_LAST, i; - const char *p = own_buf + strlen ("QProgramSignals:"); - CORE_ADDR cursig; - - cs.program_signals_p = 1; - - p = decode_address_to_semicolon (&cursig, p); - for (i = 0; i < numsigs; i++) - { - if (i == cursig) - { - cs.program_signals[i] = 1; - if (*p == '\0') - /* Keep looping, to clear the remaining signals. */ - cursig = -1; - else - p = decode_address_to_semicolon (&cursig, p); - } - else - cs.program_signals[i] = 0; - } - strcpy (own_buf, "OK"); - return; - } - - if (startswith (own_buf, "QCatchSyscalls:")) - { - const char *p = own_buf + sizeof ("QCatchSyscalls:") - 1; - int enabled = -1; - CORE_ADDR sysno; - struct process_info *process; - - if (!target_running () || !target_supports_catch_syscall ()) - { - write_enn (own_buf); - return; - } - - if (strcmp (p, "0") == 0) - enabled = 0; - else if (p[0] == '1' && (p[1] == ';' || p[1] == '\0')) - enabled = 1; - else - { - fprintf (stderr, "Unknown catch-syscalls mode requested: %s\n", - own_buf); - write_enn (own_buf); - return; - } - - process = current_process (); - process->syscalls_to_catch.clear (); - - if (enabled) - { - p += 1; - if (*p == ';') - { - p += 1; - while (*p != '\0') - { - p = decode_address_to_semicolon (&sysno, p); - process->syscalls_to_catch.push_back (sysno); - } - } - else - process->syscalls_to_catch.push_back (ANY_SYSCALL); - } - - write_ok (own_buf); - return; - } - - if (strcmp (own_buf, "QEnvironmentReset") == 0) - { - our_environ = gdb_environ::from_host_environ (); - - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "QEnvironmentHexEncoded:")) - { - const char *p = own_buf + sizeof ("QEnvironmentHexEncoded:") - 1; - /* The final form of the environment variable. FINAL_VAR will - hold the 'VAR=VALUE' format. */ - std::string final_var = hex2str (p); - std::string var_name, var_value; - - if (remote_debug) - { - debug_printf (_("[QEnvironmentHexEncoded received '%s']\n"), p); - debug_printf (_("[Environment variable to be set: '%s']\n"), - final_var.c_str ()); - debug_flush (); - } - - size_t pos = final_var.find ('='); - if (pos == std::string::npos) - { - warning (_("Unexpected format for environment variable: '%s'"), - final_var.c_str ()); - write_enn (own_buf); - return; - } - - var_name = final_var.substr (0, pos); - var_value = final_var.substr (pos + 1, std::string::npos); - - our_environ.set (var_name.c_str (), var_value.c_str ()); - - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "QEnvironmentUnset:")) - { - const char *p = own_buf + sizeof ("QEnvironmentUnset:") - 1; - std::string varname = hex2str (p); - - if (remote_debug) - { - debug_printf (_("[QEnvironmentUnset received '%s']\n"), p); - debug_printf (_("[Environment variable to be unset: '%s']\n"), - varname.c_str ()); - debug_flush (); - } - - our_environ.unset (varname.c_str ()); - - write_ok (own_buf); - return; - } - - if (strcmp (own_buf, "QStartNoAckMode") == 0) - { - if (remote_debug) - { - debug_printf ("[noack mode enabled]\n"); - debug_flush (); - } - - cs.noack_mode = 1; - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "QNonStop:")) - { - char *mode = own_buf + 9; - int req = -1; - const char *req_str; - - if (strcmp (mode, "0") == 0) - req = 0; - else if (strcmp (mode, "1") == 0) - req = 1; - else - { - /* We don't know what this mode is, so complain to - GDB. */ - fprintf (stderr, "Unknown non-stop mode requested: %s\n", - own_buf); - write_enn (own_buf); - return; - } - - req_str = req ? "non-stop" : "all-stop"; - if (start_non_stop (req) != 0) - { - fprintf (stderr, "Setting %s mode failed\n", req_str); - write_enn (own_buf); - return; - } - - non_stop = (req != 0); - - if (remote_debug) - debug_printf ("[%s mode enabled]\n", req_str); - - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "QDisableRandomization:")) - { - char *packet = own_buf + strlen ("QDisableRandomization:"); - ULONGEST setting; - - unpack_varlen_hex (packet, &setting); - cs.disable_randomization = setting; - - if (remote_debug) - { - debug_printf (cs.disable_randomization - ? "[address space randomization disabled]\n" - : "[address space randomization enabled]\n"); - } - - write_ok (own_buf); - return; - } - - if (target_supports_tracepoints () - && handle_tracepoint_general_set (own_buf)) - return; - - if (startswith (own_buf, "QAgent:")) - { - char *mode = own_buf + strlen ("QAgent:"); - int req = 0; - - if (strcmp (mode, "0") == 0) - req = 0; - else if (strcmp (mode, "1") == 0) - req = 1; - else - { - /* We don't know what this value is, so complain to GDB. */ - sprintf (own_buf, "E.Unknown QAgent value"); - return; - } - - /* Update the flag. */ - use_agent = req; - if (remote_debug) - debug_printf ("[%s agent]\n", req ? "Enable" : "Disable"); - write_ok (own_buf); - return; - } - - if (handle_btrace_general_set (own_buf)) - return; - - if (handle_btrace_conf_general_set (own_buf)) - return; - - if (startswith (own_buf, "QThreadEvents:")) - { - char *mode = own_buf + strlen ("QThreadEvents:"); - enum tribool req = TRIBOOL_UNKNOWN; - - if (strcmp (mode, "0") == 0) - req = TRIBOOL_FALSE; - else if (strcmp (mode, "1") == 0) - req = TRIBOOL_TRUE; - else - { - /* We don't know what this mode is, so complain to GDB. */ - sprintf (own_buf, "E.Unknown thread-events mode requested: %s\n", - mode); - return; - } - - cs.report_thread_events = (req == TRIBOOL_TRUE); - - if (remote_debug) - { - const char *req_str = cs.report_thread_events ? "enabled" : "disabled"; - - debug_printf ("[thread events are now %s]\n", req_str); - } - - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "QStartupWithShell:")) - { - const char *value = own_buf + strlen ("QStartupWithShell:"); - - if (strcmp (value, "1") == 0) - startup_with_shell = true; - else if (strcmp (value, "0") == 0) - startup_with_shell = false; - else - { - /* Unknown value. */ - fprintf (stderr, "Unknown value to startup-with-shell: %s\n", - own_buf); - write_enn (own_buf); - return; - } - - if (remote_debug) - debug_printf (_("[Inferior will %s started with shell]"), - startup_with_shell ? "be" : "not be"); - - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "QSetWorkingDir:")) - { - const char *p = own_buf + strlen ("QSetWorkingDir:"); - - if (*p != '\0') - { - std::string path = hex2str (p); - - set_inferior_cwd (path.c_str ()); - - if (remote_debug) - debug_printf (_("[Set the inferior's current directory to %s]\n"), - path.c_str ()); - } - else - { - /* An empty argument means that we should clear out any - previously set cwd for the inferior. */ - set_inferior_cwd (NULL); - - if (remote_debug) - debug_printf (_("\ -[Unset the inferior's current directory; will use gdbserver's cwd]\n")); - } - write_ok (own_buf); - - return; - } - - /* Otherwise we didn't know what packet it was. Say we didn't - understand it. */ - own_buf[0] = 0; -} - -static const char * -get_features_xml (const char *annex) -{ - const struct target_desc *desc = current_target_desc (); - - /* `desc->xmltarget' defines what to return when looking for the - "target.xml" file. Its contents can either be verbatim XML code - (prefixed with a '@') or else the name of the actual XML file to - be used in place of "target.xml". - - This variable is set up from the auto-generated - init_registers_... routine for the current target. */ - - if (strcmp (annex, "target.xml") == 0) - { - const char *ret = tdesc_get_features_xml (desc); - - if (*ret == '@') - return ret + 1; - else - annex = ret; - } - -#ifdef USE_XML - { - int i; - - /* Look for the annex. */ - for (i = 0; xml_builtin[i][0] != NULL; i++) - if (strcmp (annex, xml_builtin[i][0]) == 0) - break; - - if (xml_builtin[i][0] != NULL) - return xml_builtin[i][1]; - } -#endif - - return NULL; -} - -static void -monitor_show_help (void) -{ - monitor_output ("The following monitor commands are supported:\n"); - monitor_output (" set debug <0|1>\n"); - monitor_output (" Enable general debugging messages\n"); - monitor_output (" set debug-hw-points <0|1>\n"); - monitor_output (" Enable h/w breakpoint/watchpoint debugging messages\n"); - monitor_output (" set remote-debug <0|1>\n"); - monitor_output (" Enable remote protocol debugging messages\n"); - monitor_output (" set debug-format option1[,option2,...]\n"); - monitor_output (" Add additional information to debugging messages\n"); - monitor_output (" Options: all, none"); - monitor_output (", timestamp"); - monitor_output ("\n"); - monitor_output (" exit\n"); - monitor_output (" Quit GDBserver\n"); -} - -/* Read trace frame or inferior memory. Returns the number of bytes - actually read, zero when no further transfer is possible, and -1 on - error. Return of a positive value smaller than LEN does not - indicate there's no more to be read, only the end of the transfer. - E.g., when GDB reads memory from a traceframe, a first request may - be served from a memory block that does not cover the whole request - length. A following request gets the rest served from either - another block (of the same traceframe) or from the read-only - regions. */ - -static int -gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - client_state &cs = get_client_state (); - int res; - - if (cs.current_traceframe >= 0) - { - ULONGEST nbytes; - ULONGEST length = len; - - if (traceframe_read_mem (cs.current_traceframe, - memaddr, myaddr, len, &nbytes)) - return -1; - /* Data read from trace buffer, we're done. */ - if (nbytes > 0) - return nbytes; - if (!in_readonly_region (memaddr, length)) - return -1; - /* Otherwise we have a valid readonly case, fall through. */ - /* (assume no half-trace half-real blocks for now) */ - } - - res = prepare_to_access_memory (); - if (res == 0) - { - if (set_desired_thread ()) - res = read_inferior_memory (memaddr, myaddr, len); - else - res = 1; - done_accessing_memory (); - - return res == 0 ? len : -1; - } - else - return -1; -} - -/* Write trace frame or inferior memory. Actually, writing to trace - frames is forbidden. */ - -static int -gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) -{ - client_state &cs = get_client_state (); - if (cs.current_traceframe >= 0) - return EIO; - else - { - int ret; - - ret = prepare_to_access_memory (); - if (ret == 0) - { - if (set_desired_thread ()) - ret = target_write_memory (memaddr, myaddr, len); - else - ret = EIO; - done_accessing_memory (); - } - return ret; - } -} - -/* Subroutine of handle_search_memory to simplify it. */ - -static int -handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len, - gdb_byte *pattern, unsigned pattern_len, - gdb_byte *search_buf, - unsigned chunk_size, unsigned search_buf_size, - CORE_ADDR *found_addrp) -{ - /* Prime the search buffer. */ - - if (gdb_read_memory (start_addr, search_buf, search_buf_size) - != search_buf_size) - { - warning ("Unable to access %ld bytes of target " - "memory at 0x%lx, halting search.", - (long) search_buf_size, (long) start_addr); - return -1; - } - - /* Perform the search. - - The loop is kept simple by allocating [N + pattern-length - 1] bytes. - When we've scanned N bytes we copy the trailing bytes to the start and - read in another N bytes. */ - - while (search_space_len >= pattern_len) - { - gdb_byte *found_ptr; - unsigned nr_search_bytes = (search_space_len < search_buf_size - ? search_space_len - : search_buf_size); - - found_ptr = (gdb_byte *) memmem (search_buf, nr_search_bytes, pattern, - pattern_len); - - if (found_ptr != NULL) - { - CORE_ADDR found_addr = start_addr + (found_ptr - search_buf); - *found_addrp = found_addr; - return 1; - } - - /* Not found in this chunk, skip to next chunk. */ - - /* Don't let search_space_len wrap here, it's unsigned. */ - if (search_space_len >= chunk_size) - search_space_len -= chunk_size; - else - search_space_len = 0; - - if (search_space_len >= pattern_len) - { - unsigned keep_len = search_buf_size - chunk_size; - CORE_ADDR read_addr = start_addr + chunk_size + keep_len; - int nr_to_read; - - /* Copy the trailing part of the previous iteration to the front - of the buffer for the next iteration. */ - memcpy (search_buf, search_buf + chunk_size, keep_len); - - nr_to_read = (search_space_len - keep_len < chunk_size - ? search_space_len - keep_len - : chunk_size); - - if (gdb_read_memory (read_addr, search_buf + keep_len, - nr_to_read) != search_buf_size) - { - warning ("Unable to access %ld bytes of target memory " - "at 0x%lx, halting search.", - (long) nr_to_read, (long) read_addr); - return -1; - } - - start_addr += chunk_size; - } - } - - /* Not found. */ - - return 0; -} - -/* Handle qSearch:memory packets. */ - -static void -handle_search_memory (char *own_buf, int packet_len) -{ - CORE_ADDR start_addr; - CORE_ADDR search_space_len; - gdb_byte *pattern; - unsigned int pattern_len; - /* NOTE: also defined in find.c testcase. */ -#define SEARCH_CHUNK_SIZE 16000 - const unsigned chunk_size = SEARCH_CHUNK_SIZE; - /* Buffer to hold memory contents for searching. */ - gdb_byte *search_buf; - unsigned search_buf_size; - int found; - CORE_ADDR found_addr; - int cmd_name_len = sizeof ("qSearch:memory:") - 1; - - pattern = (gdb_byte *) malloc (packet_len); - if (pattern == NULL) - { - error ("Unable to allocate memory to perform the search"); - strcpy (own_buf, "E00"); - return; - } - if (decode_search_memory_packet (own_buf + cmd_name_len, - packet_len - cmd_name_len, - &start_addr, &search_space_len, - pattern, &pattern_len) < 0) - { - free (pattern); - error ("Error in parsing qSearch:memory packet"); - strcpy (own_buf, "E00"); - return; - } - - search_buf_size = chunk_size + pattern_len - 1; - - /* No point in trying to allocate a buffer larger than the search space. */ - if (search_space_len < search_buf_size) - search_buf_size = search_space_len; - - search_buf = (gdb_byte *) malloc (search_buf_size); - if (search_buf == NULL) - { - free (pattern); - error ("Unable to allocate memory to perform the search"); - strcpy (own_buf, "E00"); - return; - } - - found = handle_search_memory_1 (start_addr, search_space_len, - pattern, pattern_len, - search_buf, chunk_size, search_buf_size, - &found_addr); - - if (found > 0) - sprintf (own_buf, "1,%lx", (long) found_addr); - else if (found == 0) - strcpy (own_buf, "0"); - else - strcpy (own_buf, "E00"); - - free (search_buf); - free (pattern); -} - -/* Handle the "D" packet. */ - -static void -handle_detach (char *own_buf) -{ - client_state &cs = get_client_state (); - - process_info *process; - - if (cs.multi_process) - { - /* skip 'D;' */ - int pid = strtol (&own_buf[2], NULL, 16); - - process = find_process_pid (pid); - } - else - { - process = (current_thread != nullptr - ? get_thread_process (current_thread) - : nullptr); - } - - if (process == NULL) - { - write_enn (own_buf); - return; - } - - if ((tracing && disconnected_tracing) || any_persistent_commands (process)) - { - if (tracing && disconnected_tracing) - fprintf (stderr, - "Disconnected tracing in effect, " - "leaving gdbserver attached to the process\n"); - - if (any_persistent_commands (process)) - fprintf (stderr, - "Persistent commands are present, " - "leaving gdbserver attached to the process\n"); - - /* Make sure we're in non-stop/async mode, so we we can both - wait for an async socket accept, and handle async target - events simultaneously. There's also no point either in - having the target stop all threads, when we're going to - pass signals down without informing GDB. */ - if (!non_stop) - { - if (debug_threads) - debug_printf ("Forcing non-stop mode\n"); - - non_stop = true; - start_non_stop (1); - } - - process->gdb_detached = 1; - - /* Detaching implicitly resumes all threads. */ - target_continue_no_signal (minus_one_ptid); - - write_ok (own_buf); - return; - } - - fprintf (stderr, "Detaching from process %d\n", process->pid); - stop_tracing (); - - /* We'll need this after PROCESS has been destroyed. */ - int pid = process->pid; - - if (detach_inferior (process) != 0) - write_enn (own_buf); - else - { - discard_queued_stop_replies (ptid_t (pid)); - write_ok (own_buf); - - if (extended_protocol || target_running ()) - { - /* There is still at least one inferior remaining or - we are in extended mode, so don't terminate gdbserver, - and instead treat this like a normal program exit. */ - cs.last_status.kind = TARGET_WAITKIND_EXITED; - cs.last_status.value.integer = 0; - cs.last_ptid = ptid_t (pid); - - current_thread = NULL; - } - else - { - putpkt (own_buf); - remote_close (); - - /* If we are attached, then we can exit. Otherwise, we - need to hang around doing nothing, until the child is - gone. */ - join_inferior (pid); - exit (0); - } - } -} - -/* Parse options to --debug-format= and "monitor set debug-format". - ARG is the text after "--debug-format=" or "monitor set debug-format". - IS_MONITOR is non-zero if we're invoked via "monitor set debug-format". - This triggers calls to monitor_output. - The result is an empty string if all options were parsed ok, otherwise an - error message which the caller must free. - - N.B. These commands affect all debug format settings, they are not - cumulative. If a format is not specified, it is turned off. - However, we don't go to extra trouble with things like - "monitor set debug-format all,none,timestamp". - Instead we just parse them one at a time, in order. - - The syntax for "monitor set debug" we support here is not identical - to gdb's "set debug foo on|off" because we also use this function to - parse "--debug-format=foo,bar". */ - -static std::string -parse_debug_format_options (const char *arg, int is_monitor) -{ - /* First turn all debug format options off. */ - debug_timestamp = 0; - - /* First remove leading spaces, for "monitor set debug-format". */ - while (isspace (*arg)) - ++arg; - - std::vector> options - = delim_string_to_char_ptr_vec (arg, ','); - - for (const gdb::unique_xmalloc_ptr &option : options) - { - if (strcmp (option.get (), "all") == 0) - { - debug_timestamp = 1; - if (is_monitor) - monitor_output ("All extra debug format options enabled.\n"); - } - else if (strcmp (option.get (), "none") == 0) - { - debug_timestamp = 0; - if (is_monitor) - monitor_output ("All extra debug format options disabled.\n"); - } - else if (strcmp (option.get (), "timestamp") == 0) - { - debug_timestamp = 1; - if (is_monitor) - monitor_output ("Timestamps will be added to debug output.\n"); - } - else if (*option == '\0') - { - /* An empty option, e.g., "--debug-format=foo,,bar", is ignored. */ - continue; - } - else - return string_printf ("Unknown debug-format argument: \"%s\"\n", - option.get ()); - } - - return std::string (); -} - -/* Handle monitor commands not handled by target-specific handlers. */ - -static void -handle_monitor_command (char *mon, char *own_buf) -{ - if (strcmp (mon, "set debug 1") == 0) - { - debug_threads = 1; - monitor_output ("Debug output enabled.\n"); - } - else if (strcmp (mon, "set debug 0") == 0) - { - debug_threads = 0; - monitor_output ("Debug output disabled.\n"); - } - else if (strcmp (mon, "set debug-hw-points 1") == 0) - { - show_debug_regs = 1; - monitor_output ("H/W point debugging output enabled.\n"); - } - else if (strcmp (mon, "set debug-hw-points 0") == 0) - { - show_debug_regs = 0; - monitor_output ("H/W point debugging output disabled.\n"); - } - else if (strcmp (mon, "set remote-debug 1") == 0) - { - remote_debug = 1; - monitor_output ("Protocol debug output enabled.\n"); - } - else if (strcmp (mon, "set remote-debug 0") == 0) - { - remote_debug = 0; - monitor_output ("Protocol debug output disabled.\n"); - } - else if (startswith (mon, "set debug-format ")) - { - std::string error_msg - = parse_debug_format_options (mon + sizeof ("set debug-format ") - 1, - 1); - - if (!error_msg.empty ()) - { - monitor_output (error_msg.c_str ()); - monitor_show_help (); - write_enn (own_buf); - } - } - else if (strcmp (mon, "set debug-file") == 0) - debug_set_output (nullptr); - else if (startswith (mon, "set debug-file ")) - debug_set_output (mon + sizeof ("set debug-file ") - 1); - else if (strcmp (mon, "help") == 0) - monitor_show_help (); - else if (strcmp (mon, "exit") == 0) - exit_requested = true; - else - { - monitor_output ("Unknown monitor command.\n\n"); - monitor_show_help (); - write_enn (own_buf); - } -} - -/* Associates a callback with each supported qXfer'able object. */ - -struct qxfer -{ - /* The object this handler handles. */ - const char *object; - - /* Request that the target transfer up to LEN 8-bit bytes of the - target's OBJECT. The OFFSET, for a seekable object, specifies - the starting point. The ANNEX can be used to provide additional - data-specific information to the target. - - Return the number of bytes actually transfered, zero when no - further transfer is possible, -1 on error, -2 when the transfer - is not supported, and -3 on a verbose error message that should - be preserved. Return of a positive value smaller than LEN does - not indicate the end of the object, only the end of the transfer. - - One, and only one, of readbuf or writebuf must be non-NULL. */ - int (*xfer) (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len); -}; - -/* Handle qXfer:auxv:read. */ - -static int -handle_qxfer_auxv (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - if (the_target->read_auxv == NULL || writebuf != NULL) - return -2; - - if (annex[0] != '\0' || current_thread == NULL) - return -1; - - return (*the_target->read_auxv) (offset, readbuf, len); -} - -/* Handle qXfer:exec-file:read. */ - -static int -handle_qxfer_exec_file (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - char *file; - ULONGEST pid; - int total_len; - - if (the_target->pid_to_exec_file == NULL || writebuf != NULL) - return -2; - - if (annex[0] == '\0') - { - if (current_thread == NULL) - return -1; - - pid = pid_of (current_thread); - } - else - { - annex = unpack_varlen_hex (annex, &pid); - if (annex[0] != '\0') - return -1; - } - - if (pid <= 0) - return -1; - - file = (*the_target->pid_to_exec_file) (pid); - if (file == NULL) - return -1; - - total_len = strlen (file); - - if (offset > total_len) - return -1; - - if (offset + len > total_len) - len = total_len - offset; - - memcpy (readbuf, file + offset, len); - return len; -} - -/* Handle qXfer:features:read. */ - -static int -handle_qxfer_features (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - const char *document; - size_t total_len; - - if (writebuf != NULL) - return -2; - - if (!target_running ()) - return -1; - - /* Grab the correct annex. */ - document = get_features_xml (annex); - if (document == NULL) - return -1; - - total_len = strlen (document); - - if (offset > total_len) - return -1; - - if (offset + len > total_len) - len = total_len - offset; - - memcpy (readbuf, document + offset, len); - return len; -} - -/* Handle qXfer:libraries:read. */ - -static int -handle_qxfer_libraries (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - if (writebuf != NULL) - return -2; - - if (annex[0] != '\0' || current_thread == NULL) - return -1; - - std::string document = "\n"; - - for (const dll_info &dll : all_dlls) - document += string_printf - (" \n", - dll.name.c_str (), paddress (dll.base_addr)); - - document += "\n"; - - if (offset > document.length ()) - return -1; - - if (offset + len > document.length ()) - len = document.length () - offset; - - memcpy (readbuf, &document[offset], len); - - return len; -} - -/* Handle qXfer:libraries-svr4:read. */ - -static int -handle_qxfer_libraries_svr4 (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - if (writebuf != NULL) - return -2; - - if (current_thread == NULL || the_target->qxfer_libraries_svr4 == NULL) - return -1; - - return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len); -} - -/* Handle qXfer:osadata:read. */ - -static int -handle_qxfer_osdata (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - if (the_target->qxfer_osdata == NULL || writebuf != NULL) - return -2; - - return (*the_target->qxfer_osdata) (annex, readbuf, NULL, offset, len); -} - -/* Handle qXfer:siginfo:read and qXfer:siginfo:write. */ - -static int -handle_qxfer_siginfo (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - if (the_target->qxfer_siginfo == NULL) - return -2; - - if (annex[0] != '\0' || current_thread == NULL) - return -1; - - return (*the_target->qxfer_siginfo) (annex, readbuf, writebuf, offset, len); -} - -/* Handle qXfer:statictrace:read. */ - -static int -handle_qxfer_statictrace (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - client_state &cs = get_client_state (); - ULONGEST nbytes; - - if (writebuf != NULL) - return -2; - - if (annex[0] != '\0' || current_thread == NULL - || cs.current_traceframe == -1) - return -1; - - if (traceframe_read_sdata (cs.current_traceframe, offset, - readbuf, len, &nbytes)) - return -1; - return nbytes; -} - -/* Helper for handle_qxfer_threads_proper. - Emit the XML to describe the thread of INF. */ - -static void -handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer) -{ - ptid_t ptid = ptid_of (thread); - char ptid_s[100]; - int core = target_core_of_thread (ptid); - char core_s[21]; - const char *name = target_thread_name (ptid); - int handle_len; - gdb_byte *handle; - bool handle_status = target_thread_handle (ptid, &handle, &handle_len); - - write_ptid (ptid_s, ptid); - - buffer_xml_printf (buffer, "\n"); -} - -/* Helper for handle_qxfer_threads. */ - -static void -handle_qxfer_threads_proper (struct buffer *buffer) -{ - buffer_grow_str (buffer, "\n"); - - for_each_thread ([&] (thread_info *thread) - { - handle_qxfer_threads_worker (thread, buffer); - }); - - buffer_grow_str0 (buffer, "\n"); -} - -/* Handle qXfer:threads:read. */ - -static int -handle_qxfer_threads (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - static char *result = 0; - static unsigned int result_length = 0; - - if (writebuf != NULL) - return -2; - - if (annex[0] != '\0') - return -1; - - if (offset == 0) - { - struct buffer buffer; - /* When asked for data at offset 0, generate everything and store into - 'result'. Successive reads will be served off 'result'. */ - if (result) - free (result); - - buffer_init (&buffer); - - handle_qxfer_threads_proper (&buffer); - - result = buffer_finish (&buffer); - result_length = strlen (result); - buffer_free (&buffer); - } - - if (offset >= result_length) - { - /* We're out of data. */ - free (result); - result = NULL; - result_length = 0; - return 0; - } - - if (len > result_length - offset) - len = result_length - offset; - - memcpy (readbuf, result + offset, len); - - return len; -} - -/* Handle qXfer:traceframe-info:read. */ - -static int -handle_qxfer_traceframe_info (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - client_state &cs = get_client_state (); - static char *result = 0; - static unsigned int result_length = 0; - - if (writebuf != NULL) - return -2; - - if (!target_running () || annex[0] != '\0' || cs.current_traceframe == -1) - return -1; - - if (offset == 0) - { - struct buffer buffer; - - /* When asked for data at offset 0, generate everything and - store into 'result'. Successive reads will be served off - 'result'. */ - free (result); - - buffer_init (&buffer); - - traceframe_read_info (cs.current_traceframe, &buffer); - - result = buffer_finish (&buffer); - result_length = strlen (result); - buffer_free (&buffer); - } - - if (offset >= result_length) - { - /* We're out of data. */ - free (result); - result = NULL; - result_length = 0; - return 0; - } - - if (len > result_length - offset) - len = result_length - offset; - - memcpy (readbuf, result + offset, len); - return len; -} - -/* Handle qXfer:fdpic:read. */ - -static int -handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) -{ - if (the_target->read_loadmap == NULL) - return -2; - - if (current_thread == NULL) - return -1; - - return (*the_target->read_loadmap) (annex, offset, readbuf, len); -} - -/* Handle qXfer:btrace:read. */ - -static int -handle_qxfer_btrace (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - client_state &cs = get_client_state (); - static struct buffer cache; - struct thread_info *thread; - enum btrace_read_type type; - int result; - - if (writebuf != NULL) - return -2; - - if (cs.general_thread == null_ptid - || cs.general_thread == minus_one_ptid) - { - strcpy (cs.own_buf, "E.Must select a single thread."); - return -3; - } - - thread = find_thread_ptid (cs.general_thread); - if (thread == NULL) - { - strcpy (cs.own_buf, "E.No such thread."); - return -3; - } - - if (thread->btrace == NULL) - { - strcpy (cs.own_buf, "E.Btrace not enabled."); - return -3; - } - - if (strcmp (annex, "all") == 0) - type = BTRACE_READ_ALL; - else if (strcmp (annex, "new") == 0) - type = BTRACE_READ_NEW; - else if (strcmp (annex, "delta") == 0) - type = BTRACE_READ_DELTA; - else - { - strcpy (cs.own_buf, "E.Bad annex."); - return -3; - } - - if (offset == 0) - { - buffer_free (&cache); - - try - { - result = target_read_btrace (thread->btrace, &cache, type); - if (result != 0) - memcpy (cs.own_buf, cache.buffer, cache.used_size); - } - catch (const gdb_exception_error &exception) - { - sprintf (cs.own_buf, "E.%s", exception.what ()); - result = -1; - } - - if (result != 0) - return -3; - } - else if (offset > cache.used_size) - { - buffer_free (&cache); - return -3; - } - - if (len > cache.used_size - offset) - len = cache.used_size - offset; - - memcpy (readbuf, cache.buffer + offset, len); - - return len; -} - -/* Handle qXfer:btrace-conf:read. */ - -static int -handle_qxfer_btrace_conf (const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) -{ - client_state &cs = get_client_state (); - static struct buffer cache; - struct thread_info *thread; - int result; - - if (writebuf != NULL) - return -2; - - if (annex[0] != '\0') - return -1; - - if (cs.general_thread == null_ptid - || cs.general_thread == minus_one_ptid) - { - strcpy (cs.own_buf, "E.Must select a single thread."); - return -3; - } - - thread = find_thread_ptid (cs.general_thread); - if (thread == NULL) - { - strcpy (cs.own_buf, "E.No such thread."); - return -3; - } - - if (thread->btrace == NULL) - { - strcpy (cs.own_buf, "E.Btrace not enabled."); - return -3; - } - - if (offset == 0) - { - buffer_free (&cache); - - try - { - result = target_read_btrace_conf (thread->btrace, &cache); - if (result != 0) - memcpy (cs.own_buf, cache.buffer, cache.used_size); - } - catch (const gdb_exception_error &exception) - { - sprintf (cs.own_buf, "E.%s", exception.what ()); - result = -1; - } - - if (result != 0) - return -3; - } - else if (offset > cache.used_size) - { - buffer_free (&cache); - return -3; - } - - if (len > cache.used_size - offset) - len = cache.used_size - offset; - - memcpy (readbuf, cache.buffer + offset, len); - - return len; -} - -static const struct qxfer qxfer_packets[] = - { - { "auxv", handle_qxfer_auxv }, - { "btrace", handle_qxfer_btrace }, - { "btrace-conf", handle_qxfer_btrace_conf }, - { "exec-file", handle_qxfer_exec_file}, - { "fdpic", handle_qxfer_fdpic}, - { "features", handle_qxfer_features }, - { "libraries", handle_qxfer_libraries }, - { "libraries-svr4", handle_qxfer_libraries_svr4 }, - { "osdata", handle_qxfer_osdata }, - { "siginfo", handle_qxfer_siginfo }, - { "statictrace", handle_qxfer_statictrace }, - { "threads", handle_qxfer_threads }, - { "traceframe-info", handle_qxfer_traceframe_info }, - }; - -static int -handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p) -{ - int i; - char *object; - char *rw; - char *annex; - char *offset; - - if (!startswith (own_buf, "qXfer:")) - return 0; - - /* Grab the object, r/w and annex. */ - if (decode_xfer (own_buf + 6, &object, &rw, &annex, &offset) < 0) - { - write_enn (own_buf); - return 1; - } - - for (i = 0; - i < sizeof (qxfer_packets) / sizeof (qxfer_packets[0]); - i++) - { - const struct qxfer *q = &qxfer_packets[i]; - - if (strcmp (object, q->object) == 0) - { - if (strcmp (rw, "read") == 0) - { - unsigned char *data; - int n; - CORE_ADDR ofs; - unsigned int len; - - /* Grab the offset and length. */ - if (decode_xfer_read (offset, &ofs, &len) < 0) - { - write_enn (own_buf); - return 1; - } - - /* Read one extra byte, as an indicator of whether there is - more. */ - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - data = (unsigned char *) malloc (len + 1); - if (data == NULL) - { - write_enn (own_buf); - return 1; - } - n = (*q->xfer) (annex, data, NULL, ofs, len + 1); - if (n == -2) - { - free (data); - return 0; - } - else if (n == -3) - { - /* Preserve error message. */ - } - else if (n < 0) - write_enn (own_buf); - else if (n > len) - *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); - - free (data); - return 1; - } - else if (strcmp (rw, "write") == 0) - { - int n; - unsigned int len; - CORE_ADDR ofs; - unsigned char *data; - - strcpy (own_buf, "E00"); - data = (unsigned char *) malloc (packet_len - (offset - own_buf)); - if (data == NULL) - { - write_enn (own_buf); - return 1; - } - if (decode_xfer_write (offset, packet_len - (offset - own_buf), - &ofs, &len, data) < 0) - { - free (data); - write_enn (own_buf); - return 1; - } - - n = (*q->xfer) (annex, NULL, data, ofs, len); - if (n == -2) - { - free (data); - return 0; - } - else if (n == -3) - { - /* Preserve error message. */ - } - else if (n < 0) - write_enn (own_buf); - else - sprintf (own_buf, "%x", n); - - free (data); - return 1; - } - - return 0; - } - } - - return 0; -} - -/* Compute 32 bit CRC from inferior memory. - - On success, return 32 bit CRC. - On failure, return (unsigned long long) -1. */ - -static unsigned long long -crc32 (CORE_ADDR base, int len, unsigned int crc) -{ - while (len--) - { - unsigned char byte = 0; - - /* Return failure if memory read fails. */ - if (read_inferior_memory (base, &byte, 1) != 0) - return (unsigned long long) -1; - - crc = xcrc32 (&byte, 1, crc); - base++; - } - return (unsigned long long) crc; -} - -/* Add supported btrace packets to BUF. */ - -static void -supported_btrace_packets (char *buf) -{ - strcat (buf, ";Qbtrace:bts+"); - strcat (buf, ";Qbtrace-conf:bts:size+"); - strcat (buf, ";Qbtrace:pt+"); - strcat (buf, ";Qbtrace-conf:pt:size+"); - strcat (buf, ";Qbtrace:off+"); - strcat (buf, ";qXfer:btrace:read+"); - strcat (buf, ";qXfer:btrace-conf:read+"); -} - -/* Handle all of the extended 'q' packets. */ - -static void -handle_query (char *own_buf, int packet_len, int *new_packet_len_p) -{ - client_state &cs = get_client_state (); - static std::list::const_iterator thread_iter; - - /* Reply the current thread id. */ - if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC) - { - ptid_t ptid; - require_running_or_return (own_buf); - - if (cs.general_thread != null_ptid && cs.general_thread != minus_one_ptid) - ptid = cs.general_thread; - else - { - thread_iter = all_threads.begin (); - ptid = (*thread_iter)->id; - } - - sprintf (own_buf, "QC"); - own_buf += 2; - write_ptid (own_buf, ptid); - return; - } - - if (strcmp ("qSymbol::", own_buf) == 0) - { - struct thread_info *save_thread = current_thread; - - /* For qSymbol, GDB only changes the current thread if the - previous current thread was of a different process. So if - the previous thread is gone, we need to pick another one of - the same process. This can happen e.g., if we followed an - exec in a non-leader thread. */ - if (current_thread == NULL) - { - current_thread - = find_any_thread_of_pid (cs.general_thread.pid ()); - - /* Just in case, if we didn't find a thread, then bail out - instead of crashing. */ - if (current_thread == NULL) - { - write_enn (own_buf); - current_thread = save_thread; - return; - } - } - - /* GDB is suggesting new symbols have been loaded. This may - mean a new shared library has been detected as loaded, so - take the opportunity to check if breakpoints we think are - inserted, still are. Note that it isn't guaranteed that - we'll see this when a shared library is loaded, and nor will - we see this for unloads (although breakpoints in unloaded - libraries shouldn't trigger), as GDB may not find symbols for - the library at all. We also re-validate breakpoints when we - see a second GDB breakpoint for the same address, and or when - we access breakpoint shadows. */ - validate_breakpoints (); - - if (target_supports_tracepoints ()) - tracepoint_look_up_symbols (); - - if (current_thread != NULL && the_target->look_up_symbols != NULL) - (*the_target->look_up_symbols) (); - - current_thread = save_thread; - - strcpy (own_buf, "OK"); - return; - } - - if (!disable_packet_qfThreadInfo) - { - if (strcmp ("qfThreadInfo", own_buf) == 0) - { - require_running_or_return (own_buf); - thread_iter = all_threads.begin (); - - *own_buf++ = 'm'; - ptid_t ptid = (*thread_iter)->id; - write_ptid (own_buf, ptid); - thread_iter++; - return; - } - - if (strcmp ("qsThreadInfo", own_buf) == 0) - { - require_running_or_return (own_buf); - if (thread_iter != all_threads.end ()) - { - *own_buf++ = 'm'; - ptid_t ptid = (*thread_iter)->id; - write_ptid (own_buf, ptid); - thread_iter++; - return; - } - else - { - sprintf (own_buf, "l"); - return; - } - } - } - - if (the_target->read_offsets != NULL - && strcmp ("qOffsets", own_buf) == 0) - { - CORE_ADDR text, data; - - require_running_or_return (own_buf); - if (the_target->read_offsets (&text, &data)) - sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX", - (long)text, (long)data, (long)data); - else - write_enn (own_buf); - - return; - } - - /* Protocol features query. */ - if (startswith (own_buf, "qSupported") - && (own_buf[10] == ':' || own_buf[10] == '\0')) - { - char *p = &own_buf[10]; - int gdb_supports_qRelocInsn = 0; - - /* Process each feature being provided by GDB. The first - feature will follow a ':', and latter features will follow - ';'. */ - if (*p == ':') - { - char **qsupported = NULL; - int count = 0; - int unknown = 0; - int i; - - /* Two passes, to avoid nested strtok calls in - target_process_qsupported. */ - char *saveptr; - for (p = strtok_r (p + 1, ";", &saveptr); - p != NULL; - p = strtok_r (NULL, ";", &saveptr)) - { - count++; - qsupported = XRESIZEVEC (char *, qsupported, count); - qsupported[count - 1] = xstrdup (p); - } - - for (i = 0; i < count; i++) - { - p = qsupported[i]; - if (strcmp (p, "multiprocess+") == 0) - { - /* GDB supports and wants multi-process support if - possible. */ - if (target_supports_multi_process ()) - cs.multi_process = 1; - } - else if (strcmp (p, "qRelocInsn+") == 0) - { - /* GDB supports relocate instruction requests. */ - gdb_supports_qRelocInsn = 1; - } - else if (strcmp (p, "swbreak+") == 0) - { - /* GDB wants us to report whether a trap is caused - by a software breakpoint and for us to handle PC - adjustment if necessary on this target. */ - if (target_supports_stopped_by_sw_breakpoint ()) - cs.swbreak_feature = 1; - } - else if (strcmp (p, "hwbreak+") == 0) - { - /* GDB wants us to report whether a trap is caused - by a hardware breakpoint. */ - if (target_supports_stopped_by_hw_breakpoint ()) - cs.hwbreak_feature = 1; - } - else if (strcmp (p, "fork-events+") == 0) - { - /* GDB supports and wants fork events if possible. */ - if (target_supports_fork_events ()) - cs.report_fork_events = 1; - } - else if (strcmp (p, "vfork-events+") == 0) - { - /* GDB supports and wants vfork events if possible. */ - if (target_supports_vfork_events ()) - cs.report_vfork_events = 1; - } - else if (strcmp (p, "exec-events+") == 0) - { - /* GDB supports and wants exec events if possible. */ - if (target_supports_exec_events ()) - cs.report_exec_events = 1; - } - else if (strcmp (p, "vContSupported+") == 0) - cs.vCont_supported = 1; - else if (strcmp (p, "QThreadEvents+") == 0) - ; - else if (strcmp (p, "no-resumed+") == 0) - { - /* GDB supports and wants TARGET_WAITKIND_NO_RESUMED - events. */ - report_no_resumed = true; - } - else - { - /* Move the unknown features all together. */ - qsupported[i] = NULL; - qsupported[unknown] = p; - unknown++; - } - } - - /* Give the target backend a chance to process the unknown - features. */ - target_process_qsupported (qsupported, unknown); - - for (i = 0; i < count; i++) - free (qsupported[i]); - free (qsupported); - } - - sprintf (own_buf, - "PacketSize=%x;QPassSignals+;QProgramSignals+;" - "QStartupWithShell+;QEnvironmentHexEncoded+;" - "QEnvironmentReset+;QEnvironmentUnset+;" - "QSetWorkingDir+", - PBUFSIZ - 1); - - if (target_supports_catch_syscall ()) - strcat (own_buf, ";QCatchSyscalls+"); - - if (the_target->qxfer_libraries_svr4 != NULL) - strcat (own_buf, ";qXfer:libraries-svr4:read+" - ";augmented-libraries-svr4-read+"); - else - { - /* We do not have any hook to indicate whether the non-SVR4 target - backend supports qXfer:libraries:read, so always report it. */ - strcat (own_buf, ";qXfer:libraries:read+"); - } - - if (the_target->read_auxv != NULL) - strcat (own_buf, ";qXfer:auxv:read+"); - - if (the_target->qxfer_siginfo != NULL) - strcat (own_buf, ";qXfer:siginfo:read+;qXfer:siginfo:write+"); - - if (the_target->read_loadmap != NULL) - strcat (own_buf, ";qXfer:fdpic:read+"); - - /* We always report qXfer:features:read, as targets may - install XML files on a subsequent call to arch_setup. - If we reported to GDB on startup that we don't support - qXfer:feature:read at all, we will never be re-queried. */ - strcat (own_buf, ";qXfer:features:read+"); - - if (cs.transport_is_reliable) - strcat (own_buf, ";QStartNoAckMode+"); - - if (the_target->qxfer_osdata != NULL) - strcat (own_buf, ";qXfer:osdata:read+"); - - if (target_supports_multi_process ()) - strcat (own_buf, ";multiprocess+"); - - if (target_supports_fork_events ()) - strcat (own_buf, ";fork-events+"); - - if (target_supports_vfork_events ()) - strcat (own_buf, ";vfork-events+"); - - if (target_supports_exec_events ()) - strcat (own_buf, ";exec-events+"); - - if (target_supports_non_stop ()) - strcat (own_buf, ";QNonStop+"); - - if (target_supports_disable_randomization ()) - strcat (own_buf, ";QDisableRandomization+"); - - strcat (own_buf, ";qXfer:threads:read+"); - - if (target_supports_tracepoints ()) - { - strcat (own_buf, ";ConditionalTracepoints+"); - strcat (own_buf, ";TraceStateVariables+"); - strcat (own_buf, ";TracepointSource+"); - strcat (own_buf, ";DisconnectedTracing+"); - if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ()) - strcat (own_buf, ";FastTracepoints+"); - strcat (own_buf, ";StaticTracepoints+"); - strcat (own_buf, ";InstallInTrace+"); - strcat (own_buf, ";qXfer:statictrace:read+"); - strcat (own_buf, ";qXfer:traceframe-info:read+"); - strcat (own_buf, ";EnableDisableTracepoints+"); - strcat (own_buf, ";QTBuffer:size+"); - strcat (own_buf, ";tracenz+"); - } - - if (target_supports_hardware_single_step () - || target_supports_software_single_step () ) - { - strcat (own_buf, ";ConditionalBreakpoints+"); - } - strcat (own_buf, ";BreakpointCommands+"); - - if (target_supports_agent ()) - strcat (own_buf, ";QAgent+"); - - supported_btrace_packets (own_buf); - - if (target_supports_stopped_by_sw_breakpoint ()) - strcat (own_buf, ";swbreak+"); - - if (target_supports_stopped_by_hw_breakpoint ()) - strcat (own_buf, ";hwbreak+"); - - if (the_target->pid_to_exec_file != NULL) - strcat (own_buf, ";qXfer:exec-file:read+"); - - strcat (own_buf, ";vContSupported+"); - - strcat (own_buf, ";QThreadEvents+"); - - strcat (own_buf, ";no-resumed+"); - - /* Reinitialize components as needed for the new connection. */ - hostio_handle_new_gdb_connection (); - target_handle_new_gdb_connection (); - - return; - } - - /* Thread-local storage support. */ - if (the_target->get_tls_address != NULL - && startswith (own_buf, "qGetTLSAddr:")) - { - char *p = own_buf + 12; - CORE_ADDR parts[2], address = 0; - int i, err; - ptid_t ptid = null_ptid; - - require_running_or_return (own_buf); - - for (i = 0; i < 3; i++) - { - char *p2; - int len; - - if (p == NULL) - break; - - p2 = strchr (p, ','); - if (p2) - { - len = p2 - p; - p2++; - } - else - { - len = strlen (p); - p2 = NULL; - } - - if (i == 0) - ptid = read_ptid (p, NULL); - else - decode_address (&parts[i - 1], p, len); - p = p2; - } - - if (p != NULL || i < 3) - err = 1; - else - { - struct thread_info *thread = find_thread_ptid (ptid); - - if (thread == NULL) - err = 2; - else - err = the_target->get_tls_address (thread, parts[0], parts[1], - &address); - } - - if (err == 0) - { - strcpy (own_buf, paddress(address)); - return; - } - else if (err > 0) - { - write_enn (own_buf); - return; - } - - /* Otherwise, pretend we do not understand this packet. */ - } - - /* Windows OS Thread Information Block address support. */ - if (the_target->get_tib_address != NULL - && startswith (own_buf, "qGetTIBAddr:")) - { - const char *annex; - int n; - CORE_ADDR tlb; - ptid_t ptid = read_ptid (own_buf + 12, &annex); - - n = (*the_target->get_tib_address) (ptid, &tlb); - if (n == 1) - { - strcpy (own_buf, paddress(tlb)); - return; - } - else if (n == 0) - { - write_enn (own_buf); - return; - } - return; - } - - /* Handle "monitor" commands. */ - if (startswith (own_buf, "qRcmd,")) - { - char *mon = (char *) malloc (PBUFSIZ); - int len = strlen (own_buf + 6); - - if (mon == NULL) - { - write_enn (own_buf); - return; - } - - if ((len % 2) != 0 - || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2) - { - write_enn (own_buf); - free (mon); - return; - } - mon[len / 2] = '\0'; - - write_ok (own_buf); - - if (the_target->handle_monitor_command == NULL - || (*the_target->handle_monitor_command) (mon) == 0) - /* Default processing. */ - handle_monitor_command (mon, own_buf); - - free (mon); - return; - } - - if (startswith (own_buf, "qSearch:memory:")) - { - require_running_or_return (own_buf); - handle_search_memory (own_buf, packet_len); - return; - } - - if (strcmp (own_buf, "qAttached") == 0 - || startswith (own_buf, "qAttached:")) - { - struct process_info *process; - - if (own_buf[sizeof ("qAttached") - 1]) - { - int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16); - process = find_process_pid (pid); - } - else - { - require_running_or_return (own_buf); - process = current_process (); - } - - if (process == NULL) - { - write_enn (own_buf); - return; - } - - strcpy (own_buf, process->attached ? "1" : "0"); - return; - } - - if (startswith (own_buf, "qCRC:")) - { - /* CRC check (compare-section). */ - const char *comma; - ULONGEST base; - int len; - unsigned long long crc; - - require_running_or_return (own_buf); - comma = unpack_varlen_hex (own_buf + 5, &base); - if (*comma++ != ',') - { - write_enn (own_buf); - return; - } - len = strtoul (comma, NULL, 16); - crc = crc32 (base, len, 0xffffffff); - /* Check for memory failure. */ - if (crc == (unsigned long long) -1) - { - write_enn (own_buf); - return; - } - sprintf (own_buf, "C%lx", (unsigned long) crc); - return; - } - - if (handle_qxfer (own_buf, packet_len, new_packet_len_p)) - return; - - if (target_supports_tracepoints () && handle_tracepoint_query (own_buf)) - return; - - /* Otherwise we didn't know what packet it was. Say we didn't - understand it. */ - own_buf[0] = 0; -} - -static void gdb_wants_all_threads_stopped (void); -static void resume (struct thread_resume *actions, size_t n); - -/* The callback that is passed to visit_actioned_threads. */ -typedef int (visit_actioned_threads_callback_ftype) - (const struct thread_resume *, struct thread_info *); - -/* Call CALLBACK for any thread to which ACTIONS applies to. Returns - true if CALLBACK returns true. Returns false if no matching thread - is found or CALLBACK results false. - Note: This function is itself a callback for find_thread. */ - -static bool -visit_actioned_threads (thread_info *thread, - const struct thread_resume *actions, - size_t num_actions, - visit_actioned_threads_callback_ftype *callback) -{ - for (size_t i = 0; i < num_actions; i++) - { - const struct thread_resume *action = &actions[i]; - - if (action->thread == minus_one_ptid - || action->thread == thread->id - || ((action->thread.pid () - == thread->id.pid ()) - && action->thread.lwp () == -1)) - { - if ((*callback) (action, thread)) - return true; - } - } - - return false; -} - -/* Callback for visit_actioned_threads. If the thread has a pending - status to report, report it now. */ - -static int -handle_pending_status (const struct thread_resume *resumption, - struct thread_info *thread) -{ - client_state &cs = get_client_state (); - if (thread->status_pending_p) - { - thread->status_pending_p = 0; - - cs.last_status = thread->last_status; - cs.last_ptid = thread->id; - prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status); - return 1; - } - return 0; -} - -/* Parse vCont packets. */ -static void -handle_v_cont (char *own_buf) -{ - const char *p; - int n = 0, i = 0; - struct thread_resume *resume_info; - struct thread_resume default_action { null_ptid }; - - /* Count the number of semicolons in the packet. There should be one - for every action. */ - p = &own_buf[5]; - while (p) - { - n++; - p++; - p = strchr (p, ';'); - } - - resume_info = (struct thread_resume *) malloc (n * sizeof (resume_info[0])); - if (resume_info == NULL) - goto err; - - p = &own_buf[5]; - while (*p) - { - p++; - - memset (&resume_info[i], 0, sizeof resume_info[i]); - - if (p[0] == 's' || p[0] == 'S') - resume_info[i].kind = resume_step; - else if (p[0] == 'r') - resume_info[i].kind = resume_step; - else if (p[0] == 'c' || p[0] == 'C') - resume_info[i].kind = resume_continue; - else if (p[0] == 't') - resume_info[i].kind = resume_stop; - else - goto err; - - if (p[0] == 'S' || p[0] == 'C') - { - char *q; - int sig = strtol (p + 1, &q, 16); - if (p == q) - goto err; - p = q; - - if (!gdb_signal_to_host_p ((enum gdb_signal) sig)) - goto err; - resume_info[i].sig = gdb_signal_to_host ((enum gdb_signal) sig); - } - else if (p[0] == 'r') - { - ULONGEST addr; - - p = unpack_varlen_hex (p + 1, &addr); - resume_info[i].step_range_start = addr; - - if (*p != ',') - goto err; - - p = unpack_varlen_hex (p + 1, &addr); - resume_info[i].step_range_end = addr; - } - else - { - p = p + 1; - } - - if (p[0] == 0) - { - resume_info[i].thread = minus_one_ptid; - default_action = resume_info[i]; - - /* Note: we don't increment i here, we'll overwrite this entry - the next time through. */ - } - else if (p[0] == ':') - { - const char *q; - ptid_t ptid = read_ptid (p + 1, &q); - - if (p == q) - goto err; - p = q; - if (p[0] != ';' && p[0] != 0) - goto err; - - resume_info[i].thread = ptid; - - i++; - } - } - - if (i < n) - resume_info[i] = default_action; - - resume (resume_info, n); - free (resume_info); - return; - -err: - write_enn (own_buf); - free (resume_info); - return; -} - -/* Resume target with ACTIONS, an array of NUM_ACTIONS elements. */ - -static void -resume (struct thread_resume *actions, size_t num_actions) -{ - client_state &cs = get_client_state (); - if (!non_stop) - { - /* Check if among the threads that GDB wants actioned, there's - one with a pending status to report. If so, skip actually - resuming/stopping and report the pending event - immediately. */ - - thread_info *thread_with_status = find_thread ([&] (thread_info *thread) - { - return visit_actioned_threads (thread, actions, num_actions, - handle_pending_status); - }); - - if (thread_with_status != NULL) - return; - - enable_async_io (); - } - - (*the_target->resume) (actions, num_actions); - - if (non_stop) - write_ok (cs.own_buf); - else - { - cs.last_ptid = mywait (minus_one_ptid, &cs.last_status, 0, 1); - - if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED - && !report_no_resumed) - { - /* The client does not support this stop reply. At least - return error. */ - sprintf (cs.own_buf, "E.No unwaited-for children left."); - disable_async_io (); - return; - } - - if (cs.last_status.kind != TARGET_WAITKIND_EXITED - && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED - && cs.last_status.kind != TARGET_WAITKIND_NO_RESUMED) - current_thread->last_status = cs.last_status; - - /* From the client's perspective, all-stop mode always stops all - threads implicitly (and the target backend has already done - so by now). Tag all threads as "want-stopped", so we don't - resume them implicitly without the client telling us to. */ - gdb_wants_all_threads_stopped (); - prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status); - disable_async_io (); - - if (cs.last_status.kind == TARGET_WAITKIND_EXITED - || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED) - target_mourn_inferior (cs.last_ptid); - } -} - -/* Attach to a new program. Return 1 if successful, 0 if failure. */ -static int -handle_v_attach (char *own_buf) -{ - client_state &cs = get_client_state (); - int pid; - - pid = strtol (own_buf + 8, NULL, 16); - if (pid != 0 && attach_inferior (pid) == 0) - { - /* Don't report shared library events after attaching, even if - some libraries are preloaded. GDB will always poll the - library list. Avoids the "stopped by shared library event" - notice on the GDB side. */ - dlls_changed = 0; - - if (non_stop) - { - /* In non-stop, we don't send a resume reply. Stop events - will follow up using the normal notification - mechanism. */ - write_ok (own_buf); - } - else - prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status); - - return 1; - } - else - { - write_enn (own_buf); - return 0; - } -} - -/* Run a new program. Return 1 if successful, 0 if failure. */ -static int -handle_v_run (char *own_buf) -{ - client_state &cs = get_client_state (); - char *p, *next_p; - std::vector new_argv; - char *new_program_name = NULL; - int i, new_argc; - - new_argc = 0; - for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';')) - { - p++; - new_argc++; - } - - for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i) - { - next_p = strchr (p, ';'); - if (next_p == NULL) - next_p = p + strlen (p); - - if (i == 0 && p == next_p) - { - /* No program specified. */ - new_program_name = NULL; - } - else if (p == next_p) - { - /* Empty argument. */ - new_argv.push_back (xstrdup ("''")); - } - else - { - size_t len = (next_p - p) / 2; - /* ARG is the unquoted argument received via the RSP. */ - char *arg = (char *) xmalloc (len + 1); - /* FULL_ARGS will contain the quoted version of ARG. */ - char *full_arg = (char *) xmalloc ((len + 1) * 2); - /* These are pointers used to navigate the strings above. */ - char *tmp_arg = arg; - char *tmp_full_arg = full_arg; - int need_quote = 0; - - hex2bin (p, (gdb_byte *) arg, len); - arg[len] = '\0'; - - while (*tmp_arg != '\0') - { - switch (*tmp_arg) - { - case '\n': - /* Quote \n. */ - *tmp_full_arg = '\''; - ++tmp_full_arg; - need_quote = 1; - break; - - case '\'': - /* Quote single quote. */ - *tmp_full_arg = '\\'; - ++tmp_full_arg; - break; - - default: - break; - } - - *tmp_full_arg = *tmp_arg; - ++tmp_full_arg; - ++tmp_arg; - } - - if (need_quote) - *tmp_full_arg++ = '\''; - - /* Finish FULL_ARG and push it into the vector containing - the argv. */ - *tmp_full_arg = '\0'; - if (i == 0) - new_program_name = full_arg; - else - new_argv.push_back (full_arg); - xfree (arg); - } - if (*next_p) - next_p++; - } - new_argv.push_back (NULL); - - if (new_program_name == NULL) - { - /* GDB didn't specify a program to run. Use the program from the - last run with the new argument list. */ - if (program_path.get () == NULL) - { - write_enn (own_buf); - free_vector_argv (new_argv); - return 0; - } - } - else - program_path.set (gdb::unique_xmalloc_ptr (new_program_name)); - - /* Free the old argv and install the new one. */ - free_vector_argv (program_args); - program_args = new_argv; - - create_inferior (program_path.get (), program_args); - - if (cs.last_status.kind == TARGET_WAITKIND_STOPPED) - { - prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status); - - /* In non-stop, sending a resume reply doesn't set the general - thread, but GDB assumes a vRun sets it (this is so GDB can - query which is the main thread of the new inferior. */ - if (non_stop) - cs.general_thread = cs.last_ptid; - - return 1; - } - else - { - write_enn (own_buf); - return 0; - } -} - -/* Kill process. Return 1 if successful, 0 if failure. */ -static int -handle_v_kill (char *own_buf) -{ - client_state &cs = get_client_state (); - int pid; - char *p = &own_buf[6]; - if (cs.multi_process) - pid = strtol (p, NULL, 16); - else - pid = signal_pid; - - process_info *proc = find_process_pid (pid); - - if (proc != nullptr && kill_inferior (proc) == 0) - { - cs.last_status.kind = TARGET_WAITKIND_SIGNALLED; - cs.last_status.value.sig = GDB_SIGNAL_KILL; - cs.last_ptid = ptid_t (pid); - discard_queued_stop_replies (cs.last_ptid); - write_ok (own_buf); - return 1; - } - else - { - write_enn (own_buf); - return 0; - } -} - -/* Handle all of the extended 'v' packets. */ -void -handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) -{ - client_state &cs = get_client_state (); - if (!disable_packet_vCont) - { - if (strcmp (own_buf, "vCtrlC") == 0) - { - (*the_target->request_interrupt) (); - write_ok (own_buf); - return; - } - - if (startswith (own_buf, "vCont;")) - { - handle_v_cont (own_buf); - return; - } - - if (startswith (own_buf, "vCont?")) - { - strcpy (own_buf, "vCont;c;C;t"); - - if (target_supports_hardware_single_step () - || target_supports_software_single_step () - || !cs.vCont_supported) - { - /* If target supports single step either by hardware or by - software, add actions s and S to the list of supported - actions. On the other hand, if GDB doesn't request the - supported vCont actions in qSupported packet, add s and - S to the list too. */ - own_buf = own_buf + strlen (own_buf); - strcpy (own_buf, ";s;S"); - } - - if (target_supports_range_stepping ()) - { - own_buf = own_buf + strlen (own_buf); - strcpy (own_buf, ";r"); - } - return; - } - } - - if (startswith (own_buf, "vFile:") - && handle_vFile (own_buf, packet_len, new_packet_len)) - return; - - if (startswith (own_buf, "vAttach;")) - { - if ((!extended_protocol || !cs.multi_process) && target_running ()) - { - fprintf (stderr, "Already debugging a process\n"); - write_enn (own_buf); - return; - } - handle_v_attach (own_buf); - return; - } - - if (startswith (own_buf, "vRun;")) - { - if ((!extended_protocol || !cs.multi_process) && target_running ()) - { - fprintf (stderr, "Already debugging a process\n"); - write_enn (own_buf); - return; - } - handle_v_run (own_buf); - return; - } - - if (startswith (own_buf, "vKill;")) - { - if (!target_running ()) - { - fprintf (stderr, "No process to kill\n"); - write_enn (own_buf); - return; - } - handle_v_kill (own_buf); - return; - } - - if (handle_notif_ack (own_buf, packet_len)) - return; - - /* Otherwise we didn't know what packet it was. Say we didn't - understand it. */ - own_buf[0] = 0; - return; -} - -/* Resume thread and wait for another event. In non-stop mode, - don't really wait here, but return immediatelly to the event - loop. */ -static void -myresume (char *own_buf, int step, int sig) -{ - client_state &cs = get_client_state (); - struct thread_resume resume_info[2]; - int n = 0; - int valid_cont_thread; - - valid_cont_thread = (cs.cont_thread != null_ptid - && cs.cont_thread != minus_one_ptid); - - if (step || sig || valid_cont_thread) - { - resume_info[0].thread = current_ptid; - if (step) - resume_info[0].kind = resume_step; - else - resume_info[0].kind = resume_continue; - resume_info[0].sig = sig; - n++; - } - - if (!valid_cont_thread) - { - resume_info[n].thread = minus_one_ptid; - resume_info[n].kind = resume_continue; - resume_info[n].sig = 0; - n++; - } - - resume (resume_info, n); -} - -/* Callback for for_each_thread. Make a new stop reply for each - stopped thread. */ - -static void -queue_stop_reply_callback (thread_info *thread) -{ - /* For now, assume targets that don't have this callback also don't - manage the thread's last_status field. */ - if (the_target->thread_stopped == NULL) - { - struct vstop_notif *new_notif = new struct vstop_notif; - - new_notif->ptid = thread->id; - new_notif->status = thread->last_status; - /* Pass the last stop reply back to GDB, but don't notify - yet. */ - notif_event_enque (¬if_stop, new_notif); - } - else - { - if (thread_stopped (thread)) - { - if (debug_threads) - { - std::string status_string - = target_waitstatus_to_string (&thread->last_status); - - debug_printf ("Reporting thread %s as already stopped with %s\n", - target_pid_to_str (thread->id), - status_string.c_str ()); - } - - gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE); - - /* Pass the last stop reply back to GDB, but don't notify - yet. */ - queue_stop_reply (thread->id, &thread->last_status); - } - } -} - -/* Set this inferior threads's state as "want-stopped". We won't - resume this thread until the client gives us another action for - it. */ - -static void -gdb_wants_thread_stopped (thread_info *thread) -{ - thread->last_resume_kind = resume_stop; - - if (thread->last_status.kind == TARGET_WAITKIND_IGNORE) - { - /* Most threads are stopped implicitly (all-stop); tag that with - signal 0. */ - thread->last_status.kind = TARGET_WAITKIND_STOPPED; - thread->last_status.value.sig = GDB_SIGNAL_0; - } -} - -/* Set all threads' states as "want-stopped". */ - -static void -gdb_wants_all_threads_stopped (void) -{ - for_each_thread (gdb_wants_thread_stopped); -} - -/* Callback for for_each_thread. If the thread is stopped with an - interesting event, mark it as having a pending event. */ - -static void -set_pending_status_callback (thread_info *thread) -{ - if (thread->last_status.kind != TARGET_WAITKIND_STOPPED - || (thread->last_status.value.sig != GDB_SIGNAL_0 - /* A breakpoint, watchpoint or finished step from a previous - GDB run isn't considered interesting for a new GDB run. - If we left those pending, the new GDB could consider them - random SIGTRAPs. This leaves out real async traps. We'd - have to peek into the (target-specific) siginfo to - distinguish those. */ - && thread->last_status.value.sig != GDB_SIGNAL_TRAP)) - thread->status_pending_p = 1; -} - -/* Status handler for the '?' packet. */ - -static void -handle_status (char *own_buf) -{ - client_state &cs = get_client_state (); - - /* GDB is connected, don't forward events to the target anymore. */ - for_each_process ([] (process_info *process) { - process->gdb_detached = 0; - }); - - /* In non-stop mode, we must send a stop reply for each stopped - thread. In all-stop mode, just send one for the first stopped - thread we find. */ - - if (non_stop) - { - for_each_thread (queue_stop_reply_callback); - - /* The first is sent immediatly. OK is sent if there is no - stopped thread, which is the same handling of the vStopped - packet (by design). */ - notif_write_event (¬if_stop, cs.own_buf); - } - else - { - thread_info *thread = NULL; - - pause_all (0); - stabilize_threads (); - gdb_wants_all_threads_stopped (); - - /* We can only report one status, but we might be coming out of - non-stop -- if more than one thread is stopped with - interesting events, leave events for the threads we're not - reporting now pending. They'll be reported the next time the - threads are resumed. Start by marking all interesting events - as pending. */ - for_each_thread (set_pending_status_callback); - - /* Prefer the last thread that reported an event to GDB (even if - that was a GDB_SIGNAL_TRAP). */ - if (cs.last_status.kind != TARGET_WAITKIND_IGNORE - && cs.last_status.kind != TARGET_WAITKIND_EXITED - && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED) - thread = find_thread_ptid (cs.last_ptid); - - /* If the last event thread is not found for some reason, look - for some other thread that might have an event to report. */ - if (thread == NULL) - thread = find_thread ([] (thread_info *thr_arg) - { - return thr_arg->status_pending_p; - }); - - /* If we're still out of luck, simply pick the first thread in - the thread list. */ - if (thread == NULL) - thread = get_first_thread (); - - if (thread != NULL) - { - struct thread_info *tp = (struct thread_info *) thread; - - /* We're reporting this event, so it's no longer - pending. */ - tp->status_pending_p = 0; - - /* GDB assumes the current thread is the thread we're - reporting the status for. */ - cs.general_thread = thread->id; - set_desired_thread (); - - gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE); - prepare_resume_reply (own_buf, tp->id, &tp->last_status); - } - else - strcpy (own_buf, "W00"); - } -} - -static void -gdbserver_version (void) -{ - printf ("GNU gdbserver %s%s\n" - "Copyright (C) 2020 Free Software Foundation, Inc.\n" - "gdbserver is free software, covered by the " - "GNU General Public License.\n" - "This gdbserver was configured as \"%s\"\n", - PKGVERSION, version, host_name); -} - -static void -gdbserver_usage (FILE *stream) -{ - fprintf (stream, "Usage:\tgdbserver [OPTIONS] COMM PROG [ARGS ...]\n" - "\tgdbserver [OPTIONS] --attach COMM PID\n" - "\tgdbserver [OPTIONS] --multi COMM\n" - "\n" - "COMM may either be a tty device (for serial debugging),\n" - "HOST:PORT to listen for a TCP connection, or '-' or 'stdio' to use \n" - "stdin/stdout of gdbserver.\n" - "PROG is the executable program. ARGS are arguments passed to inferior.\n" - "PID is the process ID to attach to, when --attach is specified.\n" - "\n" - "Operating modes:\n" - "\n" - " --attach Attach to running process PID.\n" - " --multi Start server without a specific program, and\n" - " only quit when explicitly commanded.\n" - " --once Exit after the first connection has closed.\n" - " --help Print this message and then exit.\n" - " --version Display version information and exit.\n" - "\n" - "Other options:\n" - "\n" - " --wrapper WRAPPER -- Run WRAPPER to start new programs.\n" - " --disable-randomization\n" - " Run PROG with address space randomization disabled.\n" - " --no-disable-randomization\n" - " Don't disable address space randomization when\n" - " starting PROG.\n" - " --startup-with-shell\n" - " Start PROG using a shell. I.e., execs a shell that\n" - " then execs PROG. (default)\n" - " --no-startup-with-shell\n" - " Exec PROG directly instead of using a shell.\n" - " Disables argument globbing and variable substitution\n" - " on UNIX-like systems.\n" - "\n" - "Debug options:\n" - "\n" - " --debug Enable general debugging output.\n" - " --debug-format=OPT1[,OPT2,...]\n" - " Specify extra content in debugging output.\n" - " Options:\n" - " all\n" - " none\n" - " timestamp\n" - " --remote-debug Enable remote protocol debugging output.\n" - " --disable-packet=OPT1[,OPT2,...]\n" - " Disable support for RSP packets or features.\n" - " Options:\n" - " vCont, Tthread, qC, qfThreadInfo and \n" - " threads (disable all threading packets).\n" - "\n" - "For more information, consult the GDB manual (available as on-line \n" - "info or a printed manual).\n"); - if (REPORT_BUGS_TO[0] && stream == stdout) - fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO); -} - -static void -gdbserver_show_disableable (FILE *stream) -{ - fprintf (stream, "Disableable packets:\n" - " vCont \tAll vCont packets\n" - " qC \tQuerying the current thread\n" - " qfThreadInfo\tThread listing\n" - " Tthread \tPassing the thread specifier in the " - "T stop reply packet\n" - " threads \tAll of the above\n"); -} - -static void -kill_inferior_callback (process_info *process) -{ - kill_inferior (process); - discard_queued_stop_replies (ptid_t (process->pid)); -} - -/* Call this when exiting gdbserver with possible inferiors that need - to be killed or detached from. */ - -static void -detach_or_kill_for_exit (void) -{ - /* First print a list of the inferiors we will be killing/detaching. - This is to assist the user, for example, in case the inferior unexpectedly - dies after we exit: did we screw up or did the inferior exit on its own? - Having this info will save some head-scratching. */ - - if (have_started_inferiors_p ()) - { - fprintf (stderr, "Killing process(es):"); - - for_each_process ([] (process_info *process) { - if (!process->attached) - fprintf (stderr, " %d", process->pid); - }); - - fprintf (stderr, "\n"); - } - if (have_attached_inferiors_p ()) - { - fprintf (stderr, "Detaching process(es):"); - - for_each_process ([] (process_info *process) { - if (process->attached) - fprintf (stderr, " %d", process->pid); - }); - - fprintf (stderr, "\n"); - } - - /* Now we can kill or detach the inferiors. */ - for_each_process ([] (process_info *process) { - int pid = process->pid; - - if (process->attached) - detach_inferior (process); - else - kill_inferior (process); - - discard_queued_stop_replies (ptid_t (pid)); - }); -} - -/* Value that will be passed to exit(3) when gdbserver exits. */ -static int exit_code; - -/* Wrapper for detach_or_kill_for_exit that catches and prints - errors. */ - -static void -detach_or_kill_for_exit_cleanup () -{ - try - { - detach_or_kill_for_exit (); - } - catch (const gdb_exception &exception) - { - fflush (stdout); - fprintf (stderr, "Detach or kill failed: %s\n", - exception.what ()); - exit_code = 1; - } -} - -/* Main function. This is called by the real "main" function, - wrapped in a TRY_CATCH that handles any uncaught exceptions. */ - -static void ATTRIBUTE_NORETURN -captured_main (int argc, char *argv[]) -{ - int bad_attach; - int pid; - char *arg_end; - const char *port = NULL; - char **next_arg = &argv[1]; - volatile int multi_mode = 0; - volatile int attach = 0; - int was_running; - bool selftest = false; -#if GDB_SELF_TEST - const char *selftest_filter = NULL; -#endif - - current_directory = getcwd (NULL, 0); - client_state &cs = get_client_state (); - - if (current_directory == NULL) - { - error (_("Could not find current working directory: %s"), - safe_strerror (errno)); - } - - while (*next_arg != NULL && **next_arg == '-') - { - if (strcmp (*next_arg, "--version") == 0) - { - gdbserver_version (); - exit (0); - } - else if (strcmp (*next_arg, "--help") == 0) - { - gdbserver_usage (stdout); - exit (0); - } - else if (strcmp (*next_arg, "--attach") == 0) - attach = 1; - else if (strcmp (*next_arg, "--multi") == 0) - multi_mode = 1; - else if (strcmp (*next_arg, "--wrapper") == 0) - { - char **tmp; - - next_arg++; - - tmp = next_arg; - while (*next_arg != NULL && strcmp (*next_arg, "--") != 0) - { - wrapper_argv += *next_arg; - wrapper_argv += ' '; - next_arg++; - } - - if (!wrapper_argv.empty ()) - { - /* Erase the last whitespace. */ - wrapper_argv.erase (wrapper_argv.end () - 1); - } - - if (next_arg == tmp || *next_arg == NULL) - { - gdbserver_usage (stderr); - exit (1); - } - - /* Consume the "--". */ - *next_arg = NULL; - } - else if (strcmp (*next_arg, "--debug") == 0) - debug_threads = 1; - else if (startswith (*next_arg, "--debug-format=")) - { - std::string error_msg - = parse_debug_format_options ((*next_arg) - + sizeof ("--debug-format=") - 1, 0); - - if (!error_msg.empty ()) - { - fprintf (stderr, "%s", error_msg.c_str ()); - exit (1); - } - } - else if (strcmp (*next_arg, "--remote-debug") == 0) - remote_debug = 1; - else if (startswith (*next_arg, "--debug-file=")) - debug_set_output ((*next_arg) + sizeof ("--debug-file=") -1); - else if (strcmp (*next_arg, "--disable-packet") == 0) - { - gdbserver_show_disableable (stdout); - exit (0); - } - else if (startswith (*next_arg, "--disable-packet=")) - { - char *packets = *next_arg += sizeof ("--disable-packet=") - 1; - char *saveptr; - for (char *tok = strtok_r (packets, ",", &saveptr); - tok != NULL; - tok = strtok_r (NULL, ",", &saveptr)) - { - if (strcmp ("vCont", tok) == 0) - disable_packet_vCont = true; - else if (strcmp ("Tthread", tok) == 0) - disable_packet_Tthread = true; - else if (strcmp ("qC", tok) == 0) - disable_packet_qC = true; - else if (strcmp ("qfThreadInfo", tok) == 0) - disable_packet_qfThreadInfo = true; - else if (strcmp ("threads", tok) == 0) - { - disable_packet_vCont = true; - disable_packet_Tthread = true; - disable_packet_qC = true; - disable_packet_qfThreadInfo = true; - } - else - { - fprintf (stderr, "Don't know how to disable \"%s\".\n\n", - tok); - gdbserver_show_disableable (stderr); - exit (1); - } - } - } - else if (strcmp (*next_arg, "-") == 0) - { - /* "-" specifies a stdio connection and is a form of port - specification. */ - port = STDIO_CONNECTION_NAME; - next_arg++; - break; - } - else if (strcmp (*next_arg, "--disable-randomization") == 0) - cs.disable_randomization = 1; - else if (strcmp (*next_arg, "--no-disable-randomization") == 0) - cs.disable_randomization = 0; - else if (strcmp (*next_arg, "--startup-with-shell") == 0) - startup_with_shell = true; - else if (strcmp (*next_arg, "--no-startup-with-shell") == 0) - startup_with_shell = false; - else if (strcmp (*next_arg, "--once") == 0) - run_once = true; - else if (strcmp (*next_arg, "--selftest") == 0) - selftest = true; - else if (startswith (*next_arg, "--selftest=")) - { - selftest = true; -#if GDB_SELF_TEST - selftest_filter = *next_arg + strlen ("--selftest="); -#endif - } - else - { - fprintf (stderr, "Unknown argument: %s\n", *next_arg); - exit (1); - } - - next_arg++; - continue; - } - - if (port == NULL) - { - port = *next_arg; - next_arg++; - } - if ((port == NULL || (!attach && !multi_mode && *next_arg == NULL)) - && !selftest) - { - gdbserver_usage (stderr); - exit (1); - } - - /* Remember stdio descriptors. LISTEN_DESC must not be listed, it will be - opened by remote_prepare. */ - notice_open_fds (); - - save_original_signals_state (false); - - /* We need to know whether the remote connection is stdio before - starting the inferior. Inferiors created in this scenario have - stdin,stdout redirected. So do this here before we call - start_inferior. */ - if (port != NULL) - remote_prepare (port); - - bad_attach = 0; - pid = 0; - - /* --attach used to come after PORT, so allow it there for - compatibility. */ - if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0) - { - attach = 1; - next_arg++; - } - - if (attach - && (*next_arg == NULL - || (*next_arg)[0] == '\0' - || (pid = strtoul (*next_arg, &arg_end, 0)) == 0 - || *arg_end != '\0' - || next_arg[1] != NULL)) - bad_attach = 1; - - if (bad_attach) - { - gdbserver_usage (stderr); - exit (1); - } - - /* Gather information about the environment. */ - our_environ = gdb_environ::from_host_environ (); - - initialize_async_io (); - initialize_low (); - have_job_control (); - initialize_event_loop (); - if (target_supports_tracepoints ()) - initialize_tracepoint (); - - mem_buf = (unsigned char *) xmalloc (PBUFSIZ); - - if (selftest) - { -#if GDB_SELF_TEST - selftests::run_tests (selftest_filter); -#else - printf (_("Selftests have been disabled for this build.\n")); -#endif - throw_quit ("Quit"); - } - - if (pid == 0 && *next_arg != NULL) - { - int i, n; - - n = argc - (next_arg - argv); - program_path.set (make_unique_xstrdup (next_arg[0])); - for (i = 1; i < n; i++) - program_args.push_back (xstrdup (next_arg[i])); - program_args.push_back (NULL); - - /* Wait till we are at first instruction in program. */ - create_inferior (program_path.get (), program_args); - - /* We are now (hopefully) stopped at the first instruction of - the target process. This assumes that the target process was - successfully created. */ - } - else if (pid != 0) - { - if (attach_inferior (pid) == -1) - error ("Attaching not supported on this target"); - - /* Otherwise succeeded. */ - } - else - { - cs.last_status.kind = TARGET_WAITKIND_EXITED; - cs.last_status.value.integer = 0; - cs.last_ptid = minus_one_ptid; - } - - SCOPE_EXIT { detach_or_kill_for_exit_cleanup (); }; - - /* Don't report shared library events on the initial connection, - even if some libraries are preloaded. Avoids the "stopped by - shared library event" notice on gdb side. */ - dlls_changed = 0; - - if (cs.last_status.kind == TARGET_WAITKIND_EXITED - || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED) - was_running = 0; - else - was_running = 1; - - if (!was_running && !multi_mode) - error ("No program to debug"); - - while (1) - { - cs.noack_mode = 0; - cs.multi_process = 0; - cs.report_fork_events = 0; - cs.report_vfork_events = 0; - cs.report_exec_events = 0; - /* Be sure we're out of tfind mode. */ - cs.current_traceframe = -1; - cs.cont_thread = null_ptid; - cs.swbreak_feature = 0; - cs.hwbreak_feature = 0; - cs.vCont_supported = 0; - - remote_open (port); - - try - { - /* Wait for events. This will return when all event sources - are removed from the event loop. */ - start_event_loop (); - - /* If an exit was requested (using the "monitor exit" - command), terminate now. */ - if (exit_requested) - throw_quit ("Quit"); - - /* The only other way to get here is for getpkt to fail: - - - If --once was specified, we're done. - - - If not in extended-remote mode, and we're no longer - debugging anything, simply exit: GDB has disconnected - after processing the last process exit. - - - Otherwise, close the connection and reopen it at the - top of the loop. */ - if (run_once || (!extended_protocol && !target_running ())) - throw_quit ("Quit"); - - fprintf (stderr, - "Remote side has terminated connection. " - "GDBserver will reopen the connection.\n"); - - /* Get rid of any pending statuses. An eventual reconnection - (by the same GDB instance or another) will refresh all its - state from scratch. */ - discard_queued_stop_replies (minus_one_ptid); - for_each_thread ([] (thread_info *thread) - { - thread->status_pending_p = 0; - }); - - if (tracing) - { - if (disconnected_tracing) - { - /* Try to enable non-stop/async mode, so we we can - both wait for an async socket accept, and handle - async target events simultaneously. There's also - no point either in having the target always stop - all threads, when we're going to pass signals - down without informing GDB. */ - if (!non_stop) - { - if (start_non_stop (1)) - non_stop = 1; - - /* Detaching implicitly resumes all threads; - simply disconnecting does not. */ - } - } - else - { - fprintf (stderr, - "Disconnected tracing disabled; " - "stopping trace run.\n"); - stop_tracing (); - } - } - } - catch (const gdb_exception_error &exception) - { - fflush (stdout); - fprintf (stderr, "gdbserver: %s\n", exception.what ()); - - if (response_needed) - { - write_enn (cs.own_buf); - putpkt (cs.own_buf); - } - - if (run_once) - throw_quit ("Quit"); - } - } -} - -/* Main function. */ - -int -main (int argc, char *argv[]) -{ - - try - { - captured_main (argc, argv); - } - catch (const gdb_exception &exception) - { - if (exception.reason == RETURN_ERROR) - { - fflush (stdout); - fprintf (stderr, "%s\n", exception.what ()); - fprintf (stderr, "Exiting\n"); - exit_code = 1; - } - - exit (exit_code); - } - - gdb_assert_not_reached ("captured_main should never return"); -} - -/* Process options coming from Z packets for a breakpoint. PACKET is - the packet buffer. *PACKET is updated to point to the first char - after the last processed option. */ - -static void -process_point_options (struct gdb_breakpoint *bp, const char **packet) -{ - const char *dataptr = *packet; - int persist; - - /* Check if data has the correct format. */ - if (*dataptr != ';') - return; - - dataptr++; - - while (*dataptr) - { - if (*dataptr == ';') - ++dataptr; - - if (*dataptr == 'X') - { - /* Conditional expression. */ - if (debug_threads) - debug_printf ("Found breakpoint condition.\n"); - if (!add_breakpoint_condition (bp, &dataptr)) - dataptr = strchrnul (dataptr, ';'); - } - else if (startswith (dataptr, "cmds:")) - { - dataptr += strlen ("cmds:"); - if (debug_threads) - debug_printf ("Found breakpoint commands %s.\n", dataptr); - persist = (*dataptr == '1'); - dataptr += 2; - if (add_breakpoint_commands (bp, &dataptr, persist)) - dataptr = strchrnul (dataptr, ';'); - } - else - { - fprintf (stderr, "Unknown token %c, ignoring.\n", - *dataptr); - /* Skip tokens until we find one that we recognize. */ - dataptr = strchrnul (dataptr, ';'); - } - } - *packet = dataptr; -} - -/* Event loop callback that handles a serial event. The first byte in - the serial buffer gets us here. We expect characters to arrive at - a brisk pace, so we read the rest of the packet with a blocking - getpkt call. */ - -static int -process_serial_event (void) -{ - client_state &cs = get_client_state (); - int signal; - unsigned int len; - CORE_ADDR mem_addr; - unsigned char sig; - int packet_len; - int new_packet_len = -1; - - disable_async_io (); - - response_needed = false; - packet_len = getpkt (cs.own_buf); - if (packet_len <= 0) - { - remote_close (); - /* Force an event loop break. */ - return -1; - } - response_needed = true; - - char ch = cs.own_buf[0]; - switch (ch) - { - case 'q': - handle_query (cs.own_buf, packet_len, &new_packet_len); - break; - case 'Q': - handle_general_set (cs.own_buf); - break; - case 'D': - handle_detach (cs.own_buf); - break; - case '!': - extended_protocol = true; - write_ok (cs.own_buf); - break; - case '?': - handle_status (cs.own_buf); - break; - case 'H': - if (cs.own_buf[1] == 'c' || cs.own_buf[1] == 'g' || cs.own_buf[1] == 's') - { - require_running_or_break (cs.own_buf); - - ptid_t thread_id = read_ptid (&cs.own_buf[2], NULL); - - if (thread_id == null_ptid || thread_id == minus_one_ptid) - thread_id = null_ptid; - else if (thread_id.is_pid ()) - { - /* The ptid represents a pid. */ - thread_info *thread = find_any_thread_of_pid (thread_id.pid ()); - - if (thread == NULL) - { - write_enn (cs.own_buf); - break; - } - - thread_id = thread->id; - } - else - { - /* The ptid represents a lwp/tid. */ - if (find_thread_ptid (thread_id) == NULL) - { - write_enn (cs.own_buf); - break; - } - } - - if (cs.own_buf[1] == 'g') - { - if (thread_id == null_ptid) - { - /* GDB is telling us to choose any thread. Check if - the currently selected thread is still valid. If - it is not, select the first available. */ - thread_info *thread = find_thread_ptid (cs.general_thread); - if (thread == NULL) - thread = get_first_thread (); - thread_id = thread->id; - } - - cs.general_thread = thread_id; - set_desired_thread (); - gdb_assert (current_thread != NULL); - } - else if (cs.own_buf[1] == 'c') - cs.cont_thread = thread_id; - - write_ok (cs.own_buf); - } - else - { - /* Silently ignore it so that gdb can extend the protocol - without compatibility headaches. */ - cs.own_buf[0] = '\0'; - } - break; - case 'g': - require_running_or_break (cs.own_buf); - if (cs.current_traceframe >= 0) - { - struct regcache *regcache - = new_register_cache (current_target_desc ()); - - if (fetch_traceframe_registers (cs.current_traceframe, - regcache, -1) == 0) - registers_to_string (regcache, cs.own_buf); - else - write_enn (cs.own_buf); - free_register_cache (regcache); - } - else - { - struct regcache *regcache; - - if (!set_desired_thread ()) - write_enn (cs.own_buf); - else - { - regcache = get_thread_regcache (current_thread, 1); - registers_to_string (regcache, cs.own_buf); - } - } - break; - case 'G': - require_running_or_break (cs.own_buf); - if (cs.current_traceframe >= 0) - write_enn (cs.own_buf); - else - { - struct regcache *regcache; - - if (!set_desired_thread ()) - write_enn (cs.own_buf); - else - { - regcache = get_thread_regcache (current_thread, 1); - registers_from_string (regcache, &cs.own_buf[1]); - write_ok (cs.own_buf); - } - } - break; - case 'm': - { - require_running_or_break (cs.own_buf); - decode_m_packet (&cs.own_buf[1], &mem_addr, &len); - int res = gdb_read_memory (mem_addr, mem_buf, len); - if (res < 0) - write_enn (cs.own_buf); - else - bin2hex (mem_buf, cs.own_buf, res); - } - break; - case 'M': - require_running_or_break (cs.own_buf); - decode_M_packet (&cs.own_buf[1], &mem_addr, &len, &mem_buf); - if (gdb_write_memory (mem_addr, mem_buf, len) == 0) - write_ok (cs.own_buf); - else - write_enn (cs.own_buf); - break; - case 'X': - require_running_or_break (cs.own_buf); - if (decode_X_packet (&cs.own_buf[1], packet_len - 1, - &mem_addr, &len, &mem_buf) < 0 - || gdb_write_memory (mem_addr, mem_buf, len) != 0) - write_enn (cs.own_buf); - else - write_ok (cs.own_buf); - break; - case 'C': - require_running_or_break (cs.own_buf); - hex2bin (cs.own_buf + 1, &sig, 1); - if (gdb_signal_to_host_p ((enum gdb_signal) sig)) - signal = gdb_signal_to_host ((enum gdb_signal) sig); - else - signal = 0; - myresume (cs.own_buf, 0, signal); - break; - case 'S': - require_running_or_break (cs.own_buf); - hex2bin (cs.own_buf + 1, &sig, 1); - if (gdb_signal_to_host_p ((enum gdb_signal) sig)) - signal = gdb_signal_to_host ((enum gdb_signal) sig); - else - signal = 0; - myresume (cs.own_buf, 1, signal); - break; - case 'c': - require_running_or_break (cs.own_buf); - signal = 0; - myresume (cs.own_buf, 0, signal); - break; - case 's': - require_running_or_break (cs.own_buf); - signal = 0; - myresume (cs.own_buf, 1, signal); - break; - case 'Z': /* insert_ ... */ - /* Fallthrough. */ - case 'z': /* remove_ ... */ - { - char *dataptr; - ULONGEST addr; - int kind; - char type = cs.own_buf[1]; - int res; - const int insert = ch == 'Z'; - const char *p = &cs.own_buf[3]; - - p = unpack_varlen_hex (p, &addr); - kind = strtol (p + 1, &dataptr, 16); - - if (insert) - { - struct gdb_breakpoint *bp; - - bp = set_gdb_breakpoint (type, addr, kind, &res); - if (bp != NULL) - { - res = 0; - - /* GDB may have sent us a list of *point parameters to - be evaluated on the target's side. Read such list - here. If we already have a list of parameters, GDB - is telling us to drop that list and use this one - instead. */ - clear_breakpoint_conditions_and_commands (bp); - const char *options = dataptr; - process_point_options (bp, &options); - } - } - else - res = delete_gdb_breakpoint (type, addr, kind); - - if (res == 0) - write_ok (cs.own_buf); - else if (res == 1) - /* Unsupported. */ - cs.own_buf[0] = '\0'; - else - write_enn (cs.own_buf); - break; - } - case 'k': - response_needed = false; - if (!target_running ()) - /* The packet we received doesn't make sense - but we can't - reply to it, either. */ - return 0; - - fprintf (stderr, "Killing all inferiors\n"); - - for_each_process (kill_inferior_callback); - - /* When using the extended protocol, we wait with no program - running. The traditional protocol will exit instead. */ - if (extended_protocol) - { - cs.last_status.kind = TARGET_WAITKIND_EXITED; - cs.last_status.value.sig = GDB_SIGNAL_KILL; - return 0; - } - else - exit (0); - - case 'T': - { - require_running_or_break (cs.own_buf); - - ptid_t thread_id = read_ptid (&cs.own_buf[1], NULL); - if (find_thread_ptid (thread_id) == NULL) - { - write_enn (cs.own_buf); - break; - } - - if (mythread_alive (thread_id)) - write_ok (cs.own_buf); - else - write_enn (cs.own_buf); - } - break; - case 'R': - response_needed = false; - - /* Restarting the inferior is only supported in the extended - protocol. */ - if (extended_protocol) - { - if (target_running ()) - for_each_process (kill_inferior_callback); - - fprintf (stderr, "GDBserver restarting\n"); - - /* Wait till we are at 1st instruction in prog. */ - if (program_path.get () != NULL) - { - create_inferior (program_path.get (), program_args); - - if (cs.last_status.kind == TARGET_WAITKIND_STOPPED) - { - /* Stopped at the first instruction of the target - process. */ - cs.general_thread = cs.last_ptid; - } - else - { - /* Something went wrong. */ - cs.general_thread = null_ptid; - } - } - else - { - cs.last_status.kind = TARGET_WAITKIND_EXITED; - cs.last_status.value.sig = GDB_SIGNAL_KILL; - } - return 0; - } - else - { - /* It is a request we don't understand. Respond with an - empty packet so that gdb knows that we don't support this - request. */ - cs.own_buf[0] = '\0'; - break; - } - case 'v': - /* Extended (long) request. */ - handle_v_requests (cs.own_buf, packet_len, &new_packet_len); - break; - - default: - /* It is a request we don't understand. Respond with an empty - packet so that gdb knows that we don't support this - request. */ - cs.own_buf[0] = '\0'; - break; - } - - if (new_packet_len != -1) - putpkt_binary (cs.own_buf, new_packet_len); - else - putpkt (cs.own_buf); - - response_needed = false; - - if (exit_requested) - return -1; - - return 0; -} - -/* Event-loop callback for serial events. */ - -int -handle_serial_event (int err, gdb_client_data client_data) -{ - if (debug_threads) - debug_printf ("handling possible serial event\n"); - - /* Really handle it. */ - if (process_serial_event () < 0) - return -1; - - /* Be sure to not change the selected thread behind GDB's back. - Important in the non-stop mode asynchronous protocol. */ - set_desired_thread (); - - return 0; -} - -/* Push a stop notification on the notification queue. */ - -static void -push_stop_notification (ptid_t ptid, struct target_waitstatus *status) -{ - struct vstop_notif *vstop_notif = new struct vstop_notif; - - vstop_notif->status = *status; - vstop_notif->ptid = ptid; - /* Push Stop notification. */ - notif_push (¬if_stop, vstop_notif); -} - -/* Event-loop callback for target events. */ - -int -handle_target_event (int err, gdb_client_data client_data) -{ - client_state &cs = get_client_state (); - if (debug_threads) - debug_printf ("handling possible target event\n"); - - cs.last_ptid = mywait (minus_one_ptid, &cs.last_status, - TARGET_WNOHANG, 1); - - if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED) - { - if (gdb_connected () && report_no_resumed) - push_stop_notification (null_ptid, &cs.last_status); - } - else if (cs.last_status.kind != TARGET_WAITKIND_IGNORE) - { - int pid = cs.last_ptid.pid (); - struct process_info *process = find_process_pid (pid); - int forward_event = !gdb_connected () || process->gdb_detached; - - if (cs.last_status.kind == TARGET_WAITKIND_EXITED - || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED) - { - mark_breakpoints_out (process); - target_mourn_inferior (cs.last_ptid); - } - else if (cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED) - ; - else - { - /* We're reporting this thread as stopped. Update its - "want-stopped" state to what the client wants, until it - gets a new resume action. */ - current_thread->last_resume_kind = resume_stop; - current_thread->last_status = cs.last_status; - } - - if (forward_event) - { - if (!target_running ()) - { - /* The last process exited. We're done. */ - exit (0); - } - - if (cs.last_status.kind == TARGET_WAITKIND_EXITED - || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED - || cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED) - ; - else - { - /* A thread stopped with a signal, but gdb isn't - connected to handle it. Pass it down to the - inferior, as if it wasn't being traced. */ - enum gdb_signal signal; - - if (debug_threads) - debug_printf ("GDB not connected; forwarding event %d for" - " [%s]\n", - (int) cs.last_status.kind, - target_pid_to_str (cs.last_ptid)); - - if (cs.last_status.kind == TARGET_WAITKIND_STOPPED) - signal = cs.last_status.value.sig; - else - signal = GDB_SIGNAL_0; - target_continue (cs.last_ptid, signal); - } - } - else - push_stop_notification (cs.last_ptid, &cs.last_status); - } - - /* Be sure to not change the selected thread behind GDB's back. - Important in the non-stop mode asynchronous protocol. */ - set_desired_thread (); - - return 0; -} - -#if GDB_SELF_TEST -namespace selftests -{ - -void -reset () -{} - -} // namespace selftests -#endif /* GDB_SELF_TEST */ diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h deleted file mode 100644 index 3c286862349..00000000000 --- a/gdb/gdbserver/server.h +++ /dev/null @@ -1,210 +0,0 @@ -/* Common definitions for remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_SERVER_H -#define GDBSERVER_SERVER_H - -#include "gdbsupport/common-defs.h" - -#undef PACKAGE -#undef PACKAGE_NAME -#undef PACKAGE_VERSION -#undef PACKAGE_STRING -#undef PACKAGE_TARNAME - -#include - -gdb_static_assert (sizeof (CORE_ADDR) >= sizeof (void *)); - -#ifdef __MINGW32CE__ -#include "wincecompat.h" -#endif - -#include "gdbsupport/version.h" - -#if !HAVE_DECL_PERROR -#ifndef perror -extern void perror (const char *); -#endif -#endif - -#if !HAVE_DECL_VASPRINTF -extern int vasprintf(char **strp, const char *fmt, va_list ap); -#endif -#if !HAVE_DECL_VSNPRINTF -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -#endif - -#ifdef IN_PROCESS_AGENT -# define PROG "ipa" -#else -# define PROG "gdbserver" -#endif - -#include "gdbsupport/buffer.h" -#include "gdbsupport/xml-utils.h" -#include "regcache.h" -#include "gdbsupport/gdb_signals.h" -#include "target.h" -#include "mem-break.h" -#include "gdbsupport/environ.h" - -/* Target-specific functions */ - -void initialize_low (); - -/* Public variables in server.c */ - -extern bool server_waiting; - -extern bool disable_packet_vCont; -extern bool disable_packet_Tthread; -extern bool disable_packet_qC; -extern bool disable_packet_qfThreadInfo; - -extern bool run_once; -extern bool non_stop; - -#if USE_WIN32API -#include -typedef SOCKET gdb_fildes_t; -#else -typedef int gdb_fildes_t; -#endif - -#include "event-loop.h" - -/* Functions from server.c. */ -extern void handle_v_requests (char *own_buf, int packet_len, - int *new_packet_len); -extern int handle_serial_event (int err, gdb_client_data client_data); -extern int handle_target_event (int err, gdb_client_data client_data); - -/* Get rid of the currently pending stop replies that match PTID. */ -extern void discard_queued_stop_replies (ptid_t ptid); - -/* Returns true if there's a pending stop reply that matches PTID in - the vStopped notifications queue. */ -extern int in_queued_stop_replies (ptid_t ptid); - -#include "remote-utils.h" - -#include "utils.h" -#include "debug.h" -#include "gdbsupport/gdb_vecs.h" - -/* Maximum number of bytes to read/write at once. The value here - is chosen to fill up a packet (the headers account for the 32). */ -#define MAXBUFBYTES(N) (((N)-32)/2) - -/* Buffer sizes for transferring memory, registers, etc. Set to a constant - value to accomodate multiple register formats. This value must be at least - as large as the largest register set supported by gdbserver. */ -#define PBUFSIZ 18432 - -/* Definition for an unknown syscall, used basically in error-cases. */ -#define UNKNOWN_SYSCALL (-1) - -/* Definition for any syscall, used for unfiltered syscall reporting. */ -#define ANY_SYSCALL (-2) - -/* After fork_inferior has been called, we need to adjust a few - signals and call startup_inferior to start the inferior and consume - its first events. This is done here. PID is the pid of the new - inferior and PROGRAM is its name. */ -extern void post_fork_inferior (int pid, const char *program); - -/* Get the gdb_environ being used in the current session. */ -extern gdb_environ *get_environ (); - -extern unsigned long signal_pid; - - -/* Description of the client remote protocol state for the currently - connected client. */ - -struct client_state -{ - client_state (): - own_buf ((char *) xmalloc (PBUFSIZ + 1)) - {} - - /* The thread set with an `Hc' packet. `Hc' is deprecated in favor of - `vCont'. Note the multi-process extensions made `vCont' a - requirement, so `Hc pPID.TID' is pretty much undefined. So - CONT_THREAD can be null_ptid for no `Hc' thread, minus_one_ptid for - resuming all threads of the process (again, `Hc' isn't used for - multi-process), or a specific thread ptid_t. */ - ptid_t cont_thread; - - /* The thread set with an `Hg' packet. */ - ptid_t general_thread; - - int multi_process = 0; - int report_fork_events = 0; - int report_vfork_events = 0; - int report_exec_events = 0; - int report_thread_events = 0; - - /* True if the "swbreak+" feature is active. In that case, GDB wants - us to report whether a trap is explained by a software breakpoint - and for the server to handle PC adjustment if necessary on this - target. Only enabled if the target supports it. */ - int swbreak_feature = 0; - /* True if the "hwbreak+" feature is active. In that case, GDB wants - us to report whether a trap is explained by a hardware breakpoint. - Only enabled if the target supports it. */ - int hwbreak_feature = 0; - - /* True if the "vContSupported" feature is active. In that case, GDB - wants us to report whether single step is supported in the reply to - "vCont?" packet. */ - int vCont_supported = 0; - - /* Whether we should attempt to disable the operating system's address - space randomization feature before starting an inferior. */ - int disable_randomization = 1; - - int pass_signals[GDB_SIGNAL_LAST]; - int program_signals[GDB_SIGNAL_LAST]; - int program_signals_p = 0; - - /* Last status reported to GDB. */ - struct target_waitstatus last_status; - ptid_t last_ptid; - - char *own_buf; - - /* If true, then GDB has requested noack mode. */ - int noack_mode = 0; - /* If true, then we tell GDB to use noack mode by default. */ - int transport_is_reliable = 0; - - /* The traceframe to be used as the source of data to send back to - GDB. A value of -1 means to get data from the live program. */ - - int current_traceframe = -1; - -}; - -client_state &get_client_state (); - -#include "gdbthread.h" -#include "inferiors.h" - -#endif /* GDBSERVER_SERVER_H */ diff --git a/gdb/gdbserver/symbol.c b/gdb/gdbserver/symbol.c deleted file mode 100644 index 467524f0faf..00000000000 --- a/gdb/gdbserver/symbol.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Symbol manipulating routines for the remote server for GDB. - - Copyright (C) 2014-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "gdbsupport/symbol.h" - -/* See gdbsupport/symbol.h. */ - -int -find_minimal_symbol_address (const char *name, CORE_ADDR *addr, - struct objfile *objfile) -{ - gdb_assert (objfile == NULL); - - return look_up_one_symbol (name, addr, 1) != 1; -} diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c deleted file mode 100644 index a4593cf6df9..00000000000 --- a/gdb/gdbserver/target.c +++ /dev/null @@ -1,395 +0,0 @@ -/* Target operations for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#include "server.h" -#include "tracepoint.h" -#include "gdbsupport/byte-vector.h" - -process_stratum_target *the_target; - -int -set_desired_thread () -{ - client_state &cs = get_client_state (); - thread_info *found = find_thread_ptid (cs.general_thread); - - current_thread = found; - return (current_thread != NULL); -} - -/* The thread that was current before prepare_to_access_memory was - called. done_accessing_memory uses this to restore the previous - selected thread. */ -static ptid_t prev_general_thread; - -/* See target.h. */ - -int -prepare_to_access_memory (void) -{ - client_state &cs = get_client_state (); - - /* The first thread found. */ - struct thread_info *first = NULL; - /* The first stopped thread found. */ - struct thread_info *stopped = NULL; - /* The current general thread, if found. */ - struct thread_info *current = NULL; - - /* Save the general thread value, since prepare_to_access_memory could change - it. */ - prev_general_thread = cs.general_thread; - - if (the_target->prepare_to_access_memory != NULL) - { - int res; - - res = the_target->prepare_to_access_memory (); - if (res != 0) - return res; - } - - for_each_thread (prev_general_thread.pid (), [&] (thread_info *thread) - { - if (mythread_alive (thread->id)) - { - if (stopped == NULL && the_target->thread_stopped != NULL - && thread_stopped (thread)) - stopped = thread; - - if (first == NULL) - first = thread; - - if (current == NULL && prev_general_thread == thread->id) - current = thread; - } - }); - - /* The thread we end up choosing. */ - struct thread_info *thread; - - /* Prefer a stopped thread. If none is found, try the current - thread. Otherwise, take the first thread in the process. If - none is found, undo the effects of - target->prepare_to_access_memory() and return error. */ - if (stopped != NULL) - thread = stopped; - else if (current != NULL) - thread = current; - else if (first != NULL) - thread = first; - else - { - done_accessing_memory (); - return 1; - } - - current_thread = thread; - cs.general_thread = ptid_of (thread); - - return 0; -} - -/* See target.h. */ - -void -done_accessing_memory (void) -{ - client_state &cs = get_client_state (); - - if (the_target->done_accessing_memory != NULL) - the_target->done_accessing_memory (); - - /* Restore the previous selected thread. */ - cs.general_thread = prev_general_thread; - switch_to_thread (the_target, cs.general_thread); -} - -int -read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - int res; - res = (*the_target->read_memory) (memaddr, myaddr, len); - check_mem_read (memaddr, myaddr, len); - return res; -} - -/* See target/target.h. */ - -int -target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) -{ - return read_inferior_memory (memaddr, myaddr, len); -} - -/* See target/target.h. */ - -int -target_read_uint32 (CORE_ADDR memaddr, uint32_t *result) -{ - return read_inferior_memory (memaddr, (gdb_byte *) result, sizeof (*result)); -} - -/* See target/target.h. */ - -int -target_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, - ssize_t len) -{ - /* Make a copy of the data because check_mem_write may need to - update it. */ - gdb::byte_vector buffer (myaddr, myaddr + len); - check_mem_write (memaddr, buffer.data (), myaddr, len); - return (*the_target->write_memory) (memaddr, buffer.data (), len); -} - -ptid_t -mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, - int connected_wait) -{ - ptid_t ret; - - if (connected_wait) - server_waiting = 1; - - ret = target_wait (ptid, ourstatus, options); - - /* We don't expose _LOADED events to gdbserver core. See the - `dlls_changed' global. */ - if (ourstatus->kind == TARGET_WAITKIND_LOADED) - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - /* If GDB is connected through TCP/serial, then GDBserver will most - probably be running on its own terminal/console, so it's nice to - print there why is GDBserver exiting. If however, GDB is - connected through stdio, then there's no need to spam the GDB - console with this -- the user will already see the exit through - regular GDB output, in that same terminal. */ - if (!remote_connection_is_stdio ()) - { - if (ourstatus->kind == TARGET_WAITKIND_EXITED) - fprintf (stderr, - "\nChild exited with status %d\n", ourstatus->value.integer); - else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) - fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", - gdb_signal_to_host (ourstatus->value.sig), - gdb_signal_to_name (ourstatus->value.sig)); - } - - if (connected_wait) - server_waiting = 0; - - return ret; -} - -/* See target/target.h. */ - -void -target_stop_and_wait (ptid_t ptid) -{ - struct target_waitstatus status; - bool was_non_stop = non_stop; - struct thread_resume resume_info; - - resume_info.thread = ptid; - resume_info.kind = resume_stop; - resume_info.sig = GDB_SIGNAL_0; - (*the_target->resume) (&resume_info, 1); - - non_stop = true; - mywait (ptid, &status, 0, 0); - non_stop = was_non_stop; -} - -/* See target/target.h. */ - -ptid_t -target_wait (ptid_t ptid, struct target_waitstatus *status, int options) -{ - return (*the_target->wait) (ptid, status, options); -} - -/* See target/target.h. */ - -void -target_mourn_inferior (ptid_t ptid) -{ - (*the_target->mourn) (find_process_pid (ptid.pid ())); -} - -/* See target/target.h. */ - -void -target_continue_no_signal (ptid_t ptid) -{ - struct thread_resume resume_info; - - resume_info.thread = ptid; - resume_info.kind = resume_continue; - resume_info.sig = GDB_SIGNAL_0; - (*the_target->resume) (&resume_info, 1); -} - -/* See target/target.h. */ - -void -target_continue (ptid_t ptid, enum gdb_signal signal) -{ - struct thread_resume resume_info; - - resume_info.thread = ptid; - resume_info.kind = resume_continue; - resume_info.sig = gdb_signal_to_host (signal); - (*the_target->resume) (&resume_info, 1); -} - -/* See target/target.h. */ - -int -target_supports_multi_process (void) -{ - return (the_target->supports_multi_process != NULL ? - (*the_target->supports_multi_process) () : 0); -} - -int -start_non_stop (int nonstop) -{ - if (the_target->start_non_stop == NULL) - { - if (nonstop) - return -1; - else - return 0; - } - - return (*the_target->start_non_stop) (nonstop); -} - -void -set_target_ops (process_stratum_target *target) -{ - the_target = XNEW (process_stratum_target); - memcpy (the_target, target, sizeof (*the_target)); -} - -/* Convert pid to printable format. */ - -const char * -target_pid_to_str (ptid_t ptid) -{ - static char buf[80]; - - if (ptid == minus_one_ptid) - xsnprintf (buf, sizeof (buf), ""); - else if (ptid == null_ptid) - xsnprintf (buf, sizeof (buf), ""); - else if (ptid.tid () != 0) - xsnprintf (buf, sizeof (buf), "Thread %d.0x%lx", - ptid.pid (), ptid.tid ()); - else if (ptid.lwp () != 0) - xsnprintf (buf, sizeof (buf), "LWP %d.%ld", - ptid.pid (), ptid.lwp ()); - else - xsnprintf (buf, sizeof (buf), "Process %d", - ptid.pid ()); - - return buf; -} - -int -kill_inferior (process_info *proc) -{ - gdb_agent_about_to_close (proc->pid); - - return (*the_target->kill) (proc); -} - -/* Target can do hardware single step. */ - -int -target_can_do_hardware_single_step (void) -{ - return 1; -} - -/* Default implementation for breakpoint_kind_for_pc. - - The default behavior for targets that don't implement breakpoint_kind_for_pc - is to use the size of a breakpoint as the kind. */ - -int -default_breakpoint_kind_from_pc (CORE_ADDR *pcptr) -{ - int size = 0; - - gdb_assert (the_target->sw_breakpoint_from_kind != NULL); - - (*the_target->sw_breakpoint_from_kind) (0, &size); - return size; -} - -/* Define it. */ - -target_terminal_state target_terminal::m_terminal_state - = target_terminal_state::is_ours; - -/* See target/target.h. */ - -void -target_terminal::init () -{ - /* Placeholder needed because of fork_inferior. Not necessary on - GDBserver. */ -} - -/* See target/target.h. */ - -void -target_terminal::inferior () -{ - /* Placeholder needed because of fork_inferior. Not necessary on - GDBserver. */ -} - -/* See target/target.h. */ - -void -target_terminal::ours () -{ - /* Placeholder needed because of fork_inferior. Not necessary on - GDBserver. */ -} - -/* See target/target.h. */ - -void -target_terminal::ours_for_output (void) -{ - /* Placeholder. */ -} - -/* See target/target.h. */ - -void -target_terminal::info (const char *arg, int from_tty) -{ - /* Placeholder. */ -} diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h deleted file mode 100644 index 1b0810ba049..00000000000 --- a/gdb/gdbserver/target.h +++ /dev/null @@ -1,736 +0,0 @@ -/* Target operations for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#ifndef GDBSERVER_TARGET_H -#define GDBSERVER_TARGET_H - -#include /* for mode_t */ -#include "target/target.h" -#include "target/resume.h" -#include "target/wait.h" -#include "target/waitstatus.h" -#include "mem-break.h" -#include "gdbsupport/btrace-common.h" -#include - -struct emit_ops; -struct buffer; -struct process_info; - -/* This structure describes how to resume a particular thread (or all - threads) based on the client's request. If thread is -1, then this - entry applies to all threads. These are passed around as an - array. */ - -struct thread_resume -{ - ptid_t thread; - - /* How to "resume". */ - enum resume_kind kind; - - /* If non-zero, send this signal when we resume, or to stop the - thread. If stopping a thread, and this is 0, the target should - stop the thread however it best decides to (e.g., SIGSTOP on - linux; SuspendThread on win32). This is a host signal value (not - enum gdb_signal). */ - int sig; - - /* Range to single step within. Valid only iff KIND is resume_step. - - Single-step once, and then continuing stepping as long as the - thread stops in this range. (If the range is empty - [STEP_RANGE_START == STEP_RANGE_END], then this is a single-step - request.) */ - CORE_ADDR step_range_start; /* Inclusive */ - CORE_ADDR step_range_end; /* Exclusive */ -}; - -/* GDBserver doesn't have a concept of strata like GDB, but we call - its target vector "process_stratum" anyway for the benefit of - shared code. */ -struct process_stratum_target -{ - /* Start a new process. - - PROGRAM is a path to the program to execute. - PROGRAM_ARGS is a standard NULL-terminated array of arguments, - to be passed to the inferior as ``argv'' (along with PROGRAM). - - Returns the new PID on success, -1 on failure. Registers the new - process with the process list. */ - int (*create_inferior) (const char *program, - const std::vector &program_args); - - /* Do additional setup after a new process is created, including - exec-wrapper completion. */ - void (*post_create_inferior) (void); - - /* Attach to a running process. - - PID is the process ID to attach to, specified by the user - or a higher layer. - - Returns -1 if attaching is unsupported, 0 on success, and calls - error() otherwise. */ - - int (*attach) (unsigned long pid); - - /* Kill process PROC. Return -1 on failure, and 0 on success. */ - - int (*kill) (process_info *proc); - - /* Detach from process PROC. Return -1 on failure, and 0 on - success. */ - - int (*detach) (process_info *proc); - - /* The inferior process has died. Do what is right. */ - - void (*mourn) (struct process_info *proc); - - /* Wait for process PID to exit. */ - - void (*join) (int pid); - - /* Return 1 iff the thread with process ID PID is alive. */ - - int (*thread_alive) (ptid_t pid); - - /* Resume the inferior process. */ - - void (*resume) (struct thread_resume *resume_info, size_t n); - - /* Wait for the inferior process or thread to change state. Store - status through argument pointer STATUS. - - PTID = -1 to wait for any pid to do something, PTID(pid,0,0) to - wait for any thread of process pid to do something. Return ptid - of child, or -1 in case of error; store status through argument - pointer STATUS. OPTIONS is a bit set of options defined as - TARGET_W* above. If options contains TARGET_WNOHANG and there's - no child stop to report, return is - null_ptid/TARGET_WAITKIND_IGNORE. */ - - ptid_t (*wait) (ptid_t ptid, struct target_waitstatus *status, int options); - - /* Fetch registers from the inferior process. - - If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */ - - void (*fetch_registers) (struct regcache *regcache, int regno); - - /* Store registers to the inferior process. - - If REGNO is -1, store all registers; otherwise, store at least REGNO. */ - - void (*store_registers) (struct regcache *regcache, int regno); - - /* Prepare to read or write memory from the inferior process. - Targets use this to do what is necessary to get the state of the - inferior such that it is possible to access memory. - - This should generally only be called from client facing routines, - such as gdb_read_memory/gdb_write_memory, or the GDB breakpoint - insertion routine. - - Like `read_memory' and `write_memory' below, returns 0 on success - and errno on failure. */ - - int (*prepare_to_access_memory) (void); - - /* Undo the effects of prepare_to_access_memory. */ - - void (*done_accessing_memory) (void); - - /* Read memory from the inferior process. This should generally be - called through read_inferior_memory, which handles breakpoint shadowing. - - Read LEN bytes at MEMADDR into a buffer at MYADDR. - - Returns 0 on success and errno on failure. */ - - int (*read_memory) (CORE_ADDR memaddr, unsigned char *myaddr, int len); - - /* Write memory to the inferior process. This should generally be - called through target_write_memory, which handles breakpoint shadowing. - - Write LEN bytes from the buffer at MYADDR to MEMADDR. - - Returns 0 on success and errno on failure. */ - - int (*write_memory) (CORE_ADDR memaddr, const unsigned char *myaddr, - int len); - - /* Query GDB for the values of any symbols we're interested in. - This function is called whenever we receive a "qSymbols::" - query, which corresponds to every time more symbols (might) - become available. NULL if we aren't interested in any - symbols. */ - - void (*look_up_symbols) (void); - - /* Send an interrupt request to the inferior process, - however is appropriate. */ - - void (*request_interrupt) (void); - - /* Read auxiliary vector data from the inferior process. - - Read LEN bytes at OFFSET into a buffer at MYADDR. */ - - int (*read_auxv) (CORE_ADDR offset, unsigned char *myaddr, - unsigned int len); - - /* Returns true if GDB Z breakpoint type TYPE is supported, false - otherwise. The type is coded as follows: - '0' - software-breakpoint - '1' - hardware-breakpoint - '2' - write watchpoint - '3' - read watchpoint - '4' - access watchpoint - */ - int (*supports_z_point_type) (char z_type); - - /* Insert and remove a break or watchpoint. - Returns 0 on success, -1 on failure and 1 on unsupported. */ - - int (*insert_point) (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp); - int (*remove_point) (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp); - - /* Returns 1 if the target stopped because it executed a software - breakpoint instruction, 0 otherwise. */ - int (*stopped_by_sw_breakpoint) (void); - - /* Returns true if the target knows whether a trap was caused by a - SW breakpoint triggering. */ - int (*supports_stopped_by_sw_breakpoint) (void); - - /* Returns 1 if the target stopped for a hardware breakpoint. */ - int (*stopped_by_hw_breakpoint) (void); - - /* Returns true if the target knows whether a trap was caused by a - HW breakpoint triggering. */ - int (*supports_stopped_by_hw_breakpoint) (void); - - /* Returns true if the target can do hardware single step. */ - int (*supports_hardware_single_step) (void); - - /* Returns 1 if target was stopped due to a watchpoint hit, 0 otherwise. */ - - int (*stopped_by_watchpoint) (void); - - /* Returns the address associated with the watchpoint that hit, if any; - returns 0 otherwise. */ - - CORE_ADDR (*stopped_data_address) (void); - - /* Reports the text, data offsets of the executable. This is - needed for uclinux where the executable is relocated during load - time. */ - - int (*read_offsets) (CORE_ADDR *text, CORE_ADDR *data); - - /* Fetch the address associated with a specific thread local storage - area, determined by the specified THREAD, OFFSET, and LOAD_MODULE. - Stores it in *ADDRESS and returns zero on success; otherwise returns - an error code. A return value of -1 means this system does not - support the operation. */ - - int (*get_tls_address) (struct thread_info *thread, CORE_ADDR offset, - CORE_ADDR load_module, CORE_ADDR *address); - - /* Fill BUF with an hostio error packet representing the last hostio - error. */ - void (*hostio_last_error) (char *buf); - - /* Read/Write OS data using qXfer packets. */ - int (*qxfer_osdata) (const char *annex, unsigned char *readbuf, - unsigned const char *writebuf, CORE_ADDR offset, - int len); - - /* Read/Write extra signal info. */ - int (*qxfer_siginfo) (const char *annex, unsigned char *readbuf, - unsigned const char *writebuf, - CORE_ADDR offset, int len); - - int (*supports_non_stop) (void); - - /* Enables async target events. Returns the previous enable - state. */ - int (*async) (int enable); - - /* Switch to non-stop (1) or all-stop (0) mode. Return 0 on - success, -1 otherwise. */ - int (*start_non_stop) (int); - - /* Returns true if the target supports multi-process debugging. */ - int (*supports_multi_process) (void); - - /* Returns true if fork events are supported. */ - int (*supports_fork_events) (void); - - /* Returns true if vfork events are supported. */ - int (*supports_vfork_events) (void); - - /* Returns true if exec events are supported. */ - int (*supports_exec_events) (void); - - /* Allows target to re-initialize connection-specific settings. */ - void (*handle_new_gdb_connection) (void); - - /* If not NULL, target-specific routine to process monitor command. - Returns 1 if handled, or 0 to perform default processing. */ - int (*handle_monitor_command) (char *); - - /* Returns the core given a thread, or -1 if not known. */ - int (*core_of_thread) (ptid_t); - - /* Read loadmaps. Read LEN bytes at OFFSET into a buffer at MYADDR. */ - int (*read_loadmap) (const char *annex, CORE_ADDR offset, - unsigned char *myaddr, unsigned int len); - - /* Target specific qSupported support. FEATURES is an array of - features with COUNT elements. */ - void (*process_qsupported) (char **features, int count); - - /* Return 1 if the target supports tracepoints, 0 (or leave the - callback NULL) otherwise. */ - int (*supports_tracepoints) (void); - - /* Read PC from REGCACHE. */ - CORE_ADDR (*read_pc) (struct regcache *regcache); - - /* Write PC to REGCACHE. */ - void (*write_pc) (struct regcache *regcache, CORE_ADDR pc); - - /* Return true if THREAD is known to be stopped now. */ - int (*thread_stopped) (struct thread_info *thread); - - /* Read Thread Information Block address. */ - int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address); - - /* Pause all threads. If FREEZE, arrange for any resume attempt to - be ignored until an unpause_all call unfreezes threads again. - There can be nested calls to pause_all, so a freeze counter - should be maintained. */ - void (*pause_all) (int freeze); - - /* Unpause all threads. Threads that hadn't been resumed by the - client should be left stopped. Basically a pause/unpause call - pair should not end up resuming threads that were stopped before - the pause call. */ - void (*unpause_all) (int unfreeze); - - /* Stabilize all threads. That is, force them out of jump pads. */ - void (*stabilize_threads) (void); - - /* Install a fast tracepoint jump pad. TPOINT is the address of the - tracepoint internal object as used by the IPA agent. TPADDR is - the address of tracepoint. COLLECTOR is address of the function - the jump pad redirects to. LOCKADDR is the address of the jump - pad lock object. ORIG_SIZE is the size in bytes of the - instruction at TPADDR. JUMP_ENTRY points to the address of the - jump pad entry, and on return holds the address past the end of - the created jump pad. If a trampoline is created by the function, - then TRAMPOLINE and TRAMPOLINE_SIZE return the address and size of - the trampoline, else they remain unchanged. JJUMP_PAD_INSN is a - buffer containing a copy of the instruction at TPADDR. - ADJUST_INSN_ADDR and ADJUST_INSN_ADDR_END are output parameters that - return the address range where the instruction at TPADDR was relocated - to. If an error occurs, the ERR may be used to pass on an error - message. */ - int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err); - - /* Return the bytecode operations vector for the current inferior. - Returns NULL if bytecode compilation is not supported. */ - struct emit_ops *(*emit_ops) (void); - - /* Returns true if the target supports disabling randomization. */ - int (*supports_disable_randomization) (void); - - /* Return the minimum length of an instruction that can be safely overwritten - for use as a fast tracepoint. */ - int (*get_min_fast_tracepoint_insn_len) (void); - - /* Read solib info on SVR4 platforms. */ - int (*qxfer_libraries_svr4) (const char *annex, unsigned char *readbuf, - unsigned const char *writebuf, - CORE_ADDR offset, int len); - - /* Return true if target supports debugging agent. */ - int (*supports_agent) (void); - - /* Enable branch tracing for PTID based on CONF and allocate a branch trace - target information struct for reading and for disabling branch trace. */ - struct btrace_target_info *(*enable_btrace) - (ptid_t ptid, const struct btrace_config *conf); - - /* Disable branch tracing. - Returns zero on success, non-zero otherwise. */ - int (*disable_btrace) (struct btrace_target_info *tinfo); - - /* Read branch trace data into buffer. - Return 0 on success; print an error message into BUFFER and return -1, - otherwise. */ - int (*read_btrace) (struct btrace_target_info *, struct buffer *, - enum btrace_read_type type); - - /* Read the branch trace configuration into BUFFER. - Return 0 on success; print an error message into BUFFER and return -1 - otherwise. */ - int (*read_btrace_conf) (const struct btrace_target_info *, struct buffer *); - - /* Return true if target supports range stepping. */ - int (*supports_range_stepping) (void); - - /* Return the full absolute name of the executable file that was - run to create the process PID. If the executable file cannot - be determined, NULL is returned. Otherwise, a pointer to a - character string containing the pathname is returned. This - string should be copied into a buffer by the client if the string - will not be immediately used, or if it must persist. */ - char *(*pid_to_exec_file) (int pid); - - /* Multiple-filesystem-aware open. Like open(2), but operating in - the filesystem as it appears to process PID. Systems where all - processes share a common filesystem should set this to NULL. - If NULL, the caller should fall back to open(2). */ - int (*multifs_open) (int pid, const char *filename, - int flags, mode_t mode); - - /* Multiple-filesystem-aware unlink. Like unlink(2), but operates - in the filesystem as it appears to process PID. Systems where - all processes share a common filesystem should set this to NULL. - If NULL, the caller should fall back to unlink(2). */ - int (*multifs_unlink) (int pid, const char *filename); - - /* Multiple-filesystem-aware readlink. Like readlink(2), but - operating in the filesystem as it appears to process PID. - Systems where all processes share a common filesystem should - set this to NULL. If NULL, the caller should fall back to - readlink(2). */ - ssize_t (*multifs_readlink) (int pid, const char *filename, - char *buf, size_t bufsiz); - - /* Return the breakpoint kind for this target based on PC. The PCPTR is - adjusted to the real memory location in case a flag (e.g., the Thumb bit on - ARM) was present in the PC. */ - int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr); - - /* Return the software breakpoint from KIND. KIND can have target - specific meaning like the Z0 kind parameter. - SIZE is set to the software breakpoint's length in memory. */ - const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size); - - /* Return the thread's name, or NULL if the target is unable to determine it. - The returned value must not be freed by the caller. */ - const char *(*thread_name) (ptid_t thread); - - /* Return the breakpoint kind for this target based on the current - processor state (e.g. the current instruction mode on ARM) and the - PC. The PCPTR is adjusted to the real memory location in case a flag - (e.g., the Thumb bit on ARM) is present in the PC. */ - int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr); - - /* Returns true if the target can software single step. */ - int (*supports_software_single_step) (void); - - /* Return 1 if the target supports catch syscall, 0 (or leave the - callback NULL) otherwise. */ - int (*supports_catch_syscall) (void); - - /* Return tdesc index for IPA. */ - int (*get_ipa_tdesc_idx) (void); - - /* Thread ID to (numeric) thread handle: Return true on success and - false for failure. Return pointer to thread handle via HANDLE - and the handle's length via HANDLE_LEN. */ - bool (*thread_handle) (ptid_t ptid, gdb_byte **handle, int *handle_len); -}; - -extern process_stratum_target *the_target; - -void set_target_ops (process_stratum_target *); - -#define create_inferior(program, program_args) \ - (*the_target->create_inferior) (program, program_args) - -#define target_post_create_inferior() \ - do \ - { \ - if (the_target->post_create_inferior != NULL) \ - (*the_target->post_create_inferior) (); \ - } while (0) - -#define myattach(pid) \ - (*the_target->attach) (pid) - -int kill_inferior (process_info *proc); - -#define target_supports_fork_events() \ - (the_target->supports_fork_events ? \ - (*the_target->supports_fork_events) () : 0) - -#define target_supports_vfork_events() \ - (the_target->supports_vfork_events ? \ - (*the_target->supports_vfork_events) () : 0) - -#define target_supports_exec_events() \ - (the_target->supports_exec_events ? \ - (*the_target->supports_exec_events) () : 0) - -#define target_handle_new_gdb_connection() \ - do \ - { \ - if (the_target->handle_new_gdb_connection != NULL) \ - (*the_target->handle_new_gdb_connection) (); \ - } while (0) - -#define detach_inferior(proc) \ - (*the_target->detach) (proc) - -#define mythread_alive(pid) \ - (*the_target->thread_alive) (pid) - -#define fetch_inferior_registers(regcache, regno) \ - (*the_target->fetch_registers) (regcache, regno) - -#define store_inferior_registers(regcache, regno) \ - (*the_target->store_registers) (regcache, regno) - -#define join_inferior(pid) \ - (*the_target->join) (pid) - -#define target_supports_non_stop() \ - (the_target->supports_non_stop ? (*the_target->supports_non_stop ) () : 0) - -#define target_async(enable) \ - (the_target->async ? (*the_target->async) (enable) : 0) - -#define target_process_qsupported(features, count) \ - do \ - { \ - if (the_target->process_qsupported) \ - the_target->process_qsupported (features, count); \ - } while (0) - -#define target_supports_catch_syscall() \ - (the_target->supports_catch_syscall ? \ - (*the_target->supports_catch_syscall) () : 0) - -#define target_get_ipa_tdesc_idx() \ - (the_target->get_ipa_tdesc_idx \ - ? (*the_target->get_ipa_tdesc_idx) () : 0) - -#define target_supports_tracepoints() \ - (the_target->supports_tracepoints \ - ? (*the_target->supports_tracepoints) () : 0) - -#define target_supports_fast_tracepoints() \ - (the_target->install_fast_tracepoint_jump_pad != NULL) - -#define target_get_min_fast_tracepoint_insn_len() \ - (the_target->get_min_fast_tracepoint_insn_len \ - ? (*the_target->get_min_fast_tracepoint_insn_len) () : 0) - -#define thread_stopped(thread) \ - (*the_target->thread_stopped) (thread) - -#define pause_all(freeze) \ - do \ - { \ - if (the_target->pause_all) \ - (*the_target->pause_all) (freeze); \ - } while (0) - -#define unpause_all(unfreeze) \ - do \ - { \ - if (the_target->unpause_all) \ - (*the_target->unpause_all) (unfreeze); \ - } while (0) - -#define stabilize_threads() \ - do \ - { \ - if (the_target->stabilize_threads) \ - (*the_target->stabilize_threads) (); \ - } while (0) - -#define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \ - collector, lockaddr, \ - orig_size, \ - jump_entry, \ - trampoline, trampoline_size, \ - jjump_pad_insn, \ - jjump_pad_insn_size, \ - adjusted_insn_addr, \ - adjusted_insn_addr_end, \ - err) \ - (*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr, \ - collector,lockaddr, \ - orig_size, jump_entry, \ - trampoline, \ - trampoline_size, \ - jjump_pad_insn, \ - jjump_pad_insn_size, \ - adjusted_insn_addr, \ - adjusted_insn_addr_end, \ - err) - -#define target_emit_ops() \ - (the_target->emit_ops ? (*the_target->emit_ops) () : NULL) - -#define target_supports_disable_randomization() \ - (the_target->supports_disable_randomization ? \ - (*the_target->supports_disable_randomization) () : 0) - -#define target_supports_agent() \ - (the_target->supports_agent ? \ - (*the_target->supports_agent) () : 0) - -static inline struct btrace_target_info * -target_enable_btrace (ptid_t ptid, const struct btrace_config *conf) -{ - if (the_target->enable_btrace == nullptr) - error (_("Target does not support branch tracing.")); - - return (*the_target->enable_btrace) (ptid, conf); -} - -static inline int -target_disable_btrace (struct btrace_target_info *tinfo) -{ - if (the_target->disable_btrace == nullptr) - error (_("Target does not support branch tracing.")); - - return (*the_target->disable_btrace) (tinfo); -} - -static inline int -target_read_btrace (struct btrace_target_info *tinfo, - struct buffer *buffer, - enum btrace_read_type type) -{ - if (the_target->read_btrace == nullptr) - error (_("Target does not support branch tracing.")); - - return (*the_target->read_btrace) (tinfo, buffer, type); -} - -static inline int -target_read_btrace_conf (struct btrace_target_info *tinfo, - struct buffer *buffer) -{ - if (the_target->read_btrace_conf == nullptr) - error (_("Target does not support branch tracing.")); - - return (*the_target->read_btrace_conf) (tinfo, buffer); -} - -#define target_supports_range_stepping() \ - (the_target->supports_range_stepping ? \ - (*the_target->supports_range_stepping) () : 0) - -#define target_supports_stopped_by_sw_breakpoint() \ - (the_target->supports_stopped_by_sw_breakpoint ? \ - (*the_target->supports_stopped_by_sw_breakpoint) () : 0) - -#define target_stopped_by_sw_breakpoint() \ - (the_target->stopped_by_sw_breakpoint ? \ - (*the_target->stopped_by_sw_breakpoint) () : 0) - -#define target_supports_stopped_by_hw_breakpoint() \ - (the_target->supports_stopped_by_hw_breakpoint ? \ - (*the_target->supports_stopped_by_hw_breakpoint) () : 0) - -#define target_supports_hardware_single_step() \ - (the_target->supports_hardware_single_step ? \ - (*the_target->supports_hardware_single_step) () : 0) - -#define target_stopped_by_hw_breakpoint() \ - (the_target->stopped_by_hw_breakpoint ? \ - (*the_target->stopped_by_hw_breakpoint) () : 0) - -#define target_breakpoint_kind_from_pc(pcptr) \ - (the_target->breakpoint_kind_from_pc \ - ? (*the_target->breakpoint_kind_from_pc) (pcptr) \ - : default_breakpoint_kind_from_pc (pcptr)) - -#define target_breakpoint_kind_from_current_state(pcptr) \ - (the_target->breakpoint_kind_from_current_state \ - ? (*the_target->breakpoint_kind_from_current_state) (pcptr) \ - : target_breakpoint_kind_from_pc (pcptr)) - -#define target_supports_software_single_step() \ - (the_target->supports_software_single_step ? \ - (*the_target->supports_software_single_step) () : 0) - -/* Start non-stop mode, returns 0 on success, -1 on failure. */ - -int start_non_stop (int nonstop); - -ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, - int connected_wait); - -/* Prepare to read or write memory from the inferior process. See the - corresponding process_stratum_target methods for more details. */ - -int prepare_to_access_memory (void); -void done_accessing_memory (void); - -#define target_core_of_thread(ptid) \ - (the_target->core_of_thread ? (*the_target->core_of_thread) (ptid) \ - : -1) - -#define target_thread_name(ptid) \ - (the_target->thread_name ? (*the_target->thread_name) (ptid) \ - : NULL) - -#define target_thread_handle(ptid, handle, handle_len) \ - (the_target->thread_handle ? (*the_target->thread_handle) \ - (ptid, handle, handle_len) \ - : false) - -int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); - -int set_desired_thread (); - -const char *target_pid_to_str (ptid_t); - -int target_can_do_hardware_single_step (void); - -int default_breakpoint_kind_from_pc (CORE_ADDR *pcptr); - -#endif /* GDBSERVER_TARGET_H */ diff --git a/gdb/gdbserver/tdesc.c b/gdb/gdbserver/tdesc.c deleted file mode 100644 index de25e7cfb46..00000000000 --- a/gdb/gdbserver/tdesc.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Copyright (C) 2012-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "tdesc.h" -#include "regdef.h" - -#ifndef IN_PROCESS_AGENT - -target_desc::~target_desc () -{ - xfree ((char *) arch); - xfree ((char *) osabi); -} - -bool target_desc::operator== (const target_desc &other) const -{ - if (reg_defs != other.reg_defs) - return false; - - /* Compare expedite_regs. */ - int i = 0; - for (; expedite_regs[i] != NULL; i++) - { - if (strcmp (expedite_regs[i], other.expedite_regs[i]) != 0) - return false; - } - if (other.expedite_regs[i] != NULL) - return false; - - return true; -} - -#endif - -void target_desc::accept (tdesc_element_visitor &v) const -{ -#ifndef IN_PROCESS_AGENT - v.visit_pre (this); - - for (const tdesc_feature_up &feature : features) - feature->accept (v); - - v.visit_post (this); -#endif -} - -void -init_target_desc (struct target_desc *tdesc, - const char **expedite_regs) -{ - int offset = 0; - - /* Go through all the features and populate reg_defs. */ - for (const tdesc_feature_up &feature : tdesc->features) - for (const tdesc_reg_up &treg : feature->registers) - { - int regnum = treg->target_regnum; - - /* Register number will increase (possibly with gaps) or be zero. */ - gdb_assert (regnum == 0 || regnum >= tdesc->reg_defs.size ()); - - if (regnum != 0) - tdesc->reg_defs.resize (regnum, reg (offset)); - - tdesc->reg_defs.emplace_back (treg->name.c_str (), offset, - treg->bitsize); - offset += treg->bitsize; - } - - tdesc->registers_size = offset / 8; - - /* Make sure PBUFSIZ is large enough to hold a full register - packet. */ - gdb_assert (2 * tdesc->registers_size + 32 <= PBUFSIZ); - -#ifndef IN_PROCESS_AGENT - tdesc->expedite_regs = expedite_regs; -#endif -} - -struct target_desc * -allocate_target_description (void) -{ - return new target_desc (); -} - -#ifndef IN_PROCESS_AGENT - -static const struct target_desc default_description {}; - -void -copy_target_description (struct target_desc *dest, - const struct target_desc *src) -{ - dest->reg_defs = src->reg_defs; - dest->expedite_regs = src->expedite_regs; - dest->registers_size = src->registers_size; - dest->xmltarget = src->xmltarget; -} - -const struct target_desc * -current_target_desc (void) -{ - if (current_thread == NULL) - return &default_description; - - return current_process ()->tdesc; -} - -/* See gdbsupport/tdesc.h. */ - -const char * -tdesc_architecture_name (const struct target_desc *target_desc) -{ - return target_desc->arch; -} - -/* See gdbsupport/tdesc.h. */ - -void -set_tdesc_architecture (struct target_desc *target_desc, - const char *name) -{ - target_desc->arch = xstrdup (name); -} - -/* See gdbsupport/tdesc.h. */ - -const char * -tdesc_osabi_name (const struct target_desc *target_desc) -{ - return target_desc->osabi; -} - -/* See gdbsupport/tdesc.h. */ - -void -set_tdesc_osabi (struct target_desc *target_desc, const char *name) -{ - target_desc->osabi = xstrdup (name); -} - -/* See gdbsupport/tdesc.h. */ - -const char * -tdesc_get_features_xml (const target_desc *tdesc) -{ - /* Either .xmltarget or .features is not NULL. */ - gdb_assert (tdesc->xmltarget != NULL - || (!tdesc->features.empty () - && tdesc->arch != NULL)); - - if (tdesc->xmltarget == NULL) - { - std::string buffer ("@"); - print_xml_feature v (&buffer); - tdesc->accept (v); - tdesc->xmltarget = xstrdup (buffer.c_str ()); - } - - return tdesc->xmltarget; -} -#endif - -/* See gdbsupport/tdesc.h. */ - -struct tdesc_feature * -tdesc_create_feature (struct target_desc *tdesc, const char *name) -{ - struct tdesc_feature *new_feature = new tdesc_feature (name); - tdesc->features.emplace_back (new_feature); - return new_feature; -} - -/* See gdbsupport/tdesc.h. */ - -bool -tdesc_contains_feature (const target_desc *tdesc, const std::string &feature) -{ - gdb_assert (tdesc != nullptr); - - for (const tdesc_feature_up &f : tdesc->features) - { - if (f->name == feature) - return true; - } - - return false; -} diff --git a/gdb/gdbserver/tdesc.h b/gdb/gdbserver/tdesc.h deleted file mode 100644 index 5e0df85cea8..00000000000 --- a/gdb/gdbserver/tdesc.h +++ /dev/null @@ -1,101 +0,0 @@ -/* Target description definitions for remote server for GDB. - Copyright (C) 2012-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_TDESC_H -#define GDBSERVER_TDESC_H - -#include "gdbsupport/tdesc.h" - -#include "regdef.h" -#include - -/* A target description. Inherit from tdesc_feature so that target_desc - can be used as tdesc_feature. */ - -struct target_desc : tdesc_element -{ - /* A vector of elements of register definitions that - describe the inferior's register set. */ - std::vector reg_defs; - - /* The register cache size, in bytes. */ - int registers_size; - - /* XML features in this target description. */ - std::vector features; - -#ifndef IN_PROCESS_AGENT - /* An array of register names. These are the "expedite" registers: - registers whose values are sent along with stop replies. */ - const char **expedite_regs = NULL; - - /* Defines what to return when looking for the "target.xml" file in - response to qXfer:features:read. Its contents can either be - verbatim XML code (prefixed with a '@') or else the name of the - actual XML file to be used in place of "target.xml". - - If NULL then its content will be generated by parsing the target - description into xml. */ - mutable const char *xmltarget = NULL; - - /* The value of element in the XML, replying GDB. */ - const char *arch = NULL; - - /* The value of element in the XML, replying GDB. */ - const char *osabi = NULL; - -public: - target_desc () - : registers_size (0) - {} - - ~target_desc (); - - bool operator== (const target_desc &other) const; - - bool operator!= (const target_desc &other) const - { - return !(*this == other); - } -#endif - - void accept (tdesc_element_visitor &v) const override; -}; - -/* Copy target description SRC to DEST. */ - -void copy_target_description (struct target_desc *dest, - const struct target_desc *src); - -/* Initialize TDESC, and then set its expedite_regs field to - EXPEDITE_REGS. */ - -void init_target_desc (struct target_desc *tdesc, - const char **expedite_regs); - -/* Return the current inferior's target description. Never returns - NULL. */ - -const struct target_desc *current_target_desc (void); - -/* Return true if TDESC contains the feature described by string FEATURE. - Return false otherwise. */ -bool tdesc_contains_feature (const target_desc *tdesc, - const std::string &feature); - -#endif /* GDBSERVER_TDESC_H */ diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c deleted file mode 100644 index 2bb6d28820e..00000000000 --- a/gdb/gdbserver/thread-db.c +++ /dev/null @@ -1,910 +0,0 @@ -/* Thread management interface, for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 3 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, see . */ - -#include "server.h" - -#include "linux-low.h" - -#include "debug.h" -#include "gdb_proc_service.h" -#include "nat/gdb_thread_db.h" -#include "gdbsupport/gdb_vecs.h" -#include "nat/linux-procfs.h" -#include "gdbsupport/scoped_restore.h" - -#ifndef USE_LIBTHREAD_DB_DIRECTLY -#include -#endif -#include -#include - -struct thread_db -{ - /* Structure that identifies the child process for the - interface. */ - struct ps_prochandle proc_handle; - - /* Connection to the libthread_db library. */ - td_thragent_t *thread_agent; - - /* If this flag has been set, we've already asked GDB for all - symbols we might need; assume symbol cache misses are - failures. */ - int all_symbols_looked_up; - -#ifndef USE_LIBTHREAD_DB_DIRECTLY - /* Handle of the libthread_db from dlopen. */ - void *handle; -#endif - - /* Addresses of libthread_db functions. */ - td_ta_new_ftype *td_ta_new_p; - td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p; - td_thr_get_info_ftype *td_thr_get_info_p; - td_ta_thr_iter_ftype *td_ta_thr_iter_p; - td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p; - td_thr_tlsbase_ftype *td_thr_tlsbase_p; - td_symbol_list_ftype *td_symbol_list_p; -}; - -static char *libthread_db_search_path; - -static int find_one_thread (ptid_t); -static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); - -static const char * -thread_db_err_str (td_err_e err) -{ - static char buf[64]; - - switch (err) - { - case TD_OK: - return "generic 'call succeeded'"; - case TD_ERR: - return "generic error"; - case TD_NOTHR: - return "no thread to satisfy query"; - case TD_NOSV: - return "no sync handle to satisfy query"; - case TD_NOLWP: - return "no LWP to satisfy query"; - case TD_BADPH: - return "invalid process handle"; - case TD_BADTH: - return "invalid thread handle"; - case TD_BADSH: - return "invalid synchronization handle"; - case TD_BADTA: - return "invalid thread agent"; - case TD_BADKEY: - return "invalid key"; - case TD_NOMSG: - return "no event message for getmsg"; - case TD_NOFPREGS: - return "FPU register set not available"; - case TD_NOLIBTHREAD: - return "application not linked with libthread"; - case TD_NOEVENT: - return "requested event is not supported"; - case TD_NOCAPAB: - return "capability not available"; - case TD_DBERR: - return "debugger service failed"; - case TD_NOAPLIC: - return "operation not applicable to"; - case TD_NOTSD: - return "no thread-specific data for this thread"; - case TD_MALLOC: - return "malloc failed"; - case TD_PARTIALREG: - return "only part of register set was written/read"; - case TD_NOXREGS: - return "X register set not available for this thread"; -#ifdef HAVE_TD_VERSION - case TD_VERSION: - return "version mismatch between libthread_db and libpthread"; -#endif - default: - xsnprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err); - return buf; - } -} - -#if 0 -static char * -thread_db_state_str (td_thr_state_e state) -{ - static char buf[64]; - - switch (state) - { - case TD_THR_STOPPED: - return "stopped by debugger"; - case TD_THR_RUN: - return "runnable"; - case TD_THR_ACTIVE: - return "active"; - case TD_THR_ZOMBIE: - return "zombie"; - case TD_THR_SLEEP: - return "sleeping"; - case TD_THR_STOPPED_ASLEEP: - return "stopped by debugger AND blocked"; - default: - xsnprintf (buf, sizeof (buf), "unknown thread_db state %d", state); - return buf; - } -} -#endif - -/* Get thread info about PTID, accessing memory via the current - thread. */ - -static int -find_one_thread (ptid_t ptid) -{ - td_thrhandle_t th; - td_thrinfo_t ti; - td_err_e err; - struct lwp_info *lwp; - struct thread_db *thread_db = current_process ()->priv->thread_db; - int lwpid = ptid.lwp (); - - thread_info *thread = find_thread_ptid (ptid); - lwp = get_thread_lwp (thread); - if (lwp->thread_known) - return 1; - - /* Get information about this thread. */ - err = thread_db->td_ta_map_lwp2thr_p (thread_db->thread_agent, lwpid, &th); - if (err != TD_OK) - error ("Cannot get thread handle for LWP %d: %s", - lwpid, thread_db_err_str (err)); - - err = thread_db->td_thr_get_info_p (&th, &ti); - if (err != TD_OK) - error ("Cannot get thread info for LWP %d: %s", - lwpid, thread_db_err_str (err)); - - if (debug_threads) - debug_printf ("Found thread %ld (LWP %d)\n", - (unsigned long) ti.ti_tid, ti.ti_lid); - - if (lwpid != ti.ti_lid) - { - warning ("PID mismatch! Expected %ld, got %ld", - (long) lwpid, (long) ti.ti_lid); - return 0; - } - - /* If the new thread ID is zero, a final thread ID will be available - later. Do not enable thread debugging yet. */ - if (ti.ti_tid == 0) - return 0; - - lwp->thread_known = 1; - lwp->th = th; - lwp->thread_handle = ti.ti_tid; - - return 1; -} - -/* Attach a thread. Return true on success. */ - -static int -attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) -{ - struct process_info *proc = current_process (); - int pid = pid_of (proc); - ptid_t ptid = ptid_t (pid, ti_p->ti_lid, 0); - struct lwp_info *lwp; - int err; - - if (debug_threads) - debug_printf ("Attaching to thread %ld (LWP %d)\n", - (unsigned long) ti_p->ti_tid, ti_p->ti_lid); - err = linux_attach_lwp (ptid); - if (err != 0) - { - std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err); - - warning ("Could not attach to thread %ld (LWP %d): %s", - (unsigned long) ti_p->ti_tid, ti_p->ti_lid, reason.c_str ()); - - return 0; - } - - lwp = find_lwp_pid (ptid); - gdb_assert (lwp != NULL); - lwp->thread_known = 1; - lwp->th = *th_p; - lwp->thread_handle = ti_p->ti_tid; - - return 1; -} - -/* Attach thread if we haven't seen it yet. - Increment *COUNTER if we have attached a new thread. - Return false on failure. */ - -static int -maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p, - int *counter) -{ - struct lwp_info *lwp; - - lwp = find_lwp_pid (ptid_t (ti_p->ti_lid)); - if (lwp != NULL) - return 1; - - if (!attach_thread (th_p, ti_p)) - return 0; - - if (counter != NULL) - *counter += 1; - - return 1; -} - -static int -find_new_threads_callback (const td_thrhandle_t *th_p, void *data) -{ - td_thrinfo_t ti; - td_err_e err; - struct thread_db *thread_db = current_process ()->priv->thread_db; - - err = thread_db->td_thr_get_info_p (th_p, &ti); - if (err != TD_OK) - error ("Cannot get thread info: %s", thread_db_err_str (err)); - - if (ti.ti_lid == -1) - { - /* A thread with kernel thread ID -1 is either a thread that - exited and was joined, or a thread that is being created but - hasn't started yet, and that is reusing the tcb/stack of a - thread that previously exited and was joined. (glibc marks - terminated and joined threads with kernel thread ID -1. See - glibc PR17707. */ - if (debug_threads) - debug_printf ("thread_db: skipping exited and " - "joined thread (0x%lx)\n", - (unsigned long) ti.ti_tid); - return 0; - } - - /* Check for zombies. */ - if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) - return 0; - - if (!maybe_attach_thread (th_p, &ti, (int *) data)) - { - /* Terminate iteration early: we might be looking at stale data in - the inferior. The thread_db_find_new_threads will retry. */ - return 1; - } - - return 0; -} - -static void -thread_db_find_new_threads (void) -{ - td_err_e err; - ptid_t ptid = current_ptid; - struct thread_db *thread_db = current_process ()->priv->thread_db; - int loop, iteration; - - /* This function is only called when we first initialize thread_db. - First locate the initial thread. If it is not ready for - debugging yet, then stop. */ - if (find_one_thread (ptid) == 0) - return; - - /* Require 4 successive iterations which do not find any new threads. - The 4 is a heuristic: there is an inherent race here, and I have - seen that 2 iterations in a row are not always sufficient to - "capture" all threads. */ - for (loop = 0, iteration = 0; loop < 4; ++loop, ++iteration) - { - int new_thread_count = 0; - - /* Iterate over all user-space threads to discover new threads. */ - err = thread_db->td_ta_thr_iter_p (thread_db->thread_agent, - find_new_threads_callback, - &new_thread_count, - TD_THR_ANY_STATE, - TD_THR_LOWEST_PRIORITY, - TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); - if (debug_threads) - debug_printf ("Found %d threads in iteration %d.\n", - new_thread_count, iteration); - - if (new_thread_count != 0) - { - /* Found new threads. Restart iteration from beginning. */ - loop = -1; - } - } - if (err != TD_OK) - error ("Cannot find new threads: %s", thread_db_err_str (err)); -} - -/* Cache all future symbols that thread_db might request. We can not - request symbols at arbitrary states in the remote protocol, only - when the client tells us that new symbols are available. So when - we load the thread library, make sure to check the entire list. */ - -static void -thread_db_look_up_symbols (void) -{ - struct thread_db *thread_db = current_process ()->priv->thread_db; - const char **sym_list; - CORE_ADDR unused; - - for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++) - look_up_one_symbol (*sym_list, &unused, 1); - - /* We're not interested in any other libraries loaded after this - point, only in symbols in libpthread.so. */ - thread_db->all_symbols_looked_up = 1; -} - -int -thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp) -{ - struct thread_db *thread_db = current_process ()->priv->thread_db; - int may_ask_gdb = !thread_db->all_symbols_looked_up; - - /* If we've passed the call to thread_db_look_up_symbols, then - anything not in the cache must not exist; we're not interested - in any libraries loaded after that point, only in symbols in - libpthread.so. It might not be an appropriate time to look - up a symbol, e.g. while we're trying to fetch registers. */ - return look_up_one_symbol (name, addrp, may_ask_gdb); -} - -int -thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, - CORE_ADDR load_module, CORE_ADDR *address) -{ - psaddr_t addr; - td_err_e err; - struct lwp_info *lwp; - struct thread_info *saved_thread; - struct process_info *proc; - struct thread_db *thread_db; - - proc = get_thread_process (thread); - thread_db = proc->priv->thread_db; - - /* If the thread layer is not (yet) initialized, fail. */ - if (thread_db == NULL || !thread_db->all_symbols_looked_up) - return TD_ERR; - - /* If td_thr_tls_get_addr is missing rather do not expect td_thr_tlsbase - could work. */ - if (thread_db->td_thr_tls_get_addr_p == NULL - || (load_module == 0 && thread_db->td_thr_tlsbase_p == NULL)) - return -1; - - lwp = get_thread_lwp (thread); - if (!lwp->thread_known) - find_one_thread (thread->id); - if (!lwp->thread_known) - return TD_NOTHR; - - saved_thread = current_thread; - current_thread = thread; - - if (load_module != 0) - { - /* Note the cast through uintptr_t: this interface only works if - a target address fits in a psaddr_t, which is a host pointer. - So a 32-bit debugger can not access 64-bit TLS through this. */ - err = thread_db->td_thr_tls_get_addr_p (&lwp->th, - (psaddr_t) (uintptr_t) load_module, - offset, &addr); - } - else - { - /* This code path handles the case of -static -pthread executables: - https://sourceware.org/ml/libc-help/2014-03/msg00024.html - For older GNU libc r_debug.r_map is NULL. For GNU libc after - PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL. - The constant number 1 depends on GNU __libc_setup_tls - initialization of l_tls_modid to 1. */ - err = thread_db->td_thr_tlsbase_p (&lwp->th, 1, &addr); - addr = (char *) addr + offset; - } - - current_thread = saved_thread; - if (err == TD_OK) - { - *address = (CORE_ADDR) (uintptr_t) addr; - return 0; - } - else - return err; -} - -/* See linux-low.h. */ - -bool -thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len) -{ - struct thread_db *thread_db; - struct lwp_info *lwp; - thread_info *thread = find_thread_ptid (ptid); - - if (thread == NULL) - return false; - - thread_db = get_thread_process (thread)->priv->thread_db; - - if (thread_db == NULL) - return false; - - lwp = get_thread_lwp (thread); - - if (!lwp->thread_known && !find_one_thread (thread->id)) - return false; - - gdb_assert (lwp->thread_known); - - *handle = (gdb_byte *) &lwp->thread_handle; - *handle_len = sizeof (lwp->thread_handle); - return true; -} - -#ifdef USE_LIBTHREAD_DB_DIRECTLY - -static int -thread_db_load_search (void) -{ - td_err_e err; - struct thread_db *tdb; - struct process_info *proc = current_process (); - - gdb_assert (proc->priv->thread_db == NULL); - - tdb = XCNEW (struct thread_db); - proc->priv->thread_db = tdb; - - tdb->td_ta_new_p = &td_ta_new; - - /* Attempt to open a connection to the thread library. */ - err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); - if (err != TD_OK) - { - if (debug_threads) - debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err)); - free (tdb); - proc->priv->thread_db = NULL; - return 0; - } - - tdb->td_ta_map_lwp2thr_p = &td_ta_map_lwp2thr; - tdb->td_thr_get_info_p = &td_thr_get_info; - tdb->td_ta_thr_iter_p = &td_ta_thr_iter; - tdb->td_symbol_list_p = &td_symbol_list; - - /* These are not essential. */ - tdb->td_thr_tls_get_addr_p = &td_thr_tls_get_addr; - tdb->td_thr_tlsbase_p = &td_thr_tlsbase; - - return 1; -} - -#else - -static int -try_thread_db_load_1 (void *handle) -{ - td_err_e err; - struct thread_db *tdb; - struct process_info *proc = current_process (); - - gdb_assert (proc->priv->thread_db == NULL); - - tdb = XCNEW (struct thread_db); - proc->priv->thread_db = tdb; - - tdb->handle = handle; - - /* Initialize pointers to the dynamic library functions we will use. - Essential functions first. */ - -#define CHK(required, a) \ - do \ - { \ - if ((a) == NULL) \ - { \ - if (debug_threads) \ - debug_printf ("dlsym: %s\n", dlerror ()); \ - if (required) \ - { \ - free (tdb); \ - proc->priv->thread_db = NULL; \ - return 0; \ - } \ - } \ - } \ - while (0) - -#define TDB_DLSYM(tdb, func) \ - tdb->func ## _p = (func ## _ftype *) dlsym (tdb->handle, #func) - - CHK (1, TDB_DLSYM (tdb, td_ta_new)); - - /* Attempt to open a connection to the thread library. */ - err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); - if (err != TD_OK) - { - if (debug_threads) - debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err)); - free (tdb); - proc->priv->thread_db = NULL; - return 0; - } - - CHK (1, TDB_DLSYM (tdb, td_ta_map_lwp2thr)); - CHK (1, TDB_DLSYM (tdb, td_thr_get_info)); - CHK (1, TDB_DLSYM (tdb, td_ta_thr_iter)); - CHK (1, TDB_DLSYM (tdb, td_symbol_list)); - - /* These are not essential. */ - CHK (0, TDB_DLSYM (tdb, td_thr_tls_get_addr)); - CHK (0, TDB_DLSYM (tdb, td_thr_tlsbase)); - -#undef CHK -#undef TDB_DLSYM - - return 1; -} - -#ifdef HAVE_DLADDR - -/* Lookup a library in which given symbol resides. - Note: this is looking in the GDBSERVER process, not in the inferior. - Returns library name, or NULL. */ - -static const char * -dladdr_to_soname (const void *addr) -{ - Dl_info info; - - if (dladdr (addr, &info) != 0) - return info.dli_fname; - return NULL; -} - -#endif - -static int -try_thread_db_load (const char *library) -{ - void *handle; - - if (debug_threads) - debug_printf ("Trying host libthread_db library: %s.\n", - library); - handle = dlopen (library, RTLD_NOW); - if (handle == NULL) - { - if (debug_threads) - debug_printf ("dlopen failed: %s.\n", dlerror ()); - return 0; - } - -#ifdef HAVE_DLADDR - if (debug_threads && strchr (library, '/') == NULL) - { - void *td_init; - - td_init = dlsym (handle, "td_init"); - if (td_init != NULL) - { - const char *const libpath = dladdr_to_soname (td_init); - - if (libpath != NULL) - debug_printf ("Host %s resolved to: %s.\n", library, libpath); - } - } -#endif - - if (try_thread_db_load_1 (handle)) - return 1; - - /* This library "refused" to work on current inferior. */ - dlclose (handle); - return 0; -} - -/* Handle $sdir in libthread-db-search-path. - Look for libthread_db in the system dirs, or wherever a plain - dlopen(file_without_path) will look. - The result is true for success. */ - -static int -try_thread_db_load_from_sdir (void) -{ - return try_thread_db_load (LIBTHREAD_DB_SO); -} - -/* Try to load libthread_db from directory DIR of length DIR_LEN. - The result is true for success. */ - -static int -try_thread_db_load_from_dir (const char *dir, size_t dir_len) -{ - char path[PATH_MAX]; - - if (dir_len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path)) - { - char *cp = (char *) xmalloc (dir_len + 1); - - memcpy (cp, dir, dir_len); - cp[dir_len] = '\0'; - warning (_("libthread-db-search-path component too long," - " ignored: %s."), cp); - free (cp); - return 0; - } - - memcpy (path, dir, dir_len); - path[dir_len] = '/'; - strcpy (path + dir_len + 1, LIBTHREAD_DB_SO); - return try_thread_db_load (path); -} - -/* Search libthread_db_search_path for libthread_db which "agrees" - to work on current inferior. - The result is true for success. */ - -static int -thread_db_load_search (void) -{ - int rc = 0; - - if (libthread_db_search_path == NULL) - libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH); - - std::vector> dir_vec - = dirnames_to_char_ptr_vec (libthread_db_search_path); - - for (const gdb::unique_xmalloc_ptr &this_dir_up : dir_vec) - { - char *this_dir = this_dir_up.get (); - const int pdir_len = sizeof ("$pdir") - 1; - size_t this_dir_len; - - this_dir_len = strlen (this_dir); - - if (strncmp (this_dir, "$pdir", pdir_len) == 0 - && (this_dir[pdir_len] == '\0' - || this_dir[pdir_len] == '/')) - { - /* We don't maintain a list of loaded libraries so we don't know - where libpthread lives. We *could* fetch the info, but we don't - do that yet. Ignore it. */ - } - else if (strcmp (this_dir, "$sdir") == 0) - { - if (try_thread_db_load_from_sdir ()) - { - rc = 1; - break; - } - } - else - { - if (try_thread_db_load_from_dir (this_dir, this_dir_len)) - { - rc = 1; - break; - } - } - } - - if (debug_threads) - debug_printf ("thread_db_load_search returning %d\n", rc); - return rc; -} - -#endif /* USE_LIBTHREAD_DB_DIRECTLY */ - -int -thread_db_init (void) -{ - struct process_info *proc = current_process (); - - /* FIXME drow/2004-10-16: This is the "overall process ID", which - GNU/Linux calls tgid, "thread group ID". When we support - attaching to threads, the original thread may not be the correct - thread. We would have to get the process ID from /proc for NPTL. - - This isn't the only place in gdbserver that assumes that the first - process in the list is the thread group leader. */ - - if (thread_db_load_search ()) - { - /* It's best to avoid td_ta_thr_iter if possible. That walks - data structures in the inferior's address space that may be - corrupted, or, if the target is running, the list may change - while we walk it. In the latter case, it's possible that a - thread exits just at the exact time that causes GDBserver to - get stuck in an infinite loop. As the kernel supports clone - events and /proc/PID/task/ exists, then we already know about - all threads in the process. When we need info out of - thread_db on a given thread (e.g., for TLS), we'll use - find_one_thread then. That uses thread_db entry points that - do not walk libpthread's thread list, so should be safe, as - well as more efficient. */ - if (!linux_proc_task_list_dir_exists (pid_of (proc))) - thread_db_find_new_threads (); - thread_db_look_up_symbols (); - return 1; - } - - return 0; -} - -static void -switch_to_process (struct process_info *proc) -{ - int pid = pid_of (proc); - - current_thread = find_any_thread_of_pid (pid); -} - -/* Disconnect from libthread_db and free resources. */ - -static void -disable_thread_event_reporting (struct process_info *proc) -{ - struct thread_db *thread_db = proc->priv->thread_db; - if (thread_db) - { - td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta, - td_thr_events_t *event); - -#ifndef USE_LIBTHREAD_DB_DIRECTLY - td_ta_clear_event_p - = (td_ta_clear_event_ftype *) dlsym (thread_db->handle, - "td_ta_clear_event"); -#else - td_ta_clear_event_p = &td_ta_clear_event; -#endif - - if (td_ta_clear_event_p != NULL) - { - struct thread_info *saved_thread = current_thread; - td_thr_events_t events; - - switch_to_process (proc); - - /* Set the process wide mask saying we aren't interested - in any events anymore. */ - td_event_fillset (&events); - (*td_ta_clear_event_p) (thread_db->thread_agent, &events); - - current_thread = saved_thread; - } - } -} - -void -thread_db_detach (struct process_info *proc) -{ - struct thread_db *thread_db = proc->priv->thread_db; - - if (thread_db) - { - disable_thread_event_reporting (proc); - } -} - -/* Disconnect from libthread_db and free resources. */ - -void -thread_db_mourn (struct process_info *proc) -{ - struct thread_db *thread_db = proc->priv->thread_db; - if (thread_db) - { - td_ta_delete_ftype *td_ta_delete_p; - -#ifndef USE_LIBTHREAD_DB_DIRECTLY - td_ta_delete_p = (td_ta_delete_ftype *) dlsym (thread_db->handle, "td_ta_delete"); -#else - td_ta_delete_p = &td_ta_delete; -#endif - - if (td_ta_delete_p != NULL) - (*td_ta_delete_p) (thread_db->thread_agent); - -#ifndef USE_LIBTHREAD_DB_DIRECTLY - dlclose (thread_db->handle); -#endif /* USE_LIBTHREAD_DB_DIRECTLY */ - - free (thread_db); - proc->priv->thread_db = NULL; - } -} - -/* Handle "set libthread-db-search-path" monitor command and return 1. - For any other command, return 0. */ - -int -thread_db_handle_monitor_command (char *mon) -{ - const char *cmd = "set libthread-db-search-path"; - size_t cmd_len = strlen (cmd); - - if (strncmp (mon, cmd, cmd_len) == 0 - && (mon[cmd_len] == '\0' - || mon[cmd_len] == ' ')) - { - const char *cp = mon + cmd_len; - - if (libthread_db_search_path != NULL) - free (libthread_db_search_path); - - /* Skip leading space (if any). */ - while (isspace (*cp)) - ++cp; - - if (*cp == '\0') - cp = LIBTHREAD_DB_SEARCH_PATH; - libthread_db_search_path = xstrdup (cp); - - monitor_output ("libthread-db-search-path set to `"); - monitor_output (libthread_db_search_path); - monitor_output ("'\n"); - return 1; - } - - /* Tell server.c to perform default processing. */ - return 0; -} - -/* See linux-low.h. */ - -void -thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid) -{ - process_info *parent_proc = get_thread_process (parent_thr); - struct thread_db *thread_db = parent_proc->priv->thread_db; - - /* If the thread layer isn't initialized, return. It may just - be that the program uses clone, but does not use libthread_db. */ - if (thread_db == NULL || !thread_db->all_symbols_looked_up) - return; - - /* find_one_thread calls into libthread_db which accesses memory via - the current thread. Temporarily switch to a thread we know is - stopped. */ - scoped_restore restore_current_thread - = make_scoped_restore (¤t_thread, parent_thr); - - if (!find_one_thread (child_ptid)) - warning ("Cannot find thread after clone."); -} diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c deleted file mode 100644 index bbca48b2efd..00000000000 --- a/gdb/gdbserver/tracepoint.c +++ /dev/null @@ -1,7473 +0,0 @@ -/* Tracepoint code for remote server for GDB. - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "tracepoint.h" -#include "gdbthread.h" -#include "gdbsupport/rsp-low.h" - -#include -#include -#include -#include -#include -#include "ax.h" -#include "tdesc.h" - -#define IPA_SYM_STRUCT_NAME ipa_sym_addresses -#include "gdbsupport/agent.h" - -#define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */ - -/* This file is built for both GDBserver, and the in-process - agent (IPA), a shared library that includes a tracing agent that is - loaded by the inferior to support fast tracepoints. Fast - tracepoints (or more accurately, jump based tracepoints) are - implemented by patching the tracepoint location with a jump into a - small trampoline function whose job is to save the register state, - call the in-process tracing agent, and then execute the original - instruction that was under the tracepoint jump (possibly adjusted, - if PC-relative, or some such). - - The current synchronization design is pull based. That means, - GDBserver does most of the work, by peeking/poking at the inferior - agent's memory directly for downloading tracepoint and associated - objects, and for uploading trace frames. Whenever the IPA needs - something from GDBserver (trace buffer is full, tracing stopped for - some reason, etc.) the IPA calls a corresponding hook function - where GDBserver has placed a breakpoint. - - Each of the agents has its own trace buffer. When browsing the - trace frames built from slow and fast tracepoints from GDB (tfind - mode), there's no guarantee the user is seeing the trace frames in - strict chronological creation order, although, GDBserver tries to - keep the order relatively reasonable, by syncing the trace buffers - at appropriate times. - -*/ - -#ifdef IN_PROCESS_AGENT - -static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2); - -static void -trace_vdebug (const char *fmt, ...) -{ - char buf[1024]; - va_list ap; - - va_start (ap, fmt); - vsprintf (buf, fmt, ap); - fprintf (stderr, PROG "/tracepoint: %s\n", buf); - va_end (ap); -} - -#define trace_debug_1(level, fmt, args...) \ - do { \ - if (level <= debug_threads) \ - trace_vdebug ((fmt), ##args); \ - } while (0) - -#else - -#define trace_debug_1(level, fmt, args...) \ - do { \ - if (level <= debug_threads) \ - { \ - debug_printf ((fmt), ##args); \ - debug_printf ("\n"); \ - } \ - } while (0) - -#endif - -#define trace_debug(FMT, args...) \ - trace_debug_1 (1, FMT, ##args) - -/* Prefix exported symbols, for good citizenship. All the symbols - that need exporting are defined in this module. Note that all - these symbols must be tagged with IP_AGENT_EXPORT_*. */ -#ifdef IN_PROCESS_AGENT -# define gdb_tp_heap_buffer IPA_SYM_EXPORTED_NAME (gdb_tp_heap_buffer) -# define gdb_jump_pad_buffer IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer) -# define gdb_jump_pad_buffer_end IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer_end) -# define gdb_trampoline_buffer IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer) -# define gdb_trampoline_buffer_end IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_end) -# define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error) -# define collecting IPA_SYM_EXPORTED_NAME (collecting) -# define gdb_collect_ptr IPA_SYM_EXPORTED_NAME (gdb_collect_ptr) -# define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing) -# define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer) -# define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space) -# define trace_buffer_is_full IPA_SYM_EXPORTED_NAME (trace_buffer_is_full) -# define stopping_tracepoint IPA_SYM_EXPORTED_NAME (stopping_tracepoint) -# define expr_eval_result IPA_SYM_EXPORTED_NAME (expr_eval_result) -# define error_tracepoint IPA_SYM_EXPORTED_NAME (error_tracepoint) -# define tracepoints IPA_SYM_EXPORTED_NAME (tracepoints) -# define tracing IPA_SYM_EXPORTED_NAME (tracing) -# define trace_buffer_ctrl IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl) -# define trace_buffer_ctrl_curr IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl_curr) -# define trace_buffer_lo IPA_SYM_EXPORTED_NAME (trace_buffer_lo) -# define trace_buffer_hi IPA_SYM_EXPORTED_NAME (trace_buffer_hi) -# define traceframe_read_count IPA_SYM_EXPORTED_NAME (traceframe_read_count) -# define traceframe_write_count IPA_SYM_EXPORTED_NAME (traceframe_write_count) -# define traceframes_created IPA_SYM_EXPORTED_NAME (traceframes_created) -# define trace_state_variables IPA_SYM_EXPORTED_NAME (trace_state_variables) -# define get_raw_reg_ptr IPA_SYM_EXPORTED_NAME (get_raw_reg_ptr) -# define get_trace_state_variable_value_ptr \ - IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value_ptr) -# define set_trace_state_variable_value_ptr \ - IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value_ptr) -# define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded) -# define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id) -# define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf) -# define ipa_tdesc_idx IPA_SYM_EXPORTED_NAME (ipa_tdesc_idx) -#endif - -#ifndef IN_PROCESS_AGENT - -/* Addresses of in-process agent's symbols GDBserver cares about. */ - -struct ipa_sym_addresses -{ - CORE_ADDR addr_gdb_tp_heap_buffer; - CORE_ADDR addr_gdb_jump_pad_buffer; - CORE_ADDR addr_gdb_jump_pad_buffer_end; - CORE_ADDR addr_gdb_trampoline_buffer; - CORE_ADDR addr_gdb_trampoline_buffer_end; - CORE_ADDR addr_gdb_trampoline_buffer_error; - CORE_ADDR addr_collecting; - CORE_ADDR addr_gdb_collect_ptr; - CORE_ADDR addr_stop_tracing; - CORE_ADDR addr_flush_trace_buffer; - CORE_ADDR addr_about_to_request_buffer_space; - CORE_ADDR addr_trace_buffer_is_full; - CORE_ADDR addr_stopping_tracepoint; - CORE_ADDR addr_expr_eval_result; - CORE_ADDR addr_error_tracepoint; - CORE_ADDR addr_tracepoints; - CORE_ADDR addr_tracing; - CORE_ADDR addr_trace_buffer_ctrl; - CORE_ADDR addr_trace_buffer_ctrl_curr; - CORE_ADDR addr_trace_buffer_lo; - CORE_ADDR addr_trace_buffer_hi; - CORE_ADDR addr_traceframe_read_count; - CORE_ADDR addr_traceframe_write_count; - CORE_ADDR addr_traceframes_created; - CORE_ADDR addr_trace_state_variables; - CORE_ADDR addr_get_raw_reg_ptr; - CORE_ADDR addr_get_trace_state_variable_value_ptr; - CORE_ADDR addr_set_trace_state_variable_value_ptr; - CORE_ADDR addr_ust_loaded; - CORE_ADDR addr_ipa_tdesc_idx; -}; - -static struct -{ - const char *name; - int offset; -} symbol_list[] = { - IPA_SYM(gdb_tp_heap_buffer), - IPA_SYM(gdb_jump_pad_buffer), - IPA_SYM(gdb_jump_pad_buffer_end), - IPA_SYM(gdb_trampoline_buffer), - IPA_SYM(gdb_trampoline_buffer_end), - IPA_SYM(gdb_trampoline_buffer_error), - IPA_SYM(collecting), - IPA_SYM(gdb_collect_ptr), - IPA_SYM(stop_tracing), - IPA_SYM(flush_trace_buffer), - IPA_SYM(about_to_request_buffer_space), - IPA_SYM(trace_buffer_is_full), - IPA_SYM(stopping_tracepoint), - IPA_SYM(expr_eval_result), - IPA_SYM(error_tracepoint), - IPA_SYM(tracepoints), - IPA_SYM(tracing), - IPA_SYM(trace_buffer_ctrl), - IPA_SYM(trace_buffer_ctrl_curr), - IPA_SYM(trace_buffer_lo), - IPA_SYM(trace_buffer_hi), - IPA_SYM(traceframe_read_count), - IPA_SYM(traceframe_write_count), - IPA_SYM(traceframes_created), - IPA_SYM(trace_state_variables), - IPA_SYM(get_raw_reg_ptr), - IPA_SYM(get_trace_state_variable_value_ptr), - IPA_SYM(set_trace_state_variable_value_ptr), - IPA_SYM(ust_loaded), - IPA_SYM(ipa_tdesc_idx), -}; - -static struct ipa_sym_addresses ipa_sym_addrs; - -static int read_inferior_integer (CORE_ADDR symaddr, int *val); - -/* Returns true if both the in-process agent library and the static - tracepoints libraries are loaded in the inferior, and agent has - capability on static tracepoints. */ - -static int -in_process_agent_supports_ust (void) -{ - int loaded = 0; - - if (!agent_loaded_p ()) - { - warning ("In-process agent not loaded"); - return 0; - } - - if (agent_capability_check (AGENT_CAPA_STATIC_TRACE)) - { - /* Agent understands static tracepoint, then check whether UST is in - fact loaded in the inferior. */ - if (read_inferior_integer (ipa_sym_addrs.addr_ust_loaded, &loaded)) - { - warning ("Error reading ust_loaded in lib"); - return 0; - } - - return loaded; - } - else - return 0; -} - -static void -write_e_ipa_not_loaded (char *buffer) -{ - sprintf (buffer, - "E.In-process agent library not loaded in process. " - "Fast and static tracepoints unavailable."); -} - -/* Write an error to BUFFER indicating that UST isn't loaded in the - inferior. */ - -static void -write_e_ust_not_loaded (char *buffer) -{ -#ifdef HAVE_UST - sprintf (buffer, - "E.UST library not loaded in process. " - "Static tracepoints unavailable."); -#else - sprintf (buffer, "E.GDBserver was built without static tracepoints support"); -#endif -} - -/* If the in-process agent library isn't loaded in the inferior, write - an error to BUFFER, and return 1. Otherwise, return 0. */ - -static int -maybe_write_ipa_not_loaded (char *buffer) -{ - if (!agent_loaded_p ()) - { - write_e_ipa_not_loaded (buffer); - return 1; - } - return 0; -} - -/* If the in-process agent library and the ust (static tracepoints) - library aren't loaded in the inferior, write an error to BUFFER, - and return 1. Otherwise, return 0. */ - -static int -maybe_write_ipa_ust_not_loaded (char *buffer) -{ - if (!agent_loaded_p ()) - { - write_e_ipa_not_loaded (buffer); - return 1; - } - else if (!in_process_agent_supports_ust ()) - { - write_e_ust_not_loaded (buffer); - return 1; - } - return 0; -} - -/* Cache all future symbols that the tracepoints module might request. - We can not request symbols at arbitrary states in the remote - protocol, only when the client tells us that new symbols are - available. So when we load the in-process library, make sure to - check the entire list. */ - -void -tracepoint_look_up_symbols (void) -{ - int i; - - if (agent_loaded_p ()) - return; - - for (i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++) - { - CORE_ADDR *addrp = - (CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset); - - if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0) - { - if (debug_threads) - debug_printf ("symbol `%s' not found\n", symbol_list[i].name); - return; - } - } - - agent_look_up_symbols (NULL); -} - -#endif - -/* GDBserver places a breakpoint on the IPA's version (which is a nop) - of the "stop_tracing" function. When this breakpoint is hit, - tracing stopped in the IPA for some reason. E.g., due to - tracepoint reaching the pass count, hitting conditional expression - evaluation error, etc. - - The IPA's trace buffer is never in circular tracing mode: instead, - GDBserver's is, and whenever the in-process buffer fills, it calls - "flush_trace_buffer", which triggers an internal breakpoint. - GDBserver reacts to this breakpoint by pulling the meanwhile - collected data. Old frames discarding is always handled on the - GDBserver side. */ - -#ifdef IN_PROCESS_AGENT -int -read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - memcpy (myaddr, (void *) (uintptr_t) memaddr, len); - return 0; -} - -/* Call this in the functions where GDBserver places a breakpoint, so - that the compiler doesn't try to be clever and skip calling the - function at all. This is necessary, even if we tell the compiler - to not inline said functions. */ - -#if defined(__GNUC__) -# define UNKNOWN_SIDE_EFFECTS() asm ("") -#else -# define UNKNOWN_SIDE_EFFECTS() do {} while (0) -#endif - -/* This is needed for -Wmissing-declarations. */ -IP_AGENT_EXPORT_FUNC void stop_tracing (void); - -IP_AGENT_EXPORT_FUNC void -stop_tracing (void) -{ - /* GDBserver places breakpoint here. */ - UNKNOWN_SIDE_EFFECTS(); -} - -/* This is needed for -Wmissing-declarations. */ -IP_AGENT_EXPORT_FUNC void flush_trace_buffer (void); - -IP_AGENT_EXPORT_FUNC void -flush_trace_buffer (void) -{ - /* GDBserver places breakpoint here. */ - UNKNOWN_SIDE_EFFECTS(); -} - -#endif - -#ifndef IN_PROCESS_AGENT -static int -tracepoint_handler (CORE_ADDR address) -{ - trace_debug ("tracepoint_handler: tracepoint at 0x%s hit", - paddress (address)); - return 0; -} - -/* Breakpoint at "stop_tracing" in the inferior lib. */ -struct breakpoint *stop_tracing_bkpt; -static int stop_tracing_handler (CORE_ADDR); - -/* Breakpoint at "flush_trace_buffer" in the inferior lib. */ -struct breakpoint *flush_trace_buffer_bkpt; -static int flush_trace_buffer_handler (CORE_ADDR); - -static void download_trace_state_variables (void); -static void upload_fast_traceframes (void); - -static int run_inferior_command (char *cmd, int len); - -static int -read_inferior_integer (CORE_ADDR symaddr, int *val) -{ - return read_inferior_memory (symaddr, (unsigned char *) val, - sizeof (*val)); -} - -struct tracepoint; -static int tracepoint_send_agent (struct tracepoint *tpoint); - -static int -read_inferior_uinteger (CORE_ADDR symaddr, unsigned int *val) -{ - return read_inferior_memory (symaddr, (unsigned char *) val, - sizeof (*val)); -} - -static int -read_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR *val) -{ - void *pval = (void *) (uintptr_t) val; - int ret; - - ret = read_inferior_memory (symaddr, (unsigned char *) &pval, sizeof (pval)); - *val = (uintptr_t) pval; - return ret; -} - -static int -write_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR val) -{ - void *pval = (void *) (uintptr_t) val; - return target_write_memory (symaddr, - (unsigned char *) &pval, sizeof (pval)); -} - -static int -write_inferior_integer (CORE_ADDR symaddr, int val) -{ - return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val)); -} - -static int -write_inferior_int8 (CORE_ADDR symaddr, int8_t val) -{ - return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val)); -} - -static int -write_inferior_uinteger (CORE_ADDR symaddr, unsigned int val) -{ - return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val)); -} - -static CORE_ADDR target_malloc (ULONGEST size); - -#define COPY_FIELD_TO_BUF(BUF, OBJ, FIELD) \ - do { \ - memcpy (BUF, &(OBJ)->FIELD, sizeof ((OBJ)->FIELD)); \ - BUF += sizeof ((OBJ)->FIELD); \ - } while (0) - -#endif - -/* Base action. Concrete actions inherit this. */ - -struct tracepoint_action -{ - char type; -}; - -/* An 'M' (collect memory) action. */ -struct collect_memory_action -{ - struct tracepoint_action base; - - ULONGEST addr; - ULONGEST len; - int32_t basereg; -}; - -/* An 'R' (collect registers) action. */ - -struct collect_registers_action -{ - struct tracepoint_action base; -}; - -/* An 'X' (evaluate expression) action. */ - -struct eval_expr_action -{ - struct tracepoint_action base; - - struct agent_expr *expr; -}; - -/* An 'L' (collect static trace data) action. */ -struct collect_static_trace_data_action -{ - struct tracepoint_action base; -}; - -#ifndef IN_PROCESS_AGENT -static CORE_ADDR -m_tracepoint_action_download (const struct tracepoint_action *action) -{ - CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_memory_action)); - - target_write_memory (ipa_action, (unsigned char *) action, - sizeof (struct collect_memory_action)); - - return ipa_action; -} -static char * -m_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) -{ - struct collect_memory_action *maction - = (struct collect_memory_action *) action; - - COPY_FIELD_TO_BUF (buffer, maction, addr); - COPY_FIELD_TO_BUF (buffer, maction, len); - COPY_FIELD_TO_BUF (buffer, maction, basereg); - - return buffer; -} - -static CORE_ADDR -r_tracepoint_action_download (const struct tracepoint_action *action) -{ - CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_registers_action)); - - target_write_memory (ipa_action, (unsigned char *) action, - sizeof (struct collect_registers_action)); - - return ipa_action; -} - -static char * -r_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) -{ - return buffer; -} - -static CORE_ADDR download_agent_expr (struct agent_expr *expr); - -static CORE_ADDR -x_tracepoint_action_download (const struct tracepoint_action *action) -{ - CORE_ADDR ipa_action = target_malloc (sizeof (struct eval_expr_action)); - CORE_ADDR expr; - - target_write_memory (ipa_action, (unsigned char *) action, - sizeof (struct eval_expr_action)); - expr = download_agent_expr (((struct eval_expr_action *) action)->expr); - write_inferior_data_pointer (ipa_action - + offsetof (struct eval_expr_action, expr), - expr); - - return ipa_action; -} - -/* Copy agent expression AEXPR to buffer pointed by P. If AEXPR is NULL, - copy 0 to P. Return updated header of buffer. */ - -static char * -agent_expr_send (char *p, const struct agent_expr *aexpr) -{ - /* Copy the length of condition first, and then copy its - content. */ - if (aexpr == NULL) - { - memset (p, 0, 4); - p += 4; - } - else - { - memcpy (p, &aexpr->length, 4); - p +=4; - - memcpy (p, aexpr->bytes, aexpr->length); - p += aexpr->length; - } - return p; -} - -static char * -x_tracepoint_action_send ( char *buffer, const struct tracepoint_action *action) -{ - struct eval_expr_action *eaction = (struct eval_expr_action *) action; - - return agent_expr_send (buffer, eaction->expr); -} - -static CORE_ADDR -l_tracepoint_action_download (const struct tracepoint_action *action) -{ - CORE_ADDR ipa_action - = target_malloc (sizeof (struct collect_static_trace_data_action)); - - target_write_memory (ipa_action, (unsigned char *) action, - sizeof (struct collect_static_trace_data_action)); - - return ipa_action; -} - -static char * -l_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) -{ - return buffer; -} - -static char * -tracepoint_action_send (char *buffer, const struct tracepoint_action *action) -{ - switch (action->type) - { - case 'M': - return m_tracepoint_action_send (buffer, action); - case 'R': - return r_tracepoint_action_send (buffer, action); - case 'X': - return x_tracepoint_action_send (buffer, action); - case 'L': - return l_tracepoint_action_send (buffer, action); - } - error ("Unknown trace action '%c'.", action->type); -} - -static CORE_ADDR -tracepoint_action_download (const struct tracepoint_action *action) -{ - switch (action->type) - { - case 'M': - return m_tracepoint_action_download (action); - case 'R': - return r_tracepoint_action_download (action); - case 'X': - return x_tracepoint_action_download (action); - case 'L': - return l_tracepoint_action_download (action); - } - error ("Unknown trace action '%c'.", action->type); -} -#endif - -/* This structure describes a piece of the source-level definition of - the tracepoint. The contents are not interpreted by the target, - but preserved verbatim for uploading upon reconnection. */ - -struct source_string -{ - /* The type of string, such as "cond" for a conditional. */ - char *type; - - /* The source-level string itself. For the sake of target - debugging, we store it in plaintext, even though it is always - transmitted in hex. */ - char *str; - - /* Link to the next one in the list. We link them in the order - received, in case some make up an ordered list of commands or - some such. */ - struct source_string *next; -}; - -enum tracepoint_type -{ - /* Trap based tracepoint. */ - trap_tracepoint, - - /* A fast tracepoint implemented with a jump instead of a trap. */ - fast_tracepoint, - - /* A static tracepoint, implemented by a program call into a tracing - library. */ - static_tracepoint -}; - -struct tracepoint_hit_ctx; - -typedef enum eval_result_type (*condfn) (unsigned char *, - ULONGEST *); - -/* The definition of a tracepoint. */ - -/* Tracepoints may have multiple locations, each at a different - address. This can occur with optimizations, template - instantiation, etc. Since the locations may be in different - scopes, the conditions and actions may be different for each - location. Our target version of tracepoints is more like GDB's - notion of "breakpoint locations", but we have almost nothing that - is not per-location, so we bother having two kinds of objects. The - key consequence is that numbers are not unique, and that it takes - both number and address to identify a tracepoint uniquely. */ - -struct tracepoint -{ - /* The number of the tracepoint, as specified by GDB. Several - tracepoint objects here may share a number. */ - uint32_t number; - - /* Address at which the tracepoint is supposed to trigger. Several - tracepoints may share an address. */ - CORE_ADDR address; - - /* Tracepoint type. */ - enum tracepoint_type type; - - /* True if the tracepoint is currently enabled. */ - int8_t enabled; - - /* The number of single steps that will be performed after each - tracepoint hit. */ - uint64_t step_count; - - /* The number of times the tracepoint may be hit before it will - terminate the entire tracing run. */ - uint64_t pass_count; - - /* Pointer to the agent expression that is the tracepoint's - conditional, or NULL if the tracepoint is unconditional. */ - struct agent_expr *cond; - - /* The list of actions to take when the tracepoint triggers. */ - uint32_t numactions; - struct tracepoint_action **actions; - - /* Count of the times we've hit this tracepoint during the run. - Note that while-stepping steps are not counted as "hits". */ - uint64_t hit_count; - - /* Cached sum of the sizes of traceframes created by this point. */ - uint64_t traceframe_usage; - - CORE_ADDR compiled_cond; - - /* Link to the next tracepoint in the list. */ - struct tracepoint *next; - -#ifndef IN_PROCESS_AGENT - /* The list of actions to take when the tracepoint triggers, in - string/packet form. */ - char **actions_str; - - /* The collection of strings that describe the tracepoint as it was - entered into GDB. These are not used by the target, but are - reported back to GDB upon reconnection. */ - struct source_string *source_strings; - - /* The number of bytes displaced by fast tracepoints. It may subsume - multiple instructions, for multi-byte fast tracepoints. This - field is only valid for fast tracepoints. */ - uint32_t orig_size; - - /* Only for fast tracepoints. */ - CORE_ADDR obj_addr_on_target; - - /* Address range where the original instruction under a fast - tracepoint was relocated to. (_end is actually one byte past - the end). */ - CORE_ADDR adjusted_insn_addr; - CORE_ADDR adjusted_insn_addr_end; - - /* The address range of the piece of the jump pad buffer that was - assigned to this fast tracepoint. (_end is actually one byte - past the end).*/ - CORE_ADDR jump_pad; - CORE_ADDR jump_pad_end; - - /* The address range of the piece of the trampoline buffer that was - assigned to this fast tracepoint. (_end is actually one byte - past the end). */ - CORE_ADDR trampoline; - CORE_ADDR trampoline_end; - - /* The list of actions to take while in a stepping loop. These - fields are only valid for patch-based tracepoints. */ - int num_step_actions; - struct tracepoint_action **step_actions; - /* Same, but in string/packet form. */ - char **step_actions_str; - - /* Handle returned by the breakpoint or tracepoint module when we - inserted the trap or jump, or hooked into a static tracepoint. - NULL if we haven't inserted it yet. */ - void *handle; -#endif - -}; - -#ifndef IN_PROCESS_AGENT - -/* Given `while-stepping', a thread may be collecting data for more - than one tracepoint simultaneously. On the other hand, the same - tracepoint with a while-stepping action may be hit by more than one - thread simultaneously (but not quite, each thread could be handling - a different step). Each thread holds a list of these objects, - representing the current step of each while-stepping action being - collected. */ - -struct wstep_state -{ - struct wstep_state *next; - - /* The tracepoint number. */ - int tp_number; - /* The tracepoint's address. */ - CORE_ADDR tp_address; - - /* The number of the current step in this 'while-stepping' - action. */ - long current_step; -}; - -#endif - -EXTERN_C_PUSH - -/* The linked list of all tracepoints. Marked explicitly as used as - the in-process library doesn't use it for the fast tracepoints - support. */ -IP_AGENT_EXPORT_VAR struct tracepoint *tracepoints; - -/* The first tracepoint to exceed its pass count. */ - -IP_AGENT_EXPORT_VAR struct tracepoint *stopping_tracepoint; - -/* True if the trace buffer is full or otherwise no longer usable. */ - -IP_AGENT_EXPORT_VAR int trace_buffer_is_full; - -/* The first error that occurred during expression evaluation. */ - -/* Stored as an int to avoid the IPA ABI being dependent on whatever - the compiler decides to use for the enum's underlying type. Holds - enum eval_result_type values. */ -IP_AGENT_EXPORT_VAR int expr_eval_result = expr_eval_no_error; - -EXTERN_C_POP - -#ifndef IN_PROCESS_AGENT - -/* Pointer to the last tracepoint in the list, new tracepoints are - linked in at the end. */ - -static struct tracepoint *last_tracepoint; - -static const char *eval_result_names[] = - { - "terror:in the attic", /* this should never be reported */ - "terror:empty expression", - "terror:empty stack", - "terror:stack overflow", - "terror:stack underflow", - "terror:unhandled opcode", - "terror:unrecognized opcode", - "terror:divide by zero" - }; - -#endif - -/* The tracepoint in which the error occurred. */ - -EXTERN_C_PUSH -IP_AGENT_EXPORT_VAR struct tracepoint *error_tracepoint; -EXTERN_C_POP - -struct trace_state_variable -{ - /* This is the name of the variable as used in GDB. The target - doesn't use the name, but needs to have it for saving and - reconnection purposes. */ - char *name; - - /* This number identifies the variable uniquely. Numbers may be - assigned either by the target (in the case of builtin variables), - or by GDB, and are presumed unique during the course of a trace - experiment. */ - int number; - - /* The variable's initial value, a 64-bit signed integer always. */ - LONGEST initial_value; - - /* The variable's value, a 64-bit signed integer always. */ - LONGEST value; - - /* Pointer to a getter function, used to supply computed values. */ - LONGEST (*getter) (void); - - /* Link to the next variable. */ - struct trace_state_variable *next; -}; - -/* Linked list of all trace state variables. */ - -#ifdef IN_PROCESS_AGENT -struct trace_state_variable *alloced_trace_state_variables; -#endif - -IP_AGENT_EXPORT_VAR struct trace_state_variable *trace_state_variables; - -/* The results of tracing go into a fixed-size space known as the - "trace buffer". Because usage follows a limited number of - patterns, we manage it ourselves rather than with malloc. Basic - rules are that we create only one trace frame at a time, each is - variable in size, they are never moved once created, and we only - discard if we are doing a circular buffer, and then only the oldest - ones. Each trace frame includes its own size, so we don't need to - link them together, and the trace frame number is relative to the - first one, so we don't need to record numbers. A trace frame also - records the number of the tracepoint that created it. The data - itself is a series of blocks, each introduced by a single character - and with a defined format. Each type of block has enough - type/length info to allow scanners to jump quickly from one block - to the next without reading each byte in the block. */ - -/* Trace buffer management would be simple - advance a free pointer - from beginning to end, then stop - were it not for the circular - buffer option, which is a useful way to prevent a trace run from - stopping prematurely because the buffer filled up. In the circular - case, the location of the first trace frame (trace_buffer_start) - moves as old trace frames are discarded. Also, since we grow trace - frames incrementally as actions are performed, we wrap around to - the beginning of the trace buffer. This is per-block, so each - block within a trace frame remains contiguous. Things get messy - when the wrapped-around trace frame is the one being discarded; the - free space ends up in two parts at opposite ends of the buffer. */ - -#ifndef ATTR_PACKED -# if defined(__GNUC__) -# define ATTR_PACKED __attribute__ ((packed)) -# else -# define ATTR_PACKED /* nothing */ -# endif -#endif - -/* The data collected at a tracepoint hit. This object should be as - small as possible, since there may be a great many of them. We do - not need to keep a frame number, because they are all sequential - and there are no deletions; so the Nth frame in the buffer is - always frame number N. */ - -struct traceframe -{ - /* Number of the tracepoint that collected this traceframe. A value - of 0 indicates the current end of the trace buffer. We make this - a 16-bit field because it's never going to happen that GDB's - numbering of tracepoints reaches 32,000. */ - int tpnum : 16; - - /* The size of the data in this trace frame. We limit this to 32 - bits, even on a 64-bit target, because it's just implausible that - one is validly going to collect 4 gigabytes of data at a single - tracepoint hit. */ - unsigned int data_size : 32; - - /* The base of the trace data, which is contiguous from this point. */ - unsigned char data[0]; - -} ATTR_PACKED; - -/* The size of the EOB marker, in bytes. A traceframe with zeroed - fields (and no data) marks the end of trace data. */ -#define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data) - -/* This flag is true if the trace buffer is circular, meaning that - when it fills, the oldest trace frames are discarded in order to - make room. */ - -#ifndef IN_PROCESS_AGENT -static int circular_trace_buffer; -#endif - -/* Size of the trace buffer. */ - -static LONGEST trace_buffer_size; - -EXTERN_C_PUSH - -/* Pointer to the block of memory that traceframes all go into. */ - -IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_lo; - -/* Pointer to the end of the trace buffer, more precisely to the byte - after the end of the buffer. */ - -IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_hi; - -EXTERN_C_POP - -/* Control structure holding the read/write/etc. pointers into the - trace buffer. We need more than one of these to implement a - transaction-like mechanism to guarantees that both GDBserver and the - in-process agent can try to change the trace buffer - simultaneously. */ - -struct trace_buffer_control -{ - /* Pointer to the first trace frame in the buffer. In the - non-circular case, this is equal to trace_buffer_lo, otherwise it - moves around in the buffer. */ - unsigned char *start; - - /* Pointer to the free part of the trace buffer. Note that we clear - several bytes at and after this pointer, so that traceframe - scans/searches terminate properly. */ - unsigned char *free; - - /* Pointer to the byte after the end of the free part. Note that - this may be smaller than trace_buffer_free in the circular case, - and means that the free part is in two pieces. Initially it is - equal to trace_buffer_hi, then is generally equivalent to - trace_buffer_start. */ - unsigned char *end_free; - - /* Pointer to the wraparound. If not equal to trace_buffer_hi, then - this is the point at which the trace data breaks, and resumes at - trace_buffer_lo. */ - unsigned char *wrap; -}; - -/* Same as above, to be used by GDBserver when updating the in-process - agent. */ -struct ipa_trace_buffer_control -{ - uintptr_t start; - uintptr_t free; - uintptr_t end_free; - uintptr_t wrap; -}; - - -/* We have possibly both GDBserver and an inferior thread accessing - the same IPA trace buffer memory. The IPA is the producer (tries - to put new frames in the buffer), while GDBserver occasionally - consumes them, that is, flushes the IPA's buffer into its own - buffer. Both sides need to update the trace buffer control - pointers (current head, tail, etc.). We can't use a global lock to - synchronize the accesses, as otherwise we could deadlock GDBserver - (if the thread holding the lock stops for a signal, say). So - instead of that, we use a transaction scheme where GDBserver writes - always prevail over the IPAs writes, and, we have the IPA detect - the commit failure/overwrite, and retry the whole attempt. This is - mainly implemented by having a global token object that represents - who wrote last to the buffer control structure. We need to freeze - any inferior writing to the buffer while GDBserver touches memory, - so that the inferior can correctly detect that GDBserver had been - there, otherwise, it could mistakingly think its commit was - successful; that's implemented by simply having GDBserver set a - breakpoint the inferior hits if it is the critical region. - - There are three cycling trace buffer control structure copies - (buffer head, tail, etc.), with the token object including an index - indicating which is current live copy. The IPA tentatively builds - an updated copy in a non-current control structure, while GDBserver - always clobbers the current version directly. The IPA then tries - to atomically "commit" its version; if GDBserver clobbered the - structure meanwhile, that will fail, and the IPA restarts the - allocation process. - - Listing the step in further detail, we have: - - In-process agent (producer): - - - passes by `about_to_request_buffer_space' breakpoint/lock - - - reads current token, extracts current trace buffer control index, - and starts tentatively updating the rightmost one (0->1, 1->2, - 2->0). Note that only one inferior thread is executing this code - at any given time, due to an outer lock in the jump pads. - - - updates counters, and tries to commit the token. - - - passes by second `about_to_request_buffer_space' breakpoint/lock, - leaving the sync region. - - - checks if the update was effective. - - - if trace buffer was found full, hits flush_trace_buffer - breakpoint, and restarts later afterwards. - - GDBserver (consumer): - - - sets `about_to_request_buffer_space' breakpoint/lock. - - - updates the token unconditionally, using the current buffer - control index, since it knows that the IP agent always writes to - the rightmost, and due to the breakpoint, at most one IP thread - can try to update the trace buffer concurrently to GDBserver, so - there will be no danger of trace buffer control index wrap making - the IPA write to the same index as GDBserver. - - - flushes the IP agent's trace buffer completely, and updates the - current trace buffer control structure. GDBserver *always* wins. - - - removes the `about_to_request_buffer_space' breakpoint. - -The token is stored in the `trace_buffer_ctrl_curr' variable. -Internally, it's bits are defined as: - - |-------------+-----+-------------+--------+-------------+--------------| - | Bit offsets | 31 | 30 - 20 | 19 | 18-8 | 7-0 | - |-------------+-----+-------------+--------+-------------+--------------| - | What | GSB | PC (11-bit) | unused | CC (11-bit) | TBCI (8-bit) | - |-------------+-----+-------------+--------+-------------+--------------| - - GSB - GDBserver Stamp Bit - PC - Previous Counter - CC - Current Counter - TBCI - Trace Buffer Control Index - - -An IPA update of `trace_buffer_ctrl_curr' does: - - - read CC from the current token, save as PC. - - updates pointers - - atomically tries to write PC+1,CC - -A GDBserver update of `trace_buffer_ctrl_curr' does: - - - reads PC and CC from the current token. - - updates pointers - - writes GSB,PC,CC -*/ - -/* These are the bits of `trace_buffer_ctrl_curr' that are reserved - for the counters described below. The cleared bits are used to - hold the index of the items of the `trace_buffer_ctrl' array that - is "current". */ -#define GDBSERVER_FLUSH_COUNT_MASK 0xfffffff0 - -/* `trace_buffer_ctrl_curr' contains two counters. The `previous' - counter, and the `current' counter. */ - -#define GDBSERVER_FLUSH_COUNT_MASK_PREV 0x7ff00000 -#define GDBSERVER_FLUSH_COUNT_MASK_CURR 0x0007ff00 - -/* When GDBserver update the IP agent's `trace_buffer_ctrl_curr', it - always stamps this bit as set. */ -#define GDBSERVER_UPDATED_FLUSH_COUNT_BIT 0x80000000 - -#ifdef IN_PROCESS_AGENT -IP_AGENT_EXPORT_VAR struct trace_buffer_control trace_buffer_ctrl[3]; -IP_AGENT_EXPORT_VAR unsigned int trace_buffer_ctrl_curr; - -# define TRACE_BUFFER_CTRL_CURR \ - (trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK) - -#else - -/* The GDBserver side agent only needs one instance of this object, as - it doesn't need to sync with itself. Define it as array anyway so - that the rest of the code base doesn't need to care for the - difference. */ -struct trace_buffer_control trace_buffer_ctrl[1]; -# define TRACE_BUFFER_CTRL_CURR 0 -#endif - -/* These are convenience macros used to access the current trace - buffer control in effect. */ -#define trace_buffer_start (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].start) -#define trace_buffer_free (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].free) -#define trace_buffer_end_free \ - (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].end_free) -#define trace_buffer_wrap (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].wrap) - - -/* Macro that returns a pointer to the first traceframe in the buffer. */ - -#define FIRST_TRACEFRAME() ((struct traceframe *) trace_buffer_start) - -/* Macro that returns a pointer to the next traceframe in the buffer. - If the computed location is beyond the wraparound point, subtract - the offset of the wraparound. */ - -#define NEXT_TRACEFRAME_1(TF) \ - (((unsigned char *) (TF)) + sizeof (struct traceframe) + (TF)->data_size) - -#define NEXT_TRACEFRAME(TF) \ - ((struct traceframe *) (NEXT_TRACEFRAME_1 (TF) \ - - ((NEXT_TRACEFRAME_1 (TF) >= trace_buffer_wrap) \ - ? (trace_buffer_wrap - trace_buffer_lo) \ - : 0))) - -/* The difference between these counters represents the total number - of complete traceframes present in the trace buffer. The IP agent - writes to the write count, GDBserver writes to read count. */ - -IP_AGENT_EXPORT_VAR unsigned int traceframe_write_count; -IP_AGENT_EXPORT_VAR unsigned int traceframe_read_count; - -/* Convenience macro. */ - -#define traceframe_count \ - ((unsigned int) (traceframe_write_count - traceframe_read_count)) - -/* The count of all traceframes created in the current run, including - ones that were discarded to make room. */ - -IP_AGENT_EXPORT_VAR int traceframes_created; - -#ifndef IN_PROCESS_AGENT - -/* Read-only regions are address ranges whose contents don't change, - and so can be read from target memory even while looking at a trace - frame. Without these, disassembly for instance will likely fail, - because the program code is not usually collected into a trace - frame. This data structure does not need to be very complicated or - particularly efficient, it's only going to be used occasionally, - and only by some commands. */ - -struct readonly_region -{ - /* The bounds of the region. */ - CORE_ADDR start, end; - - /* Link to the next one. */ - struct readonly_region *next; -}; - -/* Linked list of readonly regions. This list stays in effect from - one tstart to the next. */ - -static struct readonly_region *readonly_regions; - -#endif - -/* The global that controls tracing overall. */ - -IP_AGENT_EXPORT_VAR int tracing; - -#ifndef IN_PROCESS_AGENT - -/* Controls whether tracing should continue after GDB disconnects. */ - -int disconnected_tracing; - -/* The reason for the last tracing run to have stopped. We initialize - to a distinct string so that GDB can distinguish between "stopped - after running" and "stopped because never run" cases. */ - -static const char *tracing_stop_reason = "tnotrun"; - -static int tracing_stop_tpnum; - -/* 64-bit timestamps for the trace run's start and finish, expressed - in microseconds from the Unix epoch. */ - -LONGEST tracing_start_time; -LONGEST tracing_stop_time; - -/* The (optional) user-supplied name of the user that started the run. - This is an arbitrary string, and may be NULL. */ - -char *tracing_user_name; - -/* Optional user-supplied text describing the run. This is - an arbitrary string, and may be NULL. */ - -char *tracing_notes; - -/* Optional user-supplied text explaining a tstop command. This is an - arbitrary string, and may be NULL. */ - -char *tracing_stop_note; - -#endif - -/* Functions local to this file. */ - -/* Base "class" for tracepoint type specific data to be passed down to - collect_data_at_tracepoint. */ -struct tracepoint_hit_ctx -{ - enum tracepoint_type type; -}; - -#ifdef IN_PROCESS_AGENT - -/* Fast/jump tracepoint specific data to be passed down to - collect_data_at_tracepoint. */ -struct fast_tracepoint_ctx -{ - struct tracepoint_hit_ctx base; - - struct regcache regcache; - int regcache_initted; - unsigned char *regspace; - - unsigned char *regs; - struct tracepoint *tpoint; -}; - -/* Static tracepoint specific data to be passed down to - collect_data_at_tracepoint. */ -struct static_tracepoint_ctx -{ - struct tracepoint_hit_ctx base; - - /* The regcache corresponding to the registers state at the time of - the tracepoint hit. Initialized lazily, from REGS. */ - struct regcache regcache; - int regcache_initted; - - /* The buffer space REGCACHE above uses. We use a separate buffer - instead of letting the regcache malloc for both signal safety and - performance reasons; this is allocated on the stack instead. */ - unsigned char *regspace; - - /* The register buffer as passed on by lttng/ust. */ - struct registers *regs; - - /* The "printf" formatter and the args the user passed to the marker - call. We use this to be able to collect "static trace data" - ($_sdata). */ - const char *fmt; - va_list *args; - - /* The GDB tracepoint matching the probed marker that was "hit". */ - struct tracepoint *tpoint; -}; - -#else - -/* Static tracepoint specific data to be passed down to - collect_data_at_tracepoint. */ -struct trap_tracepoint_ctx -{ - struct tracepoint_hit_ctx base; - - struct regcache *regcache; -}; - -#endif - -#ifndef IN_PROCESS_AGENT -static CORE_ADDR traceframe_get_pc (struct traceframe *tframe); -static int traceframe_read_tsv (int num, LONGEST *val); -#endif - -static int condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx, - struct tracepoint *tpoint); - -#ifndef IN_PROCESS_AGENT -static void clear_readonly_regions (void); -static void clear_installed_tracepoints (void); -#endif - -static void collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, - CORE_ADDR stop_pc, - struct tracepoint *tpoint); -#ifndef IN_PROCESS_AGENT -static void collect_data_at_step (struct tracepoint_hit_ctx *ctx, - CORE_ADDR stop_pc, - struct tracepoint *tpoint, int current_step); -static void compile_tracepoint_condition (struct tracepoint *tpoint, - CORE_ADDR *jump_entry); -#endif -static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, - CORE_ADDR stop_pc, - struct tracepoint *tpoint, - struct traceframe *tframe, - struct tracepoint_action *taction); - -#ifndef IN_PROCESS_AGENT -static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR); - -static void install_tracepoint (struct tracepoint *, char *own_buf); -static void download_tracepoint (struct tracepoint *); -static int install_fast_tracepoint (struct tracepoint *, char *errbuf); -static void clone_fast_tracepoint (struct tracepoint *to, - const struct tracepoint *from); -#endif - -static LONGEST get_timestamp (void); - -#if defined(__GNUC__) -# define memory_barrier() asm volatile ("" : : : "memory") -#else -# define memory_barrier() do {} while (0) -#endif - -/* We only build the IPA if this builtin is supported, and there are - no uses of this in GDBserver itself, so we're safe in defining this - unconditionally. */ -#define cmpxchg(mem, oldval, newval) \ - __sync_val_compare_and_swap (mem, oldval, newval) - -/* Record that an error occurred during expression evaluation. */ - -static void -record_tracepoint_error (struct tracepoint *tpoint, const char *which, - enum eval_result_type rtype) -{ - trace_debug ("Tracepoint %d at %s %s eval reports error %d", - tpoint->number, paddress (tpoint->address), which, rtype); - -#ifdef IN_PROCESS_AGENT - /* Only record the first error we get. */ - if (cmpxchg (&expr_eval_result, - expr_eval_no_error, - rtype) != expr_eval_no_error) - return; -#else - if (expr_eval_result != expr_eval_no_error) - return; -#endif - - error_tracepoint = tpoint; -} - -/* Trace buffer management. */ - -static void -clear_trace_buffer (void) -{ - trace_buffer_start = trace_buffer_lo; - trace_buffer_free = trace_buffer_lo; - trace_buffer_end_free = trace_buffer_hi; - trace_buffer_wrap = trace_buffer_hi; - /* A traceframe with zeroed fields marks the end of trace data. */ - ((struct traceframe *) trace_buffer_free)->tpnum = 0; - ((struct traceframe *) trace_buffer_free)->data_size = 0; - traceframe_read_count = traceframe_write_count = 0; - traceframes_created = 0; -} - -#ifndef IN_PROCESS_AGENT - -static void -clear_inferior_trace_buffer (void) -{ - CORE_ADDR ipa_trace_buffer_lo; - CORE_ADDR ipa_trace_buffer_hi; - struct traceframe ipa_traceframe = { 0 }; - struct ipa_trace_buffer_control ipa_trace_buffer_ctrl; - - read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo, - &ipa_trace_buffer_lo); - read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi, - &ipa_trace_buffer_hi); - - ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo; - ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo; - ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi; - ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi; - - /* A traceframe with zeroed fields marks the end of trace data. */ - target_write_memory (ipa_sym_addrs.addr_trace_buffer_ctrl, - (unsigned char *) &ipa_trace_buffer_ctrl, - sizeof (ipa_trace_buffer_ctrl)); - - write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, 0); - - /* A traceframe with zeroed fields marks the end of trace data. */ - target_write_memory (ipa_trace_buffer_lo, - (unsigned char *) &ipa_traceframe, - sizeof (ipa_traceframe)); - - write_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, 0); - write_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, 0); - write_inferior_integer (ipa_sym_addrs.addr_traceframes_created, 0); -} - -#endif - -static void -init_trace_buffer (LONGEST bufsize) -{ - size_t alloc_size; - - trace_buffer_size = bufsize; - - /* Make sure to internally allocate at least space for the EOB - marker. */ - alloc_size = (bufsize < TRACEFRAME_EOB_MARKER_SIZE - ? TRACEFRAME_EOB_MARKER_SIZE : bufsize); - trace_buffer_lo = (unsigned char *) xrealloc (trace_buffer_lo, alloc_size); - - trace_buffer_hi = trace_buffer_lo + trace_buffer_size; - - clear_trace_buffer (); -} - -#ifdef IN_PROCESS_AGENT - -/* This is needed for -Wmissing-declarations. */ -IP_AGENT_EXPORT_FUNC void about_to_request_buffer_space (void); - -IP_AGENT_EXPORT_FUNC void -about_to_request_buffer_space (void) -{ - /* GDBserver places breakpoint here while it goes about to flush - data at random times. */ - UNKNOWN_SIDE_EFFECTS(); -} - -#endif - -/* Carve out a piece of the trace buffer, returning NULL in case of - failure. */ - -static void * -trace_buffer_alloc (size_t amt) -{ - unsigned char *rslt; - struct trace_buffer_control *tbctrl; - unsigned int curr; -#ifdef IN_PROCESS_AGENT - unsigned int prev, prev_filtered; - unsigned int commit_count; - unsigned int commit; - unsigned int readout; -#else - struct traceframe *oldest; - unsigned char *new_start; -#endif - - trace_debug ("Want to allocate %ld+%ld bytes in trace buffer", - (long) amt, (long) sizeof (struct traceframe)); - - /* Account for the EOB marker. */ - amt += TRACEFRAME_EOB_MARKER_SIZE; - -#ifdef IN_PROCESS_AGENT - again: - memory_barrier (); - - /* Read the current token and extract the index to try to write to, - storing it in CURR. */ - prev = trace_buffer_ctrl_curr; - prev_filtered = prev & ~GDBSERVER_FLUSH_COUNT_MASK; - curr = prev_filtered + 1; - if (curr > 2) - curr = 0; - - about_to_request_buffer_space (); - - /* Start out with a copy of the current state. GDBserver may be - midway writing to the PREV_FILTERED TBC, but, that's OK, we won't - be able to commit anyway if that happens. */ - trace_buffer_ctrl[curr] - = trace_buffer_ctrl[prev_filtered]; - trace_debug ("trying curr=%u", curr); -#else - /* The GDBserver's agent doesn't need all that syncing, and always - updates TCB 0 (there's only one, mind you). */ - curr = 0; -#endif - tbctrl = &trace_buffer_ctrl[curr]; - - /* Offsets are easier to grok for debugging than raw addresses, - especially for the small trace buffer sizes that are useful for - testing. */ - trace_debug ("Trace buffer [%d] start=%d free=%d endfree=%d wrap=%d hi=%d", - curr, - (int) (tbctrl->start - trace_buffer_lo), - (int) (tbctrl->free - trace_buffer_lo), - (int) (tbctrl->end_free - trace_buffer_lo), - (int) (tbctrl->wrap - trace_buffer_lo), - (int) (trace_buffer_hi - trace_buffer_lo)); - - /* The algorithm here is to keep trying to get a contiguous block of - the requested size, possibly discarding older traceframes to free - up space. Since free space might come in one or two pieces, - depending on whether discarded traceframes wrapped around at the - high end of the buffer, we test both pieces after each - discard. */ - while (1) - { - /* First, if we have two free parts, try the upper one first. */ - if (tbctrl->end_free < tbctrl->free) - { - if (tbctrl->free + amt <= trace_buffer_hi) - /* We have enough in the upper part. */ - break; - else - { - /* Our high part of free space wasn't enough. Give up - on it for now, set wraparound. We will recover the - space later, if/when the wrapped-around traceframe is - discarded. */ - trace_debug ("Upper part too small, setting wraparound"); - tbctrl->wrap = tbctrl->free; - tbctrl->free = trace_buffer_lo; - } - } - - /* The normal case. */ - if (tbctrl->free + amt <= tbctrl->end_free) - break; - -#ifdef IN_PROCESS_AGENT - /* The IP Agent's buffer is always circular. It isn't used - currently, but `circular_trace_buffer' could represent - GDBserver's mode. If we didn't find space, ask GDBserver to - flush. */ - - flush_trace_buffer (); - memory_barrier (); - if (tracing) - { - trace_debug ("gdbserver flushed buffer, retrying"); - goto again; - } - - /* GDBserver cancelled the tracing. Bail out as well. */ - return NULL; -#else - /* If we're here, then neither part is big enough, and - non-circular trace buffers are now full. */ - if (!circular_trace_buffer) - { - trace_debug ("Not enough space in the trace buffer"); - return NULL; - } - - trace_debug ("Need more space in the trace buffer"); - - /* If we have a circular buffer, we can try discarding the - oldest traceframe and see if that helps. */ - oldest = FIRST_TRACEFRAME (); - if (oldest->tpnum == 0) - { - /* Not good; we have no traceframes to free. Perhaps we're - asking for a block that is larger than the buffer? In - any case, give up. */ - trace_debug ("No traceframes to discard"); - return NULL; - } - - /* We don't run this code in the in-process agent currently. - E.g., we could leave the in-process agent in autonomous - circular mode if we only have fast tracepoints. If we do - that, then this bit becomes racy with GDBserver, which also - writes to this counter. */ - --traceframe_write_count; - - new_start = (unsigned char *) NEXT_TRACEFRAME (oldest); - /* If we freed the traceframe that wrapped around, go back - to the non-wrap case. */ - if (new_start < tbctrl->start) - { - trace_debug ("Discarding past the wraparound"); - tbctrl->wrap = trace_buffer_hi; - } - tbctrl->start = new_start; - tbctrl->end_free = tbctrl->start; - - trace_debug ("Discarded a traceframe\n" - "Trace buffer [%d], start=%d free=%d " - "endfree=%d wrap=%d hi=%d", - curr, - (int) (tbctrl->start - trace_buffer_lo), - (int) (tbctrl->free - trace_buffer_lo), - (int) (tbctrl->end_free - trace_buffer_lo), - (int) (tbctrl->wrap - trace_buffer_lo), - (int) (trace_buffer_hi - trace_buffer_lo)); - - /* Now go back around the loop. The discard might have resulted - in either one or two pieces of free space, so we want to try - both before freeing any more traceframes. */ -#endif - } - - /* If we get here, we know we can provide the asked-for space. */ - - rslt = tbctrl->free; - - /* Adjust the request back down, now that we know we have space for - the marker, but don't commit to AMT yet, we may still need to - restart the operation if GDBserver touches the trace buffer - (obviously only important in the in-process agent's version). */ - tbctrl->free += (amt - sizeof (struct traceframe)); - - /* Or not. If GDBserver changed the trace buffer behind our back, - we get to restart a new allocation attempt. */ - -#ifdef IN_PROCESS_AGENT - /* Build the tentative token. */ - commit_count = (((prev & GDBSERVER_FLUSH_COUNT_MASK_CURR) + 0x100) - & GDBSERVER_FLUSH_COUNT_MASK_CURR); - commit = (((prev & GDBSERVER_FLUSH_COUNT_MASK_CURR) << 12) - | commit_count - | curr); - - /* Try to commit it. */ - readout = cmpxchg (&trace_buffer_ctrl_curr, prev, commit); - if (readout != prev) - { - trace_debug ("GDBserver has touched the trace buffer, restarting." - " (prev=%08x, commit=%08x, readout=%08x)", - prev, commit, readout); - goto again; - } - - /* Hold your horses here. Even if that change was committed, - GDBserver could come in, and clobber it. We need to hold to be - able to tell if GDBserver clobbers before or after we committed - the change. Whenever GDBserver goes about touching the IPA - buffer, it sets a breakpoint in this routine, so we have a sync - point here. */ - about_to_request_buffer_space (); - - /* Check if the change has been effective, even if GDBserver stopped - us at the breakpoint. */ - - { - unsigned int refetch; - - memory_barrier (); - - refetch = trace_buffer_ctrl_curr; - - if (refetch == commit - || ((refetch & GDBSERVER_FLUSH_COUNT_MASK_PREV) >> 12) == commit_count) - { - /* effective */ - trace_debug ("change is effective: (prev=%08x, commit=%08x, " - "readout=%08x, refetch=%08x)", - prev, commit, readout, refetch); - } - else - { - trace_debug ("GDBserver has touched the trace buffer, not effective." - " (prev=%08x, commit=%08x, readout=%08x, refetch=%08x)", - prev, commit, readout, refetch); - goto again; - } - } -#endif - - /* We have a new piece of the trace buffer. Hurray! */ - - /* Add an EOB marker just past this allocation. */ - ((struct traceframe *) tbctrl->free)->tpnum = 0; - ((struct traceframe *) tbctrl->free)->data_size = 0; - - /* Adjust the request back down, now that we know we have space for - the marker. */ - amt -= sizeof (struct traceframe); - - if (debug_threads) - { - trace_debug ("Allocated %d bytes", (int) amt); - trace_debug ("Trace buffer [%d] start=%d free=%d " - "endfree=%d wrap=%d hi=%d", - curr, - (int) (tbctrl->start - trace_buffer_lo), - (int) (tbctrl->free - trace_buffer_lo), - (int) (tbctrl->end_free - trace_buffer_lo), - (int) (tbctrl->wrap - trace_buffer_lo), - (int) (trace_buffer_hi - trace_buffer_lo)); - } - - return rslt; -} - -#ifndef IN_PROCESS_AGENT - -/* Return the total free space. This is not necessarily the largest - block we can allocate, because of the two-part case. */ - -static int -free_space (void) -{ - if (trace_buffer_free <= trace_buffer_end_free) - return trace_buffer_end_free - trace_buffer_free; - else - return ((trace_buffer_end_free - trace_buffer_lo) - + (trace_buffer_hi - trace_buffer_free)); -} - -/* An 'S' in continuation packets indicates remainder are for - while-stepping. */ - -static int seen_step_action_flag; - -/* Create a tracepoint (location) with given number and address. Add this - new tracepoint to list and sort this list. */ - -static struct tracepoint * -add_tracepoint (int num, CORE_ADDR addr) -{ - struct tracepoint *tpoint, **tp_next; - - tpoint = XNEW (struct tracepoint); - tpoint->number = num; - tpoint->address = addr; - tpoint->numactions = 0; - tpoint->actions = NULL; - tpoint->actions_str = NULL; - tpoint->cond = NULL; - tpoint->num_step_actions = 0; - tpoint->step_actions = NULL; - tpoint->step_actions_str = NULL; - /* Start all off as regular (slow) tracepoints. */ - tpoint->type = trap_tracepoint; - tpoint->orig_size = -1; - tpoint->source_strings = NULL; - tpoint->compiled_cond = 0; - tpoint->handle = NULL; - tpoint->next = NULL; - - /* Find a place to insert this tracepoint into list in order to keep - the tracepoint list still in the ascending order. There may be - multiple tracepoints at the same address as TPOINT's, and this - guarantees TPOINT is inserted after all the tracepoints which are - set at the same address. For example, fast tracepoints A, B, C are - set at the same address, and D is to be insert at the same place as - well, - - -->| A |--> | B |-->| C |->... - - One jump pad was created for tracepoint A, B, and C, and the target - address of A is referenced/used in jump pad. So jump pad will let - inferior jump to A. If D is inserted in front of A, like this, - - -->| D |-->| A |--> | B |-->| C |->... - - without updating jump pad, D is not reachable during collect, which - is wrong. As we can see, the order of B, C and D doesn't matter, but - A should always be the `first' one. */ - for (tp_next = &tracepoints; - (*tp_next) != NULL && (*tp_next)->address <= tpoint->address; - tp_next = &(*tp_next)->next) - ; - tpoint->next = *tp_next; - *tp_next = tpoint; - last_tracepoint = tpoint; - - seen_step_action_flag = 0; - - return tpoint; -} - -#ifndef IN_PROCESS_AGENT - -/* Return the tracepoint with the given number and address, or NULL. */ - -static struct tracepoint * -find_tracepoint (int id, CORE_ADDR addr) -{ - struct tracepoint *tpoint; - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - if (tpoint->number == id && tpoint->address == addr) - return tpoint; - - return NULL; -} - -/* Remove TPOINT from global list. */ - -static void -remove_tracepoint (struct tracepoint *tpoint) -{ - struct tracepoint *tp, *tp_prev; - - for (tp = tracepoints, tp_prev = NULL; tp && tp != tpoint; - tp_prev = tp, tp = tp->next) - ; - - if (tp) - { - if (tp_prev) - tp_prev->next = tp->next; - else - tracepoints = tp->next; - - xfree (tp); - } -} - -/* There may be several tracepoints with the same number (because they - are "locations", in GDB parlance); return the next one after the - given tracepoint, or search from the beginning of the list if the - first argument is NULL. */ - -static struct tracepoint * -find_next_tracepoint_by_number (struct tracepoint *prev_tp, int num) -{ - struct tracepoint *tpoint; - - if (prev_tp) - tpoint = prev_tp->next; - else - tpoint = tracepoints; - for (; tpoint; tpoint = tpoint->next) - if (tpoint->number == num) - return tpoint; - - return NULL; -} - -#endif - -/* Append another action to perform when the tracepoint triggers. */ - -static void -add_tracepoint_action (struct tracepoint *tpoint, const char *packet) -{ - const char *act; - - if (*packet == 'S') - { - seen_step_action_flag = 1; - ++packet; - } - - act = packet; - - while (*act) - { - const char *act_start = act; - struct tracepoint_action *action = NULL; - - switch (*act) - { - case 'M': - { - struct collect_memory_action *maction = - XNEW (struct collect_memory_action); - ULONGEST basereg; - int is_neg; - - maction->base.type = *act; - action = &maction->base; - - ++act; - is_neg = (*act == '-'); - if (*act == '-') - ++act; - act = unpack_varlen_hex (act, &basereg); - ++act; - act = unpack_varlen_hex (act, &maction->addr); - ++act; - act = unpack_varlen_hex (act, &maction->len); - maction->basereg = (is_neg - ? - (int) basereg - : (int) basereg); - trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)", - pulongest (maction->len), - paddress (maction->addr), maction->basereg); - break; - } - case 'R': - { - struct collect_registers_action *raction = - XNEW (struct collect_registers_action); - - raction->base.type = *act; - action = &raction->base; - - trace_debug ("Want to collect registers"); - ++act; - /* skip past hex digits of mask for now */ - while (isxdigit(*act)) - ++act; - break; - } - case 'L': - { - struct collect_static_trace_data_action *raction = - XNEW (struct collect_static_trace_data_action); - - raction->base.type = *act; - action = &raction->base; - - trace_debug ("Want to collect static trace data"); - ++act; - break; - } - case 'S': - trace_debug ("Unexpected step action, ignoring"); - ++act; - break; - case 'X': - { - struct eval_expr_action *xaction = XNEW (struct eval_expr_action); - - xaction->base.type = *act; - action = &xaction->base; - - trace_debug ("Want to evaluate expression"); - xaction->expr = gdb_parse_agent_expr (&act); - break; - } - default: - trace_debug ("unknown trace action '%c', ignoring...", *act); - break; - case '-': - break; - } - - if (action == NULL) - break; - - if (seen_step_action_flag) - { - tpoint->num_step_actions++; - - tpoint->step_actions - = XRESIZEVEC (struct tracepoint_action *, tpoint->step_actions, - tpoint->num_step_actions); - tpoint->step_actions_str - = XRESIZEVEC (char *, tpoint->step_actions_str, - tpoint->num_step_actions); - tpoint->step_actions[tpoint->num_step_actions - 1] = action; - tpoint->step_actions_str[tpoint->num_step_actions - 1] - = savestring (act_start, act - act_start); - } - else - { - tpoint->numactions++; - tpoint->actions - = XRESIZEVEC (struct tracepoint_action *, tpoint->actions, - tpoint->numactions); - tpoint->actions_str - = XRESIZEVEC (char *, tpoint->actions_str, tpoint->numactions); - tpoint->actions[tpoint->numactions - 1] = action; - tpoint->actions_str[tpoint->numactions - 1] - = savestring (act_start, act - act_start); - } - } -} - -#endif - -/* Find or create a trace state variable with the given number. */ - -static struct trace_state_variable * -get_trace_state_variable (int num) -{ - struct trace_state_variable *tsv; - -#ifdef IN_PROCESS_AGENT - /* Search for an existing variable. */ - for (tsv = alloced_trace_state_variables; tsv; tsv = tsv->next) - if (tsv->number == num) - return tsv; -#endif - - /* Search for an existing variable. */ - for (tsv = trace_state_variables; tsv; tsv = tsv->next) - if (tsv->number == num) - return tsv; - - return NULL; -} - -/* Find or create a trace state variable with the given number. */ - -static struct trace_state_variable * -create_trace_state_variable (int num, int gdb) -{ - struct trace_state_variable *tsv; - - tsv = get_trace_state_variable (num); - if (tsv != NULL) - return tsv; - - /* Create a new variable. */ - tsv = XNEW (struct trace_state_variable); - tsv->number = num; - tsv->initial_value = 0; - tsv->value = 0; - tsv->getter = NULL; - tsv->name = NULL; -#ifdef IN_PROCESS_AGENT - if (!gdb) - { - tsv->next = alloced_trace_state_variables; - alloced_trace_state_variables = tsv; - } - else -#endif - { - tsv->next = trace_state_variables; - trace_state_variables = tsv; - } - return tsv; -} - -/* This is needed for -Wmissing-declarations. */ -IP_AGENT_EXPORT_FUNC LONGEST get_trace_state_variable_value (int num); - -IP_AGENT_EXPORT_FUNC LONGEST -get_trace_state_variable_value (int num) -{ - struct trace_state_variable *tsv; - - tsv = get_trace_state_variable (num); - - if (!tsv) - { - trace_debug ("No trace state variable %d, skipping value get", num); - return 0; - } - - /* Call a getter function if we have one. While it's tempting to - set up something to only call the getter once per tracepoint hit, - it could run afoul of thread races. Better to let the getter - handle it directly, if necessary to worry about it. */ - if (tsv->getter) - tsv->value = (tsv->getter) (); - - trace_debug ("get_trace_state_variable_value(%d) ==> %s", - num, plongest (tsv->value)); - - return tsv->value; -} - -/* This is needed for -Wmissing-declarations. */ -IP_AGENT_EXPORT_FUNC void set_trace_state_variable_value (int num, - LONGEST val); - -IP_AGENT_EXPORT_FUNC void -set_trace_state_variable_value (int num, LONGEST val) -{ - struct trace_state_variable *tsv; - - tsv = get_trace_state_variable (num); - - if (!tsv) - { - trace_debug ("No trace state variable %d, skipping value set", num); - return; - } - - tsv->value = val; -} - -LONGEST -agent_get_trace_state_variable_value (int num) -{ - return get_trace_state_variable_value (num); -} - -void -agent_set_trace_state_variable_value (int num, LONGEST val) -{ - set_trace_state_variable_value (num, val); -} - -static void -set_trace_state_variable_name (int num, const char *name) -{ - struct trace_state_variable *tsv; - - tsv = get_trace_state_variable (num); - - if (!tsv) - { - trace_debug ("No trace state variable %d, skipping name set", num); - return; - } - - tsv->name = (char *) name; -} - -static void -set_trace_state_variable_getter (int num, LONGEST (*getter) (void)) -{ - struct trace_state_variable *tsv; - - tsv = get_trace_state_variable (num); - - if (!tsv) - { - trace_debug ("No trace state variable %d, skipping getter set", num); - return; - } - - tsv->getter = getter; -} - -/* Add a raw traceframe for the given tracepoint. */ - -static struct traceframe * -add_traceframe (struct tracepoint *tpoint) -{ - struct traceframe *tframe; - - tframe - = (struct traceframe *) trace_buffer_alloc (sizeof (struct traceframe)); - - if (tframe == NULL) - return NULL; - - tframe->tpnum = tpoint->number; - tframe->data_size = 0; - - return tframe; -} - -/* Add a block to the traceframe currently being worked on. */ - -static unsigned char * -add_traceframe_block (struct traceframe *tframe, - struct tracepoint *tpoint, int amt) -{ - unsigned char *block; - - if (!tframe) - return NULL; - - block = (unsigned char *) trace_buffer_alloc (amt); - - if (!block) - return NULL; - - gdb_assert (tframe->tpnum == tpoint->number); - - tframe->data_size += amt; - tpoint->traceframe_usage += amt; - - return block; -} - -/* Flag that the current traceframe is finished. */ - -static void -finish_traceframe (struct traceframe *tframe) -{ - ++traceframe_write_count; - ++traceframes_created; -} - -#ifndef IN_PROCESS_AGENT - -/* Given a traceframe number NUM, find the NUMth traceframe in the - buffer. */ - -static struct traceframe * -find_traceframe (int num) -{ - struct traceframe *tframe; - int tfnum = 0; - - for (tframe = FIRST_TRACEFRAME (); - tframe->tpnum != 0; - tframe = NEXT_TRACEFRAME (tframe)) - { - if (tfnum == num) - return tframe; - ++tfnum; - } - - return NULL; -} - -static CORE_ADDR -get_traceframe_address (struct traceframe *tframe) -{ - CORE_ADDR addr; - struct tracepoint *tpoint; - - addr = traceframe_get_pc (tframe); - - if (addr) - return addr; - - /* Fallback strategy, will be incorrect for while-stepping frames - and multi-location tracepoints. */ - tpoint = find_next_tracepoint_by_number (NULL, tframe->tpnum); - return tpoint->address; -} - -/* Search for the next traceframe whose address is inside or outside - the given range. */ - -static struct traceframe * -find_next_traceframe_in_range (CORE_ADDR lo, CORE_ADDR hi, int inside_p, - int *tfnump) -{ - client_state &cs = get_client_state (); - struct traceframe *tframe; - CORE_ADDR tfaddr; - - *tfnump = cs.current_traceframe + 1; - tframe = find_traceframe (*tfnump); - /* The search is not supposed to wrap around. */ - if (!tframe) - { - *tfnump = -1; - return NULL; - } - - for (; tframe->tpnum != 0; tframe = NEXT_TRACEFRAME (tframe)) - { - tfaddr = get_traceframe_address (tframe); - if (inside_p - ? (lo <= tfaddr && tfaddr <= hi) - : (lo > tfaddr || tfaddr > hi)) - return tframe; - ++*tfnump; - } - - *tfnump = -1; - return NULL; -} - -/* Search for the next traceframe recorded by the given tracepoint. - Note that for multi-location tracepoints, this will find whatever - location appears first. */ - -static struct traceframe * -find_next_traceframe_by_tracepoint (int num, int *tfnump) -{ - client_state &cs = get_client_state (); - struct traceframe *tframe; - - *tfnump = cs.current_traceframe + 1; - tframe = find_traceframe (*tfnump); - /* The search is not supposed to wrap around. */ - if (!tframe) - { - *tfnump = -1; - return NULL; - } - - for (; tframe->tpnum != 0; tframe = NEXT_TRACEFRAME (tframe)) - { - if (tframe->tpnum == num) - return tframe; - ++*tfnump; - } - - *tfnump = -1; - return NULL; -} - -#endif - -#ifndef IN_PROCESS_AGENT - -/* Clear all past trace state. */ - -static void -cmd_qtinit (char *packet) -{ - client_state &cs = get_client_state (); - struct trace_state_variable *tsv, *prev, *next; - - /* Can't do this command without a pid attached. */ - if (current_thread == NULL) - { - write_enn (packet); - return; - } - - /* Make sure we don't try to read from a trace frame. */ - cs.current_traceframe = -1; - - stop_tracing (); - - trace_debug ("Initializing the trace"); - - clear_installed_tracepoints (); - clear_readonly_regions (); - - tracepoints = NULL; - last_tracepoint = NULL; - - /* Clear out any leftover trace state variables. Ones with target - defined getters should be kept however. */ - prev = NULL; - tsv = trace_state_variables; - while (tsv) - { - trace_debug ("Looking at var %d", tsv->number); - if (tsv->getter == NULL) - { - next = tsv->next; - if (prev) - prev->next = next; - else - trace_state_variables = next; - trace_debug ("Deleting var %d", tsv->number); - free (tsv); - tsv = next; - } - else - { - prev = tsv; - tsv = tsv->next; - } - } - - clear_trace_buffer (); - clear_inferior_trace_buffer (); - - write_ok (packet); -} - -/* Unprobe the UST marker at ADDRESS. */ - -static void -unprobe_marker_at (CORE_ADDR address) -{ - char cmd[IPA_CMD_BUF_SIZE]; - - sprintf (cmd, "unprobe_marker_at:%s", paddress (address)); - run_inferior_command (cmd, strlen (cmd) + 1); -} - -/* Restore the program to its pre-tracing state. This routine may be called - in error situations, so it needs to be careful about only restoring - from known-valid bits. */ - -static void -clear_installed_tracepoints (void) -{ - struct tracepoint *tpoint; - struct tracepoint *prev_stpoint; - - pause_all (1); - - prev_stpoint = NULL; - - /* Restore any bytes overwritten by tracepoints. */ - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - { - /* Catch the case where we might try to remove a tracepoint that - was never actually installed. */ - if (tpoint->handle == NULL) - { - trace_debug ("Tracepoint %d at 0x%s was " - "never installed, nothing to clear", - tpoint->number, paddress (tpoint->address)); - continue; - } - - switch (tpoint->type) - { - case trap_tracepoint: - { - struct breakpoint *bp - = (struct breakpoint *) tpoint->handle; - - delete_breakpoint (bp); - } - break; - case fast_tracepoint: - { - struct fast_tracepoint_jump *jump - = (struct fast_tracepoint_jump *) tpoint->handle; - - delete_fast_tracepoint_jump (jump); - } - break; - case static_tracepoint: - if (prev_stpoint != NULL - && prev_stpoint->address == tpoint->address) - /* Nothing to do. We already unprobed a tracepoint set at - this marker address (and there can only be one probe - per marker). */ - ; - else - { - unprobe_marker_at (tpoint->address); - prev_stpoint = tpoint; - } - break; - } - - tpoint->handle = NULL; - } - - unpause_all (1); -} - -/* Parse a packet that defines a tracepoint. */ - -static void -cmd_qtdp (char *own_buf) -{ - int tppacket; - /* Whether there is a trailing hyphen at the end of the QTDP packet. */ - int trail_hyphen = 0; - ULONGEST num; - ULONGEST addr; - ULONGEST count; - struct tracepoint *tpoint; - const char *packet = own_buf; - - packet += strlen ("QTDP:"); - - /* A hyphen at the beginning marks a packet specifying actions for a - tracepoint already supplied. */ - tppacket = 1; - if (*packet == '-') - { - tppacket = 0; - ++packet; - } - packet = unpack_varlen_hex (packet, &num); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &addr); - ++packet; /* skip a colon */ - - /* See if we already have this tracepoint. */ - tpoint = find_tracepoint (num, addr); - - if (tppacket) - { - /* Duplicate tracepoints are never allowed. */ - if (tpoint) - { - trace_debug ("Tracepoint error: tracepoint %d" - " at 0x%s already exists", - (int) num, paddress (addr)); - write_enn (own_buf); - return; - } - - tpoint = add_tracepoint (num, addr); - - tpoint->enabled = (*packet == 'E'); - ++packet; /* skip 'E' */ - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &count); - tpoint->step_count = count; - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &count); - tpoint->pass_count = count; - /* See if we have any of the additional optional fields. */ - while (*packet == ':') - { - ++packet; - if (*packet == 'F') - { - tpoint->type = fast_tracepoint; - ++packet; - packet = unpack_varlen_hex (packet, &count); - tpoint->orig_size = count; - } - else if (*packet == 'S') - { - tpoint->type = static_tracepoint; - ++packet; - } - else if (*packet == 'X') - { - tpoint->cond = gdb_parse_agent_expr (&packet); - } - else if (*packet == '-') - break; - else if (*packet == '\0') - break; - else - trace_debug ("Unknown optional tracepoint field"); - } - if (*packet == '-') - { - trail_hyphen = 1; - trace_debug ("Also has actions\n"); - } - - trace_debug ("Defined %stracepoint %d at 0x%s, " - "enabled %d step %" PRIu64 " pass %" PRIu64, - tpoint->type == fast_tracepoint ? "fast " - : tpoint->type == static_tracepoint ? "static " : "", - tpoint->number, paddress (tpoint->address), tpoint->enabled, - tpoint->step_count, tpoint->pass_count); - } - else if (tpoint) - add_tracepoint_action (tpoint, packet); - else - { - trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", - (int) num, paddress (addr)); - write_enn (own_buf); - return; - } - - /* Install tracepoint during tracing only once for each tracepoint location. - For each tracepoint loc, GDB may send multiple QTDP packets, and we can - determine the last QTDP packet for one tracepoint location by checking - trailing hyphen in QTDP packet. */ - if (tracing && !trail_hyphen) - { - struct tracepoint *tp = NULL; - - /* Pause all threads temporarily while we patch tracepoints. */ - pause_all (0); - - /* download_tracepoint will update global `tracepoints' - list, so it is unsafe to leave threads in jump pad. */ - stabilize_threads (); - - /* Freeze threads. */ - pause_all (1); - - - if (tpoint->type != trap_tracepoint) - { - /* Find another fast or static tracepoint at the same address. */ - for (tp = tracepoints; tp; tp = tp->next) - { - if (tp->address == tpoint->address && tp->type == tpoint->type - && tp->number != tpoint->number) - break; - } - - /* TPOINT is installed at the same address as TP. */ - if (tp) - { - if (tpoint->type == fast_tracepoint) - clone_fast_tracepoint (tpoint, tp); - else if (tpoint->type == static_tracepoint) - tpoint->handle = (void *) -1; - } - } - - if (use_agent && tpoint->type == fast_tracepoint - && agent_capability_check (AGENT_CAPA_FAST_TRACE)) - { - /* Download and install fast tracepoint by agent. */ - if (tracepoint_send_agent (tpoint) == 0) - write_ok (own_buf); - else - { - write_enn (own_buf); - remove_tracepoint (tpoint); - } - } - else - { - download_tracepoint (tpoint); - - if (tpoint->type == trap_tracepoint || tp == NULL) - { - install_tracepoint (tpoint, own_buf); - if (strcmp (own_buf, "OK") != 0) - remove_tracepoint (tpoint); - } - else - write_ok (own_buf); - } - - unpause_all (1); - return; - } - - write_ok (own_buf); -} - -static void -cmd_qtdpsrc (char *own_buf) -{ - ULONGEST num, addr, start, slen; - struct tracepoint *tpoint; - const char *packet = own_buf; - const char *saved; - char *srctype, *src; - size_t nbytes; - struct source_string *last, *newlast; - - packet += strlen ("QTDPsrc:"); - - packet = unpack_varlen_hex (packet, &num); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &addr); - ++packet; /* skip a colon */ - - /* See if we already have this tracepoint. */ - tpoint = find_tracepoint (num, addr); - - if (!tpoint) - { - trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", - (int) num, paddress (addr)); - write_enn (own_buf); - return; - } - - saved = packet; - packet = strchr (packet, ':'); - srctype = (char *) xmalloc (packet - saved + 1); - memcpy (srctype, saved, packet - saved); - srctype[packet - saved] = '\0'; - ++packet; - packet = unpack_varlen_hex (packet, &start); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &slen); - ++packet; /* skip a colon */ - src = (char *) xmalloc (slen + 1); - nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2); - src[nbytes] = '\0'; - - newlast = XNEW (struct source_string); - newlast->type = srctype; - newlast->str = src; - newlast->next = NULL; - /* Always add a source string to the end of the list; - this keeps sequences of actions/commands in the right - order. */ - if (tpoint->source_strings) - { - for (last = tpoint->source_strings; last->next; last = last->next) - ; - last->next = newlast; - } - else - tpoint->source_strings = newlast; - - write_ok (own_buf); -} - -static void -cmd_qtdv (char *own_buf) -{ - ULONGEST num, val, builtin; - char *varname; - size_t nbytes; - struct trace_state_variable *tsv; - const char *packet = own_buf; - - packet += strlen ("QTDV:"); - - packet = unpack_varlen_hex (packet, &num); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &val); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &builtin); - ++packet; /* skip a colon */ - - nbytes = strlen (packet) / 2; - varname = (char *) xmalloc (nbytes + 1); - nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes); - varname[nbytes] = '\0'; - - tsv = create_trace_state_variable (num, 1); - tsv->initial_value = (LONGEST) val; - tsv->name = varname; - - set_trace_state_variable_value (num, (LONGEST) val); - - write_ok (own_buf); -} - -static void -cmd_qtenable_disable (char *own_buf, int enable) -{ - const char *packet = own_buf; - ULONGEST num, addr; - struct tracepoint *tp; - - packet += strlen (enable ? "QTEnable:" : "QTDisable:"); - packet = unpack_varlen_hex (packet, &num); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &addr); - - tp = find_tracepoint (num, addr); - - if (tp) - { - if ((enable && tp->enabled) || (!enable && !tp->enabled)) - { - trace_debug ("Tracepoint %d at 0x%s is already %s", - (int) num, paddress (addr), - enable ? "enabled" : "disabled"); - write_ok (own_buf); - return; - } - - trace_debug ("%s tracepoint %d at 0x%s", - enable ? "Enabling" : "Disabling", - (int) num, paddress (addr)); - - tp->enabled = enable; - - if (tp->type == fast_tracepoint || tp->type == static_tracepoint) - { - int ret; - int offset = offsetof (struct tracepoint, enabled); - CORE_ADDR obj_addr = tp->obj_addr_on_target + offset; - - ret = prepare_to_access_memory (); - if (ret) - { - trace_debug ("Failed to temporarily stop inferior threads"); - write_enn (own_buf); - return; - } - - ret = write_inferior_int8 (obj_addr, enable); - done_accessing_memory (); - - if (ret) - { - trace_debug ("Cannot write enabled flag into " - "inferior process memory"); - write_enn (own_buf); - return; - } - } - - write_ok (own_buf); - } - else - { - trace_debug ("Tracepoint %d at 0x%s not found", - (int) num, paddress (addr)); - write_enn (own_buf); - } -} - -static void -cmd_qtv (char *own_buf) -{ - client_state &cs = get_client_state (); - ULONGEST num; - LONGEST val = 0; - int err; - char *packet = own_buf; - - packet += strlen ("qTV:"); - unpack_varlen_hex (packet, &num); - - if (cs.current_traceframe >= 0) - { - err = traceframe_read_tsv ((int) num, &val); - if (err) - { - strcpy (own_buf, "U"); - return; - } - } - /* Only make tsv's be undefined before the first trace run. After a - trace run is over, the user might want to see the last value of - the tsv, and it might not be available in a traceframe. */ - else if (!tracing && strcmp (tracing_stop_reason, "tnotrun") == 0) - { - strcpy (own_buf, "U"); - return; - } - else - val = get_trace_state_variable_value (num); - - sprintf (own_buf, "V%s", phex_nz (val, 0)); -} - -/* Clear out the list of readonly regions. */ - -static void -clear_readonly_regions (void) -{ - struct readonly_region *roreg; - - while (readonly_regions) - { - roreg = readonly_regions; - readonly_regions = readonly_regions->next; - free (roreg); - } -} - -/* Parse the collection of address ranges whose contents GDB believes - to be unchanging and so can be read directly from target memory - even while looking at a traceframe. */ - -static void -cmd_qtro (char *own_buf) -{ - ULONGEST start, end; - struct readonly_region *roreg; - const char *packet = own_buf; - - trace_debug ("Want to mark readonly regions"); - - clear_readonly_regions (); - - packet += strlen ("QTro"); - - while (*packet == ':') - { - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &start); - ++packet; /* skip a comma */ - packet = unpack_varlen_hex (packet, &end); - - roreg = XNEW (struct readonly_region); - roreg->start = start; - roreg->end = end; - roreg->next = readonly_regions; - readonly_regions = roreg; - trace_debug ("Added readonly region from 0x%s to 0x%s", - paddress (roreg->start), paddress (roreg->end)); - } - - write_ok (own_buf); -} - -/* Test to see if the given range is in our list of readonly ranges. - We only test for being entirely within a range, GDB is not going to - send a single memory packet that spans multiple regions. */ - -int -in_readonly_region (CORE_ADDR addr, ULONGEST length) -{ - struct readonly_region *roreg; - - for (roreg = readonly_regions; roreg; roreg = roreg->next) - if (roreg->start <= addr && (addr + length - 1) <= roreg->end) - return 1; - - return 0; -} - -static CORE_ADDR gdb_jump_pad_head; - -/* Return the address of the next free jump space. */ - -static CORE_ADDR -get_jump_space_head (void) -{ - if (gdb_jump_pad_head == 0) - { - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer, - &gdb_jump_pad_head)) - { - internal_error (__FILE__, __LINE__, - "error extracting jump_pad_buffer"); - } - } - - return gdb_jump_pad_head; -} - -/* Reserve USED bytes from the jump space. */ - -static void -claim_jump_space (ULONGEST used) -{ - trace_debug ("claim_jump_space reserves %s bytes at %s", - pulongest (used), paddress (gdb_jump_pad_head)); - gdb_jump_pad_head += used; -} - -static CORE_ADDR trampoline_buffer_head = 0; -static CORE_ADDR trampoline_buffer_tail; - -/* Reserve USED bytes from the trampoline buffer and return the - address of the start of the reserved space in TRAMPOLINE. Returns - non-zero if the space is successfully claimed. */ - -int -claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline) -{ - if (!trampoline_buffer_head) - { - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer, - &trampoline_buffer_tail)) - { - internal_error (__FILE__, __LINE__, - "error extracting trampoline_buffer"); - } - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, - &trampoline_buffer_head)) - { - internal_error (__FILE__, __LINE__, - "error extracting trampoline_buffer_end"); - } - } - - /* Start claiming space from the top of the trampoline space. If - the space is located at the bottom of the virtual address space, - this reduces the possibility that corruption will occur if a null - pointer is used to write to memory. */ - if (trampoline_buffer_head - trampoline_buffer_tail < used) - { - trace_debug ("claim_trampoline_space failed to reserve %s bytes", - pulongest (used)); - return 0; - } - - trampoline_buffer_head -= used; - - trace_debug ("claim_trampoline_space reserves %s bytes at %s", - pulongest (used), paddress (trampoline_buffer_head)); - - *trampoline = trampoline_buffer_head; - return 1; -} - -/* Returns non-zero if there is space allocated for use in trampolines - for fast tracepoints. */ - -int -have_fast_tracepoint_trampoline_buffer (char *buf) -{ - CORE_ADDR trampoline_end, errbuf; - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, - &trampoline_end)) - { - internal_error (__FILE__, __LINE__, - "error extracting trampoline_buffer_end"); - } - - if (buf) - { - buf[0] = '\0'; - strcpy (buf, "was claiming"); - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error, - &errbuf)) - { - internal_error (__FILE__, __LINE__, - "error extracting errbuf"); - } - - read_inferior_memory (errbuf, (unsigned char *) buf, 100); - } - - return trampoline_end != 0; -} - -/* Ask the IPA to probe the marker at ADDRESS. Returns -1 if running - the command fails, or 0 otherwise. If the command ran - successfully, but probing the marker failed, ERROUT will be filled - with the error to reply to GDB, and -1 is also returned. This - allows directly passing IPA errors to GDB. */ - -static int -probe_marker_at (CORE_ADDR address, char *errout) -{ - char cmd[IPA_CMD_BUF_SIZE]; - int err; - - sprintf (cmd, "probe_marker_at:%s", paddress (address)); - err = run_inferior_command (cmd, strlen (cmd) + 1); - - if (err == 0) - { - if (*cmd == 'E') - { - strcpy (errout, cmd); - return -1; - } - } - - return err; -} - -static void -clone_fast_tracepoint (struct tracepoint *to, const struct tracepoint *from) -{ - to->jump_pad = from->jump_pad; - to->jump_pad_end = from->jump_pad_end; - to->trampoline = from->trampoline; - to->trampoline_end = from->trampoline_end; - to->adjusted_insn_addr = from->adjusted_insn_addr; - to->adjusted_insn_addr_end = from->adjusted_insn_addr_end; - to->handle = from->handle; - - gdb_assert (from->handle); - inc_ref_fast_tracepoint_jump ((struct fast_tracepoint_jump *) from->handle); -} - -#define MAX_JUMP_SIZE 20 - -/* Install fast tracepoint. Return 0 if successful, otherwise return - non-zero. */ - -static int -install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf) -{ - CORE_ADDR jentry, jump_entry; - CORE_ADDR trampoline; - CORE_ADDR collect; - ULONGEST trampoline_size; - int err = 0; - /* The jump to the jump pad of the last fast tracepoint - installed. */ - unsigned char fjump[MAX_JUMP_SIZE]; - ULONGEST fjump_size; - - if (tpoint->orig_size < target_get_min_fast_tracepoint_insn_len ()) - { - trace_debug ("Requested a fast tracepoint on an instruction " - "that is of less than the minimum length."); - return 0; - } - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_collect_ptr, - &collect)) - { - error ("error extracting gdb_collect_ptr"); - return 1; - } - - jentry = jump_entry = get_jump_space_head (); - - trampoline = 0; - trampoline_size = 0; - - /* Install the jump pad. */ - err = install_fast_tracepoint_jump_pad (tpoint->obj_addr_on_target, - tpoint->address, - collect, - ipa_sym_addrs.addr_collecting, - tpoint->orig_size, - &jentry, - &trampoline, &trampoline_size, - fjump, &fjump_size, - &tpoint->adjusted_insn_addr, - &tpoint->adjusted_insn_addr_end, - errbuf); - - if (err) - return 1; - - /* Wire it in. */ - tpoint->handle = set_fast_tracepoint_jump (tpoint->address, fjump, - fjump_size); - - if (tpoint->handle != NULL) - { - tpoint->jump_pad = jump_entry; - tpoint->jump_pad_end = jentry; - tpoint->trampoline = trampoline; - tpoint->trampoline_end = trampoline + trampoline_size; - - /* Pad to 8-byte alignment. */ - jentry = ((jentry + 7) & ~0x7); - claim_jump_space (jentry - jump_entry); - } - - return 0; -} - - -/* Install tracepoint TPOINT, and write reply message in OWN_BUF. */ - -static void -install_tracepoint (struct tracepoint *tpoint, char *own_buf) -{ - tpoint->handle = NULL; - *own_buf = '\0'; - - if (tpoint->type == trap_tracepoint) - { - /* Tracepoints are installed as memory breakpoints. Just go - ahead and install the trap. The breakpoints module - handles duplicated breakpoints, and the memory read - routine handles un-patching traps from memory reads. */ - tpoint->handle = set_breakpoint_at (tpoint->address, - tracepoint_handler); - } - else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint) - { - if (!agent_loaded_p ()) - { - trace_debug ("Requested a %s tracepoint, but fast " - "tracepoints aren't supported.", - tpoint->type == static_tracepoint ? "static" : "fast"); - write_e_ipa_not_loaded (own_buf); - return; - } - if (tpoint->type == static_tracepoint - && !in_process_agent_supports_ust ()) - { - trace_debug ("Requested a static tracepoint, but static " - "tracepoints are not supported."); - write_e_ust_not_loaded (own_buf); - return; - } - - if (tpoint->type == fast_tracepoint) - install_fast_tracepoint (tpoint, own_buf); - else - { - if (probe_marker_at (tpoint->address, own_buf) == 0) - tpoint->handle = (void *) -1; - } - - } - else - internal_error (__FILE__, __LINE__, "Unknown tracepoint type"); - - if (tpoint->handle == NULL) - { - if (*own_buf == '\0') - write_enn (own_buf); - } - else - write_ok (own_buf); -} - -static void download_tracepoint_1 (struct tracepoint *tpoint); - -static void -cmd_qtstart (char *packet) -{ - struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint; - CORE_ADDR tpptr = 0, prev_tpptr = 0; - - trace_debug ("Starting the trace"); - - /* Pause all threads temporarily while we patch tracepoints. */ - pause_all (0); - - /* Get threads out of jump pads. Safe to do here, since this is a - top level command. And, required to do here, since we're - deleting/rewriting jump pads. */ - - stabilize_threads (); - - /* Freeze threads. */ - pause_all (1); - - /* Sync the fast tracepoints list in the inferior ftlib. */ - if (agent_loaded_p ()) - download_trace_state_variables (); - - /* No previous fast tpoint yet. */ - prev_ftpoint = NULL; - - /* No previous static tpoint yet. */ - prev_stpoint = NULL; - - *packet = '\0'; - - if (agent_loaded_p ()) - { - /* Tell IPA about the correct tdesc. */ - if (write_inferior_integer (ipa_sym_addrs.addr_ipa_tdesc_idx, - target_get_ipa_tdesc_idx ())) - error ("Error setting ipa_tdesc_idx variable in lib"); - } - - /* Start out empty. */ - if (agent_loaded_p ()) - write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, 0); - - /* Download and install tracepoints. */ - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - { - /* Ensure all the hit counts start at zero. */ - tpoint->hit_count = 0; - tpoint->traceframe_usage = 0; - - if (tpoint->type == trap_tracepoint) - { - /* Tracepoints are installed as memory breakpoints. Just go - ahead and install the trap. The breakpoints module - handles duplicated breakpoints, and the memory read - routine handles un-patching traps from memory reads. */ - tpoint->handle = set_breakpoint_at (tpoint->address, - tracepoint_handler); - } - else if (tpoint->type == fast_tracepoint - || tpoint->type == static_tracepoint) - { - if (maybe_write_ipa_not_loaded (packet)) - { - trace_debug ("Requested a %s tracepoint, but fast " - "tracepoints aren't supported.", - tpoint->type == static_tracepoint - ? "static" : "fast"); - break; - } - - if (tpoint->type == fast_tracepoint) - { - int use_agent_p - = use_agent && agent_capability_check (AGENT_CAPA_FAST_TRACE); - - if (prev_ftpoint != NULL - && prev_ftpoint->address == tpoint->address) - { - if (use_agent_p) - tracepoint_send_agent (tpoint); - else - download_tracepoint_1 (tpoint); - - clone_fast_tracepoint (tpoint, prev_ftpoint); - } - else - { - /* Tracepoint is installed successfully? */ - int installed = 0; - - /* Download and install fast tracepoint by agent. */ - if (use_agent_p) - installed = !tracepoint_send_agent (tpoint); - else - { - download_tracepoint_1 (tpoint); - installed = !install_fast_tracepoint (tpoint, packet); - } - - if (installed) - prev_ftpoint = tpoint; - } - } - else - { - if (!in_process_agent_supports_ust ()) - { - trace_debug ("Requested a static tracepoint, but static " - "tracepoints are not supported."); - break; - } - - download_tracepoint_1 (tpoint); - /* Can only probe a given marker once. */ - if (prev_stpoint != NULL - && prev_stpoint->address == tpoint->address) - tpoint->handle = (void *) -1; - else - { - if (probe_marker_at (tpoint->address, packet) == 0) - { - tpoint->handle = (void *) -1; - - /* So that we can handle multiple static tracepoints - at the same address easily. */ - prev_stpoint = tpoint; - } - } - } - - prev_tpptr = tpptr; - tpptr = tpoint->obj_addr_on_target; - - if (tpoint == tracepoints) - /* First object in list, set the head pointer in the - inferior. */ - write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, tpptr); - else - write_inferior_data_pointer (prev_tpptr - + offsetof (struct tracepoint, next), - tpptr); - } - - /* Any failure in the inner loop is sufficient cause to give - up. */ - if (tpoint->handle == NULL) - break; - } - - /* Any error in tracepoint insertion is unacceptable; better to - address the problem now, than end up with a useless or misleading - trace run. */ - if (tpoint != NULL) - { - clear_installed_tracepoints (); - if (*packet == '\0') - write_enn (packet); - unpause_all (1); - return; - } - - stopping_tracepoint = NULL; - trace_buffer_is_full = 0; - expr_eval_result = expr_eval_no_error; - error_tracepoint = NULL; - tracing_start_time = get_timestamp (); - - /* Tracing is now active, hits will now start being logged. */ - tracing = 1; - - if (agent_loaded_p ()) - { - if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 1)) - { - internal_error (__FILE__, __LINE__, - "Error setting tracing variable in lib"); - } - - if (write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, - 0)) - { - internal_error (__FILE__, __LINE__, - "Error clearing stopping_tracepoint variable" - " in lib"); - } - - if (write_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full, 0)) - { - internal_error (__FILE__, __LINE__, - "Error clearing trace_buffer_is_full variable" - " in lib"); - } - - stop_tracing_bkpt = set_breakpoint_at (ipa_sym_addrs.addr_stop_tracing, - stop_tracing_handler); - if (stop_tracing_bkpt == NULL) - error ("Error setting stop_tracing breakpoint"); - - flush_trace_buffer_bkpt - = set_breakpoint_at (ipa_sym_addrs.addr_flush_trace_buffer, - flush_trace_buffer_handler); - if (flush_trace_buffer_bkpt == NULL) - error ("Error setting flush_trace_buffer breakpoint"); - } - - unpause_all (1); - - write_ok (packet); -} - -/* End a tracing run, filling in a stop reason to report back to GDB, - and removing the tracepoints from the code. */ - -void -stop_tracing (void) -{ - if (!tracing) - { - trace_debug ("Tracing is already off, ignoring"); - return; - } - - trace_debug ("Stopping the trace"); - - /* Pause all threads before removing fast jumps from memory, - breakpoints, and touching IPA state variables (inferior memory). - Some thread may hit the internal tracing breakpoints, or be - collecting this moment, but that's ok, we don't release the - tpoint object's memory or the jump pads here (we only do that - when we're sure we can move all threads out of the jump pads). - We can't now, since we may be getting here due to the inferior - agent calling us. */ - pause_all (1); - - /* Stop logging. Tracepoints can still be hit, but they will not be - recorded. */ - tracing = 0; - if (agent_loaded_p ()) - { - if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 0)) - { - internal_error (__FILE__, __LINE__, - "Error clearing tracing variable in lib"); - } - } - - tracing_stop_time = get_timestamp (); - tracing_stop_reason = "t???"; - tracing_stop_tpnum = 0; - if (stopping_tracepoint) - { - trace_debug ("Stopping the trace because " - "tracepoint %d was hit %" PRIu64 " times", - stopping_tracepoint->number, - stopping_tracepoint->pass_count); - tracing_stop_reason = "tpasscount"; - tracing_stop_tpnum = stopping_tracepoint->number; - } - else if (trace_buffer_is_full) - { - trace_debug ("Stopping the trace because the trace buffer is full"); - tracing_stop_reason = "tfull"; - } - else if (expr_eval_result != expr_eval_no_error) - { - trace_debug ("Stopping the trace because of an expression eval error"); - tracing_stop_reason = eval_result_names[expr_eval_result]; - tracing_stop_tpnum = error_tracepoint->number; - } -#ifndef IN_PROCESS_AGENT - else if (!gdb_connected ()) - { - trace_debug ("Stopping the trace because GDB disconnected"); - tracing_stop_reason = "tdisconnected"; - } -#endif - else - { - trace_debug ("Stopping the trace because of a tstop command"); - tracing_stop_reason = "tstop"; - } - - stopping_tracepoint = NULL; - error_tracepoint = NULL; - - /* Clear out the tracepoints. */ - clear_installed_tracepoints (); - - if (agent_loaded_p ()) - { - /* Pull in fast tracepoint trace frames from the inferior lib - buffer into our buffer, even if our buffer is already full, - because we want to present the full number of created frames - in addition to what fit in the trace buffer. */ - upload_fast_traceframes (); - } - - if (stop_tracing_bkpt != NULL) - { - delete_breakpoint (stop_tracing_bkpt); - stop_tracing_bkpt = NULL; - } - - if (flush_trace_buffer_bkpt != NULL) - { - delete_breakpoint (flush_trace_buffer_bkpt); - flush_trace_buffer_bkpt = NULL; - } - - unpause_all (1); -} - -static int -stop_tracing_handler (CORE_ADDR addr) -{ - trace_debug ("lib hit stop_tracing"); - - /* Don't actually handle it here. When we stop tracing we remove - breakpoints from the inferior, and that is not allowed in a - breakpoint handler (as the caller is walking the breakpoint - list). */ - return 0; -} - -static int -flush_trace_buffer_handler (CORE_ADDR addr) -{ - trace_debug ("lib hit flush_trace_buffer"); - return 0; -} - -static void -cmd_qtstop (char *packet) -{ - stop_tracing (); - write_ok (packet); -} - -static void -cmd_qtdisconnected (char *own_buf) -{ - ULONGEST setting; - char *packet = own_buf; - - packet += strlen ("QTDisconnected:"); - - unpack_varlen_hex (packet, &setting); - - write_ok (own_buf); - - disconnected_tracing = setting; -} - -static void -cmd_qtframe (char *own_buf) -{ - client_state &cs = get_client_state (); - ULONGEST frame, pc, lo, hi, num; - int tfnum, tpnum; - struct traceframe *tframe; - const char *packet = own_buf; - - packet += strlen ("QTFrame:"); - - if (startswith (packet, "pc:")) - { - packet += strlen ("pc:"); - unpack_varlen_hex (packet, &pc); - trace_debug ("Want to find next traceframe at pc=0x%s", paddress (pc)); - tframe = find_next_traceframe_in_range (pc, pc, 1, &tfnum); - } - else if (startswith (packet, "range:")) - { - packet += strlen ("range:"); - packet = unpack_varlen_hex (packet, &lo); - ++packet; - unpack_varlen_hex (packet, &hi); - trace_debug ("Want to find next traceframe in the range 0x%s to 0x%s", - paddress (lo), paddress (hi)); - tframe = find_next_traceframe_in_range (lo, hi, 1, &tfnum); - } - else if (startswith (packet, "outside:")) - { - packet += strlen ("outside:"); - packet = unpack_varlen_hex (packet, &lo); - ++packet; - unpack_varlen_hex (packet, &hi); - trace_debug ("Want to find next traceframe " - "outside the range 0x%s to 0x%s", - paddress (lo), paddress (hi)); - tframe = find_next_traceframe_in_range (lo, hi, 0, &tfnum); - } - else if (startswith (packet, "tdp:")) - { - packet += strlen ("tdp:"); - unpack_varlen_hex (packet, &num); - tpnum = (int) num; - trace_debug ("Want to find next traceframe for tracepoint %d", tpnum); - tframe = find_next_traceframe_by_tracepoint (tpnum, &tfnum); - } - else - { - unpack_varlen_hex (packet, &frame); - tfnum = (int) frame; - if (tfnum == -1) - { - trace_debug ("Want to stop looking at traceframes"); - cs.current_traceframe = -1; - write_ok (own_buf); - return; - } - trace_debug ("Want to look at traceframe %d", tfnum); - tframe = find_traceframe (tfnum); - } - - if (tframe) - { - cs.current_traceframe = tfnum; - sprintf (own_buf, "F%xT%x", tfnum, tframe->tpnum); - } - else - sprintf (own_buf, "F-1"); -} - -static void -cmd_qtstatus (char *packet) -{ - char *stop_reason_rsp = NULL; - char *buf1, *buf2, *buf3; - const char *str; - int slen; - - /* Translate the plain text of the notes back into hex for - transmission. */ - - str = (tracing_user_name ? tracing_user_name : ""); - slen = strlen (str); - buf1 = (char *) alloca (slen * 2 + 1); - bin2hex ((gdb_byte *) str, buf1, slen); - - str = (tracing_notes ? tracing_notes : ""); - slen = strlen (str); - buf2 = (char *) alloca (slen * 2 + 1); - bin2hex ((gdb_byte *) str, buf2, slen); - - str = (tracing_stop_note ? tracing_stop_note : ""); - slen = strlen (str); - buf3 = (char *) alloca (slen * 2 + 1); - bin2hex ((gdb_byte *) str, buf3, slen); - - trace_debug ("Returning trace status as %d, stop reason %s", - tracing, tracing_stop_reason); - - if (agent_loaded_p ()) - { - pause_all (1); - - upload_fast_traceframes (); - - unpause_all (1); - } - - stop_reason_rsp = (char *) tracing_stop_reason; - - /* The user visible error string in terror needs to be hex encoded. - We leave it as plain string in `tracing_stop_reason' to ease - debugging. */ - if (startswith (stop_reason_rsp, "terror:")) - { - const char *result_name; - int hexstr_len; - char *p; - - result_name = stop_reason_rsp + strlen ("terror:"); - hexstr_len = strlen (result_name) * 2; - p = stop_reason_rsp - = (char *) alloca (strlen ("terror:") + hexstr_len + 1); - strcpy (p, "terror:"); - p += strlen (p); - bin2hex ((gdb_byte *) result_name, p, strlen (result_name)); - } - - /* If this was a forced stop, include any stop note that was supplied. */ - if (strcmp (stop_reason_rsp, "tstop") == 0) - { - stop_reason_rsp = (char *) alloca (strlen ("tstop:") + strlen (buf3) + 1); - strcpy (stop_reason_rsp, "tstop:"); - strcat (stop_reason_rsp, buf3); - } - - sprintf (packet, - "T%d;" - "%s:%x;" - "tframes:%x;tcreated:%x;" - "tfree:%x;tsize:%s;" - "circular:%d;" - "disconn:%d;" - "starttime:%s;stoptime:%s;" - "username:%s;notes:%s:", - tracing ? 1 : 0, - stop_reason_rsp, tracing_stop_tpnum, - traceframe_count, traceframes_created, - free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0), - circular_trace_buffer, - disconnected_tracing, - phex_nz (tracing_start_time, sizeof (tracing_start_time)), - phex_nz (tracing_stop_time, sizeof (tracing_stop_time)), - buf1, buf2); -} - -static void -cmd_qtp (char *own_buf) -{ - ULONGEST num, addr; - struct tracepoint *tpoint; - const char *packet = own_buf; - - packet += strlen ("qTP:"); - - packet = unpack_varlen_hex (packet, &num); - ++packet; /* skip a colon */ - packet = unpack_varlen_hex (packet, &addr); - - /* See if we already have this tracepoint. */ - tpoint = find_tracepoint (num, addr); - - if (!tpoint) - { - trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", - (int) num, paddress (addr)); - write_enn (own_buf); - return; - } - - sprintf (own_buf, "V%" PRIu64 ":%" PRIu64 "", tpoint->hit_count, - tpoint->traceframe_usage); -} - -/* State variables to help return all the tracepoint bits. */ -static struct tracepoint *cur_tpoint; -static unsigned int cur_action; -static unsigned int cur_step_action; -static struct source_string *cur_source_string; -static struct trace_state_variable *cur_tsv; - -/* Compose a response that is an imitation of the syntax by which the - tracepoint was originally downloaded. */ - -static void -response_tracepoint (char *packet, struct tracepoint *tpoint) -{ - char *buf; - - sprintf (packet, "T%x:%s:%c:%" PRIx64 ":%" PRIx64, tpoint->number, - paddress (tpoint->address), - (tpoint->enabled ? 'E' : 'D'), tpoint->step_count, - tpoint->pass_count); - if (tpoint->type == fast_tracepoint) - sprintf (packet + strlen (packet), ":F%x", tpoint->orig_size); - else if (tpoint->type == static_tracepoint) - sprintf (packet + strlen (packet), ":S"); - - if (tpoint->cond) - { - buf = gdb_unparse_agent_expr (tpoint->cond); - sprintf (packet + strlen (packet), ":X%x,%s", - tpoint->cond->length, buf); - free (buf); - } -} - -/* Compose a response that is an imitation of the syntax by which the - tracepoint action was originally downloaded (with the difference - that due to the way we store the actions, this will output a packet - per action, while GDB could have combined more than one action - per-packet. */ - -static void -response_action (char *packet, struct tracepoint *tpoint, - char *taction, int step) -{ - sprintf (packet, "%c%x:%s:%s", - (step ? 'S' : 'A'), tpoint->number, paddress (tpoint->address), - taction); -} - -/* Compose a response that is an imitation of the syntax by which the - tracepoint source piece was originally downloaded. */ - -static void -response_source (char *packet, - struct tracepoint *tpoint, struct source_string *src) -{ - char *buf; - int len; - - len = strlen (src->str); - buf = (char *) alloca (len * 2 + 1); - bin2hex ((gdb_byte *) src->str, buf, len); - - sprintf (packet, "Z%x:%s:%s:%x:%x:%s", - tpoint->number, paddress (tpoint->address), - src->type, 0, len, buf); -} - -/* Return the first piece of tracepoint definition, and initialize the - state machine that will iterate through all the tracepoint - bits. */ - -static void -cmd_qtfp (char *packet) -{ - trace_debug ("Returning first tracepoint definition piece"); - - cur_tpoint = tracepoints; - cur_action = cur_step_action = 0; - cur_source_string = NULL; - - if (cur_tpoint) - response_tracepoint (packet, cur_tpoint); - else - strcpy (packet, "l"); -} - -/* Return additional pieces of tracepoint definition. Each action and - stepping action must go into its own packet, because of packet size - limits, and so we use state variables to deliver one piece at a - time. */ - -static void -cmd_qtsp (char *packet) -{ - trace_debug ("Returning subsequent tracepoint definition piece"); - - if (!cur_tpoint) - { - /* This case would normally never occur, but be prepared for - GDB misbehavior. */ - strcpy (packet, "l"); - } - else if (cur_action < cur_tpoint->numactions) - { - response_action (packet, cur_tpoint, - cur_tpoint->actions_str[cur_action], 0); - ++cur_action; - } - else if (cur_step_action < cur_tpoint->num_step_actions) - { - response_action (packet, cur_tpoint, - cur_tpoint->step_actions_str[cur_step_action], 1); - ++cur_step_action; - } - else if ((cur_source_string - ? cur_source_string->next - : cur_tpoint->source_strings)) - { - if (cur_source_string) - cur_source_string = cur_source_string->next; - else - cur_source_string = cur_tpoint->source_strings; - response_source (packet, cur_tpoint, cur_source_string); - } - else - { - cur_tpoint = cur_tpoint->next; - cur_action = cur_step_action = 0; - cur_source_string = NULL; - if (cur_tpoint) - response_tracepoint (packet, cur_tpoint); - else - strcpy (packet, "l"); - } -} - -/* Compose a response that is an imitation of the syntax by which the - trace state variable was originally downloaded. */ - -static void -response_tsv (char *packet, struct trace_state_variable *tsv) -{ - char *buf = (char *) ""; - int namelen; - - if (tsv->name) - { - namelen = strlen (tsv->name); - buf = (char *) alloca (namelen * 2 + 1); - bin2hex ((gdb_byte *) tsv->name, buf, namelen); - } - - sprintf (packet, "%x:%s:%x:%s", tsv->number, phex_nz (tsv->initial_value, 0), - tsv->getter ? 1 : 0, buf); -} - -/* Return the first trace state variable definition, and initialize - the state machine that will iterate through all the tsv bits. */ - -static void -cmd_qtfv (char *packet) -{ - trace_debug ("Returning first trace state variable definition"); - - cur_tsv = trace_state_variables; - - if (cur_tsv) - response_tsv (packet, cur_tsv); - else - strcpy (packet, "l"); -} - -/* Return additional trace state variable definitions. */ - -static void -cmd_qtsv (char *packet) -{ - trace_debug ("Returning additional trace state variable definition"); - - if (cur_tsv) - { - cur_tsv = cur_tsv->next; - if (cur_tsv) - response_tsv (packet, cur_tsv); - else - strcpy (packet, "l"); - } - else - strcpy (packet, "l"); -} - -/* Return the first static tracepoint marker, and initialize the state - machine that will iterate through all the static tracepoints - markers. */ - -static void -cmd_qtfstm (char *packet) -{ - if (!maybe_write_ipa_ust_not_loaded (packet)) - run_inferior_command (packet, strlen (packet) + 1); -} - -/* Return additional static tracepoints markers. */ - -static void -cmd_qtsstm (char *packet) -{ - if (!maybe_write_ipa_ust_not_loaded (packet)) - run_inferior_command (packet, strlen (packet) + 1); -} - -/* Return the definition of the static tracepoint at a given address. - Result packet is the same as qTsST's. */ - -static void -cmd_qtstmat (char *packet) -{ - if (!maybe_write_ipa_ust_not_loaded (packet)) - run_inferior_command (packet, strlen (packet) + 1); -} - -/* Sent the agent a command to close it. */ - -void -gdb_agent_about_to_close (int pid) -{ - char buf[IPA_CMD_BUF_SIZE]; - - if (!maybe_write_ipa_not_loaded (buf)) - { - struct thread_info *saved_thread; - - saved_thread = current_thread; - - /* Find any thread which belongs to process PID. */ - current_thread = find_any_thread_of_pid (pid); - - strcpy (buf, "close"); - - run_inferior_command (buf, strlen (buf) + 1); - - current_thread = saved_thread; - } -} - -/* Return the minimum instruction size needed for fast tracepoints as a - hexadecimal number. */ - -static void -cmd_qtminftpilen (char *packet) -{ - if (current_thread == NULL) - { - /* Indicate that the minimum length is currently unknown. */ - strcpy (packet, "0"); - return; - } - - sprintf (packet, "%x", target_get_min_fast_tracepoint_insn_len ()); -} - -/* Respond to qTBuffer packet with a block of raw data from the trace - buffer. GDB may ask for a lot, but we are allowed to reply with - only as much as will fit within packet limits or whatever. */ - -static void -cmd_qtbuffer (char *own_buf) -{ - ULONGEST offset, num, tot; - unsigned char *tbp; - const char *packet = own_buf; - - packet += strlen ("qTBuffer:"); - - packet = unpack_varlen_hex (packet, &offset); - ++packet; /* skip a comma */ - unpack_varlen_hex (packet, &num); - - trace_debug ("Want to get trace buffer, %d bytes at offset 0x%s", - (int) num, phex_nz (offset, 0)); - - tot = (trace_buffer_hi - trace_buffer_lo) - free_space (); - - /* If we're right at the end, reply specially that we're done. */ - if (offset == tot) - { - strcpy (own_buf, "l"); - return; - } - - /* Object to any other out-of-bounds request. */ - if (offset > tot) - { - write_enn (own_buf); - return; - } - - /* Compute the pointer corresponding to the given offset, accounting - for wraparound. */ - tbp = trace_buffer_start + offset; - if (tbp >= trace_buffer_wrap) - tbp -= (trace_buffer_wrap - trace_buffer_lo); - - /* Trim to the remaining bytes if we're close to the end. */ - if (num > tot - offset) - num = tot - offset; - - /* Trim to available packet size. */ - if (num >= (PBUFSIZ - 16) / 2 ) - num = (PBUFSIZ - 16) / 2; - - bin2hex (tbp, own_buf, num); -} - -static void -cmd_bigqtbuffer_circular (char *own_buf) -{ - ULONGEST val; - char *packet = own_buf; - - packet += strlen ("QTBuffer:circular:"); - - unpack_varlen_hex (packet, &val); - circular_trace_buffer = val; - trace_debug ("Trace buffer is now %s", - circular_trace_buffer ? "circular" : "linear"); - write_ok (own_buf); -} - -static void -cmd_bigqtbuffer_size (char *own_buf) -{ - ULONGEST val; - LONGEST sval; - char *packet = own_buf; - - /* Can't change the size during a tracing run. */ - if (tracing) - { - write_enn (own_buf); - return; - } - - packet += strlen ("QTBuffer:size:"); - - /* -1 is sent as literal "-1". */ - if (strcmp (packet, "-1") == 0) - sval = DEFAULT_TRACE_BUFFER_SIZE; - else - { - unpack_varlen_hex (packet, &val); - sval = (LONGEST) val; - } - - init_trace_buffer (sval); - trace_debug ("Trace buffer is now %s bytes", - plongest (trace_buffer_size)); - write_ok (own_buf); -} - -static void -cmd_qtnotes (char *own_buf) -{ - size_t nbytes; - char *saved, *user, *notes, *stopnote; - char *packet = own_buf; - - packet += strlen ("QTNotes:"); - - while (*packet) - { - if (startswith (packet, "user:")) - { - packet += strlen ("user:"); - saved = packet; - packet = strchr (packet, ';'); - nbytes = (packet - saved) / 2; - user = (char *) xmalloc (nbytes + 1); - nbytes = hex2bin (saved, (gdb_byte *) user, nbytes); - user[nbytes] = '\0'; - ++packet; /* skip the semicolon */ - trace_debug ("User is '%s'", user); - xfree (tracing_user_name); - tracing_user_name = user; - } - else if (startswith (packet, "notes:")) - { - packet += strlen ("notes:"); - saved = packet; - packet = strchr (packet, ';'); - nbytes = (packet - saved) / 2; - notes = (char *) xmalloc (nbytes + 1); - nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes); - notes[nbytes] = '\0'; - ++packet; /* skip the semicolon */ - trace_debug ("Notes is '%s'", notes); - xfree (tracing_notes); - tracing_notes = notes; - } - else if (startswith (packet, "tstop:")) - { - packet += strlen ("tstop:"); - saved = packet; - packet = strchr (packet, ';'); - nbytes = (packet - saved) / 2; - stopnote = (char *) xmalloc (nbytes + 1); - nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes); - stopnote[nbytes] = '\0'; - ++packet; /* skip the semicolon */ - trace_debug ("tstop note is '%s'", stopnote); - xfree (tracing_stop_note); - tracing_stop_note = stopnote; - } - else - break; - } - - write_ok (own_buf); -} - -int -handle_tracepoint_general_set (char *packet) -{ - if (strcmp ("QTinit", packet) == 0) - { - cmd_qtinit (packet); - return 1; - } - else if (startswith (packet, "QTDP:")) - { - cmd_qtdp (packet); - return 1; - } - else if (startswith (packet, "QTDPsrc:")) - { - cmd_qtdpsrc (packet); - return 1; - } - else if (startswith (packet, "QTEnable:")) - { - cmd_qtenable_disable (packet, 1); - return 1; - } - else if (startswith (packet, "QTDisable:")) - { - cmd_qtenable_disable (packet, 0); - return 1; - } - else if (startswith (packet, "QTDV:")) - { - cmd_qtdv (packet); - return 1; - } - else if (startswith (packet, "QTro:")) - { - cmd_qtro (packet); - return 1; - } - else if (strcmp ("QTStart", packet) == 0) - { - cmd_qtstart (packet); - return 1; - } - else if (strcmp ("QTStop", packet) == 0) - { - cmd_qtstop (packet); - return 1; - } - else if (startswith (packet, "QTDisconnected:")) - { - cmd_qtdisconnected (packet); - return 1; - } - else if (startswith (packet, "QTFrame:")) - { - cmd_qtframe (packet); - return 1; - } - else if (startswith (packet, "QTBuffer:circular:")) - { - cmd_bigqtbuffer_circular (packet); - return 1; - } - else if (startswith (packet, "QTBuffer:size:")) - { - cmd_bigqtbuffer_size (packet); - return 1; - } - else if (startswith (packet, "QTNotes:")) - { - cmd_qtnotes (packet); - return 1; - } - - return 0; -} - -int -handle_tracepoint_query (char *packet) -{ - if (strcmp ("qTStatus", packet) == 0) - { - cmd_qtstatus (packet); - return 1; - } - else if (startswith (packet, "qTP:")) - { - cmd_qtp (packet); - return 1; - } - else if (strcmp ("qTfP", packet) == 0) - { - cmd_qtfp (packet); - return 1; - } - else if (strcmp ("qTsP", packet) == 0) - { - cmd_qtsp (packet); - return 1; - } - else if (strcmp ("qTfV", packet) == 0) - { - cmd_qtfv (packet); - return 1; - } - else if (strcmp ("qTsV", packet) == 0) - { - cmd_qtsv (packet); - return 1; - } - else if (startswith (packet, "qTV:")) - { - cmd_qtv (packet); - return 1; - } - else if (startswith (packet, "qTBuffer:")) - { - cmd_qtbuffer (packet); - return 1; - } - else if (strcmp ("qTfSTM", packet) == 0) - { - cmd_qtfstm (packet); - return 1; - } - else if (strcmp ("qTsSTM", packet) == 0) - { - cmd_qtsstm (packet); - return 1; - } - else if (startswith (packet, "qTSTMat:")) - { - cmd_qtstmat (packet); - return 1; - } - else if (strcmp ("qTMinFTPILen", packet) == 0) - { - cmd_qtminftpilen (packet); - return 1; - } - - return 0; -} - -#endif -#ifndef IN_PROCESS_AGENT - -/* Call this when thread TINFO has hit the tracepoint defined by - TP_NUMBER and TP_ADDRESS, and that tracepoint has a while-stepping - action. This adds a while-stepping collecting state item to the - threads' collecting state list, so that we can keep track of - multiple simultaneous while-stepping actions being collected by the - same thread. This can happen in cases like: - - ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs - ff0002 INSN2 - ff0003 INSN3 <-- TP2, collect $regs - ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs - ff0005 INSN5 - - Notice that when instruction INSN5 is reached, the while-stepping - actions of both TP1 and TP3 are still being collected, and that TP2 - had been collected meanwhile. The whole range of ff0001-ff0005 - should be single-stepped, due to at least TP1's while-stepping - action covering the whole range. */ - -static void -add_while_stepping_state (struct thread_info *tinfo, - int tp_number, CORE_ADDR tp_address) -{ - struct wstep_state *wstep = XNEW (struct wstep_state); - - wstep->next = tinfo->while_stepping; - - wstep->tp_number = tp_number; - wstep->tp_address = tp_address; - wstep->current_step = 0; - - tinfo->while_stepping = wstep; -} - -/* Release the while-stepping collecting state WSTEP. */ - -static void -release_while_stepping_state (struct wstep_state *wstep) -{ - free (wstep); -} - -/* Release all while-stepping collecting states currently associated - with thread TINFO. */ - -void -release_while_stepping_state_list (struct thread_info *tinfo) -{ - struct wstep_state *head; - - while (tinfo->while_stepping) - { - head = tinfo->while_stepping; - tinfo->while_stepping = head->next; - release_while_stepping_state (head); - } -} - -/* If TINFO was handling a 'while-stepping' action, the step has - finished, so collect any step data needed, and check if any more - steps are required. Return true if the thread was indeed - collecting tracepoint data, false otherwise. */ - -int -tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc) -{ - struct tracepoint *tpoint; - struct wstep_state *wstep; - struct wstep_state **wstep_link; - struct trap_tracepoint_ctx ctx; - - /* Pull in fast tracepoint trace frames from the inferior lib buffer into - our buffer. */ - if (agent_loaded_p ()) - upload_fast_traceframes (); - - /* Check if we were indeed collecting data for one of more - tracepoints with a 'while-stepping' count. */ - if (tinfo->while_stepping == NULL) - return 0; - - if (!tracing) - { - /* We're not even tracing anymore. Stop this thread from - collecting. */ - release_while_stepping_state_list (tinfo); - - /* The thread had stopped due to a single-step request indeed - explained by a tracepoint. */ - return 1; - } - - wstep = tinfo->while_stepping; - wstep_link = &tinfo->while_stepping; - - trace_debug ("Thread %s finished a single-step for tracepoint %d at 0x%s", - target_pid_to_str (tinfo->id), - wstep->tp_number, paddress (wstep->tp_address)); - - ctx.base.type = trap_tracepoint; - ctx.regcache = get_thread_regcache (tinfo, 1); - - while (wstep != NULL) - { - tpoint = find_tracepoint (wstep->tp_number, wstep->tp_address); - if (tpoint == NULL) - { - trace_debug ("NO TRACEPOINT %d at 0x%s FOR THREAD %s!", - wstep->tp_number, paddress (wstep->tp_address), - target_pid_to_str (tinfo->id)); - - /* Unlink. */ - *wstep_link = wstep->next; - release_while_stepping_state (wstep); - wstep = *wstep_link; - continue; - } - - /* We've just finished one step. */ - ++wstep->current_step; - - /* Collect data. */ - collect_data_at_step ((struct tracepoint_hit_ctx *) &ctx, - stop_pc, tpoint, wstep->current_step); - - if (wstep->current_step >= tpoint->step_count) - { - /* The requested numbers of steps have occurred. */ - trace_debug ("Thread %s done stepping for tracepoint %d at 0x%s", - target_pid_to_str (tinfo->id), - wstep->tp_number, paddress (wstep->tp_address)); - - /* Unlink the wstep. */ - *wstep_link = wstep->next; - release_while_stepping_state (wstep); - wstep = *wstep_link; - - /* Only check the hit count now, which ensure that we do all - our stepping before stopping the run. */ - if (tpoint->pass_count > 0 - && tpoint->hit_count >= tpoint->pass_count - && stopping_tracepoint == NULL) - stopping_tracepoint = tpoint; - } - else - { - /* Keep single-stepping until the requested numbers of steps - have occurred. */ - wstep_link = &wstep->next; - wstep = *wstep_link; - } - - if (stopping_tracepoint - || trace_buffer_is_full - || expr_eval_result != expr_eval_no_error) - { - stop_tracing (); - break; - } - } - - return 1; -} - -/* Handle any internal tracing control breakpoint hits. That means, - pull traceframes from the IPA to our buffer, and syncing both - tracing agents when the IPA's tracing stops for some reason. */ - -int -handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc) -{ - /* Pull in fast tracepoint trace frames from the inferior in-process - agent's buffer into our buffer. */ - - if (!agent_loaded_p ()) - return 0; - - upload_fast_traceframes (); - - /* Check if the in-process agent had decided we should stop - tracing. */ - if (stop_pc == ipa_sym_addrs.addr_stop_tracing) - { - int ipa_trace_buffer_is_full; - CORE_ADDR ipa_stopping_tracepoint; - int ipa_expr_eval_result; - CORE_ADDR ipa_error_tracepoint; - - trace_debug ("lib stopped at stop_tracing"); - - read_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full, - &ipa_trace_buffer_is_full); - - read_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, - &ipa_stopping_tracepoint); - write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, 0); - - read_inferior_data_pointer (ipa_sym_addrs.addr_error_tracepoint, - &ipa_error_tracepoint); - write_inferior_data_pointer (ipa_sym_addrs.addr_error_tracepoint, 0); - - read_inferior_integer (ipa_sym_addrs.addr_expr_eval_result, - &ipa_expr_eval_result); - write_inferior_integer (ipa_sym_addrs.addr_expr_eval_result, 0); - - trace_debug ("lib: trace_buffer_is_full: %d, " - "stopping_tracepoint: %s, " - "ipa_expr_eval_result: %d, " - "error_tracepoint: %s, ", - ipa_trace_buffer_is_full, - paddress (ipa_stopping_tracepoint), - ipa_expr_eval_result, - paddress (ipa_error_tracepoint)); - - if (debug_threads) - { - if (ipa_trace_buffer_is_full) - trace_debug ("lib stopped due to full buffer."); - if (ipa_stopping_tracepoint) - trace_debug ("lib stopped due to tpoint"); - if (ipa_error_tracepoint) - trace_debug ("lib stopped due to error"); - } - - if (ipa_stopping_tracepoint != 0) - { - stopping_tracepoint - = fast_tracepoint_from_ipa_tpoint_address (ipa_stopping_tracepoint); - } - else if (ipa_expr_eval_result != expr_eval_no_error) - { - expr_eval_result = ipa_expr_eval_result; - error_tracepoint - = fast_tracepoint_from_ipa_tpoint_address (ipa_error_tracepoint); - } - stop_tracing (); - return 1; - } - else if (stop_pc == ipa_sym_addrs.addr_flush_trace_buffer) - { - trace_debug ("lib stopped at flush_trace_buffer"); - return 1; - } - - return 0; -} - -/* Return true if TINFO just hit a tracepoint. Collect data if - so. */ - -int -tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc) -{ - struct tracepoint *tpoint; - int ret = 0; - struct trap_tracepoint_ctx ctx; - - /* Not tracing, don't handle. */ - if (!tracing) - return 0; - - ctx.base.type = trap_tracepoint; - ctx.regcache = get_thread_regcache (tinfo, 1); - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - { - /* Note that we collect fast tracepoints here as well. We'll - step over the fast tracepoint jump later, which avoids the - double collect. However, we don't collect for static - tracepoints here, because UST markers are compiled in program, - and probes will be executed in program. So static tracepoints - are collected there. */ - if (tpoint->enabled && stop_pc == tpoint->address - && tpoint->type != static_tracepoint) - { - trace_debug ("Thread %s at address of tracepoint %d at 0x%s", - target_pid_to_str (tinfo->id), - tpoint->number, paddress (tpoint->address)); - - /* Test the condition if present, and collect if true. */ - if (!tpoint->cond - || (condition_true_at_tracepoint - ((struct tracepoint_hit_ctx *) &ctx, tpoint))) - collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, - stop_pc, tpoint); - - if (stopping_tracepoint - || trace_buffer_is_full - || expr_eval_result != expr_eval_no_error) - { - stop_tracing (); - } - /* If the tracepoint had a 'while-stepping' action, then set - the thread to collect this tracepoint on the following - single-steps. */ - else if (tpoint->step_count > 0) - { - add_while_stepping_state (tinfo, - tpoint->number, tpoint->address); - } - - ret = 1; - } - } - - return ret; -} - -#endif - -#if defined IN_PROCESS_AGENT && defined HAVE_UST -struct ust_marker_data; -static void collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, - struct traceframe *tframe); -#endif - -/* Create a trace frame for the hit of the given tracepoint in the - given thread. */ - -static void -collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, CORE_ADDR stop_pc, - struct tracepoint *tpoint) -{ - struct traceframe *tframe; - int acti; - - /* Only count it as a hit when we actually collect data. */ - tpoint->hit_count++; - - /* If we've exceeded a defined pass count, record the event for - later, and finish the collection for this hit. This test is only - for nonstepping tracepoints, stepping tracepoints test at the end - of their while-stepping loop. */ - if (tpoint->pass_count > 0 - && tpoint->hit_count >= tpoint->pass_count - && tpoint->step_count == 0 - && stopping_tracepoint == NULL) - stopping_tracepoint = tpoint; - - trace_debug ("Making new traceframe for tracepoint %d at 0x%s, hit %" PRIu64, - tpoint->number, paddress (tpoint->address), tpoint->hit_count); - - tframe = add_traceframe (tpoint); - - if (tframe) - { - for (acti = 0; acti < tpoint->numactions; ++acti) - { -#ifndef IN_PROCESS_AGENT - trace_debug ("Tracepoint %d at 0x%s about to do action '%s'", - tpoint->number, paddress (tpoint->address), - tpoint->actions_str[acti]); -#endif - - do_action_at_tracepoint (ctx, stop_pc, tpoint, tframe, - tpoint->actions[acti]); - } - - finish_traceframe (tframe); - } - - if (tframe == NULL && tracing) - trace_buffer_is_full = 1; -} - -#ifndef IN_PROCESS_AGENT - -static void -collect_data_at_step (struct tracepoint_hit_ctx *ctx, - CORE_ADDR stop_pc, - struct tracepoint *tpoint, int current_step) -{ - struct traceframe *tframe; - int acti; - - trace_debug ("Making new step traceframe for " - "tracepoint %d at 0x%s, step %d of %" PRIu64 ", hit %" PRIu64, - tpoint->number, paddress (tpoint->address), - current_step, tpoint->step_count, - tpoint->hit_count); - - tframe = add_traceframe (tpoint); - - if (tframe) - { - for (acti = 0; acti < tpoint->num_step_actions; ++acti) - { - trace_debug ("Tracepoint %d at 0x%s about to do step action '%s'", - tpoint->number, paddress (tpoint->address), - tpoint->step_actions_str[acti]); - - do_action_at_tracepoint (ctx, stop_pc, tpoint, tframe, - tpoint->step_actions[acti]); - } - - finish_traceframe (tframe); - } - - if (tframe == NULL && tracing) - trace_buffer_is_full = 1; -} - -#endif - -#ifdef IN_PROCESS_AGENT -/* The target description index for IPA. Passed from gdbserver, used - to select ipa_tdesc. */ -EXTERN_C_PUSH -IP_AGENT_EXPORT_VAR int ipa_tdesc_idx; -EXTERN_C_POP -#endif - -static struct regcache * -get_context_regcache (struct tracepoint_hit_ctx *ctx) -{ - struct regcache *regcache = NULL; -#ifdef IN_PROCESS_AGENT - const struct target_desc *ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx); - - if (ctx->type == fast_tracepoint) - { - struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx; - if (!fctx->regcache_initted) - { - fctx->regcache_initted = 1; - init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace); - supply_regblock (&fctx->regcache, NULL); - supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs); - } - regcache = &fctx->regcache; - } -#ifdef HAVE_UST - if (ctx->type == static_tracepoint) - { - struct static_tracepoint_ctx *sctx - = (struct static_tracepoint_ctx *) ctx; - - if (!sctx->regcache_initted) - { - sctx->regcache_initted = 1; - init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace); - supply_regblock (&sctx->regcache, NULL); - /* Pass down the tracepoint address, because REGS doesn't - include the PC, but we know what it must have been. */ - supply_static_tracepoint_registers (&sctx->regcache, - (const unsigned char *) - sctx->regs, - sctx->tpoint->address); - } - regcache = &sctx->regcache; - } -#endif -#else - if (ctx->type == trap_tracepoint) - { - struct trap_tracepoint_ctx *tctx = (struct trap_tracepoint_ctx *) ctx; - regcache = tctx->regcache; - } -#endif - - gdb_assert (regcache != NULL); - - return regcache; -} - -static void -do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, - CORE_ADDR stop_pc, - struct tracepoint *tpoint, - struct traceframe *tframe, - struct tracepoint_action *taction) -{ - enum eval_result_type err; - - switch (taction->type) - { - case 'M': - { - struct collect_memory_action *maction; - struct eval_agent_expr_context ax_ctx; - - maction = (struct collect_memory_action *) taction; - ax_ctx.regcache = NULL; - ax_ctx.tframe = tframe; - ax_ctx.tpoint = tpoint; - - trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)", - pulongest (maction->len), - paddress (maction->addr), maction->basereg); - /* (should use basereg) */ - agent_mem_read (&ax_ctx, NULL, (CORE_ADDR) maction->addr, - maction->len); - break; - } - case 'R': - { - unsigned char *regspace; - struct regcache tregcache; - struct regcache *context_regcache; - int regcache_size; - - trace_debug ("Want to collect registers"); - - context_regcache = get_context_regcache (ctx); - regcache_size = register_cache_size (context_regcache->tdesc); - - /* Collect all registers for now. */ - regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size); - if (regspace == NULL) - { - trace_debug ("Trace buffer block allocation failed, skipping"); - break; - } - /* Identify a register block. */ - *regspace = 'R'; - - /* Wrap the regblock in a register cache (in the stack, we - don't want to malloc here). */ - init_register_cache (&tregcache, context_regcache->tdesc, - regspace + 1); - - /* Copy the register data to the regblock. */ - regcache_cpy (&tregcache, context_regcache); - -#ifndef IN_PROCESS_AGENT - /* On some platforms, trap-based tracepoints will have the PC - pointing to the next instruction after the trap, but we - don't want the user or GDB trying to guess whether the - saved PC needs adjusting; so always record the adjusted - stop_pc. Note that we can't use tpoint->address instead, - since it will be wrong for while-stepping actions. This - adjustment is a nop for fast tracepoints collected from the - in-process lib (but not if GDBserver is collecting one - preemptively), since the PC had already been adjusted to - contain the tracepoint's address by the jump pad. */ - trace_debug ("Storing stop pc (0x%s) in regblock", - paddress (stop_pc)); - - /* This changes the regblock, not the thread's - regcache. */ - regcache_write_pc (&tregcache, stop_pc); -#endif - } - break; - case 'X': - { - struct eval_expr_action *eaction; - struct eval_agent_expr_context ax_ctx; - - eaction = (struct eval_expr_action *) taction; - ax_ctx.regcache = get_context_regcache (ctx); - ax_ctx.tframe = tframe; - ax_ctx.tpoint = tpoint; - - trace_debug ("Want to evaluate expression"); - - err = gdb_eval_agent_expr (&ax_ctx, eaction->expr, NULL); - - if (err != expr_eval_no_error) - { - record_tracepoint_error (tpoint, "action expression", err); - return; - } - } - break; - case 'L': - { -#if defined IN_PROCESS_AGENT && defined HAVE_UST - trace_debug ("Want to collect static trace data"); - collect_ust_data_at_tracepoint (ctx, tframe); -#else - trace_debug ("warning: collecting static trace data, " - "but static tracepoints are not supported"); -#endif - } - break; - default: - trace_debug ("unknown trace action '%c', ignoring", taction->type); - break; - } -} - -static int -condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx, - struct tracepoint *tpoint) -{ - ULONGEST value = 0; - enum eval_result_type err; - - /* Presently, gdbserver doesn't run compiled conditions, only the - IPA does. If the program stops at a fast tracepoint's address - (e.g., due to a breakpoint, trap tracepoint, or stepping), - gdbserver preemptively collect the fast tracepoint. Later, on - resume, gdbserver steps over the fast tracepoint like it steps - over breakpoints, so that the IPA doesn't see that fast - tracepoint. This avoids double collects of fast tracepoints in - that stopping scenario. Having gdbserver itself handle the fast - tracepoint gives the user a consistent view of when fast or trap - tracepoints are collected, compared to an alternative where only - trap tracepoints are collected on stop, and fast tracepoints on - resume. When a fast tracepoint is being processed by gdbserver, - it is always the non-compiled condition expression that is - used. */ -#ifdef IN_PROCESS_AGENT - if (tpoint->compiled_cond) - { - struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx; - err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (fctx->regs, &value); - } - else -#endif - { - struct eval_agent_expr_context ax_ctx; - - ax_ctx.regcache = get_context_regcache (ctx); - ax_ctx.tframe = NULL; - ax_ctx.tpoint = tpoint; - - err = gdb_eval_agent_expr (&ax_ctx, tpoint->cond, &value); - } - if (err != expr_eval_no_error) - { - record_tracepoint_error (tpoint, "condition", err); - /* The error case must return false. */ - return 0; - } - - trace_debug ("Tracepoint %d at 0x%s condition evals to %s", - tpoint->number, paddress (tpoint->address), - pulongest (value)); - return (value ? 1 : 0); -} - -/* Do memory copies for bytecodes. */ -/* Do the recording of memory blocks for actions and bytecodes. */ - -int -agent_mem_read (struct eval_agent_expr_context *ctx, - unsigned char *to, CORE_ADDR from, ULONGEST len) -{ - unsigned char *mspace; - ULONGEST remaining = len; - unsigned short blocklen; - - /* If a 'to' buffer is specified, use it. */ - if (to != NULL) - { - read_inferior_memory (from, to, len); - return 0; - } - - /* Otherwise, create a new memory block in the trace buffer. */ - while (remaining > 0) - { - size_t sp; - - blocklen = (remaining > 65535 ? 65535 : remaining); - sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen; - mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp); - if (mspace == NULL) - return 1; - /* Identify block as a memory block. */ - *mspace = 'M'; - ++mspace; - /* Record address and size. */ - memcpy (mspace, &from, sizeof (from)); - mspace += sizeof (from); - memcpy (mspace, &blocklen, sizeof (blocklen)); - mspace += sizeof (blocklen); - /* Record the memory block proper. */ - read_inferior_memory (from, mspace, blocklen); - trace_debug ("%d bytes recorded", blocklen); - remaining -= blocklen; - from += blocklen; - } - return 0; -} - -int -agent_mem_read_string (struct eval_agent_expr_context *ctx, - unsigned char *to, CORE_ADDR from, ULONGEST len) -{ - unsigned char *buf, *mspace; - ULONGEST remaining = len; - unsigned short blocklen, i; - - /* To save a bit of space, block lengths are 16-bit, so break large - requests into multiple blocks. Bordering on overkill for strings, - but it could happen that someone specifies a large max length. */ - while (remaining > 0) - { - size_t sp; - - blocklen = (remaining > 65535 ? 65535 : remaining); - /* We want working space to accumulate nonzero bytes, since - traceframes must have a predecided size (otherwise it gets - harder to wrap correctly for the circular case, etc). */ - buf = (unsigned char *) xmalloc (blocklen + 1); - for (i = 0; i < blocklen; ++i) - { - /* Read the string one byte at a time, in case the string is - at the end of a valid memory area - we don't want a - correctly-terminated string to engender segvio - complaints. */ - read_inferior_memory (from + i, buf + i, 1); - - if (buf[i] == '\0') - { - blocklen = i + 1; - /* Make sure outer loop stops now too. */ - remaining = blocklen; - break; - } - } - sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen; - mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp); - if (mspace == NULL) - { - xfree (buf); - return 1; - } - /* Identify block as a memory block. */ - *mspace = 'M'; - ++mspace; - /* Record address and size. */ - memcpy ((void *) mspace, (void *) &from, sizeof (from)); - mspace += sizeof (from); - memcpy ((void *) mspace, (void *) &blocklen, sizeof (blocklen)); - mspace += sizeof (blocklen); - /* Copy the string contents. */ - memcpy ((void *) mspace, (void *) buf, blocklen); - remaining -= blocklen; - from += blocklen; - xfree (buf); - } - return 0; -} - -/* Record the value of a trace state variable. */ - -int -agent_tsv_read (struct eval_agent_expr_context *ctx, int n) -{ - unsigned char *vspace; - LONGEST val; - - vspace = add_traceframe_block (ctx->tframe, ctx->tpoint, - 1 + sizeof (n) + sizeof (LONGEST)); - if (vspace == NULL) - return 1; - /* Identify block as a variable. */ - *vspace = 'V'; - /* Record variable's number and value. */ - memcpy (vspace + 1, &n, sizeof (n)); - val = get_trace_state_variable_value (n); - memcpy (vspace + 1 + sizeof (n), &val, sizeof (val)); - trace_debug ("Variable %d recorded", n); - return 0; -} - -#ifndef IN_PROCESS_AGENT - -/* Callback for traceframe_walk_blocks, used to find a given block - type in a traceframe. */ - -static int -match_blocktype (char blocktype, unsigned char *dataptr, void *data) -{ - char *wantedp = (char *) data; - - if (*wantedp == blocktype) - return 1; - - return 0; -} - -/* Walk over all traceframe blocks of the traceframe buffer starting - at DATABASE, of DATASIZE bytes long, and call CALLBACK for each - block found, passing in DATA unmodified. If CALLBACK returns true, - this returns a pointer to where the block is found. Returns NULL - if no callback call returned true, indicating that all blocks have - been walked. */ - -static unsigned char * -traceframe_walk_blocks (unsigned char *database, unsigned int datasize, - int tfnum, - int (*callback) (char blocktype, - unsigned char *dataptr, - void *data), - void *data) -{ - unsigned char *dataptr; - - if (datasize == 0) - { - trace_debug ("traceframe %d has no data", tfnum); - return NULL; - } - - /* Iterate through a traceframe's blocks, looking for a block of the - requested type. */ - for (dataptr = database; - dataptr < database + datasize; - /* nothing */) - { - char blocktype; - unsigned short mlen; - - if (dataptr == trace_buffer_wrap) - { - /* Adjust to reflect wrapping part of the frame around to - the beginning. */ - datasize = dataptr - database; - dataptr = database = trace_buffer_lo; - } - - blocktype = *dataptr++; - - if ((*callback) (blocktype, dataptr, data)) - return dataptr; - - switch (blocktype) - { - case 'R': - /* Skip over the registers block. */ - dataptr += current_target_desc ()->registers_size; - break; - case 'M': - /* Skip over the memory block. */ - dataptr += sizeof (CORE_ADDR); - memcpy (&mlen, dataptr, sizeof (mlen)); - dataptr += (sizeof (mlen) + mlen); - break; - case 'V': - /* Skip over the TSV block. */ - dataptr += (sizeof (int) + sizeof (LONGEST)); - break; - case 'S': - /* Skip over the static trace data block. */ - memcpy (&mlen, dataptr, sizeof (mlen)); - dataptr += (sizeof (mlen) + mlen); - break; - default: - trace_debug ("traceframe %d has unknown block type 0x%x", - tfnum, blocktype); - return NULL; - } - } - - return NULL; -} - -/* Look for the block of type TYPE_WANTED in the traceframe starting - at DATABASE of DATASIZE bytes long. TFNUM is the traceframe - number. */ - -static unsigned char * -traceframe_find_block_type (unsigned char *database, unsigned int datasize, - int tfnum, char type_wanted) -{ - return traceframe_walk_blocks (database, datasize, tfnum, - match_blocktype, &type_wanted); -} - -static unsigned char * -traceframe_find_regblock (struct traceframe *tframe, int tfnum) -{ - unsigned char *regblock; - - regblock = traceframe_find_block_type (tframe->data, - tframe->data_size, - tfnum, 'R'); - - if (regblock == NULL) - trace_debug ("traceframe %d has no register data", tfnum); - - return regblock; -} - -/* Get registers from a traceframe. */ - -int -fetch_traceframe_registers (int tfnum, struct regcache *regcache, int regnum) -{ - unsigned char *dataptr; - struct tracepoint *tpoint; - struct traceframe *tframe; - - tframe = find_traceframe (tfnum); - - if (tframe == NULL) - { - trace_debug ("traceframe %d not found", tfnum); - return 1; - } - - dataptr = traceframe_find_regblock (tframe, tfnum); - if (dataptr == NULL) - { - /* Mark registers unavailable. */ - supply_regblock (regcache, NULL); - - /* We can generally guess at a PC, although this will be - misleading for while-stepping frames and multi-location - tracepoints. */ - tpoint = find_next_tracepoint_by_number (NULL, tframe->tpnum); - if (tpoint != NULL) - regcache_write_pc (regcache, tpoint->address); - } - else - supply_regblock (regcache, dataptr); - - return 0; -} - -static CORE_ADDR -traceframe_get_pc (struct traceframe *tframe) -{ - struct regcache regcache; - unsigned char *dataptr; - const struct target_desc *tdesc = current_target_desc (); - - dataptr = traceframe_find_regblock (tframe, -1); - if (dataptr == NULL) - return 0; - - init_register_cache (®cache, tdesc, dataptr); - return regcache_read_pc (®cache); -} - -/* Read a requested block of memory from a trace frame. */ - -int -traceframe_read_mem (int tfnum, CORE_ADDR addr, - unsigned char *buf, ULONGEST length, - ULONGEST *nbytes) -{ - struct traceframe *tframe; - unsigned char *database, *dataptr; - unsigned int datasize; - CORE_ADDR maddr; - unsigned short mlen; - - trace_debug ("traceframe_read_mem"); - - tframe = find_traceframe (tfnum); - - if (!tframe) - { - trace_debug ("traceframe %d not found", tfnum); - return 1; - } - - datasize = tframe->data_size; - database = dataptr = &tframe->data[0]; - - /* Iterate through a traceframe's blocks, looking for memory. */ - while ((dataptr = traceframe_find_block_type (dataptr, - datasize - - (dataptr - database), - tfnum, 'M')) != NULL) - { - memcpy (&maddr, dataptr, sizeof (maddr)); - dataptr += sizeof (maddr); - memcpy (&mlen, dataptr, sizeof (mlen)); - dataptr += sizeof (mlen); - trace_debug ("traceframe %d has %d bytes at %s", - tfnum, mlen, paddress (maddr)); - - /* If the block includes the first part of the desired range, - return as much it has; GDB will re-request the remainder, - which might be in a different block of this trace frame. */ - if (maddr <= addr && addr < (maddr + mlen)) - { - ULONGEST amt = (maddr + mlen) - addr; - if (amt > length) - amt = length; - - memcpy (buf, dataptr + (addr - maddr), amt); - *nbytes = amt; - return 0; - } - - /* Skip over this block. */ - dataptr += mlen; - } - - trace_debug ("traceframe %d has no memory data for the desired region", - tfnum); - - *nbytes = 0; - return 0; -} - -static int -traceframe_read_tsv (int tsvnum, LONGEST *val) -{ - client_state &cs = get_client_state (); - int tfnum; - struct traceframe *tframe; - unsigned char *database, *dataptr; - unsigned int datasize; - int vnum; - int found = 0; - - trace_debug ("traceframe_read_tsv"); - - tfnum = cs.current_traceframe; - - if (tfnum < 0) - { - trace_debug ("no current traceframe"); - return 1; - } - - tframe = find_traceframe (tfnum); - - if (tframe == NULL) - { - trace_debug ("traceframe %d not found", tfnum); - return 1; - } - - datasize = tframe->data_size; - database = dataptr = &tframe->data[0]; - - /* Iterate through a traceframe's blocks, looking for the last - matched tsv. */ - while ((dataptr = traceframe_find_block_type (dataptr, - datasize - - (dataptr - database), - tfnum, 'V')) != NULL) - { - memcpy (&vnum, dataptr, sizeof (vnum)); - dataptr += sizeof (vnum); - - trace_debug ("traceframe %d has variable %d", tfnum, vnum); - - /* Check that this is the variable we want. */ - if (tsvnum == vnum) - { - memcpy (val, dataptr, sizeof (*val)); - found = 1; - } - - /* Skip over this block. */ - dataptr += sizeof (LONGEST); - } - - if (!found) - trace_debug ("traceframe %d has no data for variable %d", - tfnum, tsvnum); - return !found; -} - -/* Read a requested block of static tracepoint data from a trace - frame. */ - -int -traceframe_read_sdata (int tfnum, ULONGEST offset, - unsigned char *buf, ULONGEST length, - ULONGEST *nbytes) -{ - struct traceframe *tframe; - unsigned char *database, *dataptr; - unsigned int datasize; - unsigned short mlen; - - trace_debug ("traceframe_read_sdata"); - - tframe = find_traceframe (tfnum); - - if (!tframe) - { - trace_debug ("traceframe %d not found", tfnum); - return 1; - } - - datasize = tframe->data_size; - database = &tframe->data[0]; - - /* Iterate through a traceframe's blocks, looking for static - tracepoint data. */ - dataptr = traceframe_find_block_type (database, datasize, - tfnum, 'S'); - if (dataptr != NULL) - { - memcpy (&mlen, dataptr, sizeof (mlen)); - dataptr += sizeof (mlen); - if (offset < mlen) - { - if (offset + length > mlen) - length = mlen - offset; - - memcpy (buf, dataptr, length); - *nbytes = length; - } - else - *nbytes = 0; - return 0; - } - - trace_debug ("traceframe %d has no static trace data", tfnum); - - *nbytes = 0; - return 0; -} - -/* Callback for traceframe_walk_blocks. Builds a traceframe-info - object. DATA is pointer to a struct buffer holding the - traceframe-info object being built. */ - -static int -build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data) -{ - struct buffer *buffer = (struct buffer *) data; - - switch (blocktype) - { - case 'M': - { - unsigned short mlen; - CORE_ADDR maddr; - - memcpy (&maddr, dataptr, sizeof (maddr)); - dataptr += sizeof (maddr); - memcpy (&mlen, dataptr, sizeof (mlen)); - dataptr += sizeof (mlen); - buffer_xml_printf (buffer, - "\n", - paddress (maddr), phex_nz (mlen, sizeof (mlen))); - break; - } - case 'V': - { - int vnum; - - memcpy (&vnum, dataptr, sizeof (vnum)); - buffer_xml_printf (buffer, "\n", vnum); - break; - } - case 'R': - case 'S': - { - break; - } - default: - warning ("Unhandled trace block type (%d) '%c ' " - "while building trace frame info.", - blocktype, blocktype); - break; - } - - return 0; -} - -/* Build a traceframe-info object for traceframe number TFNUM into - BUFFER. */ - -int -traceframe_read_info (int tfnum, struct buffer *buffer) -{ - struct traceframe *tframe; - - trace_debug ("traceframe_read_info"); - - tframe = find_traceframe (tfnum); - - if (!tframe) - { - trace_debug ("traceframe %d not found", tfnum); - return 1; - } - - buffer_grow_str (buffer, "\n"); - traceframe_walk_blocks (tframe->data, tframe->data_size, - tfnum, build_traceframe_info_xml, buffer); - buffer_grow_str0 (buffer, "\n"); - return 0; -} - -/* Return the first fast tracepoint whose jump pad contains PC. */ - -static struct tracepoint * -fast_tracepoint_from_jump_pad_address (CORE_ADDR pc) -{ - struct tracepoint *tpoint; - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - if (tpoint->type == fast_tracepoint) - if (tpoint->jump_pad <= pc && pc < tpoint->jump_pad_end) - return tpoint; - - return NULL; -} - -/* Return the first fast tracepoint whose trampoline contains PC. */ - -static struct tracepoint * -fast_tracepoint_from_trampoline_address (CORE_ADDR pc) -{ - struct tracepoint *tpoint; - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - { - if (tpoint->type == fast_tracepoint - && tpoint->trampoline <= pc && pc < tpoint->trampoline_end) - return tpoint; - } - - return NULL; -} - -/* Return GDBserver's tracepoint that matches the IP Agent's - tracepoint object that lives at IPA_TPOINT_OBJ in the IP Agent's - address space. */ - -static struct tracepoint * -fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR ipa_tpoint_obj) -{ - struct tracepoint *tpoint; - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - if (tpoint->type == fast_tracepoint) - if (tpoint->obj_addr_on_target == ipa_tpoint_obj) - return tpoint; - - return NULL; -} - -#endif - -/* The type of the object that is used to synchronize fast tracepoint - collection. */ - -typedef struct collecting_t -{ - /* The fast tracepoint number currently collecting. */ - uintptr_t tpoint; - - /* A number that GDBserver can use to identify the thread that is - presently holding the collect lock. This need not (and usually - is not) the thread id, as getting the current thread ID usually - requires a system call, which we want to avoid like the plague. - Usually this is thread's TCB, found in the TLS (pseudo-) - register, which is readable with a single insn on several - architectures. */ - uintptr_t thread_area; -} collecting_t; - -#ifndef IN_PROCESS_AGENT - -void -force_unlock_trace_buffer (void) -{ - write_inferior_data_pointer (ipa_sym_addrs.addr_collecting, 0); -} - -/* Check if the thread identified by THREAD_AREA which is stopped at - STOP_PC, is presently locking the fast tracepoint collection, and - if so, gather some status of said collection. Returns 0 if the - thread isn't collecting or in the jump pad at all. 1, if in the - jump pad (or within gdb_collect) and hasn't executed the adjusted - original insn yet (can set a breakpoint there and run to it). 2, - if presently executing the adjusted original insn --- in which - case, if we want to move the thread out of the jump pad, we need to - single-step it until this function returns 0. */ - -fast_tpoint_collect_result -fast_tracepoint_collecting (CORE_ADDR thread_area, - CORE_ADDR stop_pc, - struct fast_tpoint_collect_status *status) -{ - CORE_ADDR ipa_collecting; - CORE_ADDR ipa_gdb_jump_pad_buffer, ipa_gdb_jump_pad_buffer_end; - CORE_ADDR ipa_gdb_trampoline_buffer; - CORE_ADDR ipa_gdb_trampoline_buffer_end; - struct tracepoint *tpoint; - int needs_breakpoint; - - /* The thread THREAD_AREA is either: - - 0. not collecting at all, not within the jump pad, or within - gdb_collect or one of its callees. - - 1. in the jump pad and haven't reached gdb_collect - - 2. within gdb_collect (out of the jump pad) (collect is set) - - 3. we're in the jump pad, after gdb_collect having returned, - possibly executing the adjusted insns. - - For cases 1 and 3, `collecting' may or not be set. The jump pad - doesn't have any complicated jump logic, so we can tell if the - thread is executing the adjust original insn or not by just - matching STOP_PC with known jump pad addresses. If we it isn't - yet executing the original insn, set a breakpoint there, and let - the thread run to it, so to quickly step over a possible (many - insns) gdb_collect call. Otherwise, or when the breakpoint is - hit, only a few (small number of) insns are left to be executed - in the jump pad. Single-step the thread until it leaves the - jump pad. */ - - again: - tpoint = NULL; - needs_breakpoint = 0; - trace_debug ("fast_tracepoint_collecting"); - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer, - &ipa_gdb_jump_pad_buffer)) - { - internal_error (__FILE__, __LINE__, - "error extracting `gdb_jump_pad_buffer'"); - } - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer_end, - &ipa_gdb_jump_pad_buffer_end)) - { - internal_error (__FILE__, __LINE__, - "error extracting `gdb_jump_pad_buffer_end'"); - } - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer, - &ipa_gdb_trampoline_buffer)) - { - internal_error (__FILE__, __LINE__, - "error extracting `gdb_trampoline_buffer'"); - } - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, - &ipa_gdb_trampoline_buffer_end)) - { - internal_error (__FILE__, __LINE__, - "error extracting `gdb_trampoline_buffer_end'"); - } - - if (ipa_gdb_jump_pad_buffer <= stop_pc - && stop_pc < ipa_gdb_jump_pad_buffer_end) - { - /* We can tell which tracepoint(s) the thread is collecting by - matching the jump pad address back to the tracepoint. */ - tpoint = fast_tracepoint_from_jump_pad_address (stop_pc); - if (tpoint == NULL) - { - warning ("in jump pad, but no matching tpoint?"); - return fast_tpoint_collect_result::not_collecting; - } - else - { - trace_debug ("in jump pad of tpoint (%d, %s); jump_pad(%s, %s); " - "adj_insn(%s, %s)", - tpoint->number, paddress (tpoint->address), - paddress (tpoint->jump_pad), - paddress (tpoint->jump_pad_end), - paddress (tpoint->adjusted_insn_addr), - paddress (tpoint->adjusted_insn_addr_end)); - } - - /* Definitely in the jump pad. May or may not need - fast-exit-jump-pad breakpoint. */ - if (tpoint->jump_pad <= stop_pc - && stop_pc < tpoint->adjusted_insn_addr) - needs_breakpoint = 1; - } - else if (ipa_gdb_trampoline_buffer <= stop_pc - && stop_pc < ipa_gdb_trampoline_buffer_end) - { - /* We can tell which tracepoint(s) the thread is collecting by - matching the trampoline address back to the tracepoint. */ - tpoint = fast_tracepoint_from_trampoline_address (stop_pc); - if (tpoint == NULL) - { - warning ("in trampoline, but no matching tpoint?"); - return fast_tpoint_collect_result::not_collecting; - } - else - { - trace_debug ("in trampoline of tpoint (%d, %s); trampoline(%s, %s)", - tpoint->number, paddress (tpoint->address), - paddress (tpoint->trampoline), - paddress (tpoint->trampoline_end)); - } - - /* Have not reached jump pad yet, but treat the trampoline as a - part of the jump pad that is before the adjusted original - instruction. */ - needs_breakpoint = 1; - } - else - { - collecting_t ipa_collecting_obj; - - /* If `collecting' is set/locked, then the THREAD_AREA thread - may or not be the one holding the lock. We have to read the - lock to find out. */ - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_collecting, - &ipa_collecting)) - { - trace_debug ("fast_tracepoint_collecting:" - " failed reading 'collecting' in the inferior"); - return fast_tpoint_collect_result::not_collecting; - } - - if (!ipa_collecting) - { - trace_debug ("fast_tracepoint_collecting: not collecting" - " (and nobody is)."); - return fast_tpoint_collect_result::not_collecting; - } - - /* Some thread is collecting. Check which. */ - if (read_inferior_memory (ipa_collecting, - (unsigned char *) &ipa_collecting_obj, - sizeof (ipa_collecting_obj)) != 0) - goto again; - - if (ipa_collecting_obj.thread_area != thread_area) - { - trace_debug ("fast_tracepoint_collecting: not collecting " - "(another thread is)"); - return fast_tpoint_collect_result::not_collecting; - } - - tpoint - = fast_tracepoint_from_ipa_tpoint_address (ipa_collecting_obj.tpoint); - if (tpoint == NULL) - { - warning ("fast_tracepoint_collecting: collecting, " - "but tpoint %s not found?", - paddress ((CORE_ADDR) ipa_collecting_obj.tpoint)); - return fast_tpoint_collect_result::not_collecting; - } - - /* The thread is within `gdb_collect', skip over the rest of - fast tracepoint collection quickly using a breakpoint. */ - needs_breakpoint = 1; - } - - /* The caller wants a bit of status detail. */ - if (status != NULL) - { - status->tpoint_num = tpoint->number; - status->tpoint_addr = tpoint->address; - status->adjusted_insn_addr = tpoint->adjusted_insn_addr; - status->adjusted_insn_addr_end = tpoint->adjusted_insn_addr_end; - } - - if (needs_breakpoint) - { - /* Hasn't executed the original instruction yet. Set breakpoint - there, and wait till it's hit, then single-step until exiting - the jump pad. */ - - trace_debug ("\ -fast_tracepoint_collecting, returning continue-until-break at %s", - paddress (tpoint->adjusted_insn_addr)); - - return fast_tpoint_collect_result::before_insn; /* continue */ - } - else - { - /* Just single-step until exiting the jump pad. */ - - trace_debug ("fast_tracepoint_collecting, returning " - "need-single-step (%s-%s)", - paddress (tpoint->adjusted_insn_addr), - paddress (tpoint->adjusted_insn_addr_end)); - - return fast_tpoint_collect_result::at_insn; /* single-step */ - } -} - -#endif - -#ifdef IN_PROCESS_AGENT - -/* The global fast tracepoint collect lock. Points to a collecting_t - object built on the stack by the jump pad, if presently locked; - NULL if it isn't locked. Note that this lock *must* be set while - executing any *function other than the jump pad. See - fast_tracepoint_collecting. */ -EXTERN_C_PUSH -IP_AGENT_EXPORT_VAR collecting_t *collecting; -EXTERN_C_POP - -/* This is needed for -Wmissing-declarations. */ -IP_AGENT_EXPORT_FUNC void gdb_collect (struct tracepoint *tpoint, - unsigned char *regs); - -/* This routine, called from the jump pad (in asm) is designed to be - called from the jump pads of fast tracepoints, thus it is on the - critical path. */ - -IP_AGENT_EXPORT_FUNC void -gdb_collect (struct tracepoint *tpoint, unsigned char *regs) -{ - struct fast_tracepoint_ctx ctx; - const struct target_desc *ipa_tdesc; - - /* Don't do anything until the trace run is completely set up. */ - if (!tracing) - return; - - ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx); - ctx.base.type = fast_tracepoint; - ctx.regs = regs; - ctx.regcache_initted = 0; - /* Wrap the regblock in a register cache (in the stack, we don't - want to malloc here). */ - ctx.regspace = (unsigned char *) alloca (ipa_tdesc->registers_size); - if (ctx.regspace == NULL) - { - trace_debug ("Trace buffer block allocation failed, skipping"); - return; - } - - for (ctx.tpoint = tpoint; - ctx.tpoint != NULL && ctx.tpoint->address == tpoint->address; - ctx.tpoint = ctx.tpoint->next) - { - if (!ctx.tpoint->enabled) - continue; - - /* Multiple tracepoints of different types, such as fast tracepoint and - static tracepoint, can be set at the same address. */ - if (ctx.tpoint->type != tpoint->type) - continue; - - /* Test the condition if present, and collect if true. */ - if (ctx.tpoint->cond == NULL - || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, - ctx.tpoint)) - { - collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, - ctx.tpoint->address, ctx.tpoint); - - /* Note that this will cause original insns to be written back - to where we jumped from, but that's OK because we're jumping - back to the next whole instruction. This will go badly if - instruction restoration is not atomic though. */ - if (stopping_tracepoint - || trace_buffer_is_full - || expr_eval_result != expr_eval_no_error) - { - stop_tracing (); - break; - } - } - else - { - /* If there was a condition and it evaluated to false, the only - way we would stop tracing is if there was an error during - condition expression evaluation. */ - if (expr_eval_result != expr_eval_no_error) - { - stop_tracing (); - break; - } - } - } -} - -/* These global variables points to the corresponding functions. This is - necessary on powerpc64, where asking for function symbol address from gdb - results in returning the actual code pointer, instead of the descriptor - pointer. */ - -typedef void (*gdb_collect_ptr_type) (struct tracepoint *, unsigned char *); -typedef ULONGEST (*get_raw_reg_ptr_type) (const unsigned char *, int); -typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int); -typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST); - -EXTERN_C_PUSH -IP_AGENT_EXPORT_VAR gdb_collect_ptr_type gdb_collect_ptr = gdb_collect; -IP_AGENT_EXPORT_VAR get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg; -IP_AGENT_EXPORT_VAR get_trace_state_variable_value_ptr_type - get_trace_state_variable_value_ptr = get_trace_state_variable_value; -IP_AGENT_EXPORT_VAR set_trace_state_variable_value_ptr_type - set_trace_state_variable_value_ptr = set_trace_state_variable_value; -EXTERN_C_POP - -#endif - -#ifndef IN_PROCESS_AGENT - -CORE_ADDR -get_raw_reg_func_addr (void) -{ - CORE_ADDR res; - if (read_inferior_data_pointer (ipa_sym_addrs.addr_get_raw_reg_ptr, &res)) - { - error ("error extracting get_raw_reg_ptr"); - return 0; - } - return res; -} - -CORE_ADDR -get_get_tsv_func_addr (void) -{ - CORE_ADDR res; - if (read_inferior_data_pointer ( - ipa_sym_addrs.addr_get_trace_state_variable_value_ptr, &res)) - { - error ("error extracting get_trace_state_variable_value_ptr"); - return 0; - } - return res; -} - -CORE_ADDR -get_set_tsv_func_addr (void) -{ - CORE_ADDR res; - if (read_inferior_data_pointer ( - ipa_sym_addrs.addr_set_trace_state_variable_value_ptr, &res)) - { - error ("error extracting set_trace_state_variable_value_ptr"); - return 0; - } - return res; -} - -static void -compile_tracepoint_condition (struct tracepoint *tpoint, - CORE_ADDR *jump_entry) -{ - CORE_ADDR entry_point = *jump_entry; - enum eval_result_type err; - - trace_debug ("Starting condition compilation for tracepoint %d\n", - tpoint->number); - - /* Initialize the global pointer to the code being built. */ - current_insn_ptr = *jump_entry; - - emit_prologue (); - - err = compile_bytecodes (tpoint->cond); - - if (err == expr_eval_no_error) - { - emit_epilogue (); - - /* Record the beginning of the compiled code. */ - tpoint->compiled_cond = entry_point; - - trace_debug ("Condition compilation for tracepoint %d complete\n", - tpoint->number); - } - else - { - /* Leave the unfinished code in situ, but don't point to it. */ - - tpoint->compiled_cond = 0; - - trace_debug ("Condition compilation for tracepoint %d failed, " - "error code %d", - tpoint->number, err); - } - - /* Update the code pointer passed in. Note that we do this even if - the compile fails, so that we can look at the partial results - instead of letting them be overwritten. */ - *jump_entry = current_insn_ptr; - - /* Leave a gap, to aid dump decipherment. */ - *jump_entry += 16; -} - -/* The base pointer of the IPA's heap. This is the only memory the - IPA is allowed to use. The IPA should _not_ call the inferior's - `malloc' during operation. That'd be slow, and, most importantly, - it may not be safe. We may be collecting a tracepoint in a signal - handler, for example. */ -static CORE_ADDR target_tp_heap; - -/* Allocate at least SIZE bytes of memory from the IPA heap, aligned - to 8 bytes. */ - -static CORE_ADDR -target_malloc (ULONGEST size) -{ - CORE_ADDR ptr; - - if (target_tp_heap == 0) - { - /* We have the pointer *address*, need what it points to. */ - if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_tp_heap_buffer, - &target_tp_heap)) - { - internal_error (__FILE__, __LINE__, - "couldn't get target heap head pointer"); - } - } - - ptr = target_tp_heap; - target_tp_heap += size; - - /* Pad to 8-byte alignment. */ - target_tp_heap = ((target_tp_heap + 7) & ~0x7); - - return ptr; -} - -static CORE_ADDR -download_agent_expr (struct agent_expr *expr) -{ - CORE_ADDR expr_addr; - CORE_ADDR expr_bytes; - - expr_addr = target_malloc (sizeof (*expr)); - target_write_memory (expr_addr, (unsigned char *) expr, sizeof (*expr)); - - expr_bytes = target_malloc (expr->length); - write_inferior_data_pointer (expr_addr + offsetof (struct agent_expr, bytes), - expr_bytes); - target_write_memory (expr_bytes, expr->bytes, expr->length); - - return expr_addr; -} - -/* Align V up to N bits. */ -#define UALIGN(V, N) (((V) + ((N) - 1)) & ~((N) - 1)) - -/* Sync tracepoint with IPA, but leave maintenance of linked list to caller. */ - -static void -download_tracepoint_1 (struct tracepoint *tpoint) -{ - struct tracepoint target_tracepoint; - CORE_ADDR tpptr = 0; - - gdb_assert (tpoint->type == fast_tracepoint - || tpoint->type == static_tracepoint); - - if (tpoint->cond != NULL && target_emit_ops () != NULL) - { - CORE_ADDR jentry, jump_entry; - - jentry = jump_entry = get_jump_space_head (); - - if (tpoint->cond != NULL) - { - /* Pad to 8-byte alignment. (needed?) */ - /* Actually this should be left for the target to - decide. */ - jentry = UALIGN (jentry, 8); - - compile_tracepoint_condition (tpoint, &jentry); - } - - /* Pad to 8-byte alignment. */ - jentry = UALIGN (jentry, 8); - claim_jump_space (jentry - jump_entry); - } - - target_tracepoint = *tpoint; - - tpptr = target_malloc (sizeof (*tpoint)); - tpoint->obj_addr_on_target = tpptr; - - /* Write the whole object. We'll fix up its pointers in a bit. - Assume no next for now. This is fixed up above on the next - iteration, if there's any. */ - target_tracepoint.next = NULL; - /* Need to clear this here too, since we're downloading the - tracepoints before clearing our own copy. */ - target_tracepoint.hit_count = 0; - - target_write_memory (tpptr, (unsigned char *) &target_tracepoint, - sizeof (target_tracepoint)); - - if (tpoint->cond) - write_inferior_data_pointer (tpptr - + offsetof (struct tracepoint, cond), - download_agent_expr (tpoint->cond)); - - if (tpoint->numactions) - { - int i; - CORE_ADDR actions_array; - - /* The pointers array. */ - actions_array - = target_malloc (sizeof (*tpoint->actions) * tpoint->numactions); - write_inferior_data_pointer (tpptr + offsetof (struct tracepoint, - actions), - actions_array); - - /* Now for each pointer, download the action. */ - for (i = 0; i < tpoint->numactions; i++) - { - struct tracepoint_action *action = tpoint->actions[i]; - CORE_ADDR ipa_action = tracepoint_action_download (action); - - if (ipa_action != 0) - write_inferior_data_pointer (actions_array - + i * sizeof (*tpoint->actions), - ipa_action); - } - } -} - -#define IPA_PROTO_FAST_TRACE_FLAG 0 -#define IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET 2 -#define IPA_PROTO_FAST_TRACE_JUMP_PAD 10 -#define IPA_PROTO_FAST_TRACE_FJUMP_SIZE 18 -#define IPA_PROTO_FAST_TRACE_FJUMP_INSN 22 - -/* Send a command to agent to download and install tracepoint TPOINT. */ - -static int -tracepoint_send_agent (struct tracepoint *tpoint) -{ - char buf[IPA_CMD_BUF_SIZE]; - char *p; - int i, ret; - - p = buf; - strcpy (p, "FastTrace:"); - p += 10; - - COPY_FIELD_TO_BUF (p, tpoint, number); - COPY_FIELD_TO_BUF (p, tpoint, address); - COPY_FIELD_TO_BUF (p, tpoint, type); - COPY_FIELD_TO_BUF (p, tpoint, enabled); - COPY_FIELD_TO_BUF (p, tpoint, step_count); - COPY_FIELD_TO_BUF (p, tpoint, pass_count); - COPY_FIELD_TO_BUF (p, tpoint, numactions); - COPY_FIELD_TO_BUF (p, tpoint, hit_count); - COPY_FIELD_TO_BUF (p, tpoint, traceframe_usage); - COPY_FIELD_TO_BUF (p, tpoint, compiled_cond); - COPY_FIELD_TO_BUF (p, tpoint, orig_size); - - /* condition */ - p = agent_expr_send (p, tpoint->cond); - - /* tracepoint_action */ - for (i = 0; i < tpoint->numactions; i++) - { - struct tracepoint_action *action = tpoint->actions[i]; - - p[0] = action->type; - p = tracepoint_action_send (&p[1], action); - } - - get_jump_space_head (); - /* Copy the value of GDB_JUMP_PAD_HEAD to command buffer, so that - agent can use jump pad from it. */ - if (tpoint->type == fast_tracepoint) - { - memcpy (p, &gdb_jump_pad_head, 8); - p += 8; - } - - ret = run_inferior_command (buf, (int) (ptrdiff_t) (p - buf)); - if (ret) - return ret; - - if (!startswith (buf, "OK")) - return 1; - - /* The value of tracepoint's target address is stored in BUF. */ - memcpy (&tpoint->obj_addr_on_target, - &buf[IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET], 8); - - if (tpoint->type == fast_tracepoint) - { - unsigned char *insn - = (unsigned char *) &buf[IPA_PROTO_FAST_TRACE_FJUMP_INSN]; - int fjump_size; - - trace_debug ("agent: read from cmd_buf 0x%x 0x%x\n", - (unsigned int) tpoint->obj_addr_on_target, - (unsigned int) gdb_jump_pad_head); - - memcpy (&gdb_jump_pad_head, &buf[IPA_PROTO_FAST_TRACE_JUMP_PAD], 8); - - /* This has been done in agent. We should also set up record for it. */ - memcpy (&fjump_size, &buf[IPA_PROTO_FAST_TRACE_FJUMP_SIZE], 4); - /* Wire it in. */ - tpoint->handle - = set_fast_tracepoint_jump (tpoint->address, insn, fjump_size); - } - - return 0; -} - -static void -download_tracepoint (struct tracepoint *tpoint) -{ - struct tracepoint *tp, *tp_prev; - - if (tpoint->type != fast_tracepoint - && tpoint->type != static_tracepoint) - return; - - download_tracepoint_1 (tpoint); - - /* Find the previous entry of TPOINT, which is fast tracepoint or - static tracepoint. */ - tp_prev = NULL; - for (tp = tracepoints; tp != tpoint; tp = tp->next) - { - if (tp->type == fast_tracepoint || tp->type == static_tracepoint) - tp_prev = tp; - } - - if (tp_prev) - { - CORE_ADDR tp_prev_target_next_addr; - - /* Insert TPOINT after TP_PREV in IPA. */ - if (read_inferior_data_pointer (tp_prev->obj_addr_on_target - + offsetof (struct tracepoint, next), - &tp_prev_target_next_addr)) - { - internal_error (__FILE__, __LINE__, - "error reading `tp_prev->next'"); - } - - /* tpoint->next = tp_prev->next */ - write_inferior_data_pointer (tpoint->obj_addr_on_target - + offsetof (struct tracepoint, next), - tp_prev_target_next_addr); - /* tp_prev->next = tpoint */ - write_inferior_data_pointer (tp_prev->obj_addr_on_target - + offsetof (struct tracepoint, next), - tpoint->obj_addr_on_target); - } - else - /* First object in list, set the head pointer in the - inferior. */ - write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, - tpoint->obj_addr_on_target); - -} - -static void -download_trace_state_variables (void) -{ - CORE_ADDR ptr = 0, prev_ptr = 0; - struct trace_state_variable *tsv; - - /* Start out empty. */ - write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables, 0); - - for (tsv = trace_state_variables; tsv != NULL; tsv = tsv->next) - { - struct trace_state_variable target_tsv; - - /* TSV's with a getter have been initialized equally in both the - inferior and GDBserver. Skip them. */ - if (tsv->getter != NULL) - continue; - - target_tsv = *tsv; - - prev_ptr = ptr; - ptr = target_malloc (sizeof (*tsv)); - - if (tsv == trace_state_variables) - { - /* First object in list, set the head pointer in the - inferior. */ - - write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables, - ptr); - } - else - { - write_inferior_data_pointer (prev_ptr - + offsetof (struct trace_state_variable, - next), - ptr); - } - - /* Write the whole object. We'll fix up its pointers in a bit. - Assume no next, fixup when needed. */ - target_tsv.next = NULL; - - target_write_memory (ptr, (unsigned char *) &target_tsv, - sizeof (target_tsv)); - - if (tsv->name != NULL) - { - size_t size = strlen (tsv->name) + 1; - CORE_ADDR name_addr = target_malloc (size); - target_write_memory (name_addr, - (unsigned char *) tsv->name, size); - write_inferior_data_pointer (ptr - + offsetof (struct trace_state_variable, - name), - name_addr); - } - - gdb_assert (tsv->getter == NULL); - } - - if (prev_ptr != 0) - { - /* Fixup the next pointer in the last item in the list. */ - write_inferior_data_pointer (prev_ptr - + offsetof (struct trace_state_variable, - next), 0); - } -} - -/* Upload complete trace frames out of the IP Agent's trace buffer - into GDBserver's trace buffer. This always uploads either all or - no trace frames. This is the counter part of - `trace_alloc_trace_buffer'. See its description of the atomic - syncing mechanism. */ - -static void -upload_fast_traceframes (void) -{ - unsigned int ipa_traceframe_read_count, ipa_traceframe_write_count; - unsigned int ipa_traceframe_read_count_racy, ipa_traceframe_write_count_racy; - CORE_ADDR tf; - struct ipa_trace_buffer_control ipa_trace_buffer_ctrl; - unsigned int curr_tbctrl_idx; - unsigned int ipa_trace_buffer_ctrl_curr; - unsigned int ipa_trace_buffer_ctrl_curr_old; - CORE_ADDR ipa_trace_buffer_ctrl_addr; - struct breakpoint *about_to_request_buffer_space_bkpt; - CORE_ADDR ipa_trace_buffer_lo; - CORE_ADDR ipa_trace_buffer_hi; - - if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, - &ipa_traceframe_read_count_racy)) - { - /* This will happen in most targets if the current thread is - running. */ - return; - } - - if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, - &ipa_traceframe_write_count_racy)) - return; - - trace_debug ("ipa_traceframe_count (racy area): %d (w=%d, r=%d)", - ipa_traceframe_write_count_racy - - ipa_traceframe_read_count_racy, - ipa_traceframe_write_count_racy, - ipa_traceframe_read_count_racy); - - if (ipa_traceframe_write_count_racy == ipa_traceframe_read_count_racy) - return; - - about_to_request_buffer_space_bkpt - = set_breakpoint_at (ipa_sym_addrs.addr_about_to_request_buffer_space, - NULL); - - if (read_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, - &ipa_trace_buffer_ctrl_curr)) - return; - - ipa_trace_buffer_ctrl_curr_old = ipa_trace_buffer_ctrl_curr; - - curr_tbctrl_idx = ipa_trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK; - - { - unsigned int prev, counter; - - /* Update the token, with new counters, and the GDBserver stamp - bit. Alway reuse the current TBC index. */ - prev = ipa_trace_buffer_ctrl_curr & GDBSERVER_FLUSH_COUNT_MASK_CURR; - counter = (prev + 0x100) & GDBSERVER_FLUSH_COUNT_MASK_CURR; - - ipa_trace_buffer_ctrl_curr = (GDBSERVER_UPDATED_FLUSH_COUNT_BIT - | (prev << 12) - | counter - | curr_tbctrl_idx); - } - - if (write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, - ipa_trace_buffer_ctrl_curr)) - return; - - trace_debug ("Lib: Committed %08x -> %08x", - ipa_trace_buffer_ctrl_curr_old, - ipa_trace_buffer_ctrl_curr); - - /* Re-read these, now that we've installed the - `about_to_request_buffer_space' breakpoint/lock. A thread could - have finished a traceframe between the last read of these - counters and setting the breakpoint above. If we start - uploading, we never want to leave this function with - traceframe_read_count != 0, otherwise, GDBserver could end up - incrementing the counter tokens more than once (due to event loop - nesting), which would break the IP agent's "effective" detection - (see trace_alloc_trace_buffer). */ - if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, - &ipa_traceframe_read_count)) - return; - if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, - &ipa_traceframe_write_count)) - return; - - if (debug_threads) - { - trace_debug ("ipa_traceframe_count (blocked area): %d (w=%d, r=%d)", - ipa_traceframe_write_count - ipa_traceframe_read_count, - ipa_traceframe_write_count, ipa_traceframe_read_count); - - if (ipa_traceframe_write_count != ipa_traceframe_write_count_racy - || ipa_traceframe_read_count != ipa_traceframe_read_count_racy) - trace_debug ("note that ipa_traceframe_count's parts changed"); - } - - /* Get the address of the current TBC object (the IP agent has an - array of 3 such objects). The index is stored in the TBC - token. */ - ipa_trace_buffer_ctrl_addr = ipa_sym_addrs.addr_trace_buffer_ctrl; - ipa_trace_buffer_ctrl_addr - += sizeof (struct ipa_trace_buffer_control) * curr_tbctrl_idx; - - if (read_inferior_memory (ipa_trace_buffer_ctrl_addr, - (unsigned char *) &ipa_trace_buffer_ctrl, - sizeof (struct ipa_trace_buffer_control))) - return; - - if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo, - &ipa_trace_buffer_lo)) - return; - if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi, - &ipa_trace_buffer_hi)) - return; - - /* Offsets are easier to grok for debugging than raw addresses, - especially for the small trace buffer sizes that are useful for - testing. */ - trace_debug ("Lib: Trace buffer [%d] start=%d free=%d " - "endfree=%d wrap=%d hi=%d", - curr_tbctrl_idx, - (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo)); - - /* Note that the IPA's buffer is always circular. */ - -#define IPA_FIRST_TRACEFRAME() (ipa_trace_buffer_ctrl.start) - -#define IPA_NEXT_TRACEFRAME_1(TF, TFOBJ) \ - ((TF) + sizeof (struct traceframe) + (TFOBJ)->data_size) - -#define IPA_NEXT_TRACEFRAME(TF, TFOBJ) \ - (IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) \ - - ((IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) >= ipa_trace_buffer_ctrl.wrap) \ - ? (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo) \ - : 0)) - - tf = IPA_FIRST_TRACEFRAME (); - - while (ipa_traceframe_write_count - ipa_traceframe_read_count) - { - struct tracepoint *tpoint; - struct traceframe *tframe; - unsigned char *block; - struct traceframe ipa_tframe; - - if (read_inferior_memory (tf, (unsigned char *) &ipa_tframe, - offsetof (struct traceframe, data))) - error ("Uploading: couldn't read traceframe at %s\n", paddress (tf)); - - if (ipa_tframe.tpnum == 0) - { - internal_error (__FILE__, __LINE__, - "Uploading: No (more) fast traceframes, but" - " ipa_traceframe_count == %u??\n", - ipa_traceframe_write_count - - ipa_traceframe_read_count); - } - - /* Note that this will be incorrect for multi-location - tracepoints... */ - tpoint = find_next_tracepoint_by_number (NULL, ipa_tframe.tpnum); - - tframe = add_traceframe (tpoint); - if (tframe == NULL) - { - trace_buffer_is_full = 1; - trace_debug ("Uploading: trace buffer is full"); - } - else - { - /* Copy the whole set of blocks in one go for now. FIXME: - split this in smaller blocks. */ - block = add_traceframe_block (tframe, tpoint, - ipa_tframe.data_size); - if (block != NULL) - { - if (read_inferior_memory (tf - + offsetof (struct traceframe, data), - block, ipa_tframe.data_size)) - error ("Uploading: Couldn't read traceframe data at %s\n", - paddress (tf + offsetof (struct traceframe, data))); - } - - trace_debug ("Uploading: traceframe didn't fit"); - finish_traceframe (tframe); - } - - tf = IPA_NEXT_TRACEFRAME (tf, &ipa_tframe); - - /* If we freed the traceframe that wrapped around, go back - to the non-wrap case. */ - if (tf < ipa_trace_buffer_ctrl.start) - { - trace_debug ("Lib: Discarding past the wraparound"); - ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi; - } - ipa_trace_buffer_ctrl.start = tf; - ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_ctrl.start; - ++ipa_traceframe_read_count; - - if (ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.free - && ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.end_free) - { - trace_debug ("Lib: buffer is fully empty. " - "Trace buffer [%d] start=%d free=%d endfree=%d", - curr_tbctrl_idx, - (int) (ipa_trace_buffer_ctrl.start - - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.free - - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.end_free - - ipa_trace_buffer_lo)); - - ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo; - ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo; - ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi; - ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi; - } - - trace_debug ("Uploaded a traceframe\n" - "Lib: Trace buffer [%d] start=%d free=%d " - "endfree=%d wrap=%d hi=%d", - curr_tbctrl_idx, - (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.end_free - - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo), - (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo)); - } - - if (target_write_memory (ipa_trace_buffer_ctrl_addr, - (unsigned char *) &ipa_trace_buffer_ctrl, - sizeof (struct ipa_trace_buffer_control))) - return; - - write_inferior_integer (ipa_sym_addrs.addr_traceframe_read_count, - ipa_traceframe_read_count); - - trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx); - - pause_all (1); - - delete_breakpoint (about_to_request_buffer_space_bkpt); - about_to_request_buffer_space_bkpt = NULL; - - unpause_all (1); - - if (trace_buffer_is_full) - stop_tracing (); -} -#endif - -#ifdef IN_PROCESS_AGENT - -IP_AGENT_EXPORT_VAR int ust_loaded; -IP_AGENT_EXPORT_VAR char cmd_buf[IPA_CMD_BUF_SIZE]; - -#ifdef HAVE_UST - -/* Static tracepoints. */ - -/* UST puts a "struct tracepoint" in the global namespace, which - conflicts with our tracepoint. Arguably, being a library, it - shouldn't take ownership of such a generic name. We work around it - here. */ -#define tracepoint ust_tracepoint -#include -#undef tracepoint - -extern int serialize_to_text (char *outbuf, int bufsize, - const char *fmt, va_list ap); - -#define GDB_PROBE_NAME "gdb" - -/* We dynamically search for the UST symbols instead of linking them - in. This lets the user decide if the application uses static - tracepoints, instead of always pulling libust.so in. This vector - holds pointers to all functions we care about. */ - -static struct -{ - int (*serialize_to_text) (char *outbuf, int bufsize, - const char *fmt, va_list ap); - - int (*ltt_probe_register) (struct ltt_available_probe *pdata); - int (*ltt_probe_unregister) (struct ltt_available_probe *pdata); - - int (*ltt_marker_connect) (const char *channel, const char *mname, - const char *pname); - int (*ltt_marker_disconnect) (const char *channel, const char *mname, - const char *pname); - - void (*marker_iter_start) (struct marker_iter *iter); - void (*marker_iter_next) (struct marker_iter *iter); - void (*marker_iter_stop) (struct marker_iter *iter); - void (*marker_iter_reset) (struct marker_iter *iter); -} ust_ops; - -#include - -/* Cast through typeof to catch incompatible API changes. Since UST - only builds with gcc, we can freely use gcc extensions here - too. */ -#define GET_UST_SYM(SYM) \ - do \ - { \ - if (ust_ops.SYM == NULL) \ - ust_ops.SYM = (typeof (&SYM)) dlsym (RTLD_DEFAULT, #SYM); \ - if (ust_ops.SYM == NULL) \ - return 0; \ - } while (0) - -#define USTF(SYM) ust_ops.SYM - -/* Get pointers to all libust.so functions we care about. */ - -static int -dlsym_ust (void) -{ - GET_UST_SYM (serialize_to_text); - - GET_UST_SYM (ltt_probe_register); - GET_UST_SYM (ltt_probe_unregister); - GET_UST_SYM (ltt_marker_connect); - GET_UST_SYM (ltt_marker_disconnect); - - GET_UST_SYM (marker_iter_start); - GET_UST_SYM (marker_iter_next); - GET_UST_SYM (marker_iter_stop); - GET_UST_SYM (marker_iter_reset); - - ust_loaded = 1; - return 1; -} - -/* Given an UST marker, return the matching gdb static tracepoint. - The match is done by address. */ - -static struct tracepoint * -ust_marker_to_static_tracepoint (const struct marker *mdata) -{ - struct tracepoint *tpoint; - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - { - if (tpoint->type != static_tracepoint) - continue; - - if (tpoint->address == (uintptr_t) mdata->location) - return tpoint; - } - - return NULL; -} - -/* The probe function we install on lttng/ust markers. Whenever a - probed ust marker is hit, this function is called. This is similar - to gdb_collect, only for static tracepoints, instead of fast - tracepoints. */ - -static void -gdb_probe (const struct marker *mdata, void *probe_private, - struct registers *regs, void *call_private, - const char *fmt, va_list *args) -{ - struct tracepoint *tpoint; - struct static_tracepoint_ctx ctx; - const struct target_desc *ipa_tdesc; - - /* Don't do anything until the trace run is completely set up. */ - if (!tracing) - { - trace_debug ("gdb_probe: not tracing\n"); - return; - } - - ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx); - ctx.base.type = static_tracepoint; - ctx.regcache_initted = 0; - ctx.regs = regs; - ctx.fmt = fmt; - ctx.args = args; - - /* Wrap the regblock in a register cache (in the stack, we don't - want to malloc here). */ - ctx.regspace = alloca (ipa_tdesc->registers_size); - if (ctx.regspace == NULL) - { - trace_debug ("Trace buffer block allocation failed, skipping"); - return; - } - - tpoint = ust_marker_to_static_tracepoint (mdata); - if (tpoint == NULL) - { - trace_debug ("gdb_probe: marker not known: " - "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"", - mdata->location, mdata->channel, - mdata->name, mdata->format); - return; - } - - if (!tpoint->enabled) - { - trace_debug ("gdb_probe: tracepoint disabled"); - return; - } - - ctx.tpoint = tpoint; - - trace_debug ("gdb_probe: collecting marker: " - "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"", - mdata->location, mdata->channel, - mdata->name, mdata->format); - - /* Test the condition if present, and collect if true. */ - if (tpoint->cond == NULL - || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, - tpoint)) - { - collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, - tpoint->address, tpoint); - - if (stopping_tracepoint - || trace_buffer_is_full - || expr_eval_result != expr_eval_no_error) - stop_tracing (); - } - else - { - /* If there was a condition and it evaluated to false, the only - way we would stop tracing is if there was an error during - condition expression evaluation. */ - if (expr_eval_result != expr_eval_no_error) - stop_tracing (); - } -} - -/* Called if the gdb static tracepoint requested collecting "$_sdata", - static tracepoint string data. This is a string passed to the - tracing library by the user, at the time of the tracepoint marker - call. E.g., in the UST marker call: - - trace_mark (ust, bar33, "str %s", "FOOBAZ"); - - the collected data is "str FOOBAZ". -*/ - -static void -collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, - struct traceframe *tframe) -{ - struct static_tracepoint_ctx *umd = (struct static_tracepoint_ctx *) ctx; - unsigned char *bufspace; - int size; - va_list copy; - unsigned short blocklen; - - if (umd == NULL) - { - trace_debug ("Wanted to collect static trace data, " - "but there's no static trace data"); - return; - } - - va_copy (copy, *umd->args); - size = USTF(serialize_to_text) (NULL, 0, umd->fmt, copy); - va_end (copy); - - trace_debug ("Want to collect ust data"); - - /* 'S' + size + string */ - bufspace = add_traceframe_block (tframe, umd->tpoint, - 1 + sizeof (blocklen) + size + 1); - if (bufspace == NULL) - { - trace_debug ("Trace buffer block allocation failed, skipping"); - return; - } - - /* Identify a static trace data block. */ - *bufspace = 'S'; - - blocklen = size + 1; - memcpy (bufspace + 1, &blocklen, sizeof (blocklen)); - - va_copy (copy, *umd->args); - USTF(serialize_to_text) ((char *) bufspace + 1 + sizeof (blocklen), - size + 1, umd->fmt, copy); - va_end (copy); - - trace_debug ("Storing static tracepoint data in regblock: %s", - bufspace + 1 + sizeof (blocklen)); -} - -/* The probe to register with lttng/ust. */ -static struct ltt_available_probe gdb_ust_probe = - { - GDB_PROBE_NAME, - NULL, - gdb_probe, - }; - -#endif /* HAVE_UST */ -#endif /* IN_PROCESS_AGENT */ - -#ifndef IN_PROCESS_AGENT - -/* Ask the in-process agent to run a command. Since we don't want to - have to handle the IPA hitting breakpoints while running the - command, we pause all threads, remove all breakpoints, and then set - the helper thread re-running. We communicate with the helper - thread by means of direct memory xfering, and a socket for - synchronization. */ - -static int -run_inferior_command (char *cmd, int len) -{ - int err = -1; - int pid = current_ptid.pid (); - - trace_debug ("run_inferior_command: running: %s", cmd); - - pause_all (0); - uninsert_all_breakpoints (); - - err = agent_run_command (pid, (const char *) cmd, len); - - reinsert_all_breakpoints (); - unpause_all (0); - - return err; -} - -#else /* !IN_PROCESS_AGENT */ - -#include -#include - -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) -#endif - -/* Where we put the socked used for synchronization. */ -#define SOCK_DIR P_tmpdir - -/* Thread ID of the helper thread. GDBserver reads this to know which - is the help thread. This is an LWP id on Linux. */ -EXTERN_C_PUSH -IP_AGENT_EXPORT_VAR int helper_thread_id; -EXTERN_C_POP - -static int -init_named_socket (const char *name) -{ - int result, fd; - struct sockaddr_un addr; - - result = fd = socket (PF_UNIX, SOCK_STREAM, 0); - if (result == -1) - { - warning ("socket creation failed: %s", safe_strerror (errno)); - return -1; - } - - addr.sun_family = AF_UNIX; - - strncpy (addr.sun_path, name, UNIX_PATH_MAX); - addr.sun_path[UNIX_PATH_MAX - 1] = '\0'; - - result = access (name, F_OK); - if (result == 0) - { - /* File exists. */ - result = unlink (name); - if (result == -1) - { - warning ("unlink failed: %s", safe_strerror (errno)); - close (fd); - return -1; - } - warning ("socket %s already exists; overwriting", name); - } - - result = bind (fd, (struct sockaddr *) &addr, sizeof (addr)); - if (result == -1) - { - warning ("bind failed: %s", safe_strerror (errno)); - close (fd); - return -1; - } - - result = listen (fd, 1); - if (result == -1) - { - warning ("listen: %s", safe_strerror (errno)); - close (fd); - return -1; - } - - return fd; -} - -static char agent_socket_name[UNIX_PATH_MAX]; - -static int -gdb_agent_socket_init (void) -{ - int result, fd; - - result = xsnprintf (agent_socket_name, UNIX_PATH_MAX, "%s/gdb_ust%d", - SOCK_DIR, getpid ()); - if (result >= UNIX_PATH_MAX) - { - trace_debug ("string overflow allocating socket name"); - return -1; - } - - fd = init_named_socket (agent_socket_name); - if (fd < 0) - warning ("Error initializing named socket (%s) for communication with the " - "ust helper thread. Check that directory exists and that it " - "is writable.", agent_socket_name); - - return fd; -} - -#ifdef HAVE_UST - -/* The next marker to be returned on a qTsSTM command. */ -static const struct marker *next_st; - -/* Returns the first known marker. */ - -struct marker * -first_marker (void) -{ - struct marker_iter iter; - - USTF(marker_iter_reset) (&iter); - USTF(marker_iter_start) (&iter); - - return iter.marker; -} - -/* Returns the marker following M. */ - -const struct marker * -next_marker (const struct marker *m) -{ - struct marker_iter iter; - - USTF(marker_iter_reset) (&iter); - USTF(marker_iter_start) (&iter); - - for (; iter.marker != NULL; USTF(marker_iter_next) (&iter)) - { - if (iter.marker == m) - { - USTF(marker_iter_next) (&iter); - return iter.marker; - } - } - - return NULL; -} - -/* Return an hexstr version of the STR C string, fit for sending to - GDB. */ - -static char * -cstr_to_hexstr (const char *str) -{ - int len = strlen (str); - char *hexstr = xmalloc (len * 2 + 1); - bin2hex ((gdb_byte *) str, hexstr, len); - return hexstr; -} - -/* Compose packet that is the response to the qTsSTM/qTfSTM/qTSTMat - packets. */ - -static void -response_ust_marker (char *packet, const struct marker *st) -{ - char *strid, *format, *tmp; - - next_st = next_marker (st); - - tmp = xmalloc (strlen (st->channel) + 1 + - strlen (st->name) + 1); - sprintf (tmp, "%s/%s", st->channel, st->name); - - strid = cstr_to_hexstr (tmp); - free (tmp); - - format = cstr_to_hexstr (st->format); - - sprintf (packet, "m%s:%s:%s", - paddress ((uintptr_t) st->location), - strid, - format); - - free (strid); - free (format); -} - -/* Return the first static tracepoint, and initialize the state - machine that will iterate through all the static tracepoints. */ - -static void -cmd_qtfstm (char *packet) -{ - trace_debug ("Returning first trace state variable definition"); - - if (first_marker ()) - response_ust_marker (packet, first_marker ()); - else - strcpy (packet, "l"); -} - -/* Return additional trace state variable definitions. */ - -static void -cmd_qtsstm (char *packet) -{ - trace_debug ("Returning static tracepoint"); - - if (next_st) - response_ust_marker (packet, next_st); - else - strcpy (packet, "l"); -} - -/* Disconnect the GDB probe from a marker at a given address. */ - -static void -unprobe_marker_at (char *packet) -{ - char *p = packet; - ULONGEST address; - struct marker_iter iter; - - p += sizeof ("unprobe_marker_at:") - 1; - - p = unpack_varlen_hex (p, &address); - - USTF(marker_iter_reset) (&iter); - USTF(marker_iter_start) (&iter); - for (; iter.marker != NULL; USTF(marker_iter_next) (&iter)) - if ((uintptr_t ) iter.marker->location == address) - { - int result; - - result = USTF(ltt_marker_disconnect) (iter.marker->channel, - iter.marker->name, - GDB_PROBE_NAME); - if (result < 0) - warning ("could not disable marker %s/%s", - iter.marker->channel, iter.marker->name); - break; - } -} - -/* Connect the GDB probe to a marker at a given address. */ - -static int -probe_marker_at (char *packet) -{ - char *p = packet; - ULONGEST address; - struct marker_iter iter; - struct marker *m; - - p += sizeof ("probe_marker_at:") - 1; - - p = unpack_varlen_hex (p, &address); - - USTF(marker_iter_reset) (&iter); - - for (USTF(marker_iter_start) (&iter), m = iter.marker; - m != NULL; - USTF(marker_iter_next) (&iter), m = iter.marker) - if ((uintptr_t ) m->location == address) - { - int result; - - trace_debug ("found marker for address. " - "ltt_marker_connect (marker = %s/%s)", - m->channel, m->name); - - result = USTF(ltt_marker_connect) (m->channel, m->name, - GDB_PROBE_NAME); - if (result && result != -EEXIST) - trace_debug ("ltt_marker_connect (marker = %s/%s, errno = %d)", - m->channel, m->name, -result); - - if (result < 0) - { - sprintf (packet, "E.could not connect marker: channel=%s, name=%s", - m->channel, m->name); - return -1; - } - - strcpy (packet, "OK"); - return 0; - } - - sprintf (packet, "E.no marker found at 0x%s", paddress (address)); - return -1; -} - -static int -cmd_qtstmat (char *packet) -{ - char *p = packet; - ULONGEST address; - struct marker_iter iter; - struct marker *m; - - p += sizeof ("qTSTMat:") - 1; - - p = unpack_varlen_hex (p, &address); - - USTF(marker_iter_reset) (&iter); - - for (USTF(marker_iter_start) (&iter), m = iter.marker; - m != NULL; - USTF(marker_iter_next) (&iter), m = iter.marker) - if ((uintptr_t ) m->location == address) - { - response_ust_marker (packet, m); - return 0; - } - - strcpy (packet, "l"); - return -1; -} - -static void -gdb_ust_init (void) -{ - if (!dlsym_ust ()) - return; - - USTF(ltt_probe_register) (&gdb_ust_probe); -} - -#endif /* HAVE_UST */ - -#include - -static void -gdb_agent_remove_socket (void) -{ - unlink (agent_socket_name); -} - -/* Helper thread of agent. */ - -static void * -gdb_agent_helper_thread (void *arg) -{ - int listen_fd; - - atexit (gdb_agent_remove_socket); - - while (1) - { - listen_fd = gdb_agent_socket_init (); - - if (helper_thread_id == 0) - helper_thread_id = syscall (SYS_gettid); - - if (listen_fd == -1) - { - warning ("could not create sync socket"); - break; - } - - while (1) - { - socklen_t tmp; - struct sockaddr_un sockaddr; - int fd; - char buf[1]; - int ret; - int stop_loop = 0; - - tmp = sizeof (sockaddr); - - do - { - fd = accept (listen_fd, (struct sockaddr *) &sockaddr, &tmp); - } - /* It seems an ERESTARTSYS can escape out of accept. */ - while (fd == -512 || (fd == -1 && errno == EINTR)); - - if (fd < 0) - { - warning ("Accept returned %d, error: %s", - fd, safe_strerror (errno)); - break; - } - - do - { - ret = read (fd, buf, 1); - } while (ret == -1 && errno == EINTR); - - if (ret == -1) - { - warning ("reading socket (fd=%d) failed with %s", - fd, safe_strerror (errno)); - close (fd); - break; - } - - if (cmd_buf[0]) - { - if (startswith (cmd_buf, "close")) - { - stop_loop = 1; - } -#ifdef HAVE_UST - else if (strcmp ("qTfSTM", cmd_buf) == 0) - { - cmd_qtfstm (cmd_buf); - } - else if (strcmp ("qTsSTM", cmd_buf) == 0) - { - cmd_qtsstm (cmd_buf); - } - else if (startswith (cmd_buf, "unprobe_marker_at:")) - { - unprobe_marker_at (cmd_buf); - } - else if (startswith (cmd_buf, "probe_marker_at:")) - { - probe_marker_at (cmd_buf); - } - else if (startswith (cmd_buf, "qTSTMat:")) - { - cmd_qtstmat (cmd_buf); - } -#endif /* HAVE_UST */ - } - - /* Fix compiler's warning: ignoring return value of 'write'. */ - ret = write (fd, buf, 1); - close (fd); - - if (stop_loop) - { - close (listen_fd); - unlink (agent_socket_name); - - /* Sleep endlessly to wait the whole inferior stops. This - thread can not exit because GDB or GDBserver may still need - 'current_thread' (representing this thread) to access - inferior memory. Otherwise, this thread exits earlier than - other threads, and 'current_thread' is set to NULL. */ - while (1) - sleep (10); - } - } - } - - return NULL; -} - -#include -#include - -EXTERN_C_PUSH -IP_AGENT_EXPORT_VAR int gdb_agent_capability = AGENT_CAPA_STATIC_TRACE; -EXTERN_C_POP - -static void -gdb_agent_init (void) -{ - int res; - pthread_t thread; - sigset_t new_mask; - sigset_t orig_mask; - - /* We want the helper thread to be as transparent as possible, so - have it inherit an all-signals-blocked mask. */ - - sigfillset (&new_mask); - res = pthread_sigmask (SIG_SETMASK, &new_mask, &orig_mask); - if (res) - perror_with_name ("pthread_sigmask (1)"); - - res = pthread_create (&thread, - NULL, - gdb_agent_helper_thread, - NULL); - - res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL); - if (res) - perror_with_name ("pthread_sigmask (2)"); - - while (helper_thread_id == 0) - usleep (1); - -#ifdef HAVE_UST - gdb_ust_init (); -#endif -} - -#include - -IP_AGENT_EXPORT_VAR char *gdb_tp_heap_buffer; -IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer; -IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer_end; -IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer; -IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_end; -IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_error; - -/* Record the result of getting buffer space for fast tracepoint - trampolines. Any error message is copied, since caller may not be - using persistent storage. */ - -void -set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, char *errmsg) -{ - gdb_trampoline_buffer = (char *) (uintptr_t) begin; - gdb_trampoline_buffer_end = (char *) (uintptr_t) end; - if (errmsg) - strncpy (gdb_trampoline_buffer_error, errmsg, 99); - else - strcpy (gdb_trampoline_buffer_error, "no buffer passed"); -} - -static void __attribute__ ((constructor)) -initialize_tracepoint_ftlib (void) -{ - initialize_tracepoint (); - - gdb_agent_init (); -} - -#ifndef HAVE_GETAUXVAL -/* Retrieve the value of TYPE from the auxiliary vector. If TYPE is not - found, 0 is returned. This function is provided if glibc is too old. */ - -unsigned long -getauxval (unsigned long type) -{ - unsigned long data[2]; - FILE *f = fopen ("/proc/self/auxv", "r"); - unsigned long value = 0; - - if (f == NULL) - return 0; - - while (fread (data, sizeof (data), 1, f) > 0) - { - if (data[0] == type) - { - value = data[1]; - break; - } - } - - fclose (f); - return value; -} -#endif - -#endif /* IN_PROCESS_AGENT */ - -/* Return a timestamp, expressed as microseconds of the usual Unix - time. (As the result is a 64-bit number, it will not overflow any - time soon.) */ - -static LONGEST -get_timestamp (void) -{ - using namespace std::chrono; - - steady_clock::time_point now = steady_clock::now (); - return duration_cast (now.time_since_epoch ()).count (); -} - -void -initialize_tracepoint (void) -{ - /* Start with the default size. */ - init_trace_buffer (DEFAULT_TRACE_BUFFER_SIZE); - - /* Wire trace state variable 1 to be the timestamp. This will be - uploaded to GDB upon connection and become one of its trace state - variables. (In case you're wondering, if GDB already has a trace - variable numbered 1, it will be renumbered.) */ - create_trace_state_variable (1, 0); - set_trace_state_variable_name (1, "trace_timestamp"); - set_trace_state_variable_getter (1, get_timestamp); - -#ifdef IN_PROCESS_AGENT - { - int pagesize; - size_t jump_pad_size; - - pagesize = sysconf (_SC_PAGE_SIZE); - if (pagesize == -1) - perror_with_name ("sysconf"); - -#define SCRATCH_BUFFER_NPAGES 20 - - jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES; - - gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024); - gdb_jump_pad_buffer = (char *) alloc_jump_pad_buffer (jump_pad_size); - if (gdb_jump_pad_buffer == NULL) - perror_with_name ("mmap"); - gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size; - } - - gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0; - - /* It's not a fatal error for something to go wrong with trampoline - buffer setup, but it can be mysterious, so create a channel to - report back on what went wrong, using a fixed size since we may - not be able to allocate space later when the problem occurs. */ - gdb_trampoline_buffer_error = (char *) xmalloc (IPA_BUFSIZ); - - strcpy (gdb_trampoline_buffer_error, "No errors reported"); - - initialize_low_tracepoint (); -#endif -} diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h deleted file mode 100644 index 030b2a92344..00000000000 --- a/gdb/gdbserver/tracepoint.h +++ /dev/null @@ -1,195 +0,0 @@ -/* Tracepoint code for remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_TRACEPOINT_H -#define GDBSERVER_TRACEPOINT_H - -/* Size for a small buffer to report problems from the in-process - agent back to GDBserver. */ -#define IPA_BUFSIZ 100 - -void initialize_tracepoint (void); - -#if defined(__GNUC__) -# define ATTR_USED __attribute__((used)) -# define ATTR_NOINLINE __attribute__((noinline)) -#else -# define ATTR_USED -# define ATTR_NOINLINE -#endif - -/* How to make symbol public/exported. */ - -#if defined _WIN32 || defined __CYGWIN__ -# define EXPORTED_SYMBOL __declspec (dllexport) -#else -# if __GNUC__ >= 4 -# define EXPORTED_SYMBOL __attribute__ ((visibility ("default"))) -# else -# define EXPORTED_SYMBOL -# endif -#endif - -/* Use these to make sure the functions and variables the IPA needs to - export (symbols GDBserver needs to query GDB about) are visible and - have C linkage. - - Tag exported functions with IP_AGENT_EXPORT_FUNC, tag the - definitions of exported variables with IP_AGENT_EXPORT_VAR, and - variable declarations with IP_AGENT_EXPORT_VAR_DECL. Variables - must also be exported with C linkage. As we can't both use extern - "C" and initialize a variable in the same statement, variables that - don't have a separate declaration must use - EXTERN_C_PUSH/EXTERN_C_POP around their definition. */ - -#ifdef IN_PROCESS_AGENT -# define IP_AGENT_EXPORT_FUNC EXTERN_C EXPORTED_SYMBOL ATTR_NOINLINE ATTR_USED -# define IP_AGENT_EXPORT_VAR EXPORTED_SYMBOL ATTR_USED -# define IP_AGENT_EXPORT_VAR_DECL EXTERN_C EXPORTED_SYMBOL -#else -# define IP_AGENT_EXPORT_FUNC static -# define IP_AGENT_EXPORT_VAR -# define IP_AGENT_EXPORT_VAR_DECL extern -#endif - -IP_AGENT_EXPORT_VAR_DECL int tracing; - -extern int disconnected_tracing; - -void tracepoint_look_up_symbols (void); - -void stop_tracing (void); - -int handle_tracepoint_general_set (char *own_buf); -int handle_tracepoint_query (char *own_buf); - -int tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc); -int tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc); - -void release_while_stepping_state_list (struct thread_info *tinfo); - -int in_readonly_region (CORE_ADDR addr, ULONGEST length); -int traceframe_read_mem (int tfnum, CORE_ADDR addr, - unsigned char *buf, ULONGEST length, - ULONGEST *nbytes); -int fetch_traceframe_registers (int tfnum, - struct regcache *regcache, - int regnum); - -int traceframe_read_sdata (int tfnum, ULONGEST offset, - unsigned char *buf, ULONGEST length, - ULONGEST *nbytes); - -int traceframe_read_info (int tfnum, struct buffer *buffer); - -/* If a thread is determined to be collecting a fast tracepoint, this - structure holds the collect status. */ - -struct fast_tpoint_collect_status -{ - /* The tracepoint that is presently being collected. */ - int tpoint_num; - CORE_ADDR tpoint_addr; - - /* The address range in the jump pad of where the original - instruction the tracepoint jump was inserted was relocated - to. */ - CORE_ADDR adjusted_insn_addr; - CORE_ADDR adjusted_insn_addr_end; -}; - -/* The possible states a thread can be in, related to the collection of fast - tracepoint. */ - -enum class fast_tpoint_collect_result -{ - /* Not collecting a fast tracepoint. */ - not_collecting, - - /* In the jump pad, but before the relocated instruction. */ - before_insn, - - /* In the jump pad, but at (or after) the relocated instruction. */ - at_insn, -}; - -fast_tpoint_collect_result fast_tracepoint_collecting - (CORE_ADDR thread_area, CORE_ADDR stop_pc, - struct fast_tpoint_collect_status *status); - -void force_unlock_trace_buffer (void); - -int handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc); - -#ifdef IN_PROCESS_AGENT -void initialize_low_tracepoint (void); -const struct target_desc *get_ipa_tdesc (int idx); -void supply_fast_tracepoint_registers (struct regcache *regcache, - const unsigned char *regs); -void supply_static_tracepoint_registers (struct regcache *regcache, - const unsigned char *regs, - CORE_ADDR pc); -void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, - char *errmsg); -void *alloc_jump_pad_buffer (size_t size); -#ifndef HAVE_GETAUXVAL -unsigned long getauxval (unsigned long type); -#endif -#else -void stop_tracing (void); - -int claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline); -int have_fast_tracepoint_trampoline_buffer (char *msgbuf); -void gdb_agent_about_to_close (int pid); -#endif - -struct traceframe; -struct eval_agent_expr_context; - -/* Do memory copies for bytecodes. */ -/* Do the recording of memory blocks for actions and bytecodes. */ - -int agent_mem_read (struct eval_agent_expr_context *ctx, - unsigned char *to, CORE_ADDR from, - ULONGEST len); - -LONGEST agent_get_trace_state_variable_value (int num); -void agent_set_trace_state_variable_value (int num, LONGEST val); - -/* Record the value of a trace state variable. */ - -int agent_tsv_read (struct eval_agent_expr_context *ctx, int n); -int agent_mem_read_string (struct eval_agent_expr_context *ctx, - unsigned char *to, - CORE_ADDR from, - ULONGEST len); - -/* The prototype the get_raw_reg function in the IPA. Each arch's - bytecode compiler emits calls to this function. */ -ULONGEST get_raw_reg (const unsigned char *raw_regs, int regnum); - -/* Returns the address of the get_raw_reg function in the IPA. */ -CORE_ADDR get_raw_reg_func_addr (void); -/* Returns the address of the get_trace_state_variable_value - function in the IPA. */ -CORE_ADDR get_get_tsv_func_addr (void); -/* Returns the address of the set_trace_state_variable_value - function in the IPA. */ -CORE_ADDR get_set_tsv_func_addr (void); - -#endif /* GDBSERVER_TRACEPOINT_H */ diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c deleted file mode 100644 index d88f4ac5ca7..00000000000 --- a/gdb/gdbserver/utils.c +++ /dev/null @@ -1,127 +0,0 @@ -/* General utility routines for the remote server for GDB. - Copyright (C) 1986-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" - -#ifdef IN_PROCESS_AGENT -# define PREFIX "ipa: " -# define TOOLNAME "GDBserver in-process agent" -#else -# define PREFIX "gdbserver: " -# define TOOLNAME "GDBserver" -#endif - -/* Generally useful subroutines used throughout the program. */ - -void -malloc_failure (long size) -{ - fprintf (stderr, - PREFIX "ran out of memory while trying to allocate %lu bytes\n", - (unsigned long) size); - exit (1); -} - -/* Print the system error message for errno, and also mention STRING - as the file name for which the error was encountered. - Then return to command level. */ - -void -perror_with_name (const char *string) -{ - const char *err; - char *combined; - - err = safe_strerror (errno); - if (err == NULL) - err = "unknown error"; - - combined = (char *) alloca (strlen (err) + strlen (string) + 3); - strcpy (combined, string); - strcat (combined, ": "); - strcat (combined, err); - - error ("%s.", combined); -} - -/* Print an error message and return to top level. */ - -void -verror (const char *string, va_list args) -{ -#ifdef IN_PROCESS_AGENT - fflush (stdout); - vfprintf (stderr, string, args); - fprintf (stderr, "\n"); - exit (1); -#else - throw_verror (GENERIC_ERROR, string, args); -#endif -} - -void -vwarning (const char *string, va_list args) -{ - fprintf (stderr, PREFIX); - vfprintf (stderr, string, args); - fprintf (stderr, "\n"); -} - -/* Report a problem internal to GDBserver, and exit. */ - -void -internal_verror (const char *file, int line, const char *fmt, va_list args) -{ - fprintf (stderr, "\ -%s:%d: A problem internal to " TOOLNAME " has been detected.\n", file, line); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - exit (1); -} - -/* Report a problem internal to GDBserver. */ - -void -internal_vwarning (const char *file, int line, const char *fmt, va_list args) -{ - fprintf (stderr, "\ -%s:%d: A problem internal to " TOOLNAME " has been detected.\n", file, line); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); -} - -/* Convert a CORE_ADDR into a HEX string, like %lx. - The result is stored in a circular static buffer, NUMCELLS deep. */ - -char * -paddress (CORE_ADDR addr) -{ - return phex_nz (addr, sizeof (CORE_ADDR)); -} - -/* Convert a file descriptor into a printable string. */ - -char * -pfildes (gdb_fildes_t fd) -{ -#if USE_WIN32API - return phex_nz (fd, sizeof (gdb_fildes_t)); -#else - return plongest (fd); -#endif -} diff --git a/gdb/gdbserver/utils.h b/gdb/gdbserver/utils.h deleted file mode 100644 index fa3ca9bb945..00000000000 --- a/gdb/gdbserver/utils.h +++ /dev/null @@ -1,25 +0,0 @@ -/* General utility routines for the remote server for GDB. - Copyright (C) 1993-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_UTILS_H -#define GDBSERVER_UTILS_H - -char *paddress (CORE_ADDR addr); -char *pfildes (gdb_fildes_t fd); - -#endif /* GDBSERVER_UTILS_H */ diff --git a/gdb/gdbserver/win32-arm-low.c b/gdb/gdbserver/win32-arm-low.c deleted file mode 100644 index 619847d10fc..00000000000 --- a/gdb/gdbserver/win32-arm-low.c +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "win32-low.h" - -#ifndef CONTEXT_FLOATING_POINT -#define CONTEXT_FLOATING_POINT 0 -#endif - -/* Defined in auto-generated file reg-arm.c. */ -void init_registers_arm (void); -extern const struct target_desc *tdesc_arm; - -static void -arm_get_thread_context (win32_thread_info *th) -{ - th->context.ContextFlags = \ - CONTEXT_FULL | \ - CONTEXT_FLOATING_POINT; - - GetThreadContext (th->h, &th->context); -} - -#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) -static const int mappings[] = { - context_offset (R0), - context_offset (R1), - context_offset (R2), - context_offset (R3), - context_offset (R4), - context_offset (R5), - context_offset (R6), - context_offset (R7), - context_offset (R8), - context_offset (R9), - context_offset (R10), - context_offset (R11), - context_offset (R12), - context_offset (Sp), - context_offset (Lr), - context_offset (Pc), - -1, /* f0 */ - -1, /* f1 */ - -1, /* f2 */ - -1, /* f3 */ - -1, /* f4 */ - -1, /* f5 */ - -1, /* f6 */ - -1, /* f7 */ - -1, /* fps */ - context_offset (Psr), -}; -#undef context_offset - -/* Return a pointer into a CONTEXT field indexed by gdb register number. - Return a pointer to an dummy register holding zero if there is no - corresponding CONTEXT field for the given register number. */ -static char * -regptr (CONTEXT* c, int r) -{ - if (mappings[r] < 0) - { - static ULONG zero; - /* Always force value to zero, in case the user tried to write - to this register before. */ - zero = 0; - return (char *) &zero; - } - else - return (char *) c + mappings[r]; -} - -/* Fetch register from gdbserver regcache data. */ -static void -arm_fetch_inferior_register (struct regcache *regcache, - win32_thread_info *th, int r) -{ - char *context_offset = regptr (&th->context, r); - supply_register (regcache, r, context_offset); -} - -/* Store a new register value into the thread context of TH. */ -static void -arm_store_inferior_register (struct regcache *regcache, - win32_thread_info *th, int r) -{ - collect_register (regcache, r, regptr (&th->context, r)); -} - -static void -arm_arch_setup (void) -{ - init_registers_arm (); - win32_tdesc = tdesc_arm; -} - -/* Correct in either endianness. We do not support Thumb yet. */ -static const unsigned long arm_wince_breakpoint = 0xe6000010; -#define arm_wince_breakpoint_len 4 - -struct win32_target_ops the_low_target = { - arm_arch_setup, - sizeof (mappings) / sizeof (mappings[0]), - NULL, /* initial_stuff */ - arm_get_thread_context, - NULL, /* prepare_to_resume */ - NULL, /* thread_added */ - arm_fetch_inferior_register, - arm_store_inferior_register, - NULL, /* single_step */ - (const unsigned char *) &arm_wince_breakpoint, - arm_wince_breakpoint_len, - /* Watchpoint related functions. See target.h for comments. */ - NULL, /* supports_z_point_type */ - NULL, /* insert_point */ - NULL, /* remove_point */ - NULL, /* stopped_by_watchpoint */ - NULL /* stopped_data_address */ -}; diff --git a/gdb/gdbserver/win32-i386-low.c b/gdb/gdbserver/win32-i386-low.c deleted file mode 100644 index f5f09e96a57..00000000000 --- a/gdb/gdbserver/win32-i386-low.c +++ /dev/null @@ -1,468 +0,0 @@ -/* Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "win32-low.h" -#include "x86-low.h" -#include "gdbsupport/x86-xstate.h" -#ifdef __x86_64__ -#include "arch/amd64.h" -#endif -#include "arch/i386.h" -#include "tdesc.h" -#include "x86-tdesc.h" - -#ifndef CONTEXT_EXTENDED_REGISTERS -#define CONTEXT_EXTENDED_REGISTERS 0 -#endif - -#define FCS_REGNUM 27 -#define FOP_REGNUM 31 - -#define FLAG_TRACE_BIT 0x100 - -static struct x86_debug_reg_state debug_reg_state; - -static void -update_debug_registers (thread_info *thread) -{ - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); - - /* The actual update is done later just before resuming the lwp, - we just mark that the registers need updating. */ - th->debug_registers_changed = 1; -} - -/* Update the inferior's debug register REGNUM from STATE. */ - -static void -x86_dr_low_set_addr (int regnum, CORE_ADDR addr) -{ - gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); - - /* Only update the threads of this process. */ - for_each_thread (current_thread->id.pid (), update_debug_registers); -} - -/* Update the inferior's DR7 debug control register from STATE. */ - -static void -x86_dr_low_set_control (unsigned long control) -{ - /* Only update the threads of this process. */ - for_each_thread (current_thread->id.pid (), update_debug_registers); -} - -/* Return the current value of a DR register of the current thread's - context. */ - -static DWORD64 -win32_get_current_dr (int dr) -{ - win32_thread_info *th - = (win32_thread_info *) thread_target_data (current_thread); - - win32_require_context (th); - -#define RET_DR(DR) \ - case DR: \ - return th->context.Dr ## DR - - switch (dr) - { - RET_DR (0); - RET_DR (1); - RET_DR (2); - RET_DR (3); - RET_DR (6); - RET_DR (7); - } - -#undef RET_DR - - gdb_assert_not_reached ("unhandled dr"); -} - -static CORE_ADDR -x86_dr_low_get_addr (int regnum) -{ - gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); - - return win32_get_current_dr (regnum - DR_FIRSTADDR); -} - -static unsigned long -x86_dr_low_get_control (void) -{ - return win32_get_current_dr (7); -} - -/* Get the value of the DR6 debug status register from the inferior - and record it in STATE. */ - -static unsigned long -x86_dr_low_get_status (void) -{ - return win32_get_current_dr (6); -} - -/* Low-level function vector. */ -struct x86_dr_low_type x86_dr_low = - { - x86_dr_low_set_control, - x86_dr_low_set_addr, - x86_dr_low_get_addr, - x86_dr_low_get_status, - x86_dr_low_get_control, - sizeof (void *), - }; - -/* Breakpoint/watchpoint support. */ - -static int -i386_supports_z_point_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_WRITE_WP: - case Z_PACKET_ACCESS_WP: - return 1; - default: - return 0; - } -} - -static int -i386_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - switch (type) - { - case raw_bkpt_type_write_wp: - case raw_bkpt_type_access_wp: - { - enum target_hw_bp_type hw_type - = raw_bkpt_type_to_target_hw_bp_type (type); - - return x86_dr_insert_watchpoint (&debug_reg_state, - hw_type, addr, size); - } - default: - /* Unsupported. */ - return 1; - } -} - -static int -i386_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - switch (type) - { - case raw_bkpt_type_write_wp: - case raw_bkpt_type_access_wp: - { - enum target_hw_bp_type hw_type - = raw_bkpt_type_to_target_hw_bp_type (type); - - return x86_dr_remove_watchpoint (&debug_reg_state, - hw_type, addr, size); - } - default: - /* Unsupported. */ - return 1; - } -} - -static int -x86_stopped_by_watchpoint (void) -{ - return x86_dr_stopped_by_watchpoint (&debug_reg_state); -} - -static CORE_ADDR -x86_stopped_data_address (void) -{ - CORE_ADDR addr; - if (x86_dr_stopped_data_address (&debug_reg_state, &addr)) - return addr; - return 0; -} - -static void -i386_initial_stuff (void) -{ - x86_low_init_dregs (&debug_reg_state); -} - -static void -i386_get_thread_context (win32_thread_info *th) -{ - /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if - the system doesn't support extended registers. */ - static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS; - - again: - th->context.ContextFlags = (CONTEXT_FULL - | CONTEXT_FLOATING_POINT - | CONTEXT_DEBUG_REGISTERS - | extended_registers); - - if (!GetThreadContext (th->h, &th->context)) - { - DWORD e = GetLastError (); - - if (extended_registers && e == ERROR_INVALID_PARAMETER) - { - extended_registers = 0; - goto again; - } - - error ("GetThreadContext failure %ld\n", (long) e); - } -} - -static void -i386_prepare_to_resume (win32_thread_info *th) -{ - if (th->debug_registers_changed) - { - struct x86_debug_reg_state *dr = &debug_reg_state; - - win32_require_context (th); - - th->context.Dr0 = dr->dr_mirror[0]; - th->context.Dr1 = dr->dr_mirror[1]; - th->context.Dr2 = dr->dr_mirror[2]; - th->context.Dr3 = dr->dr_mirror[3]; - /* th->context.Dr6 = dr->dr_status_mirror; - FIXME: should we set dr6 also ?? */ - th->context.Dr7 = dr->dr_control_mirror; - - th->debug_registers_changed = 0; - } -} - -static void -i386_thread_added (win32_thread_info *th) -{ - th->debug_registers_changed = 1; -} - -static void -i386_single_step (win32_thread_info *th) -{ - th->context.EFlags |= FLAG_TRACE_BIT; -} - -#ifndef __x86_64__ - -/* An array of offset mappings into a Win32 Context structure. - This is a one-to-one mapping which is indexed by gdb's register - numbers. It retrieves an offset into the context structure where - the 4 byte register is located. - An offset value of -1 indicates that Win32 does not provide this - register in it's CONTEXT structure. In this case regptr will return - a pointer into a dummy register. */ -#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) -static const int mappings[] = { - context_offset (Eax), - context_offset (Ecx), - context_offset (Edx), - context_offset (Ebx), - context_offset (Esp), - context_offset (Ebp), - context_offset (Esi), - context_offset (Edi), - context_offset (Eip), - context_offset (EFlags), - context_offset (SegCs), - context_offset (SegSs), - context_offset (SegDs), - context_offset (SegEs), - context_offset (SegFs), - context_offset (SegGs), - context_offset (FloatSave.RegisterArea[0 * 10]), - context_offset (FloatSave.RegisterArea[1 * 10]), - context_offset (FloatSave.RegisterArea[2 * 10]), - context_offset (FloatSave.RegisterArea[3 * 10]), - context_offset (FloatSave.RegisterArea[4 * 10]), - context_offset (FloatSave.RegisterArea[5 * 10]), - context_offset (FloatSave.RegisterArea[6 * 10]), - context_offset (FloatSave.RegisterArea[7 * 10]), - context_offset (FloatSave.ControlWord), - context_offset (FloatSave.StatusWord), - context_offset (FloatSave.TagWord), - context_offset (FloatSave.ErrorSelector), - context_offset (FloatSave.ErrorOffset), - context_offset (FloatSave.DataSelector), - context_offset (FloatSave.DataOffset), - context_offset (FloatSave.ErrorSelector), - /* XMM0-7 */ - context_offset (ExtendedRegisters[10 * 16]), - context_offset (ExtendedRegisters[11 * 16]), - context_offset (ExtendedRegisters[12 * 16]), - context_offset (ExtendedRegisters[13 * 16]), - context_offset (ExtendedRegisters[14 * 16]), - context_offset (ExtendedRegisters[15 * 16]), - context_offset (ExtendedRegisters[16 * 16]), - context_offset (ExtendedRegisters[17 * 16]), - /* MXCSR */ - context_offset (ExtendedRegisters[24]) -}; -#undef context_offset - -#else /* __x86_64__ */ - -#define context_offset(x) (offsetof (CONTEXT, x)) -static const int mappings[] = -{ - context_offset (Rax), - context_offset (Rbx), - context_offset (Rcx), - context_offset (Rdx), - context_offset (Rsi), - context_offset (Rdi), - context_offset (Rbp), - context_offset (Rsp), - context_offset (R8), - context_offset (R9), - context_offset (R10), - context_offset (R11), - context_offset (R12), - context_offset (R13), - context_offset (R14), - context_offset (R15), - context_offset (Rip), - context_offset (EFlags), - context_offset (SegCs), - context_offset (SegSs), - context_offset (SegDs), - context_offset (SegEs), - context_offset (SegFs), - context_offset (SegGs), - context_offset (FloatSave.FloatRegisters[0]), - context_offset (FloatSave.FloatRegisters[1]), - context_offset (FloatSave.FloatRegisters[2]), - context_offset (FloatSave.FloatRegisters[3]), - context_offset (FloatSave.FloatRegisters[4]), - context_offset (FloatSave.FloatRegisters[5]), - context_offset (FloatSave.FloatRegisters[6]), - context_offset (FloatSave.FloatRegisters[7]), - context_offset (FloatSave.ControlWord), - context_offset (FloatSave.StatusWord), - context_offset (FloatSave.TagWord), - context_offset (FloatSave.ErrorSelector), - context_offset (FloatSave.ErrorOffset), - context_offset (FloatSave.DataSelector), - context_offset (FloatSave.DataOffset), - context_offset (FloatSave.ErrorSelector) - /* XMM0-7 */ , - context_offset (Xmm0), - context_offset (Xmm1), - context_offset (Xmm2), - context_offset (Xmm3), - context_offset (Xmm4), - context_offset (Xmm5), - context_offset (Xmm6), - context_offset (Xmm7), - context_offset (Xmm8), - context_offset (Xmm9), - context_offset (Xmm10), - context_offset (Xmm11), - context_offset (Xmm12), - context_offset (Xmm13), - context_offset (Xmm14), - context_offset (Xmm15), - /* MXCSR */ - context_offset (FloatSave.MxCsr) -}; -#undef context_offset - -#endif /* __x86_64__ */ - -/* Fetch register from gdbserver regcache data. */ -static void -i386_fetch_inferior_register (struct regcache *regcache, - win32_thread_info *th, int r) -{ - char *context_offset = (char *) &th->context + mappings[r]; - - long l; - if (r == FCS_REGNUM) - { - l = *((long *) context_offset) & 0xffff; - supply_register (regcache, r, (char *) &l); - } - else if (r == FOP_REGNUM) - { - l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); - supply_register (regcache, r, (char *) &l); - } - else - supply_register (regcache, r, context_offset); -} - -/* Store a new register value into the thread context of TH. */ -static void -i386_store_inferior_register (struct regcache *regcache, - win32_thread_info *th, int r) -{ - char *context_offset = (char *) &th->context + mappings[r]; - collect_register (regcache, r, context_offset); -} - -static const unsigned char i386_win32_breakpoint = 0xcc; -#define i386_win32_breakpoint_len 1 - -static void -i386_arch_setup (void) -{ - struct target_desc *tdesc; - -#ifdef __x86_64__ - tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false, - false, false); - const char **expedite_regs = amd64_expedite_regs; -#else - tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); - const char **expedite_regs = i386_expedite_regs; -#endif - - init_target_desc (tdesc, expedite_regs); - - win32_tdesc = tdesc; -} - -struct win32_target_ops the_low_target = { - i386_arch_setup, - sizeof (mappings) / sizeof (mappings[0]), - i386_initial_stuff, - i386_get_thread_context, - i386_prepare_to_resume, - i386_thread_added, - i386_fetch_inferior_register, - i386_store_inferior_register, - i386_single_step, - &i386_win32_breakpoint, - i386_win32_breakpoint_len, - i386_supports_z_point_type, - i386_insert_point, - i386_remove_point, - x86_stopped_by_watchpoint, - x86_stopped_data_address -}; diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c deleted file mode 100644 index 2c4a9b1074b..00000000000 --- a/gdb/gdbserver/win32-low.c +++ /dev/null @@ -1,1882 +0,0 @@ -/* Low level interface to Windows debugging, for gdbserver. - Copyright (C) 2006-2020 Free Software Foundation, Inc. - - Contributed by Leo Zayas. Based on "win32-nat.c" from GDB. - - 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 3 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, see . */ - -#include "server.h" -#include "regcache.h" -#include "gdb/fileio.h" -#include "mem-break.h" -#include "win32-low.h" -#include "gdbthread.h" -#include "dll.h" -#include "hostio.h" -#include -#include -#include -#include -#include -#include -#include "gdbsupport/gdb_tilde_expand.h" -#include "gdbsupport/common-inferior.h" -#include "gdbsupport/gdb_wait.h" - -#ifndef USE_WIN32API -#include -#endif - -#define OUTMSG(X) do { printf X; fflush (stderr); } while (0) - -#define OUTMSG2(X) \ - do \ - { \ - if (debug_threads) \ - { \ - printf X; \ - fflush (stderr); \ - } \ - } while (0) - -#ifndef _T -#define _T(x) TEXT (x) -#endif - -#ifndef COUNTOF -#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0])) -#endif - -#ifdef _WIN32_WCE -# define GETPROCADDRESS(DLL, PROC) \ - ((winapi_ ## PROC) GetProcAddress (DLL, TEXT (#PROC))) -#else -# define GETPROCADDRESS(DLL, PROC) \ - ((winapi_ ## PROC) GetProcAddress (DLL, #PROC)) -#endif - -int using_threads = 1; - -/* Globals. */ -static int attaching = 0; -static HANDLE current_process_handle = NULL; -static DWORD current_process_id = 0; -static DWORD main_thread_id = 0; -static enum gdb_signal last_sig = GDB_SIGNAL_0; - -/* The current debug event from WaitForDebugEvent. */ -static DEBUG_EVENT current_event; - -/* A status that hasn't been reported to the core yet, and so - win32_wait should return it next, instead of fetching the next - debug event off the win32 API. */ -static struct target_waitstatus cached_status; - -/* Non zero if an interrupt request is to be satisfied by suspending - all threads. */ -static int soft_interrupt_requested = 0; - -/* Non zero if the inferior is stopped in a simulated breakpoint done - by suspending all the threads. */ -static int faked_breakpoint = 0; - -const struct target_desc *win32_tdesc; - -#define NUM_REGS (the_low_target.num_regs) - -typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId); -typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit); -typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE); -typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD); - -static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, - int options); -static void win32_resume (struct thread_resume *resume_info, size_t n); -#ifndef _WIN32_WCE -static void win32_add_all_dlls (void); -#endif - -/* Get the thread ID from the current selected inferior (the current - thread). */ -static ptid_t -current_thread_ptid (void) -{ - return current_ptid; -} - -/* The current debug event from WaitForDebugEvent. */ -static ptid_t -debug_event_ptid (DEBUG_EVENT *event) -{ - return ptid_t (event->dwProcessId, event->dwThreadId, 0); -} - -/* Get the thread context of the thread associated with TH. */ - -static void -win32_get_thread_context (win32_thread_info *th) -{ - memset (&th->context, 0, sizeof (CONTEXT)); - (*the_low_target.get_thread_context) (th); -#ifdef _WIN32_WCE - memcpy (&th->base_context, &th->context, sizeof (CONTEXT)); -#endif -} - -/* Set the thread context of the thread associated with TH. */ - -static void -win32_set_thread_context (win32_thread_info *th) -{ -#ifdef _WIN32_WCE - /* Calling SuspendThread on a thread that is running kernel code - will report that the suspending was successful, but in fact, that - will often not be true. In those cases, the context returned by - GetThreadContext will not be correct by the time the thread - stops, hence we can't set that context back into the thread when - resuming - it will most likely crash the inferior. - Unfortunately, there is no way to know when the thread will - really stop. To work around it, we'll only write the context - back to the thread when either the user or GDB explicitly change - it between stopping and resuming. */ - if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0) -#endif - SetThreadContext (th->h, &th->context); -} - -/* Set the thread context of the thread associated with TH. */ - -static void -win32_prepare_to_resume (win32_thread_info *th) -{ - if (the_low_target.prepare_to_resume != NULL) - (*the_low_target.prepare_to_resume) (th); -} - -/* See win32-low.h. */ - -void -win32_require_context (win32_thread_info *th) -{ - if (th->context.ContextFlags == 0) - { - if (!th->suspended) - { - if (SuspendThread (th->h) == (DWORD) -1) - { - DWORD err = GetLastError (); - OUTMSG (("warning: SuspendThread failed in thread_rec, " - "(error %d): %s\n", (int) err, strwinerror (err))); - } - else - th->suspended = 1; - } - - win32_get_thread_context (th); - } -} - -/* Find a thread record given a thread id. If GET_CONTEXT is set then - also retrieve the context for this thread. */ -static win32_thread_info * -thread_rec (ptid_t ptid, int get_context) -{ - thread_info *thread = find_thread_ptid (ptid); - if (thread == NULL) - return NULL; - - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); - if (get_context) - win32_require_context (th); - return th; -} - -/* Add a thread to the thread list. */ -static win32_thread_info * -child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) -{ - win32_thread_info *th; - ptid_t ptid = ptid_t (pid, tid, 0); - - if ((th = thread_rec (ptid, FALSE))) - return th; - - th = XCNEW (win32_thread_info); - th->tid = tid; - th->h = h; - th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; - - add_thread (ptid, th); - - if (the_low_target.thread_added != NULL) - (*the_low_target.thread_added) (th); - - return th; -} - -/* Delete a thread from the list of threads. */ -static void -delete_thread_info (thread_info *thread) -{ - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); - - remove_thread (thread); - CloseHandle (th->h); - free (th); -} - -/* Delete a thread from the list of threads. */ -static void -child_delete_thread (DWORD pid, DWORD tid) -{ - /* If the last thread is exiting, just return. */ - if (all_threads.size () == 1) - return; - - thread_info *thread = find_thread_ptid (ptid_t (pid, tid)); - if (thread == NULL) - return; - - delete_thread_info (thread); -} - -/* These watchpoint related wrapper functions simply pass on the function call - if the low target has registered a corresponding function. */ - -static int -win32_supports_z_point_type (char z_type) -{ - return (the_low_target.supports_z_point_type != NULL - && the_low_target.supports_z_point_type (z_type)); -} - -static int -win32_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - if (the_low_target.insert_point != NULL) - return the_low_target.insert_point (type, addr, size, bp); - else - /* Unsupported (see target.h). */ - return 1; -} - -static int -win32_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp) -{ - if (the_low_target.remove_point != NULL) - return the_low_target.remove_point (type, addr, size, bp); - else - /* Unsupported (see target.h). */ - return 1; -} - -static int -win32_stopped_by_watchpoint (void) -{ - if (the_low_target.stopped_by_watchpoint != NULL) - return the_low_target.stopped_by_watchpoint (); - else - return 0; -} - -static CORE_ADDR -win32_stopped_data_address (void) -{ - if (the_low_target.stopped_data_address != NULL) - return the_low_target.stopped_data_address (); - else - return 0; -} - - -/* Transfer memory from/to the debugged process. */ -static int -child_xfer_memory (CORE_ADDR memaddr, char *our, int len, - int write, process_stratum_target *target) -{ - BOOL success; - SIZE_T done = 0; - DWORD lasterror = 0; - uintptr_t addr = (uintptr_t) memaddr; - - if (write) - { - success = WriteProcessMemory (current_process_handle, (LPVOID) addr, - (LPCVOID) our, len, &done); - if (!success) - lasterror = GetLastError (); - FlushInstructionCache (current_process_handle, (LPCVOID) addr, len); - } - else - { - success = ReadProcessMemory (current_process_handle, (LPCVOID) addr, - (LPVOID) our, len, &done); - if (!success) - lasterror = GetLastError (); - } - if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) - return done; - else - return success ? done : -1; -} - -/* Clear out any old thread list and reinitialize it to a pristine - state. */ -static void -child_init_thread_list (void) -{ - for_each_thread (delete_thread_info); -} - -/* Zero during the child initialization phase, and nonzero otherwise. */ - -static int child_initialization_done = 0; - -static void -do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) -{ - struct process_info *proc; - - last_sig = GDB_SIGNAL_0; - - current_process_handle = proch; - current_process_id = pid; - main_thread_id = 0; - - soft_interrupt_requested = 0; - faked_breakpoint = 0; - - memset (¤t_event, 0, sizeof (current_event)); - - proc = add_process (pid, attached); - proc->tdesc = win32_tdesc; - child_init_thread_list (); - child_initialization_done = 0; - - if (the_low_target.initial_stuff != NULL) - (*the_low_target.initial_stuff) (); - - cached_status.kind = TARGET_WAITKIND_IGNORE; - - /* Flush all currently pending debug events (thread and dll list) up - to the initial breakpoint. */ - while (1) - { - struct target_waitstatus status; - - win32_wait (minus_one_ptid, &status, 0); - - /* Note win32_wait doesn't return thread events. */ - if (status.kind != TARGET_WAITKIND_LOADED) - { - cached_status = status; - break; - } - - { - struct thread_resume resume; - - resume.thread = minus_one_ptid; - resume.kind = resume_continue; - resume.sig = 0; - - win32_resume (&resume, 1); - } - } - -#ifndef _WIN32_WCE - /* Now that the inferior has been started and all DLLs have been mapped, - we can iterate over all DLLs and load them in. - - We avoid doing it any earlier because, on certain versions of Windows, - LOAD_DLL_DEBUG_EVENTs are sometimes not complete. In particular, - we have seen on Windows 8.1 that the ntdll.dll load event does not - include the DLL name, preventing us from creating an associated SO. - A possible explanation is that ntdll.dll might be mapped before - the SO info gets created by the Windows system -- ntdll.dll is - the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs - do not seem to suffer from that problem. - - Rather than try to work around this sort of issue, it is much - simpler to just ignore DLL load/unload events during the startup - phase, and then process them all in one batch now. */ - win32_add_all_dlls (); -#endif - - child_initialization_done = 1; -} - -/* Resume all artificially suspended threads if we are continuing - execution. */ -static void -continue_one_thread (thread_info *thread, int thread_id) -{ - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); - - if (thread_id == -1 || thread_id == th->tid) - { - win32_prepare_to_resume (th); - - if (th->suspended) - { - if (th->context.ContextFlags) - { - win32_set_thread_context (th); - th->context.ContextFlags = 0; - } - - if (ResumeThread (th->h) == (DWORD) -1) - { - DWORD err = GetLastError (); - OUTMSG (("warning: ResumeThread failed in continue_one_thread, " - "(error %d): %s\n", (int) err, strwinerror (err))); - } - th->suspended = 0; - } - } -} - -static BOOL -child_continue (DWORD continue_status, int thread_id) -{ - /* The inferior will only continue after the ContinueDebugEvent - call. */ - for_each_thread ([&] (thread_info *thread) - { - continue_one_thread (thread, thread_id); - }); - faked_breakpoint = 0; - - if (!ContinueDebugEvent (current_event.dwProcessId, - current_event.dwThreadId, - continue_status)) - return FALSE; - - return TRUE; -} - -/* Fetch register(s) from the current thread context. */ -static void -child_fetch_inferior_registers (struct regcache *regcache, int r) -{ - int regno; - win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE); - if (r == -1 || r > NUM_REGS) - child_fetch_inferior_registers (regcache, NUM_REGS); - else - for (regno = 0; regno < r; regno++) - (*the_low_target.fetch_inferior_register) (regcache, th, regno); -} - -/* Store a new register value into the current thread context. We don't - change the program's context until later, when we resume it. */ -static void -child_store_inferior_registers (struct regcache *regcache, int r) -{ - int regno; - win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE); - if (r == -1 || r == 0 || r > NUM_REGS) - child_store_inferior_registers (regcache, NUM_REGS); - else - for (regno = 0; regno < r; regno++) - (*the_low_target.store_inferior_register) (regcache, th, regno); -} - -/* Map the Windows error number in ERROR to a locale-dependent error - message string and return a pointer to it. Typically, the values - for ERROR come from GetLastError. - - The string pointed to shall not be modified by the application, - but may be overwritten by a subsequent call to strwinerror - - The strwinerror function does not change the current setting - of GetLastError. */ - -char * -strwinerror (DWORD error) -{ - static char buf[1024]; - TCHAR *msgbuf; - DWORD lasterr = GetLastError (); - DWORD chars = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_ALLOCATE_BUFFER, - NULL, - error, - 0, /* Default language */ - (LPTSTR) &msgbuf, - 0, - NULL); - if (chars != 0) - { - /* If there is an \r\n appended, zap it. */ - if (chars >= 2 - && msgbuf[chars - 2] == '\r' - && msgbuf[chars - 1] == '\n') - { - chars -= 2; - msgbuf[chars] = 0; - } - - if (chars > ((COUNTOF (buf)) - 1)) - { - chars = COUNTOF (buf) - 1; - msgbuf [chars] = 0; - } - -#ifdef UNICODE - wcstombs (buf, msgbuf, chars + 1); -#else - strncpy (buf, msgbuf, chars + 1); -#endif - LocalFree (msgbuf); - } - else - sprintf (buf, "unknown win32 error (%u)", (unsigned) error); - - SetLastError (lasterr); - return buf; -} - -static BOOL -create_process (const char *program, char *args, - DWORD flags, PROCESS_INFORMATION *pi) -{ - const char *inferior_cwd = get_inferior_cwd (); - BOOL ret; - -#ifdef _WIN32_WCE - wchar_t *p, *wprogram, *wargs, *wcwd = NULL; - size_t argslen; - - wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t)); - mbstowcs (wprogram, program, strlen (program) + 1); - - for (p = wprogram; *p; ++p) - if (L'/' == *p) - *p = L'\\'; - - argslen = strlen (args); - wargs = alloca ((argslen + 1) * sizeof (wchar_t)); - mbstowcs (wargs, args, argslen + 1); - - if (inferior_cwd != NULL) - { - std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd); - std::replace (expanded_infcwd.begin (), expanded_infcwd.end (), - '/', '\\'); - wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t)); - if (mbstowcs (wcwd, expanded_infcwd.c_str (), - expanded_infcwd.size () + 1) == NULL) - { - error (_("\ -Could not convert the expanded inferior cwd to wide-char.")); - } - } - - ret = CreateProcessW (wprogram, /* image name */ - wargs, /* command line */ - NULL, /* security, not supported */ - NULL, /* thread, not supported */ - FALSE, /* inherit handles, not supported */ - flags, /* start flags */ - NULL, /* environment, not supported */ - wcwd, /* current directory */ - NULL, /* start info, not supported */ - pi); /* proc info */ -#else - STARTUPINFOA si = { sizeof (STARTUPINFOA) }; - - ret = CreateProcessA (program, /* image name */ - args, /* command line */ - NULL, /* security */ - NULL, /* thread */ - TRUE, /* inherit handles */ - flags, /* start flags */ - NULL, /* environment */ - /* current directory */ - (inferior_cwd == NULL - ? NULL - : gdb_tilde_expand (inferior_cwd).c_str()), - &si, /* start info */ - pi); /* proc info */ -#endif - - return ret; -} - -/* Start a new process. - PROGRAM is the program name. - PROGRAM_ARGS is the vector containing the inferior's args. - Returns the new PID on success, -1 on failure. Registers the new - process with the process list. */ -static int -win32_create_inferior (const char *program, - const std::vector &program_args) -{ - client_state &cs = get_client_state (); -#ifndef USE_WIN32API - char real_path[PATH_MAX]; - char *orig_path, *new_path, *path_ptr; -#endif - BOOL ret; - DWORD flags; - PROCESS_INFORMATION pi; - DWORD err; - std::string str_program_args = stringify_argv (program_args); - char *args = (char *) str_program_args.c_str (); - - /* win32_wait needs to know we're not attaching. */ - attaching = 0; - - if (!program) - error ("No executable specified, specify executable to debug.\n"); - - flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; - -#ifndef USE_WIN32API - orig_path = NULL; - path_ptr = getenv ("PATH"); - if (path_ptr) - { - int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0); - orig_path = (char *) alloca (strlen (path_ptr) + 1); - new_path = (char *) alloca (size); - strcpy (orig_path, path_ptr); - cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size); - setenv ("PATH", new_path, 1); - } - cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX); - program = real_path; -#endif - - OUTMSG2 (("Command line is \"%s\"\n", args)); - -#ifdef CREATE_NEW_PROCESS_GROUP - flags |= CREATE_NEW_PROCESS_GROUP; -#endif - - ret = create_process (program, args, flags, &pi); - err = GetLastError (); - if (!ret && err == ERROR_FILE_NOT_FOUND) - { - char *exename = (char *) alloca (strlen (program) + 5); - strcat (strcpy (exename, program), ".exe"); - ret = create_process (exename, args, flags, &pi); - err = GetLastError (); - } - -#ifndef USE_WIN32API - if (orig_path) - setenv ("PATH", orig_path, 1); -#endif - - if (!ret) - { - error ("Error creating process \"%s%s\", (error %d): %s\n", - program, args, (int) err, strwinerror (err)); - } - else - { - OUTMSG2 (("Process created: %s\n", (char *) args)); - } - -#ifndef _WIN32_WCE - /* On Windows CE this handle can't be closed. The OS reuses - it in the debug events, while the 9x/NT versions of Windows - probably use a DuplicateHandle'd one. */ - CloseHandle (pi.hThread); -#endif - - do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0); - - /* Wait till we are at 1st instruction in program, return new pid - (assuming success). */ - cs.last_ptid = win32_wait (ptid_t (current_process_id), &cs.last_status, 0); - - return current_process_id; -} - -/* Attach to a running process. - PID is the process ID to attach to, specified by the user - or a higher layer. */ -static int -win32_attach (unsigned long pid) -{ - HANDLE h; - winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; - DWORD err; -#ifdef _WIN32_WCE - HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); -#else - HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); -#endif - DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit); - - h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); - if (h != NULL) - { - if (DebugActiveProcess (pid)) - { - if (DebugSetProcessKillOnExit != NULL) - DebugSetProcessKillOnExit (FALSE); - - /* win32_wait needs to know we're attaching. */ - attaching = 1; - do_initial_child_stuff (h, pid, 1); - return 0; - } - - CloseHandle (h); - } - - err = GetLastError (); - error ("Attach to process failed (error %d): %s\n", - (int) err, strwinerror (err)); -} - -/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */ -static void -handle_output_debug_string (void) -{ -#define READ_BUFFER_LEN 1024 - CORE_ADDR addr; - char s[READ_BUFFER_LEN + 1] = { 0 }; - DWORD nbytes = current_event.u.DebugString.nDebugStringLength; - - if (nbytes == 0) - return; - - if (nbytes > READ_BUFFER_LEN) - nbytes = READ_BUFFER_LEN; - - addr = (CORE_ADDR) (size_t) current_event.u.DebugString.lpDebugStringData; - - if (current_event.u.DebugString.fUnicode) - { - /* The event tells us how many bytes, not chars, even - in Unicode. */ - WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 }; - if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0) - return; - wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR)); - } - else - { - if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0) - return; - } - - if (!startswith (s, "cYg")) - { - if (!server_waiting) - { - OUTMSG2(("%s", s)); - return; - } - - monitor_output (s); - } -#undef READ_BUFFER_LEN -} - -static void -win32_clear_inferiors (void) -{ - if (current_process_handle != NULL) - CloseHandle (current_process_handle); - - for_each_thread (delete_thread_info); - clear_inferiors (); -} - -/* Implementation of target_ops::kill. */ - -static int -win32_kill (process_info *process) -{ - TerminateProcess (current_process_handle, 0); - for (;;) - { - if (!child_continue (DBG_CONTINUE, -1)) - break; - if (!WaitForDebugEvent (¤t_event, INFINITE)) - break; - if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) - break; - else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) - handle_output_debug_string (); - } - - win32_clear_inferiors (); - - remove_process (process); - return 0; -} - -/* Implementation of target_ops::detach. */ - -static int -win32_detach (process_info *process) -{ - winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL; - winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; -#ifdef _WIN32_WCE - HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); -#else - HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); -#endif - DebugActiveProcessStop = GETPROCADDRESS (dll, DebugActiveProcessStop); - DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit); - - if (DebugSetProcessKillOnExit == NULL - || DebugActiveProcessStop == NULL) - return -1; - - { - struct thread_resume resume; - resume.thread = minus_one_ptid; - resume.kind = resume_continue; - resume.sig = 0; - win32_resume (&resume, 1); - } - - if (!DebugActiveProcessStop (current_process_id)) - return -1; - - DebugSetProcessKillOnExit (FALSE); - remove_process (process); - - win32_clear_inferiors (); - return 0; -} - -static void -win32_mourn (struct process_info *process) -{ - remove_process (process); -} - -/* Implementation of target_ops::join. */ - -static void -win32_join (int pid) -{ - HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); - if (h != NULL) - { - WaitForSingleObject (h, INFINITE); - CloseHandle (h); - } -} - -/* Return 1 iff the thread with thread ID TID is alive. */ -static int -win32_thread_alive (ptid_t ptid) -{ - /* Our thread list is reliable; don't bother to poll target - threads. */ - return find_thread_ptid (ptid) != NULL; -} - -/* Resume the inferior process. RESUME_INFO describes how we want - to resume. */ -static void -win32_resume (struct thread_resume *resume_info, size_t n) -{ - DWORD tid; - enum gdb_signal sig; - int step; - win32_thread_info *th; - DWORD continue_status = DBG_CONTINUE; - ptid_t ptid; - - /* This handles the very limited set of resume packets that GDB can - currently produce. */ - - if (n == 1 && resume_info[0].thread == minus_one_ptid) - tid = -1; - else if (n > 1) - tid = -1; - else - /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make - the Windows resume code do the right thing for thread switching. */ - tid = current_event.dwThreadId; - - if (resume_info[0].thread != minus_one_ptid) - { - sig = gdb_signal_from_host (resume_info[0].sig); - step = resume_info[0].kind == resume_step; - } - else - { - sig = GDB_SIGNAL_0; - step = 0; - } - - if (sig != GDB_SIGNAL_0) - { - if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) - { - OUTMSG (("Cannot continue with signal %s here.\n", - gdb_signal_to_string (sig))); - } - else if (sig == last_sig) - continue_status = DBG_EXCEPTION_NOT_HANDLED; - else - OUTMSG (("Can only continue with received signal %s.\n", - gdb_signal_to_string (last_sig))); - } - - last_sig = GDB_SIGNAL_0; - - /* Get context for the currently selected thread. */ - ptid = debug_event_ptid (¤t_event); - th = thread_rec (ptid, FALSE); - if (th) - { - win32_prepare_to_resume (th); - - if (th->context.ContextFlags) - { - /* Move register values from the inferior into the thread - context structure. */ - regcache_invalidate (); - - if (step) - { - if (the_low_target.single_step != NULL) - (*the_low_target.single_step) (th); - else - error ("Single stepping is not supported " - "in this configuration.\n"); - } - - win32_set_thread_context (th); - th->context.ContextFlags = 0; - } - } - - /* Allow continuing with the same signal that interrupted us. - Otherwise complain. */ - - child_continue (continue_status, tid); -} - -static void -win32_add_one_solib (const char *name, CORE_ADDR load_addr) -{ - char buf[MAX_PATH + 1]; - char buf2[MAX_PATH + 1]; - -#ifdef _WIN32_WCE - WIN32_FIND_DATA w32_fd; - WCHAR wname[MAX_PATH + 1]; - mbstowcs (wname, name, MAX_PATH); - HANDLE h = FindFirstFile (wname, &w32_fd); -#else - WIN32_FIND_DATAA w32_fd; - HANDLE h = FindFirstFileA (name, &w32_fd); -#endif - - /* The symbols in a dll are offset by 0x1000, which is the - offset from 0 of the first byte in an image - because - of the file header and the section alignment. */ - load_addr += 0x1000; - - if (h == INVALID_HANDLE_VALUE) - strcpy (buf, name); - else - { - FindClose (h); - strcpy (buf, name); -#ifndef _WIN32_WCE - { - char cwd[MAX_PATH + 1]; - char *p; - if (GetCurrentDirectoryA (MAX_PATH + 1, cwd)) - { - p = strrchr (buf, '\\'); - if (p) - p[1] = '\0'; - SetCurrentDirectoryA (buf); - GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p); - SetCurrentDirectoryA (cwd); - } - } -#endif - } - -#ifndef _WIN32_WCE - if (strcasecmp (buf, "ntdll.dll") == 0) - { - GetSystemDirectoryA (buf, sizeof (buf)); - strcat (buf, "\\ntdll.dll"); - } -#endif - -#ifdef __CYGWIN__ - cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2)); -#else - strcpy (buf2, buf); -#endif - - loaded_dll (buf2, load_addr); -} - -static char * -get_image_name (HANDLE h, void *address, int unicode) -{ - static char buf[(2 * MAX_PATH) + 1]; - DWORD size = unicode ? sizeof (WCHAR) : sizeof (char); - char *address_ptr; - int len = 0; - char b[2]; - SIZE_T done; - - /* Attempt to read the name of the dll that was detected. - This is documented to work only when actively debugging - a program. It will not work for attached processes. */ - if (address == NULL) - return NULL; - -#ifdef _WIN32_WCE - /* Windows CE reports the address of the image name, - instead of an address of a pointer into the image name. */ - address_ptr = address; -#else - /* See if we could read the address of a string, and that the - address isn't null. */ - if (!ReadProcessMemory (h, address, &address_ptr, - sizeof (address_ptr), &done) - || done != sizeof (address_ptr) - || !address_ptr) - return NULL; -#endif - - /* Find the length of the string */ - while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done) - && (b[0] != 0 || b[size - 1] != 0) && done == size) - continue; - - if (!unicode) - ReadProcessMemory (h, address_ptr, buf, len, &done); - else - { - WCHAR *unicode_address = XALLOCAVEC (WCHAR, len); - ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR), - &done); - - WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0); - } - - return buf; -} - -typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *, - DWORD, LPDWORD); -typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE, - LPMODULEINFO, DWORD); -typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE, - LPSTR, DWORD); - -static winapi_EnumProcessModules win32_EnumProcessModules; -static winapi_GetModuleInformation win32_GetModuleInformation; -static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA; - -static BOOL -load_psapi (void) -{ - static int psapi_loaded = 0; - static HMODULE dll = NULL; - - if (!psapi_loaded) - { - psapi_loaded = 1; - dll = LoadLibrary (TEXT("psapi.dll")); - if (!dll) - return FALSE; - win32_EnumProcessModules = - GETPROCADDRESS (dll, EnumProcessModules); - win32_GetModuleInformation = - GETPROCADDRESS (dll, GetModuleInformation); - win32_GetModuleFileNameExA = - GETPROCADDRESS (dll, GetModuleFileNameExA); - } - - return (win32_EnumProcessModules != NULL - && win32_GetModuleInformation != NULL - && win32_GetModuleFileNameExA != NULL); -} - -#ifndef _WIN32_WCE - -/* Iterate over all DLLs currently mapped by our inferior, and - add them to our list of solibs. */ - -static void -win32_add_all_dlls (void) -{ - size_t i; - HMODULE dh_buf[1]; - HMODULE *DllHandle = dh_buf; - DWORD cbNeeded; - BOOL ok; - - if (!load_psapi ()) - return; - - cbNeeded = 0; - ok = (*win32_EnumProcessModules) (current_process_handle, - DllHandle, - sizeof (HMODULE), - &cbNeeded); - - if (!ok || !cbNeeded) - return; - - DllHandle = (HMODULE *) alloca (cbNeeded); - if (!DllHandle) - return; - - ok = (*win32_EnumProcessModules) (current_process_handle, - DllHandle, - cbNeeded, - &cbNeeded); - if (!ok) - return; - - for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++) - { - MODULEINFO mi; - char dll_name[MAX_PATH]; - - if (!(*win32_GetModuleInformation) (current_process_handle, - DllHandle[i], - &mi, - sizeof (mi))) - continue; - if ((*win32_GetModuleFileNameExA) (current_process_handle, - DllHandle[i], - dll_name, - MAX_PATH) == 0) - continue; - win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll); - } -} -#endif - -typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD); -typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32); -typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32); - -/* Handle a DLL load event. - - This function assumes that this event did not occur during inferior - initialization, where their event info may be incomplete (see - do_initial_child_stuff and win32_add_all_dlls for more info on - how we handle DLL loading during that phase). */ - -static void -handle_load_dll (void) -{ - LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; - char *dll_name; - - dll_name = get_image_name (current_process_handle, - event->lpImageName, event->fUnicode); - if (!dll_name) - return; - - win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll); -} - -/* Handle a DLL unload event. - - This function assumes that this event did not occur during inferior - initialization, where their event info may be incomplete (see - do_initial_child_stuff and win32_add_one_solib for more info - on how we handle DLL loading during that phase). */ - -static void -handle_unload_dll (void) -{ - CORE_ADDR load_addr = - (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; - - /* The symbols in a dll are offset by 0x1000, which is the - offset from 0 of the first byte in an image - because - of the file header and the section alignment. */ - load_addr += 0x1000; - unloaded_dll (NULL, load_addr); -} - -static void -handle_exception (struct target_waitstatus *ourstatus) -{ - DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; - - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - switch (code) - { - case EXCEPTION_ACCESS_VIOLATION: - OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION")); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_STACK_OVERFLOW: - OUTMSG2 (("STATUS_STACK_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_FLOAT_DENORMAL_OPERAND: - OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INEXACT_RESULT: - OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INVALID_OPERATION: - OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_OVERFLOW: - OUTMSG2 (("STATUS_FLOAT_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_STACK_CHECK: - OUTMSG2 (("STATUS_FLOAT_STACK_CHECK")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_UNDERFLOW: - OUTMSG2 (("STATUS_FLOAT_UNDERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_DIVIDE_BY_ZERO: - OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_DIVIDE_BY_ZERO: - OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_OVERFLOW: - OUTMSG2 (("STATUS_INTEGER_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_BREAKPOINT: - OUTMSG2 (("EXCEPTION_BREAKPOINT")); - ourstatus->value.sig = GDB_SIGNAL_TRAP; -#ifdef _WIN32_WCE - /* Remove the initial breakpoint. */ - check_breakpoints ((CORE_ADDR) (long) current_event - .u.Exception.ExceptionRecord.ExceptionAddress); -#endif - break; - case DBG_CONTROL_C: - OUTMSG2 (("DBG_CONTROL_C")); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case DBG_CONTROL_BREAK: - OUTMSG2 (("DBG_CONTROL_BREAK")); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case EXCEPTION_SINGLE_STEP: - OUTMSG2 (("EXCEPTION_SINGLE_STEP")); - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_PRIV_INSTRUCTION: - OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - default: - if (current_event.u.Exception.dwFirstChance) - { - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - return; - } - OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s", - (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, - phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord. - ExceptionAddress, sizeof (uintptr_t)))); - ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; - break; - } - OUTMSG2 (("\n")); - last_sig = ourstatus->value.sig; -} - - -static void -suspend_one_thread (thread_info *thread) -{ - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); - - if (!th->suspended) - { - if (SuspendThread (th->h) == (DWORD) -1) - { - DWORD err = GetLastError (); - OUTMSG (("warning: SuspendThread failed in suspend_one_thread, " - "(error %d): %s\n", (int) err, strwinerror (err))); - } - else - th->suspended = 1; - } -} - -static void -fake_breakpoint_event (void) -{ - OUTMSG2(("fake_breakpoint_event\n")); - - faked_breakpoint = 1; - - memset (¤t_event, 0, sizeof (current_event)); - current_event.dwThreadId = main_thread_id; - current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT; - current_event.u.Exception.ExceptionRecord.ExceptionCode - = EXCEPTION_BREAKPOINT; - - for_each_thread (suspend_one_thread); -} - -#ifdef _WIN32_WCE -static int -auto_delete_breakpoint (CORE_ADDR stop_pc) -{ - return 1; -} -#endif - -/* Get the next event from the child. */ - -static int -get_child_debug_event (struct target_waitstatus *ourstatus) -{ - ptid_t ptid; - - last_sig = GDB_SIGNAL_0; - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - - /* Check if GDB sent us an interrupt request. */ - check_remote_input_interrupt_request (); - - if (soft_interrupt_requested) - { - soft_interrupt_requested = 0; - fake_breakpoint_event (); - goto gotevent; - } - -#ifndef _WIN32_WCE - attaching = 0; -#else - if (attaching) - { - /* WinCE doesn't set an initial breakpoint automatically. To - stop the inferior, we flush all currently pending debug - events -- the thread list and the dll list are always - reported immediatelly without delay, then, we suspend all - threads and pretend we saw a trap at the current PC of the - main thread. - - Contrary to desktop Windows, Windows CE *does* report the dll - names on LOAD_DLL_DEBUG_EVENTs resulting from a - DebugActiveProcess call. This limits the way we can detect - if all the dlls have already been reported. If we get a real - debug event before leaving attaching, the worst that will - happen is the user will see a spurious breakpoint. */ - - current_event.dwDebugEventCode = 0; - if (!WaitForDebugEvent (¤t_event, 0)) - { - OUTMSG2(("no attach events left\n")); - fake_breakpoint_event (); - attaching = 0; - } - else - OUTMSG2(("got attach event\n")); - } - else -#endif - { - /* Keep the wait time low enough for comfortable remote - interruption, but high enough so gdbserver doesn't become a - bottleneck. */ - if (!WaitForDebugEvent (¤t_event, 250)) - { - DWORD e = GetLastError(); - - if (e == ERROR_PIPE_NOT_CONNECTED) - { - /* This will happen if the loader fails to succesfully - load the application, e.g., if the main executable - tries to pull in a non-existing export from a - DLL. */ - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = 1; - return 1; - } - - return 0; - } - } - - gotevent: - - switch (current_event.dwDebugEventCode) - { - case CREATE_THREAD_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT " - "for pid=%u tid=%x)\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - - /* Record the existence of this thread. */ - child_add_thread (current_event.dwProcessId, - current_event.dwThreadId, - current_event.u.CreateThread.hThread, - current_event.u.CreateThread.lpThreadLocalBase); - break; - - case EXIT_THREAD_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - child_delete_thread (current_event.dwProcessId, - current_event.dwThreadId); - - current_thread = get_first_thread (); - return 1; - - case CREATE_PROCESS_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - CloseHandle (current_event.u.CreateProcessInfo.hFile); - - current_process_handle = current_event.u.CreateProcessInfo.hProcess; - main_thread_id = current_event.dwThreadId; - - /* Add the main thread. */ - child_add_thread (current_event.dwProcessId, - main_thread_id, - current_event.u.CreateProcessInfo.hThread, - current_event.u.CreateProcessInfo.lpThreadLocalBase); - -#ifdef _WIN32_WCE - if (!attaching) - { - /* Windows CE doesn't set the initial breakpoint - automatically like the desktop versions of Windows do. - We add it explicitly here. It will be removed as soon as - it is hit. */ - set_breakpoint_at ((CORE_ADDR) (long) current_event.u - .CreateProcessInfo.lpStartAddress, - auto_delete_breakpoint); - } -#endif - break; - - case EXIT_PROCESS_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - { - DWORD exit_status = current_event.u.ExitProcess.dwExitCode; - /* If the exit status looks like a fatal exception, but we - don't recognize the exception's code, make the original - exit status value available, to avoid losing information. */ - int exit_signal - = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1; - if (exit_signal == -1) - { - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = exit_status; - } - else - { - ourstatus->kind = TARGET_WAITKIND_SIGNALLED; - ourstatus->value.sig = gdb_signal_from_host (exit_signal); - } - } - child_continue (DBG_CONTINUE, -1); - CloseHandle (current_process_handle); - current_process_handle = NULL; - break; - - case LOAD_DLL_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - CloseHandle (current_event.u.LoadDll.hFile); - if (! child_initialization_done) - break; - handle_load_dll (); - - ourstatus->kind = TARGET_WAITKIND_LOADED; - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - - case UNLOAD_DLL_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - if (! child_initialization_done) - break; - handle_unload_dll (); - ourstatus->kind = TARGET_WAITKIND_LOADED; - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - - case EXCEPTION_DEBUG_EVENT: - OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - handle_exception (ourstatus); - break; - - case OUTPUT_DEBUG_STRING_EVENT: - /* A message from the kernel (or Cygwin). */ - OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT " - "for pid=%u tid=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId)); - handle_output_debug_string (); - break; - - default: - OUTMSG2 (("gdbserver: kernel event unknown " - "for pid=%u tid=%x code=%x\n", - (unsigned) current_event.dwProcessId, - (unsigned) current_event.dwThreadId, - (unsigned) current_event.dwDebugEventCode)); - break; - } - - ptid = debug_event_ptid (¤t_event); - current_thread = find_thread_ptid (ptid); - return 1; -} - -/* Wait for the inferior process to change state. - STATUS will be filled in with a response code to send to GDB. - Returns the signal which caused the process to stop. */ -static ptid_t -win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) -{ - struct regcache *regcache; - - if (cached_status.kind != TARGET_WAITKIND_IGNORE) - { - /* The core always does a wait after creating the inferior, and - do_initial_child_stuff already ran the inferior to the - initial breakpoint (or an exit, if creating the process - fails). Report it now. */ - *ourstatus = cached_status; - cached_status.kind = TARGET_WAITKIND_IGNORE; - return debug_event_ptid (¤t_event); - } - - while (1) - { - if (!get_child_debug_event (ourstatus)) - continue; - - switch (ourstatus->kind) - { - case TARGET_WAITKIND_EXITED: - OUTMSG2 (("Child exited with retcode = %x\n", - ourstatus->value.integer)); - win32_clear_inferiors (); - return ptid_t (current_event.dwProcessId); - case TARGET_WAITKIND_STOPPED: - case TARGET_WAITKIND_SIGNALLED: - case TARGET_WAITKIND_LOADED: - OUTMSG2 (("Child Stopped with signal = %d \n", - ourstatus->value.sig)); - - regcache = get_thread_regcache (current_thread, 1); - child_fetch_inferior_registers (regcache, -1); - return debug_event_ptid (¤t_event); - default: - OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind)); - /* fall-through */ - case TARGET_WAITKIND_SPURIOUS: - /* do nothing, just continue */ - child_continue (DBG_CONTINUE, -1); - break; - } - } -} - -/* Fetch registers from the inferior process. - If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */ -static void -win32_fetch_inferior_registers (struct regcache *regcache, int regno) -{ - child_fetch_inferior_registers (regcache, regno); -} - -/* Store registers to the inferior process. - If REGNO is -1, store all registers; otherwise, store at least REGNO. */ -static void -win32_store_inferior_registers (struct regcache *regcache, int regno) -{ - child_store_inferior_registers (regcache, regno); -} - -/* Read memory from the inferior process. This should generally be - called through read_inferior_memory, which handles breakpoint shadowing. - Read LEN bytes at MEMADDR into a buffer at MYADDR. */ -static int -win32_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -{ - return child_xfer_memory (memaddr, (char *) myaddr, len, 0, 0) != len; -} - -/* Write memory to the inferior process. This should generally be - called through write_inferior_memory, which handles breakpoint shadowing. - Write LEN bytes from the buffer at MYADDR to MEMADDR. - Returns 0 on success and errno on failure. */ -static int -win32_write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, - int len) -{ - return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len; -} - -/* Send an interrupt request to the inferior process. */ -static void -win32_request_interrupt (void) -{ - winapi_DebugBreakProcess DebugBreakProcess; - winapi_GenerateConsoleCtrlEvent GenerateConsoleCtrlEvent; - -#ifdef _WIN32_WCE - HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); -#else - HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); -#endif - - GenerateConsoleCtrlEvent = GETPROCADDRESS (dll, GenerateConsoleCtrlEvent); - - if (GenerateConsoleCtrlEvent != NULL - && GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id)) - return; - - /* GenerateConsoleCtrlEvent can fail if process id being debugged is - not a process group id. - Fallback to XP/Vista 'DebugBreakProcess', which generates a - breakpoint exception in the interior process. */ - - DebugBreakProcess = GETPROCADDRESS (dll, DebugBreakProcess); - - if (DebugBreakProcess != NULL - && DebugBreakProcess (current_process_handle)) - return; - - /* Last resort, suspend all threads manually. */ - soft_interrupt_requested = 1; -} - -#ifdef _WIN32_WCE -int -win32_error_to_fileio_error (DWORD err) -{ - switch (err) - { - case ERROR_BAD_PATHNAME: - case ERROR_FILE_NOT_FOUND: - case ERROR_INVALID_NAME: - case ERROR_PATH_NOT_FOUND: - return FILEIO_ENOENT; - case ERROR_CRC: - case ERROR_IO_DEVICE: - case ERROR_OPEN_FAILED: - return FILEIO_EIO; - case ERROR_INVALID_HANDLE: - return FILEIO_EBADF; - case ERROR_ACCESS_DENIED: - case ERROR_SHARING_VIOLATION: - return FILEIO_EACCES; - case ERROR_NOACCESS: - return FILEIO_EFAULT; - case ERROR_BUSY: - return FILEIO_EBUSY; - case ERROR_ALREADY_EXISTS: - case ERROR_FILE_EXISTS: - return FILEIO_EEXIST; - case ERROR_BAD_DEVICE: - return FILEIO_ENODEV; - case ERROR_DIRECTORY: - return FILEIO_ENOTDIR; - case ERROR_FILENAME_EXCED_RANGE: - case ERROR_INVALID_DATA: - case ERROR_INVALID_PARAMETER: - case ERROR_NEGATIVE_SEEK: - return FILEIO_EINVAL; - case ERROR_TOO_MANY_OPEN_FILES: - return FILEIO_EMFILE; - case ERROR_HANDLE_DISK_FULL: - case ERROR_DISK_FULL: - return FILEIO_ENOSPC; - case ERROR_WRITE_PROTECT: - return FILEIO_EROFS; - case ERROR_NOT_SUPPORTED: - return FILEIO_ENOSYS; - } - - return FILEIO_EUNKNOWN; -} - -static void -wince_hostio_last_error (char *buf) -{ - DWORD winerr = GetLastError (); - int fileio_err = win32_error_to_fileio_error (winerr); - sprintf (buf, "F-1,%x", fileio_err); -} -#endif - -/* Write Windows OS Thread Information Block address. */ - -static int -win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr) -{ - win32_thread_info *th; - th = thread_rec (ptid, 0); - if (th == NULL) - return 0; - if (addr != NULL) - *addr = th->thread_local_base; - return 1; -} - -/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ - -static const gdb_byte * -win32_sw_breakpoint_from_kind (int kind, int *size) -{ - *size = the_low_target.breakpoint_len; - return the_low_target.breakpoint; -} - -static process_stratum_target win32_target_ops = { - win32_create_inferior, - NULL, /* post_create_inferior */ - win32_attach, - win32_kill, - win32_detach, - win32_mourn, - win32_join, - win32_thread_alive, - win32_resume, - win32_wait, - win32_fetch_inferior_registers, - win32_store_inferior_registers, - NULL, /* prepare_to_access_memory */ - NULL, /* done_accessing_memory */ - win32_read_inferior_memory, - win32_write_inferior_memory, - NULL, /* lookup_symbols */ - win32_request_interrupt, - NULL, /* read_auxv */ - win32_supports_z_point_type, - win32_insert_point, - win32_remove_point, - NULL, /* stopped_by_sw_breakpoint */ - NULL, /* supports_stopped_by_sw_breakpoint */ - NULL, /* stopped_by_hw_breakpoint */ - NULL, /* supports_stopped_by_hw_breakpoint */ - target_can_do_hardware_single_step, - win32_stopped_by_watchpoint, - win32_stopped_data_address, - NULL, /* read_offsets */ - NULL, /* get_tls_address */ -#ifdef _WIN32_WCE - wince_hostio_last_error, -#else - hostio_last_error_from_errno, -#endif - NULL, /* qxfer_osdata */ - NULL, /* qxfer_siginfo */ - NULL, /* supports_non_stop */ - NULL, /* async */ - NULL, /* start_non_stop */ - NULL, /* supports_multi_process */ - NULL, /* supports_fork_events */ - NULL, /* supports_vfork_events */ - NULL, /* supports_exec_events */ - NULL, /* handle_new_gdb_connection */ - NULL, /* handle_monitor_command */ - NULL, /* core_of_thread */ - NULL, /* read_loadmap */ - NULL, /* process_qsupported */ - NULL, /* supports_tracepoints */ - NULL, /* read_pc */ - NULL, /* write_pc */ - NULL, /* thread_stopped */ - win32_get_tib_address, - NULL, /* pause_all */ - NULL, /* unpause_all */ - NULL, /* stabilize_threads */ - NULL, /* install_fast_tracepoint_jump_pad */ - NULL, /* emit_ops */ - NULL, /* supports_disable_randomization */ - NULL, /* get_min_fast_tracepoint_insn_len */ - NULL, /* qxfer_libraries_svr4 */ - NULL, /* support_agent */ - NULL, /* enable_btrace */ - NULL, /* disable_btrace */ - NULL, /* read_btrace */ - NULL, /* read_btrace_conf */ - NULL, /* supports_range_stepping */ - NULL, /* pid_to_exec_file */ - NULL, /* multifs_open */ - NULL, /* multifs_unlink */ - NULL, /* multifs_readlink */ - NULL, /* breakpoint_kind_from_pc */ - win32_sw_breakpoint_from_kind, -}; - -/* Initialize the Win32 backend. */ -void -initialize_low (void) -{ - set_target_ops (&win32_target_ops); - the_low_target.arch_setup (); -} diff --git a/gdb/gdbserver/win32-low.h b/gdb/gdbserver/win32-low.h deleted file mode 100644 index 7a3eeda6e24..00000000000 --- a/gdb/gdbserver/win32-low.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Internal interfaces for the Win32 specific target code for gdbserver. - Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_WIN32_LOW_H -#define GDBSERVER_WIN32_LOW_H - -#include - -struct target_desc; - -/* The inferior's target description. This is a global because the - Windows ports support neither bi-arch nor multi-process. */ -extern const struct target_desc *win32_tdesc; - -/* Thread information structure used to track extra information about - each thread. */ -typedef struct win32_thread_info -{ - /* The Win32 thread identifier. */ - DWORD tid; - - /* The handle to the thread. */ - HANDLE h; - - /* Thread Information Block address. */ - CORE_ADDR thread_local_base; - - /* Non zero if SuspendThread was called on this thread. */ - int suspended; - -#ifdef _WIN32_WCE - /* The context as retrieved right after suspending the thread. */ - CONTEXT base_context; -#endif - - /* The context of the thread, including any manipulations. */ - CONTEXT context; - - /* Whether debug registers changed since we last set CONTEXT back to - the thread. */ - int debug_registers_changed; -} win32_thread_info; - -struct win32_target_ops -{ - /* Architecture-specific setup. */ - void (*arch_setup) (void); - - /* The number of target registers. */ - int num_regs; - - /* Perform initializations on startup. */ - void (*initial_stuff) (void); - - /* Fetch the context from the inferior. */ - void (*get_thread_context) (win32_thread_info *th); - - /* Called just before resuming the thread. */ - void (*prepare_to_resume) (win32_thread_info *th); - - /* Called when a thread was added. */ - void (*thread_added) (win32_thread_info *th); - - /* Fetch register from gdbserver regcache data. */ - void (*fetch_inferior_register) (struct regcache *regcache, - win32_thread_info *th, int r); - - /* Store a new register value into the thread context of TH. */ - void (*store_inferior_register) (struct regcache *regcache, - win32_thread_info *th, int r); - - void (*single_step) (win32_thread_info *th); - - const unsigned char *breakpoint; - int breakpoint_len; - - /* Breakpoint/Watchpoint related functions. See target.h for comments. */ - int (*supports_z_point_type) (char z_type); - int (*insert_point) (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp); - int (*remove_point) (enum raw_bkpt_type type, CORE_ADDR addr, - int size, struct raw_breakpoint *bp); - int (*stopped_by_watchpoint) (void); - CORE_ADDR (*stopped_data_address) (void); -}; - -extern struct win32_target_ops the_low_target; - -/* Retrieve the context for this thread, if not already retrieved. */ -extern void win32_require_context (win32_thread_info *th); - -/* Map the Windows error number in ERROR to a locale-dependent error - message string and return a pointer to it. Typically, the values - for ERROR come from GetLastError. - - The string pointed to shall not be modified by the application, - but may be overwritten by a subsequent call to strwinerror - - The strwinerror function does not change the current setting - of GetLastError. */ -extern char * strwinerror (DWORD error); - -/* in wincecompat.c */ - -extern void to_back_slashes (char *); - -#endif /* GDBSERVER_WIN32_LOW_H */ diff --git a/gdb/gdbserver/wincecompat.c b/gdb/gdbserver/wincecompat.c deleted file mode 100644 index 46eece17e55..00000000000 --- a/gdb/gdbserver/wincecompat.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Compatibility routines for Windows CE. - Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" - -#include - -void -perror (const char *s) -{ - if (s && *s) - fprintf (stderr, "%s: %s\n", s, strwinerror (GetLastError ())); - else - fprintf (stderr, "%s\n", strwinerror (GetLastError ())); -} - -void -to_back_slashes (char *path) -{ - for (; *path; ++path) - if ('/' == *path) - *path = '\\'; -} diff --git a/gdb/gdbserver/wincecompat.h b/gdb/gdbserver/wincecompat.h deleted file mode 100644 index 34705c3d66c..00000000000 --- a/gdb/gdbserver/wincecompat.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Compatibility routines for Windows CE. - Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_WINCECOMPAT_H -#define GDBSERVER_WINCECOMPAT_H - -#include - -#define errno (GetLastError ()) - -/* in win32-low.c */ -extern char * strwinerror (DWORD error); -#define strerror strwinerror - -#endif /* GDBSERVER_WINCECOMPAT_H */ diff --git a/gdb/gdbserver/x86-low.c b/gdb/gdbserver/x86-low.c deleted file mode 100644 index 611e60b0137..00000000000 --- a/gdb/gdbserver/x86-low.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Low level support for x86 (i386 and x86-64). - - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#include "server.h" -#include "x86-low.h" - -/* Clear the reference counts and forget everything we knew about the - debug registers. */ - -void -x86_low_init_dregs (struct x86_debug_reg_state *state) -{ - int i; - - ALL_DEBUG_ADDRESS_REGISTERS (i) - { - state->dr_mirror[i] = 0; - state->dr_ref_count[i] = 0; - } - state->dr_control_mirror = 0; - state->dr_status_mirror = 0; -} diff --git a/gdb/gdbserver/x86-low.h b/gdb/gdbserver/x86-low.h deleted file mode 100644 index a797fc737fc..00000000000 --- a/gdb/gdbserver/x86-low.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Low level support for x86 (i386 and x86-64). - - Copyright (C) 2009-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_X86_LOW_H -#define GDBSERVER_X86_LOW_H - -#include "nat/x86-dregs.h" - -/* Initialize STATE. */ -extern void x86_low_init_dregs (struct x86_debug_reg_state *state); - -#endif /* GDBSERVER_X86_LOW_H */ diff --git a/gdb/gdbserver/x86-tdesc.h b/gdb/gdbserver/x86-tdesc.h deleted file mode 100644 index 8398cfdb836..00000000000 --- a/gdb/gdbserver/x86-tdesc.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2018-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 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, see . */ - -#ifndef GDBSERVER_X86_TDESC_H -#define GDBSERVER_X86_TDESC_H - -/* The "expedite" registers for x86 targets. Since whether the - variable is used depends on host/configuration, we mark it - ATTRIBUTE_UNUSED to keep it simple here. */ -static const char *i386_expedite_regs[] ATTRIBUTE_UNUSED - = {"ebp", "esp", "eip", NULL}; - -#ifdef __x86_64__ -/* The "expedite" registers for x86_64 targets. */ -static const char *amd64_expedite_regs[] = {"rbp", "rsp", "rip", NULL}; -#endif - -#endif /* GDBSERVER_X86_TDESC_H */ diff --git a/gdb/gdbserver/xtensa-xtregs.c b/gdb/gdbserver/xtensa-xtregs.c deleted file mode 100644 index bd14679ff80..00000000000 --- a/gdb/gdbserver/xtensa-xtregs.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Table mapping between kernel xtregset and GDB register cache. - Copyright (C) 2007-2020 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3 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, see . */ - - -typedef struct { - int gdb_regnum; - int gdb_offset; - int ptrace_cp_offset; - int ptrace_offset; - int size; - int coproc; - int dbnum; - char* name -;} xtensa_regtable_t; - -#define XTENSA_ELF_XTREG_SIZE 4 - -const xtensa_regtable_t xtensa_regmap_table[] = { - /* gnum,gofs,cpofs,ofs,siz,cp, dbnum, name */ - { 44, 176, 0, 0, 4, -1, 0x020c, "scompare1" }, - { 0 } -}; diff --git a/gdbserver/.gitignore b/gdbserver/.gitignore new file mode 100644 index 00000000000..fef0d01b14e --- /dev/null +++ b/gdbserver/.gitignore @@ -0,0 +1,10 @@ +/Makefile + +gdbreplay +gdbserver +libinproctrace.so + +build-gnulib-gdbserver +build-libiberty-gdbserver + +*-generated.c diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog new file mode 100644 index 00000000000..a1d6e2a250f --- /dev/null +++ b/gdbserver/ChangeLog @@ -0,0 +1,17997 @@ +2020-02-07 Tom Tromey + Pedro Alves + + * README: Update build documentation. + * configure.srv: Set UNSUPPORTED if host is unsupported. Check + host, not target. + * configure.ac: Update paths. + * configure: Rebuild. + * acinclude.m4: Update paths. + * Makefile.in: Update include paths. + (depcomp, INCLUDE_DIR, INCGNU, INCSUPPORT, INCLUDE_CFLAGS) + (SFILES, XML_DIR, n, $(GNULIB_BUILDDIR)/Makefile, config.status) + (version-generated.c, stamp-xml, regdat_sh, arch/%-ipa.o) + (gdbsupport/%-ipa.o, %-ipa.o, arch/%.o, gdbsupport/%.o, %.o) + (%-generated.c): Update paths. + * Move entire directory from ../gdb/gdbserver. + +2020-01-29 Maciej W. Rozycki + + * configure.srv : Fix whitespace damage. + +2020-01-29 Pedro Franco de Carvalho + + * configure.srv (powerpc*-*-linux*): Use srv_tgtobj in second + assignment instead of srv_linux_obj. + +2020-01-28 Hannes Domani + + * server.c (handle_qxfer_libraries): Write segment-address with + paddress. + +2020-01-24 Hannes Domani + + * Makefile.in (install-strip): New target. + (install_sh, INSTALL_STRIP_PROGRAM, STRIP): New variables. + * aclocal.m4: Regenerate. + * configure: Regenerate. + * configure.ac: Add AM_PROG_INSTALL_STRIP. + +2020-01-24 Maciej W. Rozycki + + * Makefile.in (SFILES): Adjust paths to point to real files. + (OBS): Move waitstatus.o to target/waitstatus.o. + (TAGS): Transform paths appropriately. + (%.o): Rename to... + (nat/%.o): ... this pattern rule. + (%.o): Rename to... + (target/%.o): ... this pattern rule. + * configure.srv: Adjust paths throughout to include nat/ prefix + with the revant files. + * configure.ac: Add `nat' and `target' to CONFIG_SRC_SUBDIR. + * configure: Regenerate. + +2020-01-24 Maciej W. Rozycki + + * Makefile.in (TAGS): Remove config files from the recipe. + +2020-01-14 Tom Tromey + + * configure: Rebuild. + * configure.ac: Remove any checks that were added to common.m4. + * acinclude.m4: Include lib-ld.m4, lib-prefix.m4, and + lib-link.m4. + +2020-01-14 Tom Tromey + + * server.h: Include config.h. + * gdbreplay.c: Include config.h. + * configure: Rebuild. + * configure.ac: Don't source common.host. + * acinclude.m4: Update path. + * Makefile.in (INCSUPPORT): New variable. + (INCLUDE_CFLAGS): Add INCSUPPORT. + (SFILES): Update paths. + (version-generated.c): Update path to create-version.sh. + (gdbsupport/%-ipa.o, gdbsupport/%.o): Update paths. + +2020-01-14 Tom Tromey + + * configure.ac (LIBS): Use WIN32APILIBS. + (USE_WIN32API): Don't define. + * configure: Rebuild. + +2020-01-14 Tom Tromey + + * configure: Rebuild. + +2020-01-13 Simon Marchi + + * Makefile.in (%-generated.c): Remove rule for files from + regformats/i386. + +2020-01-13 Simon Marchi + + * configure: Re-generate. + +2020-01-13 Simon Marchi + + * tracepoint.h (IP_AGENT_EXPORT_FUNC) [!IN_PROCESS_AGENT]: + Define to static. + * tracepoint.c (stop_tracing, flush_trace_buffer, + about_to_request_buffer_space, get_trace_state_variable_value, + set_trace_state_variable_value, gdb_collect): Add declaration. + +2020-01-13 Simon Marchi + + * linux-x86-low.c (x86_linux_regs_info, amd64_emit_eq_goto, + amd64_emit_ne_goto, amd64_emit_lt_goto, amd64_emit_le_goto, + amd64_emit_gt_goto, amd64_emit_ge_goto, amd64_emit_ge_goto, + i386_emit_eq_goto, i386_emit_ne_goto, i386_emit_lt_goto, + i386_emit_le_goto, i386_emit_gt_goto, i386_emit_ge_goto): Make + static. + +2020-01-13 Simon Marchi + + * inferiors.c: Include gdbsupport/common-inferior.h. + +2020-01-13 Simon Marchi + + * hostio-errno.c: Include hostio.h. + +2020-01-13 Simon Marchi + + * Makefile.in (%-generated.c): Make $(regdat_sh) a regular + prerequisite. + +2020-01-12 Simon Marchi + + * linux-arm-tdesc.c: Include linux-arm-tdesc.h. + * linux-arm-tdesc.h: Include arch/arm.h. + +2020-01-12 Simon Marchi + + * linux-aarch64-low.c (aarch64_write_goto_address): Make static. + +2020-01-12 Simon Marchi + + * linux-aarch32-tdesc.c: Include linux-aarch32-tdesc.h. + * linux-aarch64-tdesc.c: Include linux-aarch64-tdesc.h. + +2020-01-10 Pedro Alves + + * fork-child.c (post_fork_inferior): Pass target down to + startup_inferior. + * inferiors.c (switch_to_thread): Add process_stratum_target + parameter. + * lynx-low.c (lynx_target_ops): Now a process_stratum_target. + * nto-low.c (nto_target_ops): Now a process_stratum_target. + * linux-low.c (linux_target_ops): Now a process_stratum_target. + * remote-utils.c (prepare_resume_reply): Pass the target to + switch_to_thread. + * target.c (the_target): Now a process_stratum_target. + (done_accessing_memory): Pass the target to switch_to_thread. + (set_target_ops): Ajust to use process_stratum_target. + * target.h (struct target_ops): Rename to ... + (struct process_stratum_target): ... this. + (the_target, set_target_ops): Adjust. + (prepare_to_access_memory): Adjust comment. + * win32-low.c (child_xfer_memory): Adjust to use + process_stratum_target. + (win32_target_ops): Now a process_stratum_target. + +2020-01-06 Eli Zaretskii + Pedro Alves + + * win32-low.c (get_child_debug_event): Extract the fatal exception + from the exit status and convert to the equivalent Posix signal + number. + (win32_wait): Allow TARGET_WAITKIND_SIGNALLED status as well. + * Makefile.in (OBS, SFILES): Add gdb_wait.[co]. + +2020-01-01 Hannes Domani + + * Makefile.in: Use INSTALL_PROGRAM_ENV. + +2020-01-01 Joel Brobecker + + * server.c (gdbserver_version): Change copyright year to 2020. + * gdbreplay.c (gdbreplay_version): Likewise. + +2019-12-19 Christian Biesinger + + * configure: Regenerate. + * configure.ac: Quote variable arguments of test. + +2019-12-16 Bernd Edlinger + + * Makefile.in: Fix build with GNU Make 3.81 + +2019-12-16 Tom Tromey + + * server.c (get_exec_file): Constify result. + +2019-12-10 Christian Biesinger + + * Makefile.in: Add safe-strerror.c to gdbreplay and IPA, and change + UNDO_GNULIB_CFLAGS to undo strerror_r instead of strerror. + * config.in: Regenerate. + * configure: Regenerate. + * configure.ac: Don't check for strerror. + * linux-i386-ipa.c (initialize_fast_tracepoint_trampoline_buffer): + Call safe_strerror instead of strerror. + * server.h (strerror): Remove this now-unnecessary declaration. + * tracepoint.c (init_named_socket): Call safe_strerror instead of + strerror. + (gdb_agent_helper_thread): Likewise. + * utils.c (perror_with_name): Likewise. + +2019-11-26 Tom Tromey + + * configure, config.in: Rebuild. + +2019-11-26 Tom Tromey + + * remote-utils.c (block_unblock_async_io): Use gdb_sigmask. + * linux-low.c (linux_wait_for_event_filtered, linux_async): Use + gdb_sigmask. + * configure, config.in: Rebuild. + +2019-11-26 Tom Tromey + + * Makefile.in (PTHREAD_CFLAGS, PTHREAD_LIBS): New variables. + (INTERNAL_CFLAGS_BASE): Use PTHREAD_CFLAGS. + (GDBSERVER_LIBS): Use PTHREAD_LIBS. + * acinclude.m4: Include ax_pthread.m4. + * config.in, configure: Rebuild. + +2019-11-26 Christian Biesinger + + * debug.c (debug_set_output): Call safe_strerror instead of + strerror. + * linux-low.c (attach_proc_task_lwp_callback): Likewise. + (linux_kill_one_lwp): Likewise. + (linux_detach_one_lwp): Likewise. + (linux_wait_for_event_filtered): Likewise. + (store_register): Likewise. + * lynx-low.c (lynx_attach): Likewise. + * mem-break.c (insert_memory_breakpoint): Likewise. + (remove_memory_breakpoint): Likewise. + (delete_fast_tracepoint_jump): Likewise. + (set_fast_tracepoint_jump): Likewise. + (uninsert_fast_tracepoint_jumps_at): Likewise. + (reinsert_fast_tracepoint_jumps_at): Likewise. + * nto-low.c (nto_xfer_memory): Likewise. + (nto_resume): Likewise. + +2019-11-20 Luis Machado + + * linux-aarch64-low.c (is_sve_tdesc): Check against target feature + instead of register count. + * tdesc.c (tdesc_contains_feature): New function. + * tdesc.h (tdesc_contains_feature): New prototype. + +2019-11-15 Christian Biesinger + + * Makefile.in: Add safe-strerror.c. + * configure: Regenerate. + * configure.ac: Don't source common.host. + +2019-11-15 Christian Biesinger + + * config.in: Regenerate. + * configure: Regenerate. + +2019-11-12 Andrew Burgess + + * ax.c (ax_printf): Handle size_t_arg. + +2019-11-06 Christian Biesinger + + * linux-tdep.c (linux_info_proc): Use strtok_r instead of strtok. + * mi/mi-main.c (output_cores): Likewise. + * nat/linux-osdata.c (linux_xfer_osdata_cpus): Likewise. + (linux_xfer_osdata_modules): Likewise. + * remote.c (register_remote_support_xml): Likewise. + * sparc64-tdep.c (adi_is_addr_mapped): Likewise. + * xml-syscall.c (syscall_create_syscall_desc): Likewise. + +2019-11-01 Christian Biesinger + + * configure: Regenerate. + * configure.ac: Remove check for strerror_r. + +2019-10-31 Christian Biesinger + + * config.in: Regenerate. + * configure: Regenerate. + * configure.ac: Also check for strerror_r. + +2019-10-31 Christian Biesinger + + * ax.h (debug_agent): Remove duplicate declaration. + +2019-10-26 Tom de Vries + + * linux-aarch64-low.c: Fix typos in comments. + * linux-arm-low.c: Same. + * linux-low.c: Same. + * linux-ppc-low.c: Same. + * proc-service.c: Same. + * regcache.h: Same. + * server.c: Same. + * tracepoint.c: Same. + * win32-low.c: Same. + +2019-10-25 Tom Tromey + + * utils.c (xstrdup): Remove. + +2019-10-23 Tom Tromey + + * configure, config.in: Rebuild. + +2019-10-23 Tom Tromey + + * configure: Rebuild. + * acinclude.m4: Use m4_include, not sinclude. + +2019-10-17 Tom Tromey + + * configure: Rebuild. + * configure.ac: Use AC_CONFIG_HEADERS. Create stamp-h there, not + in AC_CONFIG_FILES invocation. + * Makefile.in (stamp-h, Makefile): Use new-style config.status + invocation. + +2019-10-16 Christian Biesinger + + * server.c: Include xml-builtin.h. + (get_xml_features): Don't declare xml_builtins here. + +2019-10-15 Andrew Burgess + + * Makefile.in: Remove references to vec-ipa.o. + +2019-10-15 Andrew Burgess + + * Makefile.in: Remove references to vec.c. + +2019-10-02 Christian Biesinger + + * server.c (server_waiting): Change to bool. + (extended_protocol): Likewise. + (response_needed): Likewise. + (exit_requested): Likewise. + (run_once): Likewise. + (report_no_resumed): Likewise. + (non_stop): Likewise. + (disable_packet_vCont): Likewise. + (disable_packet_Tthread): Likewise. + (disable_packet_qC): Likewise. + (disable_packet_qfThreadInfo): Likewise. + (handle_general_set): Update. + (handle_detach): Update. + (handle_monitor_command): Update. + (handle_query): Update. + (captured_main): Update. + (process_serial_event): Update. + * server.h (server_waiting): Change to bool. + (disable_packet_vCont): Likewise. + (disable_packet_Tthread): Likewise. + (disable_packet_qC): Likewise. + (disable_packet_qfThreadInfo): Likewise. + (run_once): Likewise. + (non_stop): Likewise. + * target.c (target_stop_and_wait): Update. + +2019-10-02 Tom Tromey + + * Makefile.in (SFILES): Add common-inferior.c. + (OBS): Add common-inferior.o. + * server.c (startup_with_shell): Don't define. + +2019-10-02 Andrew Burgess + + * linux-low.c (linux_low_read_btrace): Update for change to + std::vector. + +2019-09-20 Christian Biesinger + + * debug.c (debug_threads): Remove comment in favor of the header. + * debug.h (using_threads): Add declaration. + (debug_threads): Add comment. + * linux-aarch64-low.c: Include debug.h and remove declaration of + debug_threads. + * nto-low.c: Likewise. + * remote-utils.c: Likewise. + * thread-db.c: Likewise. + +2019-09-20 Ulrich Weigand + + * configure.srv (ipa_ppc_linux_regobj): Remove powerpc-cell32l-ipa.o + and powerpc-cell64l-ipa.o. + (powerpc*-*-linux*): Remove powerpc-cell32l.o and powerpc-cell64l.o + from srv_regobj. Remove rs6000/powerpc-cell32l.xml and + rs6000/powerpc-cell64l.xml from srv_xmlfiles. + (spu*-*-*): Remove. + + * spu-low.c: Remove file. + + * linux-ppc-low.c (INSTR_SC, NR_spu_run): Remove. + (parse_spufs_run): Remove. + (ppc_get_pc): Remove Cell/B.E. support. + (ppc_set_pc): Likewise. + (ppc_breakpoint_at): Likewise. + (ppc_arch_setup): Likewise. + (ppc_get_ipa_tdesc_idx): Do not handle tdesc_powerpc_cell64l or + tdesc_powerpc_cell32l. + (initialize_low_arch): Do not call init_registers_powerpc_cell64l + or init_registers_powerpc_cell32l. + * linux-ppc-ipa.c (get_ipa_tdesc): Do not handle PPC_TDESC_CELL. + (initialize_low_tracepoint): Do not call init_registers_powerpc_cell64l + or init_registers_powerpc_cell32l. + * linux-ppc-tdesc-init.h (PPC_TDESC_CELL): Mark as unused. + (init_registers_powerpc_cell32l): Remove prototype. + (init_registers_powerpc_cell64l): Likewise. + + * target.h (struct target_ops): Remove qxfer_spu member. + * server.c (handle_qxfer_spu): Remove. + (qxfer_packets): Remove entry for "spu". + (handle_query): No longer support qXfer:spu:read or qXfer:spu:write. + * linux-low.c (SPUFS_MAGIC): Remove. + (spu_enumerate_spu_ids): Remove. + (linux_qxfer_spu): Remove. + (linux_target_ops): Remove qxfer_spu member. + * lynx-low.c (lynx_target_ops): Remove qxfer_spu member. + * nto-low.c (nto_target_ops): Remove qxfer_spu member. + * win32-low.c (win32_target_ops): Remove qxfer_spu member. + +2019-08-23 Sergio Durigan Junior + + * Makefile.in (SFILES): Add 'gdbsupport/gdb-dlfcn.c'. + (OBS): Add 'gdbsupport/gdb-dlfcn.o'. + * config.in: Regenerate. + * configure: Regenerate. + +2019-08-15 Tom Tromey + + * target.c (target_write_memory): Use gdb::byte_vector. + +2019-08-15 Tom Tromey + + * tracepoint.c (write_inferior_data_pointer) + (write_inferior_integer, write_inferior_int8) + (write_inferior_uinteger, m_tracepoint_action_download) + (r_tracepoint_action_download, x_tracepoint_action_download) + (l_tracepoint_action_download, clear_inferior_trace_buffer) + (download_agent_expr, download_tracepoint_1) + (download_trace_state_variables, upload_fast_traceframes): Update. + * server.c (gdb_write_memory): Update. + * remote-utils.c (relocate_instruction): Update. + * proc-service.c (ps_pdwrite): Update. + * mem-break.c (remove_memory_breakpoint) + (delete_fast_tracepoint_jump, set_fast_tracepoint_jump) + (uninsert_fast_tracepoint_jumps_at) + (reinsert_fast_tracepoint_jumps_at): Update. + * linux-x86-low.c (append_insns) + (i386_install_fast_tracepoint_jump_pad) + (amd64_write_goto_address, i386_write_goto_address): Update. + * linux-s390-low.c (append_insns, s390_write_goto_address): + Update. + * linux-ppc-low.c (ppc_relocate_instruction) + (ppc_install_fast_tracepoint_jump_pad, emit_insns) + (ppc_write_goto_address): Update. + * linux-aarch64-low.c (append_insns): Update. + * target.h (struct target_ops): Update. + (write_inferior_memory): Don't declare. + * target.c (target_write_memory): Rename from + write_inferior_memory. Remove old target_write_memory. + +2019-08-15 Tom Tromey + + * target.c (write_inferior_memory): Use std::vector. + +2019-08-06 Frank Ch. Eigler + + PR build/24886 + * configure.ac: Drop enable-libmcheck support. + * configure, config.in: Rebuild. + * acinclude.m4: Don't include it. + +2019-07-19 Alan Hayward + + * configure.srv: Remove Arm xml files. + +2019-07-19 Alan Hayward + + * configure.srv: Add new files. Remove xml generated files. + * linux-aarch32-low.c (initialize_low_arch_aarch32): Don't init + registers. + * linux-aarch32-low.h (tdesc_arm_with_neon): Remove. + * linux-aarch32-tdesc.c: New file. + * linux-aarch32-tdesc.h: New file. + * linux-aarch64-low.c (aarch64_arch_setup): Call aarch32_linux_read_description. + * linux-arm-low.c (init_registers_arm, tdesc_arm) + (init_registers_arm_with_iwmmxt, tdesc_arm_with_iwmmxt) + (init_registers_arm_with_vfpv2, tdesc_arm_with_vfpv2) + (init_registers_arm_with_vfpv3, tdesc_arm_with_vfpv3): Remove. + (arm_fill_wmmxregset, arm_store_wmmxregset, arm_fill_vfpregset) + (arm_store_vfpregset): Call arm_linux_get_tdesc_fp_type. + (arm_read_description): Call arm_linux_read_description. + (initialize_low_arch): Don't init registers. + * linux-arm-tdesc.c: New file. + * linux-arm-tdesc.h: New file. + +2019-07-10 Alan Hayward + + * linux-arm-low.c (arm_fill_wmmxregset, arm_store_wmmxregset): + Move counter inside for. + (arm_read_description): Check ptrace earlier. + (arm_arch_setup): Call arm_linux_init_hwbp_cap here. + +2019-07-09 Tom Tromey + + * configure: Rebuild. + * configure.ac: Change common to gdbsupport. + * acinclude.m4: Change common to gdbsupport. + * Makefile.in (SFILES, OBS, GDBREPLAY_OBS, IPA_OBJS) + (version-generated.c, gdbsupport/%-ipa.o, gdbsupport/%.o): Change + common to gdbsupport. + * ax.c, event-loop.c, fork-child.c, gdb_proc_service.h, + gdbreplay.c, gdbthread.h, hostio-errno.c, hostio.c, i387-fp.c, + inferiors.c, inferiors.h, linux-aarch64-tdesc-selftest.c, + linux-amd64-ipa.c, linux-i386-ipa.c, linux-low.c, + linux-tic6x-low.c, linux-x86-low.c, linux-x86-tdesc-selftest.c, + linux-x86-tdesc.c, lynx-i386-low.c, lynx-low.c, mem-break.h, + nto-x86-low.c, regcache.c, regcache.h, remote-utils.c, server.c, + server.h, spu-low.c, symbol.c, target.h, tdesc.c, tdesc.h, + thread-db.c, tracepoint.c, win32-i386-low.c, win32-low.c: Change + common to gdbsupport. + +2019-07-04 Alan Hayward + + * linux-aarch32-low.c (arm_read_description, arm_regsets): Use new + defines. + * linux-arm-low.c (arm_read_description, arm_regsets): Likewise. + +2019-07-04 Alan Hayward + + * configure.srv: Remove legacy xml. + * linux-aarch64-low.c (initialize_low_arch): Remove + initialize_low_tdesc call. + * linux-aarch64-tdesc-selftest.c: Remove file. + * linux-aarch64-tdesc.h (initialize_low_tdesc): Remove. + * linux-x86-low.c (initialize_low_arch): Remove + initialize_low_tdesc call. + * linux-x86-tdesc-selftest.c: Remove file. + * linux-x86-tdesc.h (initialize_low_tdesc): Remove. + +2019-06-20 Tom de Vries + + * linux-s390-ipa.c (get_ipa_tdesc)[!__s390x__]: Use + s390_te_linux64_ft_collect_regmap for S390_TDESC_GS. + +2019-06-19 Tom de Vries + + * debug.h (debug_write): Change return type to ssize_t. + * debug.c (debug_write): Same. + +2019-06-14 Tom Tromey + + * configure.ac: Use new path to gnulib. + * configure: Rebuild. + * Makefile.in (INCGNU, $(GNULIB_BUILDDIR)/Makefile): Use new path + to gnulib. + +2019-06-11 Tom Tromey + + * Makefile.in (SFILES): Add alloc.c. + (OBS): Add alloc.o. + (IPA_OBJS): Add alloc-ipa.o. + (alloc-ipa.o): New target. + (%.o: ../%.c): New pattern rule. + +2019-06-10 Tom Tromey + + * remote-utils.c (look_up_one_symbol, relocate_instruction): Don't + end warning with a newline. + * linux-s390-low.c (s390_get_wordsize): Don't end warning with a + newline. + * thread-db.c (attach_thread): Don't end warning with a newline. + (thread_db_notice_clone): Likewise. + * tracepoint.c (gdb_agent_helper_thread): Don't end warning with a + newline. + * linux-x86-low.c (x86_get_min_fast_tracepoint_insn_len): Don't + end warning with a newline. + +2019-06-04 Pedro Alves + + * server.c (captured_main): Use make_unique_xstrdup. + +2019-06-02 Tom Tromey + + * gdbreplay.c (fromhex): Remove. + * Makefile.in (GDBREPLAY_OBS): Add rsp-low.o. + +2019-05-29 Tom Tromey + + * configure: Rebuild. + +2019-05-06 Kevin Buettner + + * linux-x86-low.c (x86_fill_gregset): Don't compile 64-bit + sign extension code on 32-bit builds. + +2019-05-03 Eli Zaretskii + + * remote-utils.c: + * gdbreplay.c [USE_WIN32API]: Remove the _WIN32_WINNT override. + +2019-04-19 Tom Tromey + + * server.c (struct vstop_notif): Derive from notif_event. + : Remove. + (queue_stop_reply): Update. + (remove_all_on_match_ptid): Change type. Rewrite. + (discard_queued_stop_replies): Rewrite. + (in_queued_stop_replies_ptid): Change type. + (in_queued_stop_replies): Rewrite. + (notif_stop): Update. + (queue_stop_reply_callback): Update. + (captured_main): Don't call initialize_notif. + (push_stop_notification): Update. + * notif.c (notif_write_event, handle_notif_ack) + (notif_event_enque, notif_push): Update. + (notif_event_xfree, initialize_notif): Remove. + * notif.h (struct notif_event): Include , not + "common/queue.h". + (struct notif_server) : Now a std::list. + (notif_event_p): Remove typedef. + (initialize_notif): Don't declare. + (struct notif_event): Add virtual destructor. + +2019-04-17 Alan Hayward + + * ax.c (ax_vdebug): Call debug_printf. + * debug.c (debug_write): New function. + * debug.h (debug_write): New declaration. + * linux-low.c (sigchld_handler): Call debug_write. + +2019-04-17 Alan Hayward + + * debug.c (debug_set_output): New function. + (debug_vprintf): Send output to debug_file. + (debug_flush): Likewise. + * debug.h (debug_set_output): New declaration. + * server.c (handle_monitor_command): Add debug-file option. + (captured_main): Likewise. + +2019-04-17 Alan Hayward + + * debug.c (remote_debug): Add definition. + * debug.h (remote_debug): Add declaration. + * hostio.c (remote_debug): Remove declaration. + * remote-utils.c (struct ui_file): Likewise. + (remote_debug): Likewise. + * remote-utils.h (remote_debug): Likewise, + * server.c (remote_debug): Remove definition. + +2019-04-10 Kevin Buettner + + * linux-x86-low.c (x86_fill_gregset): Sign extend EAX value + when using a 64-bit gdbserver. + +2019-04-09 Tom Tromey + + * linux-low.c (select_event_lwp): Use find_thread_in_random. + +2019-04-08 Tom Tromey + + * linux-low.c (linux_detach_one_lwp): Replace throw_exception with + throw. + (linux_resume_one_lwp): Likewise. + +2019-04-08 Tom Tromey + + * gdbreplay.c: Update. + * linux-low.c: Update. + * server.c: Update. + +2019-04-08 Tom Tromey + + * server.c: Use C++ exception handling. + * linux-low.c: Use C++ exception handling. + * gdbreplay.c: Use C++ exception handling. + +2019-04-08 Tom Tromey + + * server.c (handle_btrace_general_set, handle_qxfer_btrace) + (handle_qxfer_btrace_conf, detach_or_kill_for_exit_cleanup) + (captured_main, main): Update. + * gdbreplay.c (main): Update. + +2019-04-05 Pedro Franco de Carvalho + + * linux-low.c (linux_get_auxv): Remove static. Return auxv entry + value in argument pointer, return 1 if the entry is found and 0 + otherwise. Move comment. + (linux_get_hwcap, linux_get_hwcap2): Use modified linux_get_auxv. + * linux-low.h (linux_get_auxv): Declare. + * linux-ppc-low.c (is_elfv2_inferior): Use linux_get_auxv. + +2019-04-05 Tom Tromey + + * server.c (gdbserver_usage): Use upper-case for metasyntactic + variables. + +2019-03-28 Alan Hayward + + * linux-low.c (AT_HWCAP2): Add define if not already included. + +2019-03-26 Alan Hayward + + * linux-aarch64-low.c (aarch64_get_hwcap): Remove function. + (aarch64_arch_setup): Call linux_get_hwcap. + * linux-arm-low.c (arm_get_hwcap): Remove function. + (arm_read_description): Call linux_get_hwcap. + * linux-low.c (linux_get_auxv): New function. + (linux_get_hwcap): Likewise. + (linux_get_hwcap2): Likewise. + * linux-low.h (linux_get_hwcap): New declaration. + (linux_get_hwcap2): Likewise. + * linux-ppc-low.c (ppc_get_auxv): Remove function. + (ppc_arch_setup): Call linux_get_hwcap. + * linux-s390-low.c (s390_get_hwcap): Remove function. + (s390_arch_setup): Call linux_get_hwcap. + +2019-03-22 Alan Hayward + Jiong Wang + + * linux-aarch64-low.c (aarch64_store_pauthregset): New function. + * linux-low.c (regsets_store_inferior_registers): Allow optional reads + to fail. + * linux-low.h (enum regset_type): Add OPTIONAL_REGS. + +2019-03-22 Alan Hayward + Jiong Wang + + * linux-aarch64-low.c (AARCH64_HWCAP_PACA): New define. + (aarch64_get_hwcap): New function. + (aarch64_arch_setup): Read APIA hwcap. + +2019-03-22 Alan Hayward + Jiong Wang + + * linux-aarch64-ipa.c (get_ipa_tdesc): Add pauth param. + (initialize_low_tracepoint): Likewise. + * linux-aarch64-low.c (aarch64_arch_setup): Likewise. + * linux-aarch64-tdesc-selftest.c (aarch64_tdesc_test): Likewise. + * linux-aarch64-tdesc.c (struct target_desc): Likewise. + (aarch64_linux_read_description): Likewise. + * linux-aarch64-tdesc.h (aarch64_linux_read_description): Likewise. + +2019-03-12 John Baldwin + + * linux-x86-tdesc.c (i386_linux_read_description): Update call to + i386_create_target_description for 'segments' parameter. + * lynx-i386-low.c (lynx_i386_arch_setup): Likewise. + * nto-x86-low.c (nto_x86_arch_setup): Likewise. + * win32-i386-low.c (i386_arch_setup): Likewise. + +2019-03-12 Tom Tromey + + * linux-low.c (iterate_over_lwps): Update. + +2019-03-06 Tom Tromey + + * server.c (detach_or_kill_for_exit_cleanup): Remove parameter. + (captured_main): Use SCOPE_EXIT. + +2019-03-04 Sergio Durigan Junior + + * configure.srv: Use '$enable_unittest' instead of '$development' + when checking whether to fill 'srv_regobj' on 'aarch64*-*-linux*' + case. + +2019-02-27 Tom Tromey + + * gdbreplay.c (logchar): Handle \r\n. + +2019-02-07 Alan Hayward + + * linux-low.c (linux_attach): Add process before lwp. + * server.c (attach_inferior): Check if already attached. + +2019-02-07 Tom Tromey + + * x86-tdesc.h: Rename include guard. + * x86-low.h: Add include guard. + * wincecompat.h: Rename include guard. + * win32-low.h: Add include guard. + * utils.h: Rename include guard. + * tracepoint.h: Rename include guard. + * tdesc.h: Rename include guard. + * target.h: Rename include guard. + * server.h: Rename include guard. + * remote-utils.h: Rename include guard. + * regcache.h: Rename include guard. + * nto-low.h: Rename include guard. + * notif.h: Add include guard. + * mem-break.h: Rename include guard. + * lynx-low.h: Add include guard. + * linux-x86-tdesc.h: Add include guard. + * linux-s390-tdesc.h: Add include guard. + * linux-ppc-tdesc-init.h: Add include guard. + * linux-low.h: Add include guard. + * linux-aarch64-tdesc.h: Add include guard. + * linux-aarch32-low.h: Add include guard. + * inferiors.h: Rename include guard. + * i387-fp.h: Rename include guard. + * hostio.h: Rename include guard. + * gdbthread.h: Rename include guard. + * gdb_proc_service.h: Rename include guard. + * event-loop.h: Rename include guard. + * dll.h: Rename include guard. + * debug.h: Rename include guard. + * ax.h: Rename include guard. + +2018-01-30 Szabolcs Nagy + + PR gdb/23985 + * Makefile.in (IPAGENT_CFLAGS): Add UNDO_GNULIB_CFLAGS. + (UNDO_GNULIB_CFLAGS): Undo gnulib replacements. + +2019-01-25 Tom Tromey + + * Makefile.in (INCLUDE_CFLAGS): Don't add -I for common. + +2019-01-25 Tom Tromey + + * win32-low.c: Fix common/ includes. + * win32-i386-low.c: Fix common/ includes. + * tracepoint.c: Fix common/ includes. + * thread-db.c: Fix common/ includes. + * target.h: Fix common/ includes. + * symbol.c: Fix common/ includes. + * spu-low.c: Fix common/ includes. + * server.h: Fix common/ includes. + * server.c: Fix common/ includes. + * remote-utils.c: Fix common/ includes. + * regcache.h: Fix common/ includes. + * regcache.c: Fix common/ includes. + * nto-x86-low.c: Fix common/ includes. + * notif.h: Fix common/ includes. + * mem-break.h: Fix common/ includes. + * lynx-low.c: Fix common/ includes. + * lynx-i386-low.c: Fix common/ includes. + * linux-x86-tdesc-selftest.c: Fix common/ includes. + * linux-x86-low.c: Fix common/ includes. + * linux-low.c: Fix common/ includes. + * inferiors.h: Fix common/ includes. + * i387-fp.c: Fix common/ includes. + * hostio.c: Fix common/ includes. + * hostio-errno.c: Fix common/ includes. + * gdbthread.h: Fix common/ includes. + * gdbreplay.c: Fix common/ includes. + * fork-child.c: Fix common/ includes. + * event-loop.c: Fix common/ includes. + * ax.c: + (enum gdb_agent_op): Fix common/ includes. + +2019-01-21 Tom Tromey + + * tracepoint.c: Fix includes. + * remote-utils.c: Fix includes. + * linux-x86-low.c: Fix includes. + +2019-01-01 Joel Brobecker + + * gdbreplay.c (gdbreplay_version): Update copyright year in + version message. + * server.c (gdbserver_version): Likewise. + +2018-12-05 Alan Hayward + + * linux-low.c (add_lwp): Switch ordering. + +2018-11-29 Tom Tromey + + * win32-low.c (win32_join): Take pid, not process. + * target.h (struct target_ops) : Change argument type. + (join_inferior): Change argument name. + * spu-low.c (spu_join): Take pid, not process. + * server.c (handle_detach): Preserve pid before destroying + process. + * lynx-low.c (lynx_join): Take pid, not process. + * linux-low.c (linux_join): Take pid, not process. + +2018-11-23 Alan Hayward + + * linux-aarch64-low.c (aarch64_cannot_store_register): Remove. + (aarch64_cannot_fetch_register): Likewise. + (struct linux_target_ops): Update references. + +2018-10-31 Pedro Franco de Carvalho + + * linux-ppc-low.c: Include nat/linux-ptrace.h. + +2018-10-26 Pedro Franco de Carvalho + + * configure.srv (ipa_ppc_linux_regobj): Add + powerpc-isa207-htm-vsx32l-ipa.o and + powerpc-isa207-htm-vsx64l-ipa.o. + (powerpc*-*-linux*): Add powerpc-isa207-htm-vsx32l.o and + powerpc-isa207-htm-vsx64l.o to srv_regobj. Add + rs6000/power-htm-spr.xml, rs6000/power-htm-core.xml, + rs6000/power64-htm-core.xml, rs6000/power-htm-fpu.xml, + rs6000/power-htm-altivec.xml, rs6000/power-htm-vsx.xml, + rs6000/power-htm-ppr.xml, rs6000/power-htm-dscr.xml, + rs6000/power-htm-tar.xml, rs6000/powerpc-isa207-htm-vsx32l.xml, + and rs6000/powerpc-isa207-htm-vsx64l.xml to srv_xmlfiles. + * linux-ppc-tdesc-init.h (enum ppc_linux_tdesc) + : New enum value. + (init_registers_powerpc_isa207_htm_vsx32l) + (init_registers_powerpc_isa207_htm_vsx64l): Declare. + * linux-ppc-low.c (ppc_fill_tm_sprregset, ppc_store_tm_sprregset) + (ppc_store_tm_cgprregset, ppc_store_tm_cfprregset) + (ppc_store_tm_cvrregset, ppc_store_tm_cvsxregset) + (ppc_store_tm_cpprregset, ppc_store_tm_cdscrregset) + (ppc_store_tm_ctarregset): New functions. + (ppc_regsets): Add entries for HTM regsets. + (ppc_arch_setup): Set htm in features struct when needed. Set + sizes for the HTM regsets. + (ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA207_HTM_VSX. + (initialize_low_arch): Call + init_registers_powerpc_isa207_htm_vsx32l and + init_registers_powerpc_isa207_htm_vsx64l. + * linux-ppc-ipa.c (get_ipa_tdesc): Handle + PPC_TDESC_ISA207_HTM_VSX. + (initialize_low_tracepoint): Call + init_registers_powerpc_isa207_htm_vsx32l and + init_registers_powerpc_isa207_htm_vsx64l. + +2018-10-26 Pedro Franco de Carvalho + + * configure.srv (powerpc*-*-linux*): Add rs6000/power-ebb.xml and + rs6000/power-linux-pmu.xml to srv_xmlfiles. + * linux-ppc-low.c (ppc_store_ebbregset, ppc_fill_pmuregset) + (ppc_store_pmuregset): New functions. + (ppc_regsets): Add entries for ebb and pmu regsets. + (ppc_arch_setup): Set isa207 in features struct if the ebb and + pmu regsets are available. Set sizes for these regsets. + +2018-10-26 Pedro Franco de Carvalho + + * configure.srv (ipa_ppc_linux_regobj): Add + powerpc-isa207-vsx64l-ipa.o and powerpc-isa207-vsx32l-ipa.o. + (powerpc*-*-linux*): Add powerpc-isa207-vsx32l.o and + powerpc-isa207-vsx64l.o to srv_regobj, add rs6000/power-tar.xml, + rs6000/powerpc-isa207-vsx32l.xml, and + rs6000/powerpc-isa207-vsx64l.xml to srv_xmlfiles. + * linux-ppc-tdesc-init.h (enum ppc_linux_tdesc) + : New enum value. + (init_registers_powerpc_isa207_vsx32l): Declare. + (init_registers_powerpc_isa207_vsx64l): Declare. + * linux-ppc-low.c (ppc_fill_tarregset): New function. + (ppc_store_tarregset): New function. + (ppc_regsets): Add entry for the TAR regset. + (ppc_arch_setup): Set isa207 in features struct when needed. Set + size for the TAR regsets. + (ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA207_VSX. + (initialize_low_arch): Call init_registers_powerpc_isa207_vsx32l + and init_registers_powerpc_isa207_vsx64l. + * linux-ppc-ipa.c (get_ipa_tdesc): Handle PPC_TDESC_ISA207_VSX. + (initialize_low_tracepoint): Call + init_registers_powerpc_isa207_vsx32l and + init_registers_powerpc_isa207_vsx64l. + +2018-10-26 Edjunior Barbosa Machado + Pedro Franco de Carvalho + + * configure.srv (ipa_ppc_linux_regobj): Add + powerpc-isa205-ppr-dscr-vsx32l-ipa.o and + powerpc-isa205-ppr-dscr-vsx64l-ipa.o. + (powerpc*-*-linux*): Add powerpc-isa205-ppr-dscr-vsx32l.o and + powerpc-isa205-ppr-dscr-vsx64l.o to srv_regobj, add + rs6000/power-dscr.xml, rs6000/power-ppr.xml, + rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml and + rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml to srv_xmlfiles. + * linux-ppc-tdesc-init.h (enum ppc_linux_tdesc) + : New enum value. + (init_registers_powerpc_isa205_ppr_dscr_vsx32l) + (init_registers_powerpc_isa205_ppr_dscr_vsx64l): Declare. + * linux-ppc-low.c: Include "elf/common.h" and . + (ppc_hwcap): Add comment. + (ppc_hwcap2): New global. + (ppc_check_regset, ppc_fill_pprregset, ppc_store_pprregset) + (ppc_fill_dscrregset, ppc_store_dscrregset): New functions. + (ppc_regsets): Add entries for the DSCR and PPR regsets. + (ppc_arch_setup): Get AT_HWCAP2. Set ppr_dscr in features struct + when needed. Set sizes for the the DSCR and PPR regsets. + (ppc_get_ipa_tdesc_idx): Return PPC_TDESC_ISA205_PPR_DSCR_VSX. + (initialize_low_arch): Call + init_registers_powerpc_isa205_ppr_dscr_vsx32l and + init_registers_powerpc_isa205_ppr_dscr_vsx64l. + * linux-ppc-ipa.c (get_ipa_tdesc): Handle + PPC_TDESC_ISA205_PPR_DSCR_VSX. + (initialize_low_tracepoint): Call + init_registers_powerpc_isa205_ppr_dscr_vsx32l and + init_registers_powerpc_isa205_ppr_dscr_vsx64l. + +2018-10-26 Pedro Franco de Carvalho + + * linux-ppc-low.c (ppc_fill_vrregset): Remove memset calls. + +2018-10-10 Sergio Durigan Junior + Simon Marchi + + * acinclude.m4: Include "../selftest.m4". + * configure: Regenerate. + * configure.ac: Use "GDB_AC_SELFTEST". + * configure.srv: Use "$enable_unittests" instead of + "$development" when checking whether unit tests have been + enabled. + * server.c (captured_main): Update message informing that + selftests have been disabled. + +2018-10-04 Tom Tromey + + * configure: Rebuild. + +2018-10-04 Tom Tromey + + * server.c (handle_status): Rename inner "thread". + (process_serial_event): Declare "res" in 'm' case. + * linux-low.c (last_thread_of_process_p, find_lwp_pid) + (iterate_over_lwps): Rename inner "thread". + (linux_qxfer_libraries_svr4): Rename inner "len". + * gdbthread.h (find_thread_in_random): Rename inner "thread". + +2018-10-01 Gary Benson + + * gdb_proc_service.h: Moved common code to + common/gdb_proc_service.h. + +2018-10-01 Gary Benson + + * gdb_proc_service.h: Synchronize comments and whitespace with + GDB's version of this file. + +2018-09-25 Tom Tromey + + * configure: Rebuild. + * configure.ac (WARN_CFLAGS): Don't remove -Wmissing-prototypes. + +2018-09-16 Simon Marchi + + * Makefile.in (gdbserver$(EXEEXT)): Sort OBS. + (gdbreplay$(EXEEXT)): Sort GDBREPLAY_OBS. + ($(IPA_LIB)): Sort IPA_OBJS. + +2018-09-16 Simon Marchi + + * Makefile.in: Remove references to $(ADD_DEPS). + +2018-09-16 Tom Tromey + + * remote-utils.c (remote_open): Use GNU style for metasyntactic + variables. + * gdbreplay.c (gdbreplay_usage): Use GNU style for metasyntactic + variables. + +2018-09-05 Tom Tromey + + * configure: Rebuild. + +2018-08-28 Simon Marchi + + PR build/23399 + * tracepoint.c (IPA_SYM_STRUCT_NAME): Define. + +2018-08-27 Tom Tromey + + PR build/23087: + * configure: Rebuild. + +2018-08-27 Tom Tromey + + * linux-s390-low.c (s390_emit_ext, s390_emit_litpool) + (s390_emit_const, s390_emit_reg, s390_emit_zero_ext) + (s390_emit_stack_adjust, s390_emit_set_r2, s390x_emit_ext) + (s390x_emit_const, s390x_emit_reg, s390x_emit_zero_ext) + (s390x_emit_stack_adjust): Add casts to unsigned char. + +2018-08-22 Simon Marchi + + PR gdb/23374 + PR gdb/23375 + * server.h (struct client_state) : + Initialize to 1. + +2018-07-22 Simon Marchi + + * linux-mips-low.c (mips_collect_ptrace_register): Remove unused + variable. + (mips_supply_ptrace_register): Likewise. + +2018-07-22 Tom Tromey + + * configure: Rebuild. + +2018-07-22 Tom Tromey + + * win32-low.c (win32_create_inferior): Remove unused variables. + * gdbreplay.c (remote_open): Remove unused variable. + * remote-utils.c (remote_prepare): Remove unused variable. + * x86-tdesc.h (X86_TDESC_H): Define. + (amd64_expedite_regs): Define conditionally. + (i386_expedite_regs): Mark ATTRIBUTE_UNUSED. + * linux-x86-tdesc.c (i386_tdescs): Move inside #if. + * remote-utils.c (readchar): Remove unused variable. + +2018-07-13 Pedro Alves + + * linux-low.c (linux_kill): Change parameter to process_info + pointer instead of pid. Adjust. + * lynx-low.c (lynx_kill): Likewise. + * nto-low.c (nto_kill): Likewise. + * spu-low.c (spu_kill): Likewise. + * win32-low.c (win32_kill): Likewise. + * server.c (handle_v_kill, kill_inferior_callback) + (detach_or_kill_for_exit): Adjust. + * target.c (kill_inferior): Change parameter to process_info + pointer instead of pid. Adjust. + * target.h (struct target_ops) : Change parameter to + process_info pointer instead of pid. Adjust all implementations + and callers. + (kill_inferior): Likewise. + +2018-07-13 Pedro Alves + + * linux-low.c (linux_detach, linux_join): Change parameter to + process_info pointer instead of pid. Adjust. + * lynx-low.c (lynx_detach, lynx_join): Likewise. + * nto-low.c (nto_detach): Likewise. + * spu-low.c (spu_detach, spu_join): Likewise. + * win32-low.c (win32_detach, win32_join): Likewise. + * server.c (handle_detach, detach_or_kill_for_exit): Adjust. + * target.h (struct target_ops) : Change parameter to + process_info pointer instead of pid. Adjust all implementations + and callers. + (detach_inferior, join_inferior): Rename 'pid' parameter to + 'proc'. + +2018-07-11 Sergio Durigan Junior + Jan Kratochvil + Paul Fertser + Tsutomu Seki + + * Makefile.in (SFILES): Add '$(srcdir)/common/netstuff.c'. + (OBS): Add 'common/netstuff.o'. + (GDBREPLAY_OBS): Likewise. + * gdbreplay.c: Include 'wspiapi.h' and 'netstuff.h'. + (remote_open): Implement support for IPv6 + connections. + * remote-utils.c: Include 'netstuff.h', 'filestuff.h' + and 'wspiapi.h'. + (handle_accept_event): Accept connections from IPv6 sources. + (remote_prepare): Handle IPv6-style hostnames; implement + support for IPv6 connections. + (remote_open): Implement support for printing connections from + IPv6 sources. + +2018-07-11 Pedro Alves + + PR gdb/23377 + * mem-break.c (any_persistent_commands): Add process_info + parameter and use it instead of relying on the current process. + Change return type to bool. + * mem-break.h (any_persistent_commands): Add process_info + parameter and change return type to bool. + * server.c (handle_detach): Remove require_running_or_return call. + Look up the process_info for the process we're about to detach. + If not found, return back error to GDB. Adjust + any_persistent_commands call to pass down a process pointer. + +2018-07-11 Pedro Alves + + * i387-fp.c (i387_cache_to_fsave, cache_to_fxsave) + (i387_cache_to_xsave): Use regcache_raw_get_unsigned_by_name + instead of collect_register_by_name. + * regcache.c (regcache_raw_get_unsigned_by_name): New. + * regcache.h (regcache_raw_get_unsigned_by_name): New. + +2018-07-04 Vyacheslav Barinov + Pedro Alves + + * linux-low.c (initialize_low): Call linux_proc_init_warnings. + +2018-07-03 Tom Tromey + + * linux-low.c: Update. + * lynx-low.c: Update. + * mem-break.c: Update. + * nto-low.c: Update. + * remote-utils.c: Update. + * server.c: Update. + * spu-low.c: Update. + * target.c: Update. + * win32-low.c: Update. + +2018-07-03 Tom Tromey + + * server.c: Update. + +2018-07-03 Tom Tromey + + * linux-low.c: Update. + +2018-07-03 Tom Tromey + + * target.c: Update. + +2018-07-03 Tom Tromey + + * linux-low.c: Update. + * linux-mips-low.c: Update. + * lynx-low.c: Update. + * nto-low.c: Update. + * remote-utils.c: Update. + * server.c: Update. + * spu-low.c: Update. + * target.c: Update. + * thread-db.c: Update. + +2018-07-03 Tom Tromey + + * linux-low.c: Update. + * linux-mips-low.c: Update. + * lynx-low.c: Update. + * mem-break.c: Update. + * nto-low.c: Update. + * remote-utils.c: Update. + * server.c: Update. + * spu-low.c: Update. + * target.c: Update. + * tracepoint.c: Update. + +2018-07-03 Tom Tromey + + * linux-low.c: Update. + * linux-ppc-low.c: Update. + * linux-x86-low.c: Update. + * proc-service.c: Update. + * server.c: Update. + * spu-low.c: Update. + * thread-db.c: Update. + * win32-low.c: Update. + +2018-07-03 Tom Tromey + + * linux-low.c: Update. + * lynx-low.c: Update. + * nto-low.c: Update. + * remote-utils.c: Update. + * spu-low.c: Update. + * thread-db.c: Update. + * win32-low.c: Update. + +2018-06-29 Joel Brobecker + + * linux-x86-tdesc.c (amd64_linux_read_description): Add missing + parameter in call to 'amd64_create_target_description'. + +2018-06-28 Jan Kratochvil + + * x86-tdesc.h: Remove executable permission flag. + +2018-06-19 Simon Marchi + + * configure.ac: Remove AC_PREREQ, add missing quoting. + * configure: Re-generate. + * config.in: Re-generate. + * aclocal.m4: Re-generate. + +2018-06-18 Simon Marchi + + * tracepoint.h (current_traceframe): Remove declaration. + +2018-06-18 Alan Hayward + + * linux-aarch64-low.c (is_sve_tdesc): New function. + (aarch64_sve_regs_copy_to_regcache): Likewise. + (aarch64_sve_regs_copy_from_regcache): Likewise. + (aarch64_regs_info): Add SVE checks. + (initialize_low_arch): Initialize SVE. + +2018-06-18 Alan Hayward + + * Makefile.in: Add aarch64-sve-linux-ptrace.c. + +2018-06-11 Alan Hayward + + * linux-aarch64-ipa.c (get_ipa_tdesc): Add null VQ param. + (initialize_low_tracepoint): Likewise + * linux-aarch64-low.c (aarch64_arch_setup): Get VQ. + * linux-aarch64-tdesc-selftest.c (aarch64_tdesc_test): Add null VQ + param. + * linux-aarch64-tdesc.c (aarch64_linux_read_description): Add VQ + checks. + * linux-aarch64-tdesc.h (aarch64_linux_read_description): Add VQ. + +2018-06-11 Alan Hayward + + * server.h (PBUFSIZ): Increase size + +2018-06-11 Alan Hayward + + * regcache.c (regcache::raw_compare): New function. + * regcache.h (regcache::raw_compare): New declaration. + +2018-06-11 Alan Hayward + + * regcache.c (new_register_cache): Use new. + (free_register_cache): Use delete. + (register_data): Use const. + (supply_register): Move body inside regcache. + (regcache::raw_supply): New override function. + (collect_register): Move body inside regcache. + (regcache::raw_collect): New override function. + (regcache::get_register_status): New override function. + * regcache.h (struct regcache): Inherit from reg_buffer_common. + +2018-06-09 Tom Tromey + + * event-loop.c (gdb_event, gdb_event_p): Remove typedefs. Don't + declare queue. + (event_queue): Use std::queue. + (gdb_event_xfree): Remove. + (initialize_event_loop, process_event, wait_for_event): Update. + +2018-06-08 Stan Cox + + * win32-low.c (win32_create_inferior): last_ptid and last_status + moved to client_state. + +2018-06-08 Pedro Alves + + * Makefile.in (GDBREPLAY_OBS): Add common/cleanups.o, + common/common-exceptions.o, common/common-utils.o, + common/errors.o, common/print-utils.o and utils.o. + * gdbreplay.c: Include "common-defs.h" instead of the two + 'config.h's here. Don't include stdio.h, errno.h, stdlib.h, + string.h or alloca.h. + (perror_with_name): Delete. + (remote_open): Use xstrdup instead of strdup. + (main): Rename to ... + (captured_main): ... this. + (main): New. + +2018-06-08 Tom Tromey + + * linux-low.c (linux_low_read_btrace): Update. + +2018-06-04 Stan Cox + + * server.h (struct client_state): New. + * server.c (cont_thread, general_thread, multi_process) + (report_fork_events, report_vfork_events, report_exec_events) + (report_thread_events, swbreak_feature, hwbreak_feature) + (vCont_supported, disable_randomization, pass_signals) + (program_signals, program_signals_p, last_status, last_ptid, own_buf): + Moved to client_state. + * remote-utils.c (remote_debug, noack_mode) + (transport_is_reliable): Moved to client_state. + * tracepoint.c (current_traceframe): Moved to client_state. + + Update all callers. + * server.c, remote-utils.c, tracepoint.c, fork-child.c, + linux-low.c, remote-utils.h, target.c: Use client_state. + +2018-05-31 Alan Hayward + + * configure.srv: Add new c/h file. + +2018-05-31 Alan Hayward + + * linux-aarch64-tdesc.c (aarch64_linux_read_description): Add + null VQ. + +2018-05-25 Maciej W. Rozycki + + * gdb.arch/mips-fpregset-core.exp: New test. + * gdb.arch/mips-fpregset-core.c: New test source. + +2018-05-23 Erik Kurzinger + + PR server/23198 + * hostio.c (require_int): Do not report overflow for integers + between 0xfffffff and 0x7fffffff. + +2018-05-22 Maciej W. Rozycki + + * linux-mips-low.c [HAVE_PTRACE_GETREGS] (mips_collect_register) + (mips_supply_register): Move outside HAVE_PTRACE_GETREGS. + (mips_collect_ptrace_register, mips_supply_ptrace_register): New + functions. + (the_low_target): Wire them. + +2018-05-22 Pedro Franco de Carvalho + + * linux-ppc-low.c (ppc_fill_vrregset): Add vscr_offset variable. + Set vscr_offset to 0 in little-endian mode and 12 in big-endian + mode. Call collect_register_by_name with vscr using + vscr_offset. Zero-pad vscr and vrsave fields in collector buffer. + (ppc_store_vrregset): Add and set vscr_offset variable as in + ppc_fill_vrregset. Call supply_register_by_name with vscr using + vscr_offset. + +2018-05-22 Pedro Franco de Carvalho + + * linux-ppc-low.c (SIZEOF_VSXREGS, SIZEOF_VRREGS): Remove. + (ppc_arch_setup): Change SIZEOF_VRREGS and SIZEOF_VSXREGS to + PPC_LINUX_SIZEOF_VRREGSET and PPC_LINUX_SIZEOF_VSXREGSET. + +2018-05-22 Pedro Franco de Carvalho + + * linux-ppc-low.c (ppc_fill_vsxregset): Remove ppc_hwcap check. + (ppc_store_vsxregset): Likewise. + (ppc_fill_vrregset): Likewise. + (ppc_store_vrregset): Likewise. + (ppc_fill_evrregset): Likewise. + (ppc_store_evrregset): Likewise. + (ppc_regsets): Set VSX/VR/EVR regset sizes to 0. + (ppc_arch_setup): Iterate through ppc_regsets and set sizes when + needed. + +2018-05-22 Pedro Franco de Carvalho + + * linux-ppc-low.c (ppc_arch_setup): Remove code for getting the + wordsize of the inferior. Call ppc_linux_target_wordsize. + +2018-05-22 Pedro Franco de Carvalho + + * configure.srv (srv_tgtobj): Add arch/ppc-linux-common.o. + * Makefile.in (SFILES): Add arch/ppc-linux-common.c. + * linux-ppc-tdesc.h: Rename to linux-ppc-tdesc-init.h. + * linux-ppc-tdesc-init.h (tdesc_powerpc_32l, tdesc_powerpc_64l) + (tdesc_powerpc_altivec32l, tdesc_powerpc_altivec64l) + (tdesc_powerpc_cell32l, tdesc_powerpc_cell64l) + (tdesc_powerpc_vsx32l, tdesc_powerpc_vsx64l) + (tdesc_powerpc_isa205_32l, tdesc_powerpc_isa205_64l) + (tdesc_powerpc_isa205_altivec32l, tdesc_powerpc_isa205_altivec64l) + (tdesc_powerpc_isa205_vsx32l, tdesc_powerpc_isa205_vsx64l) + (tdesc_powerpc_e500l): Remove. + * linux-ppc-ipa.c: Include arch/ppc-linux-tdesc.h and + linux-ppc-tdesc-init.h. Don't include linux-ppc-tdesc.h. + * linux-ppc-low.c: Include arch/ppc-linux-common.h, + arch/ppc-linux-tdesc.h, and linux-ppc-tdesc-init.h. Don't include + linux-ppc-tdesc.h. + (ppc_arch_setup): Remove target description matching code. Fill a + ppc_linux_features struct and call ppc_linux_match_description + with it. + +2018-05-22 Maciej W. Rozycki + + * linux-mips-low.c (mips_cannot_fetch_register): Return 1 if the + width of the requested register exceeds the width of the + `ptrace' data type. + (mips_cannot_store_register): Likewise. + +2018-05-21 Maciej W. Rozycki + + * linux-mips-low.c (mips_fetch_register): New function. Update + preceding comment. + (mips_store_gregset): Supply 0 rather than $restart for $zero. + (the_low_target): Wire `mips_fetch_register'. + +2018-05-10 Joel Brobecker + + * lynx-i386-low.c (LYNXOS_178): New macro. + [LYNXOS_178] (usr_fcontext_t): Provide a definition that matches + the layout on LynxOS-178. + (lynx_i386_fill_fpregset, lynx_i386_store_fpregset): Do not + handle floating point registers that are not supported by + LynxOS-178. + +2018-05-10 Tom Tromey + + * configure: Rebuild. + +2018-05-10 Joel Brobecker + + PR server/23158: + * tdesc.h (init_target_desc) : New parameter. + * tdesc.c (init_target_desc) : New parameter. + Use it to set the expedite_regs field in the given tdesc. + * x86-tdesc.h: New file. + * linux-aarch64-tdesc.c (aarch64_linux_read_description): + Adjust following the addition of the new expedite_regs parameter + to init_target_desc. + * linux-tic6x-low.c (tic6x_read_description): Likewise. + * linux-x86-tdesc.c: #include "x86-tdesc.h". + (i386_linux_read_description, amd64_linux_read_description): + Adjust following the addition of the new expedite_regs parameter + to init_target_desc. + * lynx-i386-low.c: #include "x86-tdesc.h". + (lynx_i386_arch_setup): Adjust following the addition of the new + expedite_regs parameter to init_target_desc. + * nto-x86-low.c: #include "x86-tdesc.h". + (nto_x86_arch_setup): Adjust following the addition of the new + expedite_regs parameter to init_target_desc. + * win32-i386-low.c: #include "x86-tdesc.h". + (i386_arch_setup): Adjust following the addition of the new + expedite_regs parameter to init_target_desc. + +2018-05-10 Joel Brobecker + + PR server/23158: + * win32-low.c (win32_create_inferior): Add call to my_wait + setting last_status global. + +2018-05-10 Joel Brobecker + + PR server/23158: + * win32-low.c (create_process): Only call gdb_tilde_expand if + inferior_cwd is not NULL. + +2018-05-08 Andrew Burgess + + * i387-fp.c (i387_cache_to_xsave): Only write x87 control + registers to the cache if their values have changed. + (i387_xsave_to_cache): Provide default values for x87 control + registers when these features are available, but disabled. + * regcache.c (supply_register_by_name_zeroed): New function. + * regcache.h (supply_register_by_name_zeroed): Declare new + function. + +2018-05-07 Tom Tromey + + * configure: Rebuild. + +2018-05-04 Tom Tromey + + * configure: Rebuild. + +2018-05-04 Jan Kratochvil + Pedro Alves + + * linux-aarch64-low.c (aarch64_stopped_data_address): + Likewise. + +2018-04-27 Tom Tromey + + * configure: Rebuild. + +2018-04-23 Tom Tromey + + * configure: Rebuild. + +2018-04-19 Simon Marchi + + * Makefile.in (depcomp): Add "..". + (all_deps_files): New and use it. + +2018-04-18 Alan Hayward + + * configure.srv (aarch64*-*-linux*): Don't include xml. + (i[34567]86-*-cygwin*): Likewise. + (i[34567]86-*-linux*): Likewise. + (i[34567]86-*-lynxos*): Likewise. + (i[34567]86-*-mingw32ce*): Likewise. + (i[34567]86-*-mingw*): Likewise. + (i[34567]86-*-nto*): Likewise. + (tic6x-*-uclinux): Likewise. + (x86_64-*-linux*): Likewise. + (x86_64-*-mingw*): Likewise. + (x86_64-*-cygwin*): Likewise. + +2018-04-18 Alan Hayward + + * tdesc.c: Remove xml parameter. + +2018-04-18 Alan Hayward + + * server.c (get_features_xml): Remove cast. + * tdesc.c (void target_desc::accept): Fill in function. + (tdesc_get_features_xml): Remove old xml creation. + (print_xml_feature::visit_pre): Add xml vistor. + * tdesc.h (struct target_desc): Make xmltarget mutable. + (tdesc_get_features_xml): Remove declaration. + +2018-04-18 Alan Hayward + + * tdesc.c (tdesc_architecture_name): Add new function. + (tdesc_osabi_name): Likewise. + (tdesc_get_features_xml): Use new functions. + +2018-04-18 Alan Hayward + + * tdesc.c (tdesc_create_flags): Remove. + (tdesc_add_flag): Likewise. + (tdesc_named_type): Likewise. + (tdesc_create_union): Likewise. + (tdesc_create_struct): Likewise. + (tdesc_create_vector): Likewise. + (tdesc_add_bitfield): Likewise. + (tdesc_add_field): Likewise. + (tdesc_set_struct_size): Likewise. + +2018-04-18 Alan Hayward + + * tdesc.c (~target_desc): Remove implictly deleted items. + (init_target_desc): Iterate all features. + (tdesc_get_features_xml): Use vector. + (tdesc_create_feature): Create feature. + * tdesc.h (tdesc_feature) Remove + (target_desc): Add features. + +2018-04-18 Alan Hayward + + * Makefile.in: Add common/tdesc.c + * tdesc.c (init_target_desc): init all reg_defs from register + vector. + (tdesc_create_reg): Create tdesc_reg. + * tdesc.h (tdesc_feature): Add register vector. + +2018-03-30 Simon Marchi + + * tdesc.h (struct target_desc) : Change type to + std::vector. + * tdesc.c (target_desc::~target_desc): Adjust to std::vector + changes. + (tdesc_get_features_xml): Likewise. + (tdesc_create_feature): Likewise. + +2018-03-26 Alan Hayward + + * regcache.c (find_register_by_number): Return a ref. + (find_regno): Use references. + (register_size): Likewise. + (register_data): Likewise. + * tdesc.c (target_desc::~target_desc): Remove free calls. + (target_desc::operator==): Use std::vector compare. + (init_target_desc): Use reference. + (tdesc_create_reg): Use reg constructors. + * tdesc.h (struct target_desc): Replace pointer with object. + +2018-03-23 Alan Hayward + + * regcache.c (find_register_by_number): Make static. + (find_regno): Use find_register_by_number + * regcache.h (struct reg): Remove declaration. + +2018-03-23 Alan Hayward + + * tdesc.c (target_desc::~target_desc): Move to here. + (target_desc::operator==): Likewise. + * tdesc.h (target_desc::~target_desc): Move from here. + (target_desc::operator==): Likewise. + +2018-03-22 Andreas Arnez + + * linux-s390-low.c (s390_get_wordsize): Correct brace style. + +2018-03-21 Andreas Arnez + + * linux-s390-ipa.c (get_ipa_tdesc): Add handling for + S390_TDESC_GS. + * linux-s390-low.c (s390_get_ipa_tdesc_idx): Likewise. + (initialize_low_tracepoint): Call init_registers_s390x_gs_linux64 + and init_registers_s390_gs_linux64. + +2018-03-21 Andreas Arnez + + * linux-s390-low.c (s390_fill_gs): Remove function. + (s390_fill_gsbc): Remove function. + (s390_regsets): Set fill functions for the guarded storage regsets + to NULL. + +2018-03-21 Andreas Arnez + + * linux-s390-low.c (s390_get_hwcap): Replace tdesc parameter by + the word size. Add comment. + (s390_get_wordsize): New function. + (s390_arch_setup): No longer select a temporary tdesc to fetch the + pswm with it. Instead, use s390_get_wordsize to determine the + word size first and derive the correct tdesc from that directly. + +2018-03-16 Simon Marchi + + * Makefile.in: Include silent-rules.mk. + (srcdir, abs_top_srcdir, abs_srcdir, VPATH): Move up. + (COMPILE): Add ECHO_CXX. + (gdbserver$(EXEEXT)): Add SILENCE and ECHO_CXXLD. + (gdbreplay$(EXEEXT)): Add SILENCE and ECHO_CXXLD. + ($(IPA_LIB)): Add SILENCE and ECHO_CXXLD. + (version-generated.c): Add ECHO_GEN. + (stamp-xml): Add SILENCE and ECHO_GEN_XML_BUILTIN_GENERATED. + (IPAGENT_COMPILE): Add ECHO_CXX. + (%-generated.c): Add ECHO_REGDAT. + +2018-03-14 Tom Tromey + + PR cli/14977: + * ax.c (ax_printf): Special case for NULL. + +2018-03-08 Simon Marchi + + * linux-low.c (linux_qxfer_libraries_svr4): Use + xml_escape_text_append. + +2018-03-08 Simon Marchi + + * linux-low.c (linux_qxfer_libraries_svr4): Use std::string. + +2018-03-02 Simon Marchi + + * server.c (handle_general_set): Remove unnecessary xstrdup. + +2018-03-02 Simon Marchi + + * server.c (parse_debug_format_options): Adjust to + delim_string_to_char_ptr_vec changes. + * thread-db.c (thread_db_load_search): Adjust to + dirnames_to_char_ptr_vec changes. + +2018-03-01 Markus Metzger + + * target.h (target_enable_btrace, target_disable_btrace) + (target_read_btrace, target_read_btrace_conf): Turn macro into + inline function. Throw error if target method is not defined. + * server.c (handle_qxfer_btrace handle_qxfer_btrace_conf): Remove + check for btrace target method. Be prepared to handle exceptions + from btrace target methods. + +2018-02-28 Sergio Durigan Junior + + * server.c (captured_main): Change order of error message printed + when the current working directory cannot be found. + +2018-02-28 Sergio Durigan Junior + + * server.c: Include "filenames.h" and "pathstuff.h". + (program_name): Delete variable. + (program_path): New anonymous class. + (get_exec_wrapper): Use "program_path" instead of + "program_name". + (handle_v_run): Likewise. + (captured_main): Likewise. + (process_serial_event): Likewise. + +2018-02-28 Sergio Durigan Junior + + * Makefile.in (SFILES): Add "$(srcdir)/common/pathstuff.c". + (OBJS): Add "pathstuff.o". + * server.c (current_directory): New global variable. + (captured_main): Initialize "current_directory". + +2018-02-26 Alan Hayward + + * tdesc.c: Use common/tdesc.h. + * tdesc.h: Likewise. + +2018-02-20 Alan Hayward + Simon Marchi + + * Makefile.in: Switch order of make rules. + +2018-02-19 Alan Hayward + + * Makefile.in: Add common directory in build. + * configure.ac: Add common reference. + * configure: Regenerate. + +2018-02-09 Markus Metzger + + * linux-low.c (linux_target_ops): Remove linux_supports_btrace. + * nto-low.c (nto_target_ops): Remove NULL for supports_btrace. + * spu-low.c (spu_target_ops): Likewise. + * win32-low.c (win32_target_ops): Likewise. + * server.c (supported_btrace_packets): Report packets unconditionally. + * target.h (target_ops) : Remove. + (target_supports_btrace): Remove. + +2018-02-09 Markus Metzger + + * server.c (handle_btrace_enable_bts, handle_btrace_enable_pt) + (handle_btrace_disable): Change return type to void. Use exceptions + to report errors. + (handle_btrace_general_set): Catch exception and copy message to + return message. + +2018-02-08 Tom Tromey + + * linux-low.c (install_software_single_step_breakpoints): Use + make_scoped_restore. + * inferiors.c (make_cleanup_restore_current_thread): Remove. + (do_restore_current_thread_cleanup): Remove. + * gdbthread.h (make_cleanup_restore_current_thread): Don't + declare. + +2018-02-08 Tom Tromey + + * mem-break.c (set_raw_breakpoint_at): Use + gdb::unique_xmalloc_ptr. + +2018-01-30 Pedro Alves + + PR gdb/13211 + * target.c (target_terminal::terminal_state): Rename to ... + (target_terminal::m_terminal_state): ... this. + +2018-01-19 James Clarke + + * linux-low.c (handle_extended_wait): Surround call to + thread_db_notice_clone with #ifdef USE_THREAD_DB. + +2018-01-17 Simon Marchi + + * linux-low.c (attach_proc_task_lwp_callback): Adjust to + linux_ptrace_attach_fail_reason_string now returning an + std::string. + (linux_attach): Likewise. + * thread-db.c (attach_thread): Likewise. + +2018-01-17 Eldar Abusalimov + + PR gdb/21559 + * configure.ac: Include prior to when + checking for fs_base/gs_base fields in struct user_regs_struct. + * configure: Regenerate. + +2018-01-16 Yao Qi + + PR gdb/18749 + * linux-low.c (fetch_register): Call supply_register instead of + error. + +2018-01-08 Yao Qi + Simon Marchi + + * Makefile.in (OBS): Remove selftest.o. + * configure.ac: Set srv_selftest_objs if $development is true. + (GDBSERVER_DEPFILES): Append $srv_selftest_objs. + * configure: Re-generated. + * server.c (captured_main): Wrap variable selftest_filter with + GDB_SELF_TEST. + +2018-01-07 Simon Marchi + + * server.c (parse_debug_format_options): Return std::string. + (handle_monitor_command, captured_main): Adjust. + +2018-01-05 Pedro Alves + + PR gdb/18653 + * server.c (captured_main): Pass quiet=false to + save_original_signals_state. + +2018-01-01 Joel Brobecker + + * gdbreplay.c (gdbreplay_version): Update copyright year in + version message. + * server.c (gdbserver_version): Likewise. + +2017-12-08 Tom Tromey + + * ax.c (ax_printf): Update. + +2017-12-07 Yao Qi + + * linux-aarch64-ipa.c (initialize_low_tracepoint): Call + aarch64_linux_read_description. + * linux-amd64-ipa.c (idx2mask): New array. + (get_ipa_tdesc): Move idx2mask out. + (initialize_low_tracepoint): Initialize target descriptions. + * linux-i386-ipa.c (idx2mask): New array. + (get_ipa_tdesc): Move idx2mask out. + (initialize_low_tracepoint): Initialize target descriptions. + +2017-12-05 Simon Marchi + + * tdesc.c (struct tdesc_type): Change return type. + (tdesc_add_flag): Change parameter type. + (tdesc_add_bitfield): Likewise. + (tdesc_add_field): Likewise. + (tdesc_set_struct_size): Likewise. + +2017-12-05 Simon Marchi + + * regcache.c (registers_to_string): Remove unused variable. + +2017-12-02 Simon Marchi + + * inferiors.c (for_each_inferior_with_data): Remove. + * inferiors.h (for_each_inferior_with_data): Remove. + * server.c (handle_qxfer_threads_worker): Change parameter type. + (handle_qxfer_threads_proper): Use for_each_thread. + +2017-12-02 Simon Marchi + + * inferiors.c (for_each_inferior): Remove. + (clear_inferiors): Use for_each_thread. + * inferiors.h (for_each_inferior): Remove. + * linux-low.c (linux_wait_for_event_filtered): Use + for_each_thread. + (linux_stabilize_threads): Likewise. + * regcache.c (regcache_release): Likewise. + * server.c (gdb_wants_all_threads_stopped): Likewise. + (clear_pending_status_callback): Remove. + (handle_status): Use for_each_thread. + (captured_main): Likewise. + * win32-low.c (child_init_thread_list): Likewise. + (win32_clear_inferiors): Likewise. + (fake_breakpoint_event): Likewise. + +2017-12-02 Simon Marchi + + * inferiors.h (find_inferior): Remove. + * inferiors.c (find_inferior): Remove. + +2017-12-02 Simon Marchi + + * linux-low.c (resume_status_pending_p): Update comment. + (need_step_over_p): Update comment. + +2017-12-02 Simon Marchi + + * linux-low.c (proceed_one_lwp): Return void, change parameter + type. + (unsuspend_and_proceed_one_lwp): Likewise. + (proceed_all_lwps): Use for_each_thread. + (unstop_all_lwps): Likewise. + +2017-12-02 Simon Marchi + + * linux-low.c (linux_resume_one_thread): Return void, take + parameter directly. + (linux_resume): Use for_each_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (send_sigstop_callback): Return void, change + parameter type. Rename to... + (send_sigstop): ... this. + (suspend_and_send_sigstop_callback): Return void, change parameter + type. Rename to... + (suspend_and_send_sigstop): ... this. + (stop_all_lwps): Use for_each_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (lwp_running): Return bool, remove unused + argument. + (linux_stabilize_threads): Use find_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (select_singlestep_lwp_callback): Remove. + (count_events_callback): Remove. + (select_event_lwp_callback): Remove. + (select_event_lwp): Use find_thread/for_each_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (not_stopped_callback): Return bool, take filter + argument directly. + (linux_wait_for_event_filtered): Use find_thread. + (linux_wait_1): Likewise. + +2017-12-02 Simon Marchi + + * linux-low.c (same_lwp): Remove. + (find_lwp_pid): Use find_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (delete_lwp_callback): Remove. + (linux_mourn): Use for_each_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (linux_detach_lwp_callback): Return void, remove + args parameter, don't check for pid. + (linux_detach): Use for_each_thread. + +2017-12-02 Simon Marchi + + * linux-low.c (struct counter): Remove. + (second_thread_of_pid_p): Remove. + (last_thread_of_process_p): Use find_thread. + +2017-12-02 Simon Marchi + + * inferiors.c (find_inferior_in_random): Remove. + * inferiors.h (find_inferior_in_random): Remove. + * linux-low.c (status_pending_p_callback): Return bool, accept + parameter ptid directly. + (linux_wait_for_event_filtered): Use find_thread_in_random. + (linux_wait_1): Likewise. + +2017-12-02 Simon Marchi + + * inferiors.c (find_inferior_id): Remove. + (find_thread_ptid): Move implemention from find_inferior_id to + here. + * inferiors.h (find_inferior_id): Remove. + * server.c (handle_status): Use find_thread_ptid. + (process_serial_event): Likewise. + * thread-db.c (find_one_thread): Likewise. + (thread_db_thread_handle): Likewise. + * win32-low.c (thread_rec): Likewise. + (child_delete_thread): Likewise. + (win32_thread_alive): Likewise. + (get_child_debug_event): Likewise. + +2017-12-02 Simon Marchi + + * linux-mips-low.c (update_watch_registers_callback): Return + void, remove pid_p parameter, don't check for pid. + (mips_insert_point, mips_remove_point): Use for_each_thread. + +2017-12-02 Simon Marchi + + * lynx.low (lynx_delete_thread_callback): Remove. + (lynx_mourn): Use for_each_thread. + +2017-12-02 Simon Marchi + + * regcache.c (regcache_invalidate_one): Remove. + (regcache_invalidate_pid): use for_each_thread. + +2017-11-26 Tom Tromey + + * linux-low.c (linux_create_inferior): Update. + +2017-11-24 Ulrich Weigand + + * spu-low.c (spu_create_inferior): Fix typo in argument name. + +2017-11-24 Alan Hayward + + * configure.srv: Add linux-aarch64-tdesc-selftest.o. + * linux-aarch64-low.c (initialize_low_arch): Call init func. + * linux-aarch64-tdesc-selftest.c: New file. + * linux-aarch64-tdesc.h (initialize_low_tdesc): New declaration. + +2017-11-24 Alan Hayward + + * configure.srv: Add new file. + * linux-aarch64-low.c (initialize_low_arch): Call init func. + * linux-aarch64-tdesc-selftest.c: New file. + * linux-aarch64-tdesc.h (initialize_low_tdesc): New declaration. + +2017-11-24 Alan Hayward + + * linux-aarch64-ipa.c (initialize_low_tracepoint): Remove init. + * linux-aarch64-low.c (initialize_low_arch): Remove init. + * linux-aarch64-tdesc.c (aarch64_linux_read_description): Add init. + +2017-11-24 Alan Hayward + + * configure.srv: Add new files. + * linux-aarch64-ipa.c (get_ipa_tdesc): Call + aarch64_linux_read_description. + * linux-aarch64-low.c (aarch64_linux_read_description): + Merge with aarch64_arch_setup. + (aarch64_arch_setup): Call aarch64_linux_read_description. + * linux-aarch64-tdesc.c: New file. + * linux-aarch64-tdesc.h: New file. + +2017-11-24 Yao Qi + + * configure.srv: Set $srv_regobj for tic6x-linux. + * linux-tic6x-low.c: Include "arch/tic6x.h" and "tdesc.h". + (tic6x_read_description): Move some code to tic6x_arch_setup. + (tic6x_tdesc_test): New function. + (initialize_low_arch): Call selftests::register_test. + +2017-11-22 Yao Qi + + * remote-utils.c (prepare_resume_reply): Use memcpy. + +2017-11-19 Simon Marchi + + * linux-low.c (kill_one_lwp_callback): Return void, take + argument directly, don't filter on pid. + (linux_kill): Use for_each_thread. + +2017-11-19 Simon Marchi + + * linux-low.c (need_step_over_p): Return bool, remove dummy + argument. + (linux_resume, proceed_all_lwps): Use find_thread. + +2017-11-19 Simon Marchi + + * linux-low.c (resume_status_pending_p): Return bool, remove + flag_p argument. + (linux_resume): Use find_thread. + +2017-11-19 Simon Marchi + + * linux-low.c (struct thread_resume_array): Remove. + (linux_set_resume_request): Return void, take arguments + directly. + (linux_resume): Use for_each_thread. + +2017-11-19 Simon Marchi + + * linux-low.c (stuck_in_jump_pad_callback): Change prototype, + return bool, remove data argument. + (linux_stabilize_threads): Use find_thread. + +2017-11-19 Simon Marchi + + * linux-low.c (unsuspend_one_lwp): Remove. + (unsuspend_all_lwps): Use for_each_thread, inline code from + unsuspend_one_lwp. + +2017-11-19 Simon Marchi + + * gdbthread.h (find_thread): Add overload with ptid_t filter. + * linux-low.c (struct iterate_over_lwps_args): Remove. + (iterate_over_lwps_filter): Remove. + (iterate_over_lwps): Use find_thread. + +2017-11-19 Simon Marchi + + * linux-low.c (reset_lwp_ptrace_options_callback): Remove. + (linux_handle_new_gdb_connection): Use for_each_thread, inline + code from reset_lwp_ptrace_options_callback. + +2017-11-19 Simon Marchi + + * linux-arm-low.c (struct update_registers_data): Remove. + (update_registers_callback): Return void, take arguments + directly, don't check thread's pid. + (arm_insert_point, arm_remove_point): Use for_each_thread. + +2017-11-19 Simon Marchi + + * win32-low.c (continue_one_thread): Return void, take argument + directly. + (child_continue): Use for_each_thread. + +2017-11-19 Simon Marchi + + * win32-i386-low.c (update_debug_registers_callback): Rename + to ... + (update_debug_registers): ... this, return void, remove pid_p arg. + (x86_dr_low_set_addr, x86_dr_low_set_control): Use for_each_thread. + +2017-11-17 Simon Marchi + + * inferiors.h (struct process_info): Add constructor, initialize + fields.. + : Change type to std::vector. + * inferiors.c (add_process): Allocate process_info with new. + (remove_process): Free process_info with delete. + * linux-low.c (handle_extended_wait): Adjust. + (gdb_catching_syscalls_p, gdb_catch_this_syscall_p): Adjust. + * server.c (handle_general_set): Adjust. + +2017-11-16 Pedro Alves + + * remote-utils.c (remote_close): Block SIGIO signals instead of + uninstalling the SIGIO handler. + +2017-11-16 Alan Hayward + + * tdesc.c (tdesc_get_features_xml): Allow null osabi. + +2017-11-16 Yao Qi + + * linux-tic6x-low.c (tic6x_fill_gregset): Cast buf. + (tic6x_store_gregset): Likewise. + (tic6x_usrregs_info): Move it up. + +2017-11-15 Alan Hayward + + * Makefile.in: Update arch rules. + * configure.srv: Explicitly mark arch/ files. + +2017-11-13 Andreas Schwab + + * linux-m68k-low.c (m68k_supports_hardware_single_step): New + function. + (struct linux_target_ops) : Initialize. + +2017-11-06 Pedro Alves + + * config.in, configure: Regenerate. + +2017-10-27 Simon Marchi + + * target.c (struct thread_search): Remove. + (thread_search_callback): Remove. + (prepare_to_access_memory): Use for_each_thread instead of + find_inferior. Inline code from thread_search_callback. + +2017-10-27 Simon Marchi + + * server.c (struct visit_actioned_threads_data): Remove. + (visit_actioned_threads): Change prototype to take arguments + directly. + (resume): Use find_thread instead of find_inferior. + +2017-10-27 Simon Marchi + + * server.c (queue_stop_reply_callback): Change prototype, return + void. + (find_status_pending_thread_callback): Remove. + (handle_status): Replace find_inferior with find_thread and + for_each_thread. + +2017-10-25 Alan Hayward + + * linux-aarch64-low.c (aarch64_fill_gregset): Replace defines + with REGNO. + (aarch64_store_gregset): Likewise. + (aarch64_fill_fpregset): Likewise. + (aarch64_store_fpregset): Likewise. + +2017-10-21 Simon Marchi + + * gdbthread.h (find_thread, for_each_thread): New functions. + * inferiors.c (thread_of_pid): Remove. + (find_any_thread_of_pid): Use find_thread. + * linux-low.c (num_lwps): Use for_each_thread. + +2017-10-17 Yao Qi + + * Makefile.in: Remove one rule. + * configure.srv: Rename aarch64-insn.o with arch/aarch64-insn.o. + +2017-10-17 Yao Qi + + * configure.srv: Rename arm-linux.o with arch/arm-linux.o. + Rename arm-get-next-pcs.o with arch/arm-get-next-pcs.o. + +2017-10-17 Yao Qi + + * configure.srv: Rename arm.o with arch/arm.o. + +2017-10-17 Yao Qi + + * Makefile.in (CONFIG_SRC_SUBDIR): New variable. + (clean): Remove .o files in CONFIG_SRC_SUBDIR. + (distclean): Remove DEPDIR in CONFIG_SRC_SUBDIR. + (arch-i386.o, arch-amd64.o): Remove rules. + (arch/%.o): New rule. + Update POSTCOMPILE and COMPILE.pre. + * configure.ac: Invoke AC_CONFIG_COMMANDS. + * configure: Re-generated. + * configure.srv: Replace arch-i386.o with arch/i386.o. + Replace arch-amd64.o with arch/amd64.o. + +2017-10-16 Yao Qi + + * configure: Regenerated. + +2017-10-14 Simon Marchi + + * inferiors.h: (struct inferior_list): Remove. + (struct inferior_list_entry); Remove. + (add_inferior_to_list, clear_inferior_list, one_inferior_p, + A_I_NEXT, ALL_INFERIORS_TYPE, ALL_INFERIORS, remove_inferior, + get_first_inferior): Remove. + (for_each_inferior, for_each_inferior_with_data, find_inferior, + find_inferior_id, find_inferior_in_random): Change signature. + * inferiors.c (all_threads): Change type to + std::list. + (get_thread): Remove macro. + (find_inferior, find_inferior_id): Change signature, implement + using find_thread. + (find_inferior_in_random): Change signature, implement using + find_thread_in_random. + (for_each_inferior, for_each_inferior_with_data): Change + signature, implement using for_each_thread. + (add_inferior_to_list, remove_inferior): Remove. + (add_thread, get_first_thread, thread_of_pid, + find_any_thread_of_pid, free_one_thread, remove_thread): Update. + (get_first_inferior, one_inferior_p, clear_inferior_list): + Remove. + (clear_inferiors, get_thread_process): Update. + * gdbthread.h: Include . + (struct thread_info) : Remove field. + : New field. + (all_threads): Change type to std::list. + (get_first_inferior): Add doc. + (find_thread, for_each_thread, find_thread_in_random): New + functions. + (current_ptid, pid_of, ptid_of, lwpid_of): Update. + * linux-arm-low.c (update_registers_callback): Update. + * linux-low.c (second_thread_of_pid_p): Update. + (kill_one_lwp_callback, linux_detach_lwp_callback, + delete_lwp_callback, status_pending_p_callback, same_lwp, + find_lwp_pid, num_lwps, iterate_over_lwps_filter, + iterate_over_lwps, not_stopped_callback, + resume_stopped_resumed_lwps, count_events_callback, + select_singlestep_lwp_callback, select_event_lwp_callback, + unsuspend_one_lwp, linux_wait_1, send_sigstop_callback, + suspend_and_send_sigstop_callback, wait_for_sigstop, + stuck_in_jump_pad_callback, move_out_of_jump_pad_callback, + lwp_running, linux_set_resume_request, resume_status_pending_p, + need_step_over_p, start_step_over, linux_resume_one_thread, + proceed_one_lwp, unsuspend_and_proceed_one_lwp, + reset_lwp_ptrace_options_callback): Update. + * linux-mips-low.c (update_watch_registers_callback): Update. + * regcache.c (regcache_invalidate_one, regcache_invalidate): + Update. + (free_register_cache_thread_one): Remove. + (regcache_release): Update. + * server.c (handle_btrace_enable_bts, handle_btrace_enable_pt, + handle_qxfer_threads_worker): Update. + (handle_query): Update, use list iterator. + (visit_actioned_threads, handle_pending_status, + queue_stop_reply_callback, gdb_wants_all_threads_stopped, + clear_pending_status_callback, set_pending_status_callback, + find_status_pending_thread_callback, handle_status, + process_serial_event): Update. + * target.c (thread_search_callback): Update. + * thread-db.c (thread_db_get_tls_address): Update. + * tracepoint.c (tracepoint_finished_step, tracepoint_was_hit): + Update. + * win32-i386-low.c (update_debug_registers_callback): Update. + * win32-low.c (delete_thread_info, child_delete_thread, + continue_one_thread, suspend_one_thread, + get_child_debug_event): Adjust. + +2017-10-14 Simon Marchi + + * gdbthread.h (ptid_of, pid_of, lwpid_of): New functions. + * inferiors.h: Include . + (struct process_info) : Remove field. + : New field. + (pid_of): Change macro to function. + (ptid_of, lwpid_of): Remove macro. + (all_processes): Change type to std::list. + (ALL_PROCESSES): Remove macro. + (for_each_process, find_process): New function. + * inferiors.c (all_processes): Change type to + std::list. + (find_thread_process): Adjust. + (add_process): Likewise. + (remove_process): Likewise. + (find_process_pid): Likewise. + (get_first_process): Likewise. + (started_inferior_callback): Remove. + (have_started_inferiors_p): Adjust. + (attached_inferior_callback): Remove. + (have_attached_inferiors_p): Adjust. + * linux-low.c (check_zombie_leaders): Likewise. + * linux-x86-low.c (x86_arch_setup_process_callback): Remove. + (x86_linux_update_xmltarget): Adjust. + * server.c (handle_query): Likewise. + (gdb_reattached_process): Remove. + (handle_status): Adjust. + (kill_inferior_callback): Likewise. + (detach_or_kill_inferior): Remove. + (print_started_pid): Likewise. + (print_attached_pid): Likewise. + (detach_or_kill_for_exit): Update. + (process_serial_event): Likewise. + * linux-arm-low.c (arm_new_fork): Likewise. + +2017-10-14 Simon Marchi + + * dll.h: Include . + (struct dll_info): Add constructor. + : Remove field. + (all_dlls): Change type to std::list. + * dll.c: Include . + (get_dll): Remove macro. + (all_dlls): Change type to std::list. + (free_one_dll): Remove. + (match_dll): Likewise. + (loaded_dll): Adjust. + (unloaded_dll): Adjust to all_dlls type change, use + std::find_if. Inline code from match_dll. + (clear_dlls): Adjust to all_dlls type change. + * server.c (emit_dll_description): Remove. + (handle_qxfer_libraries): Adjust to all_dlls type change, + integrate emit_dll_description's functionality. + +2017-10-12 Simon Marchi + + * linux-low.h (struct linux_target_ops) : New + field. + * linux-low.c (linux_mourn): Call the_low_target.delete_process. + * linux-aarch64-low.c (aarch64_linux_delete_process): New. + (struct linux_target_ops): Add delete_process callback. + * linux-arm-low.c (arm_delete_process): New. + (struct linux_target_ops): Add delete_process callback. + * linux-bfin-low.c (struct linux_target_ops): Likewise. + * linux-crisv32-low.c (struct linux_target_ops): Likewise. + * linux-m32r-low.c (struct linux_target_ops): Likewise. + * linux-mips-low.c (mips_linux_delete_process): New. + (struct linux_target_ops): Add delete_process callback. + * linux-ppc-low.c (struct linux_target_ops): Likewise. + * linux-s390-low.c (struct linux_target_ops): Likewise. + * linux-sh-low.c (struct linux_target_ops): Likewise. + * linux-tic6x-low.c (struct linux_target_ops): Likewise. + * linux-tile-low.c (struct linux_target_ops): Likewise. + * linux-x86-low.c (x86_linux_delete_process): New. + (struct linux_target_ops): Add delete_process callback. + * linux-xtensa-low.c (struct linux_target_ops): Likewise. + +2017-10-12 Simon Marchi + + * linux-aarch64-low.c (the_low_target): Add thread delete + callback. + * linux-arm-low.c (arm_delete_thread): New function. + (the_low_target): Add thread delete callback. + * linux-bfin-low.c (the_low_target): Likewise. + * linux-crisv32-low.c (the_low_target): Likewise. + * linux-low.c (delete_lwp): Invoke delete_thread callback if + set. + * linux-low.h (struct linux_target_ops) : New + field. + * linux-m32r-low.c (the_low_target): Add thread delete callback. + * linux-mips-low.c (mips_linux_delete_thread): New function. + (the_low_target): Add thread delete callback. + * linux-ppc-low.c (the_low_target): Likewise. + * linux-s390-low.c (the_low_target): Likewise. + * linux-sh-low.c (the_low_target): Likewise. + * linux-tic6x-low.c (the_low_target): Likewise. + * linux-tile-low.c (the_low_target): Likewise. + * linux-x86-low.c (the_low_target): Likewise. + * linux-xtensa-low.c (the_low_target): Likewise. + +2017-10-06 Yuanhui Zhang + + * win32-low.c: Include "common-inferior.h". + +2017-10-04 Sergio Durigan Junior + + * inferiors.c (set_inferior_cwd): New function. + * server.c (handle_general_set): Handle QSetWorkingDir packet. + (handle_query): Inform that QSetWorkingDir is supported. + * win32-low.c (create_process): Pass the inferior's cwd to + CreateProcess. + +2017-10-04 Sergio Durigan Junior + + * inferiors.c (current_inferior_cwd): New global variable. + (get_inferior_cwd): New function. + * inferiors.h (struct process_info) : New field. + +2017-10-04 Sergio Durigan Junior + + * Makefile.in (SFILES): Add $(srcdir)/common/gdb_tilde_expand.c. + (OBS): Add gdb_tilde_expand.o. + +2017-10-02 Simon Marchi + + * lynx-i386-low.c (lynx_i386_arch_setup): Call init_target_desc. + * nto-x86-low.c (nto_x86_arch_setup): Likewise. + +2017-09-29 Pedro Alves + + * ax.c (gdb_parse_agent_expr): Constify. + * ax.h (gdb_parse_agent_expr): Constify. + * mem-break.c (add_breakpoint_condition, add_breakpoint_commands): + Constify. + * mem-break.h (add_breakpoint_condition, add_breakpoint_commands): Constify. + * remote-utils.c (hex_or_minus_one, read_ptid): Constify. + * remote-utils.h (read_ptid): Constify. + * server.c (handle_qxfer_exec_file, handle_query, handle_v_cont) + (process_point_options, process_serial_event): Constify. + * tracepoint.c (add_tracepoint_action, cmd_qtdp, cmd_qtdpsrc) + (cmd_qtdv, cmd_qtenable_disable, cmd_qtro, cmd_qtframe, cmd_qtp) + (cmd_qtbuffer): Constify. + +2017-09-29 Pedro Alves + + * proc-service.c (ps_pdread): Return PS_ERR if reading memory + fails. + +2017-09-29 Pedro Alves + + * linux-low.c (handle_extended_wait): Pass parent thread instead + of process to thread_db_notice_clone. + * linux-low.h (thread_db_notice_clone): Replace parent process + parameter with parent thread parameter. + * thread-db.c (find_one_thread): Add comment. + (thread_db_notice_clone): Replace parent process parameter with + parent thread parameter. Temporarily switch to the parent thread. + +2017-09-26 Sergio Durigan Junior + + * gdbthread.h: Include "common-gdbthread.h". + * inferiors.c (switch_to_thread): Use "gdb_assert" instead of + "if" when validating the ptid. + * remote-utils.c: Include "gdbthread.h". + (prepare_resume_reply): Use "switch_to_thread". + * target.c (done_accessing_memory): Likewise. + +2017-09-25 Andreas Arnez + + * configure.srv (s390*-*-linux*): Add s390-gs-linux64.o and + s390x-gs-linux64.o to srv_regobj. Add s390-gs-linux64.xml, + s390x-gs-linux64.xml, s390-gs.xml, and s390-gsbc.xml to + srv_xmlfiles. Add s390-gs-linux64-ipa.o and + s390x-gs-linux64-ipa.o to ipa_obj. + * linux-s390-low.c (HWCAP_S390_GS): New define. + (s390_fill_gs, s390_store_gs, s390_fill_gsbc, s390_store_gsbc): + New functions. + (s390_regsets): Add regsets for NT_S390_GS_CB and NT_S390_GS_BC. + (s390_arch_setup): Check for guarded-storage support and choose + appropriate tdesc. + (initialize_low_arch): Invoke init_registers_s390_gs_linux64 and + init_registers_s390x_gs_linux64. + * linux-s390-tdesc.h (enum s390_linux_tdesc) : New + enum value. + (init_registers_s390x_gs_linux64, tdesc_s390x_gs_linux64) + (init_registers_s390_gs_linux64, tdesc_s390_gs_linux64): Declare. + +2017-09-22 Simon Marchi + + * win32-i386-low.c (i386_arch_setup): Call init_target_desc. + +2017-09-21 Kevin Buettner + + * linux-low.h (struct lwp_info): Add new field, thread_handle. + (thread_db_thread_handle): Declare. + * linux-low.c (linux_target_ops): Initialize thread_handle. + * server.c (handle_qxfer_threads_worker): Add support for + "handle" attribute. + * target.h (struct target_ops): Add new function pointer, + thread_handle. + (target_thread_handle): Define. + * thread-db.c (find_one_thread, attach_thread): Set thread_handle + field in lwp. + (thread_db_thread_handle): New function. + +2017-09-21 Kevin Buettner + + * linux-low.c (handle_extended_wait): Call thread_db_notice_clone(). + * linux-low.h (thread_db_notice_clone): Declare. + * thread-db.c (thread_db_notice_clone): New function. + +2017-09-21 Pedro Alves + + * server.c (gdb_read_memory, handle_status, process_serial_event) + (handle_serial_event, handle_target_event): Adjust to + set_desired_thread prototype change. + * target.c (set_desired_thread): Remove 'use_general' parameter + and adjust. + * target.h (set_desired_thread): Remove 'use_general' parameter. + +2017-09-20 Tom Tromey + + * target.c (target_terminal::terminal_state): Define. + (target_terminal::init): Rename from target_terminal_init. + (target_terminal::inferior): Rename from + target_terminal_inferior. + (target_terminal::ours): Rename from target_terminal_ours. + (target_terminal::ours_for_output, target_terminal::info): New. + +2017-09-16 Simon Marchi + + * server.c (accumulate_file_name_length): Remove. + (emit_dll_description): Adjust to std::string change. + (handle_qxfer_libraries): Use std::string to hold document. + +2017-09-16 Simon Marchi + + * linux-low.c (linux_qxfer_libraries_svr4): Adjust to change of + return type of xml_escape_text. + * server.c (emit_dll_description): Likewise. + +2017-09-16 Simon Marchi + + * server.c (captured_main): Accept argument for --selftest. + Update run_tests call. + * linux-x86-tdesc-selftest.c (initialize_low_tdesc): Add names + when registering selftests. + +2017-09-16 Sergio Durigan Junior + + * regcache.c (get_thread_regcache): Update code to use "std::vector" + instead of "VEC" for "target_desc.reg_defs". + (regcache_cpy): Likewise. + (registers_to_string): Likewise. + (registers_from_string): Likewise. + (find_regno): Likewise. + (supply_regblock): Likewise. + (regcache_raw_read_unsigned): Likewise. + * tdesc.c (init_target_desc): Likewise. + (tdesc_create_reg): Likewise. + * tdesc.h: Remove declaration of "tdesc_reg_p". Include . + (struct target_desc) : Convert to "std::vector". + (target_desc): Do not initialize "reg_defs". + (~target_desc): Update code to use "std::vector" instead of "VEC" + for "target_desc.reg_defs". + (operator==): Likewise. + +2017-09-15 Simon Marchi + + * inferiors.h (thread_to_gdb_id): Remove. + * inferiors.c (thread_to_gdb_id): Remove. + * server.c (handle_qxfer_threads_worker, handle_query): Adjust. + * lynx-low.c (lynx_resume, lynx_wait_1, lynx_fetch_registers, + lynx_store_registers, lynx_read_memory, lynx_write_memory): + Likewise. + * nto-low.c (nto_fetch_registers, nto_store_registers, + nto_stopped_by_watchpoint, nto_stopped_data_address): Likewise. + +2017-09-15 Simon Marchi + + * inferiors.h (gdb_id_to_thread_id): Remove. + * inferiors.c (gdb_id_to_thread_id): Remove. + * server.c (process_serial_event): Adjust to gdb_id_to_thread_id + removal. Move pid declaration closer to where it's used. + +2017-09-15 Simon Marchi + + * server.c (handle_detach): New function. + (process_serial_event): Move code out, call handle_detach. + +2017-09-15 Simon Marchi + + * server.c (require_running): Rename to ... + (require_running_or_return): ... this ... + (require_running_or_break): ... and this. + (handle_query, process_serial_event): Adjust. + +2017-09-15 Simon Marchi + + * linux-low.c (linux_set_resume_request): Remove unused + variables. + +2017-09-15 Simon Marchi + + * server.c (first_thread_of): Remove. + (process_serial_event): Replace usage of first_thread_of with + find_any_thread_of_pid. + * tracepoint.c (same_process_p): Remove. + (gdb_agent_about_to_close): Replace usage of same_process_p with + find_any_thread_of_pid. + * linux-x86-low.c (same_process_callback): Remove. + (x86_arch_setup_process_callback): Replace usage of + same_process_callback with find_any_thread_of_pid. + * thread-db.c (any_thread_of): Remove. + (switch_to_process): Replace usage of any_thread_of with + find_any_thread_of_pid. + * inferiors.c (thread_pid_matches_callback): Remove. + (find_thread_process): Adjust to use find_any_thread_of_pid. + +2017-09-10 Sergio Durigan Junior + + * regcache.c (get_thread_regcache): Guard calls to "memset" + with "!VEC_empty". + +2017-09-10 Sergio Durigan Junior + + * linux-low.c (handle_extended_wait): Use + "allocate_target_description" instead of "XNEW". + * linux-x86-low.c (initialize_low_arch): Likewise. + +2017-09-05 Yao Qi + + * configure.srv (srv_i386_regobj): Remove. + (srv_amd64_regobj): Remove. + (srv_regobj): Set it to "" for x86 non-linux targets. + * linux-x86-tdesc.c (i386_linux_read_description): + * lynx-i386-low.c: Include x86-xstate.h and arch/i386.h. + (init_registers_i386): Remove the declaration. + (tdesc_i386): Remove the declaration. + (lynx_i386_arch_setup): Call i386_create_target_description. + * nto-x86-low.c: Likewise. + * win32-i386-low.c [__x86_64__]: include arch/amd64.h. + [!__x86_64__]: include arch/i386.h. + (i386_arch_setup) [__x86_64__]: Call amd64_create_target_description. + +2017-09-05 Yao Qi + + * configure.srv (srv_amd64_linux_xmlfiles): Remove + i386/amd64-XXX-linux from it. + +2017-09-05 Yao Qi + + * configure.srv: Empty srv_amd64_linux_regobj if $development is + false. + (ipa_amd64_linux_regobj): Remove. + (ipa_x32_linux_regobj): Remove. + +2017-09-05 Yao Qi + + * Makefile.in (arch-amd64.o): New rule. + * configure.srv: Append arch-amd64.o. + * linux-amd64-ipa.c: Include common/x86-xstate.h. + (get_ipa_tdesc): Call amd64_linux_read_description. + (initialize_low_tracepoint): Don't call init_registers_x32_XXX + and init_registers_amd64_XXX. + * linux-x86-low.c (x86_linux_read_description): Call + amd64_linux_read_description. + (x86_get_ipa_tdesc_idx): Call amd64_get_ipa_tdesc_idx. + (initialize_low_arch): Don't call init_registers_x32_XXX and + init_registers_amd64_XXX. + * linux-x86-tdesc-selftest.c: Declare init_registers_amd64_XXX + and tdesc_amd64_XXX. + [__x86_64__] (amd64_tdesc_test): New function. + (initialize_low_tdesc) [__x86_64__]: Call init_registers_x32_XXX + and init_registers_amd64_XXX. + * linux-x86-tdesc.c: Include arch/amd64.h. + (xcr0_to_tdesc_idx): New function. + (i386_linux_read_description): New function. + (amd64_get_ipa_tdesc_idx): New function. + * linux-x86-tdesc.h (amd64_get_ipa_tdesc_idx): Declare. + (amd64_get_ipa_tdesc): Declare. + +2017-09-05 Yao Qi + + * configure.srv (srv_i386_linux_xmlfiles): Remove + i386/i386-XXX-linux.xml from it. + +2017-09-05 Yao Qi + + * configure.srv: Set srv_i386_linux_regobj empty if $development + is false. + * linux-i386-ipa.c (initialize_low_tracepoint): Don't call + initialize_low_tdesc. + * linux-x86-low.c (initialize_low_arch): Wrap initialize_low_tdesc + with #if initialize_low_tdesc. + * linux-x86-tdesc-selftest.c: New file. + * linux-x86-tdesc.c: Move code to linux-x86-tdesc-selftest.c. + +2017-09-05 Yao Qi + + * Makefile.in (arch-i386.o): New rule. + * configure.srv (i[34567]86-*-linux*): Add arch-i386.o. + (x86_64-*-linux*): Likewise. + * linux-x86-tdesc.c: Don't include ../features/i386/32bit-XXX.c, + include arch/i386.h. + (i386_linux_read_description): Remove code and call + i386_create_target_description. + * tdesc.c (allocate_target_description): New function. + * tdesc.h (set_tdesc_architecture): Remove declaration. + (set_tdesc_osabi): Likewise. + +2017-09-05 Yao Qi + + * linux-x86-tdesc.c: Don't include . + (i386_linux_read_description) [!IN_PROCESS_AGENT]: Call + set_tdesc_architecture and set_tdesc_osabi. Remove code setting + .xmltarget. + * server.c (get_features_xml): Call tdesc_get_features_xml. + * tdesc.c (set_tdesc_architecture): New function. + (set_tdesc_osabi): New function. + (tdesc_get_features_xml): New function. + (tdesc_create_feature): Add an argument. + * tdesc.h (struct target_desc) : New field. + : New field. + (~target_desc): xfree features, arch, and osabi. + (target_desc::oerator==): Don't compare .xmltarget. + [!IN_PROCESS_AGENT] (set_tdesc_architecture): Declare. + (set_tdesc_osabi): Likewise. + (tdesc_get_features_xml): Likewise. + +2017-09-05 Yao Qi + + * linux-x86-tdesc.c: Include selftest.h. + (i386_tdesc_test): New function. + (initialize_low_tdesc): Call selftests::register_test. + * tdesc.h: Include regdef.h. + (target_desc): Override operator == and !=. + +2017-09-05 Yao Qi + + * configure.srv (srv_tgtobj): Append linux-x86-tdesc.o. + (ipa_obj): Likewise. + * linux-i386-ipa.c: Include common/x86-xstate.h + (get_ipa_tdesc): Call i386_linux_read_description. + (initialize_low_tracepoint): Don't call init_registers_XXX + functions, call initialize_low_tdesc instead. + * linux-x86-low.c (x86_linux_read_description): Call + i386_linux_read_description. + (initialize_low_arch): Don't call init_registers_i386_XXX + functions, call initialize_low_tdesc. + * linux-x86-tdesc.c: New file. + * linux-x86-tdesc.h (x86_linux_tdesc): New X86_TDESC_LAST. + (i386_get_ipa_tdesc_idx): Declare. + (i386_get_ipa_tdesc): Declare. + (initialize_low_tdesc): Declare. + +2017-09-05 Yao Qi + + * linux-x86-low.c (x86_get_ipa_tdesc_idx): Use X86_TDESC_MMX + instead of 0. + +2017-09-05 Yao Qi + + * Makefile.in (IPA_OBJS): Add vec-ipa.o + * regcache.c (get_thread_regcache): Use VEC_length. + (init_register_cache): Likewise. + (regcache_cpy): Likewise. + (registers_to_string): Iterate reg_defs via VEC_iterate. + (find_regno): Likewise. + (find_register_by_number): Use VEC_index. + (register_size): Call find_register_by_number. + (register_data): Call find_register_by_number. + (supply_regblock): Use VEC_length. + (regcache_raw_read_unsigned): Likewise. + * tdesc.c (init_target_desc): Iterate reg_defs via + VEC_iterate. + (default_description): Update initializer. + (copy_target_description): Don't update field num_registers. + * tdesc.h (struct target_desc) : Change it to VEC. + : Remove. + +2017-09-04 Simon Marchi + + * Makefile.in (.SECONDARY): Define target. + +2017-09-03 Simon Marchi + + * linux-low.c (linux_wait_1): Adjust. + * server.c (queue_stop_reply_callback): Adjust. + +2017-08-31 Sergio Durigan Junior + + * server.c (handle_general_set): Handle QEnvironmentHexEncoded, + QEnvironmentUnset and QEnvironmentReset packets. + (handle_query): Inform remote that QEnvironmentHexEncoded, + QEnvironmentUnset and QEnvironmentReset are supported. + +2017-08-25 Simon Marchi + + * inferiors.h (inferior_target_data): Rename to ... + (thread_target_data): ... this. + (inferior_regcache_data): Rename to ... + (thread_regcache_data): ... this. + (set_inferior_regcache_data): Rename to ... + (set_thread_regcache_data): ... this. + * inferiors.c (inferior_target_data): Rename to ... + (thread_target_data): ... this. + (inferior_regcache_data): Rename to ... + (thread_regcache_data): ... this. + (set_inferior_regcache_data): Rename to ... + (set_thread_regcache_data): ... this. + (free_one_thread): Update. + * linux-low.h (get_thread_lwp): Update. + * regcache.c (get_thread_regcache): Update. + (regcache_invalidate_thread): Update. + (free_register_cache_thread): Update. + * win32-i386-low.c (update_debug_registers_callback): Update. + (win32_get_current_dr): Update. + * win32-low.c (thread_rec): Update. + (delete_thread_info): Update. + (continue_one_thread): Update. + (suspend_one_thread): Update. + +2017-08-24 Simon Marchi + + * inferiors.c (set_inferior_target_data): Remove. + * inferiors.h (set_inferior_target_data): Remove. + +2017-08-18 Yao Qi + + * Makefile.in (OBS): Add selftest.o. + * configure.ac: AC_DEFINE GDB_SELF_TEST if $development. + * configure, config.in: Re-generated. + * server.c: Include common/sefltest.h. + (captured_main): Handle option --selftest. + +2017-08-09 Yao Qi + + * configure.srv (srv_i386_regobj): Remove i386-avx.o, + i386-avx-avx512.o, i386-avx-mpx-avx512-pku.o, i386-mpx.o, + i386-avx-mpx.o and i386-mmx.o. + (srv_amd64_regobj): Remove amd64-avx.o, amd64-avx-avx512.o, + amd64-avx-mpx-avx512-pku.o, amd64-mpx.o and amd64-avx-mpx.o. + (srv_i386_xmlfiles): Remove i386/i386-avx.xml, + i386/i386-avx-avx512.xml, i386/i386-avx-mpx-avx512-pku.xml, + i386/i386-mpx.xml, i386/i386-avx-mpx.xml and i386/i386-mmx.xml. + (srv_amd64_xmlfile):i386/amd64-avx.xml, i386/amd64-avx-avx512.xml, + i386/amd64-avx-mpx-avx512-pku.xml, i386/amd64-mpx.xml, + i386/amd64-avx-mpx.xml. + +2017-08-09 Yao Qi + + * configure.srv (srv_amd64_regobj): Remove x32.o, x32-avx.o + and x32-avx-avx512.o. + (srv_amd64_xmlfiles): Remove i386/x32.xml, i386/x32-avx.xml + i386/x32-avx-avx512.xml. + +2017-07-26 Simon Marchi + + * tracepoint.h (enum class fast_tpoint_collect_result): New + enumeration. + (fast_tracepoint_collecting): Change return type to + fast_tpoint_collect_result. + * tracepoint.c (fast_tracepoint_collecting): Likewise. + * linux-low.h: Include tracepoint.h. + (struct lwp_info) : Change type to + fast_tpoint_collect_result. + * linux-low.c (handle_tracepoints): Adjust. + (linux_fast_tracepoint_collecting): Change return type to + fast_tpoint_collect_result. + (maybe_move_out_of_jump_pad, linux_wait_for_event_filtered, + linux_wait_1, stuck_in_jump_pad_callback, + lwp_signal_can_be_delivered, linux_resume_one_lwp_throw, + proceed_one_lwp): Adjust to type change. + +2017-07-10 Yao Qi + + * linux-x86-low.c (x86_linux_read_description): Re-indent the code. + +2017-06-29 Yao Qi + + * tdesc.h (struct target_desc) [IN_PROCESS_AGENT] : + Remove. + [IN_PROCESS_AGENT] : Likewise. + +2017-06-20 Simon Marchi + + * Makefile.in (IPA_OBJS): Sort and format one item per line. + +2017-06-20 Sergio Durigan Junior + + * linux-low.c (linux_create_inferior): Adjust code to access the + environment information via 'gdb_environ' class. + * lynx-low.c (lynx_create_inferior): Likewise. + * server.c (our_environ): Make it an instance of 'gdb_environ'. + (get_environ): Return a pointer to 'our_environ'. + (captured_main): Initialize 'our_environ'. + * server.h (get_environ): Adjust prototype. + * spu-low.c (spu_create_inferior): Adjust code to access the + environment information via 'gdb_environ' class. + +2017-06-17 Simon Marchi + + * linux-low.c (linux_read_memory, linux_write_memory): Remove + usage of "register" keyword. + +2017-06-17 Simon Marchi + + * configure: Re-generate. + +2017-06-17 Simon Marchi + + * configure: Re-generate. + +2017-06-17 Simon Marchi + + * Makefile.in (COMPILE.pre): Add "-x c++". + +2017-06-09 Sergio Durigan Junior + + * fork-child.c: Conditionally include . + +2017-06-07 Sergio Durigan Junior + + * server.c (handle_general_set): Handle new packet + "QStartupWithShell". + (handle_query): Add "QStartupWithShell" to the list of supported + packets. + (gdbserver_usage): Add help text explaining the + new "--startup-with-shell" and "--no-startup-with-shell" CLI + options. + (captured_main): Recognize and act upon the presence of the new + CLI options. + +2017-06-07 Sergio Durigan Junior + Pedro Alves + + * Makefile.in (SFILES): Add "nat/fork-inferior.o". + * configure: Regenerate. + * configure.srv (srv_linux_obj): Add "fork-child.o" and + "fork-inferior.o". + (i[34567]86-*-lynxos*): Likewise. + (spu*-*-*): Likewise. + * fork-child.c: New file. + * linux-low.c: Include "common-inferior.h", "nat/fork-inferior.h" + and "environ.h". + (linux_ptrace_fun): New function. + (linux_create_inferior): Adjust function prototype to reflect + change on "target.h". Adjust function code to use + "fork_inferior". + (linux_request_interrupt): Delete "signal_pid". + * lynx-low.c: Include "common-inferior.h" and "nat/fork-inferior.h". + (lynx_ptrace_fun): New function. + (lynx_create_inferior): Adjust function prototype to reflect + change on "target.h". Adjust function code to use + "fork_inferior". + * nto-low.c (nto_create_inferior): Adjust function prototype and + code to reflect change on "target.h". Update comments. + * server.c: Include "common-inferior.h", "nat/fork-inferior.h", + "common-terminal.h" and "environ.h". + (terminal_fd): Moved to fork-child.c. + (old_foreground_pgrp): Likewise. + (restore_old_foreground_pgrp): Likewise. + (last_status): Make it global. + (last_ptid): Likewise. + (our_environ): New variable. + (startup_with_shell): Likewise. + (program_name): Likewise. + (program_argv): Rename to... + (program_args): ...this. + (wrapper_argv): New variable. + (start_inferior): Delete function. + (get_exec_wrapper): New function. + (get_exec_file): Likewise. + (get_environ): Likewise. + (prefork_hook): Likewise. + (post_fork_inferior): Likewise. + (postfork_hook): Likewise. + (postfork_child_hook): Likewise. + (handle_v_run): Update code to deal with arguments coming from the + remote host. Update calls from "start_inferior" to + "create_inferior". + (captured_main): Likewise. Initialize environment variable. Call + "have_job_control". + * server.h (post_fork_inferior): New prototype. + (get_environ): Likewise. + (last_status): Declare. + (last_ptid): Likewise. + (signal_pid): Likewise. + * spu-low.c: Include "common-inferior.h" and "nat/fork-inferior.h". + (spu_ptrace_fun): New function. + (spu_create_inferior): Adjust function prototype to reflect change + on "target.h". Adjust function code to use "fork_inferior". + * target.c (target_terminal_init): New function. + (target_terminal_inferior): Likewise. + (target_terminal_ours): Likewise. + * target.h: Include . + (struct target_ops) : Update prototype. + (create_inferior): Update macro. + * utils.c (gdb_flush_out_err): New function. + * win32-low.c (win32_create_inferior): Adjust function prototype + and code to reflect change on "target.h". + +2017-06-07 Sergio Durigan Junior + + * inferiors.c (switch_to_thread): New function. + +2017-06-07 Sergio Durigan Junior + + * Makefile.in (SFILE): Add "common/job-control.c". + (OBS): Add "job-control.o". + +2017-05-06 Sergio Durigan Junior + + * Makefile: Remove "@host_makefile_frag@". + +2017-05-05 Pedro Alves + + * configure: Regenerate. + +2017-05-03 Sergio Durigan Junior + + * configure: Regenerate. + +2017-05-02 Simon Marchi + + * linux-arm-low.c (arm_gdbserver_get_next_pcs): Adjust to + software_single_step change of return type to + std::vector. + * linux-low.c (install_software_single_step_breakpoints): + Likewise. + * linux-low.h (install_software_single_step_breakpoints): + Likewise. + +2017-04-12 Sergio Durigan Junior + + * remote-utils.c: Include "gdb_termios.h" instead of + "terminal.h". + * terminal.h: Delete file. + +2017-04-12 Sergio Durigan Junior + + * server.c: Include . + : Convert to std::vector. + (start_inferior): Rewrite function to use C++. + (handle_v_run): Likewise. Update code that calculates the argv + based on the vRun packet; use C++. + (captured_main): Likewise. + +2017-04-06 Simon Marchi + + * server.c (handle_v_cont): Initialize thread_resume::thread + with null_ptid. + +2017-04-05 Pedro Alves + + * configure: Regenerate. + +2017-04-05 Pedro Alves + + * gdbreplay.c (sync_error): Constify. + * linux-x86-low.c (push_opcode): Constify. + +2017-04-05 Pedro Alves + + * win32-low.c (get_child_debug_event) + : Don't report TARGET_WAITKIND_EXECD. + Report TARGET_WAITKIND_SPURIOUS instead. + +2017-04-05 Pedro Alves + + * remote-utils.c (remote_prepare, remote_open): Constify. + * remote-utils.h (remote_prepare, remote_open): Constify. + * server.c (captured_main): Constify 'port' handling. + +2017-04-04 Simon Marchi + + * Makefile.in (clean): Clear .deps. + +2017-03-31 Simon Marchi + + * .gitignore: Remove generated files, replace with wildcard. + * (clean): Replace removal of generated files with wildcard. + (version.c): Replace with... + (version-generated.c): ...this. + (xml-builtin.c): Replace with... + (xml-builtin-generated.c): ...this. + (%-ipa.o: %-generated.c, %.o: %-generated.c): New rules. + (%.c: *regformats*): Replace with... + (%-generated.c: *regformats*): ...this. + +2017-03-27 Max Filippov + + * linux-xtensa-low.c (regnum::R_THREADPTR): New enum member. + (xtensa_fill_gregset): Call collect_register_by_name for + threadptr register. + (xtensa_store_gregset): Call supply_register_by_name for + threadptr register. + +2017-03-27 Max Filippov + + * linux-xtensa-low.c (xtensa_fill_gregset): Call collect_register + for all registers in a0_regnum..a0_regnum + C0_NREGS range. + (xtensa_store_gregset): Call supply_register for all registers in + a0_regnum..a0_regnum + C0_NREGS range. + +2017-03-13 Simon Marchi + + * Makefile.in (%-ipa.o: %-ipa.c): New rule. + (ax-ipa.o: ax.c): Remove. + (linux-i386-ipa.o: linux-i386-ipa.c): Remove. + (linux-amd64-ipa.o: linux-amd64-ipa.c): Remove. + (linux-aarch64-ipa.o: linux-aarch64-ipa.c): Remove. + (linux-s390-ipa.o: linux-s390-ipa.c): Remove. + (linux-ppc-ipa.o: linux-ppc-ipa.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in (%-ipa.o: ../common/%.c): New rule. + (print-utils-ipa.o: ../common/print-utils.c): Remove. + (rsp-low-ipa.o: ../common/rsp-low.c): Remove. + (errors-ipa.o: ../common/errors.c): Remove. + (format-ipa.o: ../common/format.c): Remove. + (common-utils-ipa.o: ../common/common-utils.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in (%-ipa.o: %.c): New rule. + (tracepoint-ipa.o: tracepoint.c): Remove. + (utils-ipa.o: utils.c): Remove. + (remote-utils-ipa.o: remote-utils.c): Remove. + (regcache-ipa.o: regcache.c): Remove. + (i386-linux-ipa.o: i386-linux.c): Remove. + (i386-mmx-linux-ipa.o: i386-mmx-linux.c): Remove. + (i386-avx-linux-ipa.o: i386-avx-linux.c): Remove. + (i386-mpx-linux-ipa.o: i386-mpx-linux.c): Remove. + (i386-avx-mpx-linux-ipa.o: i386-avx-mpx-linux.c): Remove. + (i386-avx-avx512-linux-ipa.o: i386-avx-avx512-linux.c): Remove. + (i386-avx-mpx-avx512-pku-linux-ipa.o: i386-avx-mpx-avx512-pku-linux.c): Remove. + (amd64-linux-ipa.o: amd64-linux.c): Remove. + (amd64-avx-linux-ipa.o: amd64-avx-linux.c): Remove. + (amd64-mpx-linux-ipa.o: amd64-mpx-linux.c): Remove. + (amd64-avx-mpx-linux-ipa.o: amd64-avx-mpx-linux.c): Remove. + (amd64-avx-avx512-linux-ipa.o: amd64-avx-avx512-linux.c): Remove. + (amd64-avx-mpx-avx512-pku-linux-ipa.o: amd64-avx-mpx-avx512-pku-linux.c): Remove. + (aarch64-ipa.o: aarch64.c): Remove. + (s390-linux32-ipa.o: s390-linux32.c): Remove. + (s390-linux32v1-ipa.o: s390-linux32v1.c): Remove. + (s390-linux32v2-ipa.o: s390-linux32v2.c): Remove. + (s390-linux64-ipa.o: s390-linux64.c): Remove. + (s390-linux64v1-ipa.o: s390-linux64v1.c): Remove. + (s390-linux64v2-ipa.o: s390-linux64v2.c): Remove. + (s390-te-linux64-ipa.o: s390-te-linux64.c): Remove. + (s390-vx-linux64-ipa.o: s390-vx-linux64.c): Remove. + (s390-tevx-linux64-ipa.o: s390-tevx-linux64.c): Remove. + (s390x-linux64-ipa.o: s390x-linux64.c): Remove. + (s390x-linux64v1-ipa.o: s390x-linux64v1.c): Remove. + (s390x-linux64v2-ipa.o: s390x-linux64v2.c): Remove. + (s390x-te-linux64-ipa.o: s390x-te-linux64.c): Remove. + (s390x-vx-linux64-ipa.o: s390x-vx-linux64.c): Remove. + (s390x-tevx-linux64-ipa.o: s390x-tevx-linux64.c): Remove. + (powerpc-32l-ipa.o: powerpc-32l.c): Remove. + (powerpc-altivec32l-ipa.o: powerpc-altivec32l.c): Remove. + (powerpc-cell32l-ipa.o: powerpc-cell32l.c): Remove. + (powerpc-vsx32l-ipa.o: powerpc-vsx32l.c): Remove. + (powerpc-isa205-32l-ipa.o: powerpc-isa205-32l.c): Remove. + (powerpc-isa205-altivec32l-ipa.o: powerpc-isa205-altivec32l.c): Remove. + (powerpc-isa205-vsx32l-ipa.o: powerpc-isa205-vsx32l.c): Remove. + (powerpc-e500l-ipa.o: powerpc-e500l.c): Remove. + (powerpc-64l-ipa.o: powerpc-64l.c): Remove. + (powerpc-altivec64l-ipa.o: powerpc-altivec64l.c): Remove. + (powerpc-cell64l-ipa.o: powerpc-cell64l.c): Remove. + (powerpc-vsx64l-ipa.o: powerpc-vsx64l.c): Remove. + (powerpc-isa205-64l-ipa.o: powerpc-isa205-64l.c): Remove. + (powerpc-isa205-altivec64l-ipa.o: powerpc-isa205-altivec64l.c): Remove. + (powerpc-isa205-vsx64l-ipa.o: powerpc-isa205-vsx64l.c): Remove. + (tdesc-ipa.o: tdesc.c): Remove. + (x32-linux-ipa.o: x32-linux.c): Remove. + (x32-avx-linux-ipa.o: x32-avx-linux.c): Remove. + (x32-avx512-linux-ipa.o: x32-avx512-linux.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in (%.o: ../arch/%.c): New rule. + (arm.o: ../arch/arm.c): Remove. + (arm-linux.o: ../arch/arm-linux.c): Remove. + (arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c): Remove. + (aarch64-insn.o: ../arch/aarch64-insn.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in (%.o: ../nat/%.c): New rule. + (x86-dregs.o: ../nat/x86-dregs.c): Remove. + (amd64-linux-siginfo.o: ../nat/amd64-linux-siginfo.c): Remove. + (linux-btrace.o: ../nat/linux-btrace.c): Remove. + (linux-osdata.o: ../nat/linux-osdata.c): Remove. + (linux-procfs.o: ../nat/linux-procfs.c): Remove. + (linux-ptrace.o: ../nat/linux-ptrace.c): Remove. + (linux-waitpid.o: ../nat/linux-waitpid.c): Remove. + (mips-linux-watch.o: ../nat/mips-linux-watch.c): Remove. + (ppc-linux.o: ../nat/ppc-linux.c): Remove. + (linux-personality.o: ../nat/linux-personality.c): Remove. + (aarch64-linux-hw-point.o: ../nat/aarch64-linux-hw-point.c): Remove. + (aarch64-linux.o: ../nat/aarch64-linux.c): Remove. + (x86-linux.o: ../nat/x86-linux.c): Remove. + (x86-linux-dregs.o: ../nat/x86-linux-dregs.c): Remove. + (linux-namespaces.o: ../nat/linux-namespaces.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in (%.o: ../common/%.c): New rule. + (signals.o: ../common/signals.c): Remove. + (print-utils.o: ../common/print-utils.c): Remove. + (rsp-low.o: ../common/rsp-low.c): Remove. + (common-utils.o: ../common/common-utils.c): Remove. + (posix-strerror.o: ../common/posix-strerror.c): Remove. + (mingw-strerror.o: ../common/mingw-strerror.c): Remove. + (vec.o: ../common/vec.c): Remove. + (gdb_vecs.o: ../common/gdb_vecs.c): Remove. + (xml-utils.o: ../common/xml-utils.c): Remove. + (ptid.o: ../common/ptid.c): Remove. + (buffer.o: ../common/buffer.c): Remove. + (format.o: ../common/format.c): Remove. + (filestuff.o: ../common/filestuff.c): Remove. + (agent.o: ../common/agent.c): Remove. + (errors.o: ../common/errors.c): Remove. + (environ.o: ../common/environ.c): Remove. + (common-debug.o: ../common/common-debug.c): Remove. + (cleanups.o: ../common/cleanups.c): Remove. + (common-exceptions.o: ../common/common-exceptions.c): Remove. + (fileio.o: ../common/fileio.c): Remove. + (common-regcache.o: ../common/common-regcache.c): Remove. + (signals-state-save-restore.o: ../common/signals-state-save-restore.c): Remove. + (new-op.o: ../common/new-op.c): Remove. + (btrace-common.o: ../common/btrace-common.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in (%.o: ../target/%.c): New rule. + (waitstatus.o: ../target/waitstatus.c): Remove. + +2017-03-13 Simon Marchi + + * Makefile.in + (%.c: ../regformats/%.dat, + (%.c: ../regformats/arm/%.dat, + (%.c: ../regformats/i386/%.dat, + (%.c: ../regformats/rs6000/%.dat): New rules. + (aarch64.c): Remove. + (reg-arm.c): Remove. + (arm-with-iwmmxt.c): Remove. + (arm-with-vfpv2.c): Remove. + (arm-with-vfpv3.c): Remove. + (arm-with-neon.c): Remove. + (reg-bfin.c): Remove. + (reg-cris.c): Remove. + (reg-crisv32.c): Remove. + (i386.c): Remove. + (i386-linux.c): Remove. + (i386-avx.c): Remove. + (i386-avx-linux.c): Remove. + (i386-avx-avx512.c): Remove. + (i386-avx-avx512-linux.c): Remove. + (i386-mpx.c): Remove. + (i386-mpx-linux.c): Remove. + (i386-avx-mpx-avx512-pku.c): Remove. + (i386-avx-mpx-avx512-pku-linux.c): Remove. + (i386-avx-mpx.c): Remove. + (i386-avx-mpx-linux.c): Remove. + (i386-mmx.c): Remove. + (i386-mmx-linux.c): Remove. + (reg-ia64.c): Remove. + (reg-m32r.c): Remove. + (reg-m68k.c): Remove. + (reg-cf.c): Remove. + (mips-linux.c): Remove. + (mips-dsp-linux.c): Remove. + (mips64-linux.c): Remove. + (mips64-dsp-linux.c): Remove. + (nios2-linux.c): Remove. + (powerpc-32.c): Remove. + (powerpc-32l.c): Remove. + (powerpc-altivec32l.c): Remove. + (powerpc-cell32l.c): Remove. + (powerpc-vsx32l.c): Remove. + (powerpc-isa205-32l.c): Remove. + (powerpc-isa205-altivec32l.c): Remove. + (powerpc-isa205-vsx32l.c): Remove. + (powerpc-e500l.c): Remove. + (powerpc-64l.c): Remove. + (powerpc-altivec64l.c): Remove. + (powerpc-cell64l.c): Remove. + (powerpc-vsx64l.c): Remove. + (powerpc-isa205-64l.c): Remove. + (powerpc-isa205-altivec64l.c): Remove. + (powerpc-isa205-vsx64l.c): Remove. + (s390-linux32.c): Remove. + (s390-linux32v1.c): Remove. + (s390-linux32v2.c): Remove. + (s390-linux64.c): Remove. + (s390-linux64v1.c): Remove. + (s390-linux64v2.c): Remove. + (s390-te-linux64.c): Remove. + (s390-vx-linux64.c): Remove. + (s390-tevx-linux64.c): Remove. + (s390x-linux64.c): Remove. + (s390x-linux64v1.c): Remove. + (s390x-linux64v2.c): Remove. + (s390x-te-linux64.c): Remove. + (s390x-vx-linux64.c): Remove. + (s390x-tevx-linux64.c): Remove. + (tic6x-c64xp-linux.c): Remove. + (tic6x-c64x-linux.c): Remove. + (tic6x-c62x-linux.c): Remove. + (reg-sh.c): Remove. + (reg-sparc64.c): Remove. + (reg-spu.c): Remove. + (amd64.c): Remove. + (amd64-linux.c): Remove. + (amd64-avx.c): Remove. + (amd64-avx-linux.c): Remove. + (amd64-avx-avx512.c): Remove. + (amd64-avx-avx512-linux.c): Remove. + (amd64-mpx.c): Remove. + (amd64-mpx-linux.c): Remove. + (amd64-avx-mpx-avx512-pku.c): Remove. + (amd64-avx-mpx-avx512-pku-linux.c): Remove. + (amd64-avx-mpx.c): Remove. + (amd64-avx-mpx-linux.c): Remove. + (x32.c): Remove. + (x32-linux.c): Remove. + (x32-avx.c): Remove. + (x32-avx-linux.c): Remove. + (x32-avx-avx512.c): Remove. + (x32-avx-avx512-linux.c): Remove. + (reg-xtensa.c): Remove. + (reg-tilegx.c): Remove. + (reg-tilegx32.c): Remove. + +2017-03-07 Sergio Durigan Junior + + * Makefile.in (SFILES): Add "common/environ.c". + (OBJS): Add "common/environ.h". + +2017-01-27 Walfred Tedeschi + + * configure.ac: Check if the fs_base and gs_base members of + `struct user_regs_struct' exist. + * config.in: Regenerated. + * configure: Likewise. + +2017-01-09 Antoine Tremblay + + * linux-aarch32-low.c (arm_breakpoint_kind_from_pc): Use + target_read_memory. + * linux-arm-low.c (get_next_pcs_read_memory_unsigned_integer): Likewise. + (get_next_pcs_syscall_next_pc): Likewise. + +2016-12-23 Luis Machado + + * win32-i386-low.c: Fix incorrect reference to a couple source files. + * nto-x86-low.c: Likewise. + +2016-11-30 Simon Marchi + + * Makefile.in: Include disable-implicit-rules.mk. + +2016-11-23 Pedro Alves + + * debug.c: Include instead of "gdb_sys_time.h". + (debug_vprintf): Use std::chrono::steady_clock instead of + gettimeofday. Use '.' instead of ':'. + * tracepoint.c: Include instead of "gdb_sys_time.h". + (get_timestamp): Use std::chrono::steady_clock instead of + gettimeofday. + +2016-11-22 Simon Marchi + + * Makefile.in: Fix whitespace formatting. + +2016-11-22 Simon Marchi + + * Makefile.in (SFILES, OBS): Flatten list and order + alphabetically. + +2016-11-23 Pedro Alves + + * event-loop.c (handle_file_event): Use warning. + * linux-low.c (linux_resume_one_lwp_throw): Use warning. + * mem-break.c (add_breakpoint_condition, add_breakpoint_commands): + Use warning. + +2016-11-23 Pedro Alves + + * linux-low.c (check_zombie_leaders): Use debug_printf for debug + output. + * notif.c (handle_notif_ack, notif_event_enque): Likewise. + * remote-utils.c (putpkt_binary_1, readchar, getpkt): Use + debug_printf and debug_flush for debug output. + * server.c (handle_general_set): Likewise. + * thread-db.c (try_thread_db_load): Use debug_printf for debug + output. + +2016-11-17 Simon Marchi + + * Makefile.in (.c.o): Replace rule with ... + (%.o: %.c): ... this one. + +2016-11-17 Simon Marchi + + * Makefile.in: Remove @GMAKE_TRUE@ prefixes and removes lines + prefixed with @GMAKE_FALSE@. Update comment related to non-GNU + make. + * configure.ac: Remove checks for the make program. + * configure: Re-generate. + +2016-10-28 Pedro Alves + + * Makefile.in (CXX_DIALECT): Get from configure. + (COMPILE.pre, CC_LD): Append $(CXX_DIALECT). + * acinclude.m4: Include ../ax_cxx_compile_stdcxx.m4. + * configure.ac: Call AX_CXX_COMPILE_STDCXX. + * config.in: Regenerate. + * configure: Regenerate. + +2016-10-27 Yao Qi + + * linux-low.c (linux_supports_range_stepping): Return true if + can_software_single_step return true. + +2016-10-27 Yao Qi + + * inferiors.c (find_inferior_in_random): New function. + * inferiors.h (find_inferior_in_random): Declare. + * linux-low.c (linux_wait_for_event_filtered): Call + find_inferior_in_random instead of find_inferior. + +2016-10-27 Yao Qi + + * linux-low.c (linux_wait_1): If single-step breakpoints are + inserted, remove them. + +2016-10-26 Pedro Alves + + * linux-low.c (handle_extended_wait): Link parent/child fork + threads. + (linux_wait_1): Unlink them. + (linux_set_resume_request): Ignore resume requests for + already-resumed and unhandled fork child threads. + * linux-low.h (struct lwp_info) : New field. + * server.c (in_queued_stop_replies_ptid, in_queued_stop_replies): + New functions. + (handle_v_requests) : Don't call require_running. + * server.h (in_queued_stop_replies): New declaration. + +2016-10-24 Yao Qi + + PR server/20733 + * linux-aarch64-low.c (append_insns): Cast the return value to + 'uint32_t *'. + +2016-10-10 Yao Qi + + * linux-aarch32-low.c (enum arm_breakpoint_kinds): Remove. + +2016-10-06 Sergio Durigan Junior + + * target.c (target_supports_multi_process): New function, moved + from... + * target.h (target_supports_multi_process): ... here. Remove + macro. + +2016-10-05 Tom Tromey + + PR remote/20655: + * tracepoint.c (handle_tracepoint_bkpts): Check + ipa_error_tracepoint, not ipa_stopping_tracepoint. + +2016-10-05 Yao Qi + + * configure.srv: Update the path of arm-*.xml files. + +2016-10-05 Terry Guo + Yao Qi + + * Makefile.in: Adjust the path of rules. + * configure.srv: Update the path of xml files. + * regformats/arm-with-iwmmxt.dat: Regenerated. + * regformats/arm-with-neon.dat: Likewise. + * regformats/arm-with-vfpv2.dat: Likewise. + * regformats/arm-with-vfpv3.dat Likewise. + +2016-09-30 Yao Qi + + PR gdbserver/20627 + * target.c (target_stop_and_wait): Don't call + target_continue_no_signal, use resume_stop instead. + +2016-09-26 Yao Qi + + * linux-low.c (linux_wait_1): Call debug_exit. + +2016-09-23 Pedro Alves + + * Makefile.in (SFILES): Add common/new-op.c. + (OBS): Add common/new-op.o. + (new-op.o): New rule. + +2016-09-21 Simon Marchi + + * .gitinore: Ignore more files. + +2016-09-21 Yao Qi + + * linux-aarch32-low.c (arm_fill_gregset): Keep bits 20 to + 23. + +2016-09-19 Sergio Durigan Junior + + * server.c (start_inferior): Call target_mourn_inferior instead of + mourn_inferior; pass ptid_t argument to it. + (resume): Likewise. + (handle_target_event): Likewise. + * target.c (target_mourn_inferior): New function. + * target.h (mourn_inferior): Delete macro. + +2016-09-16 Andreas Arnez + + * linux-low.c (lwp_is_stepping): New function. + +2016-09-06 Carl Love + + * server.c (start_inferior): Fixed comment, requested comment change + didn't get updated correctly. Removed reference to ptrace () call as + it is only true on Linux systems. + +2016-09-06 Carl Love + + * server.c (start_inferior): Do not call + function target_post_create_inferior () if the + inferior process has already exited. + +2016-09-05 Pedro Alves + + * Makefile.in (COMPILER, COMPILER_CFLAGS): Remove. + (COMPILE.pre, CC_LD): Use CXX directly. + (INTERNAL_CFLAGS_BASE): Use CXXFLAGS directly. + * acinclude.m4: Don't include build-with-cxx.m4. + * configure.ac: Remove GDB_AC_BUILD_WITH_CXX call. + * configure: Regenerate. + +2016-09-02 Akash Trehan + + PR gdb/19495 + * remote-utils.c (relocate_instruction): Remove redundant strcpy() + call writing data to own_buf. + +2016-09-01 Sergio Durigan Junior + + * target.c (mywait): Call target_wait instead of + the_target->wait. + (target_wait): New function. + +2016-09-01 Sergio Durigan Junior + + * server.c (start_inferior): New variable 'ptid'. Replace calls + to the_target->resume by target_continue{,_no_signal}, depending + on the case. + * target.c (target_stop_and_wait): Call target_continue_no_signal + instead of the_target->resume. + (target_continue): New function. + +2016-08-31 Antoine Tremblay + + * linux-low.c (linux_wait_1): Move event switch after unsuspend_lwps. + +2016-08-25 Adhemerval Zanella + + PR server/20491 + * gdb_proc_service.h (ps_get_thread_area): Remove const from struct + ps_prochandle. + * linux-aarch64-low.c (ps_get_thread_area): Likewise. + * linux-arm-low.c (ps_get_thread_area): Likewise. + * linux-crisv32-low.c (ps_get_thread_area): Likewise. + * linux-m68k-low.c (ps_get_thread_area): Likewise. + * linux-mips-low.c (ps_get_thread_area): Likewise. + * linux-nios2-low.c (ps_get_thread_area): Likewise. + * linux-tic6x-low.c (ps_get_thread_area): Likewise. + * linux-x86-low.c (ps_get_thread_area): Likewise. + * linux-xtensa-low.c (ps_get_thread_area): Likewise. + +2016-08-19 Pedro Alves + + * linux-x86-low.c (amd64_emit_call): Emit missing call opcode. + +2016-08-19 Pedro Alves + + * linux-x86-low.c (amd64_install_fast_tracepoint_jump_pad): Fix + comment. Use memcpy instead of casting through unsigned long. + +2016-08-19 Pedro Alves + + * linux-amd64-ipa.c (alloc_jump_pad_buffer) [__ILP32__]: Try + allocating around 0x80000000. + +2016-08-19 Pedro Alves + + PR gdb/20415 + * Makefile.in (x32-linux-ipa.o, x32-avx-linux-ipa.o) + (x32-avx512-linux-ipa.o): New rules. + * configure.ac (x86_64-*-linux*): New x32 check. + * configure.srv (ipa_x32_linux_regobj): New. + (x86_64-*-linux*): Use $ipa_x32_linux_regobj if building for x32. + * linux-amd64-ipa.c (get_ipa_tdesc) [__ILP32__]: Return x32 + descriptions. + (initialize_low_tracepoint) [__ILP32__]: Initialize x32 + descriptions. + * configure: Regenerate. + +2016-08-09 Pedro Alves + + PR gdb/18653 + * Makefile.in (OBS): Add signals-state-save-restore.o. + (signals-state-save-restore.o): New rule. + * config.in: Regenerate. + * configure: Regenerate. + * linux-low.c: Include "signals-state-save-restore.h". + (linux_create_inferior): Call + restore_original_signals_state. + * server.c: Include "dispositions-save-restore.h". + (captured_main): Call save_original_signals_state. + +2016-08-05 Pedro Alves + + * configure: Regenerate. + +2016-08-04 Yao Qi + + * linux-low.c (regsets_fetch_inferior_registers): Check + errno is ESRCH or not. + +2016-08-02 Yao Qi + + * thread-db.c (struct thread_db) : Remove. + : Remove. + (thread_db_load_search): Update. + (try_thread_db_load_1): Don't look for td_ta_event_addr, + td_ta_set_event and td_ta_event_getmsg. + +2016-07-26 Pedro Alves + + PR server/20414 + * linux-x86-low.c (x86_get_pc, x86_set_pc): Use uint64_t instead + of unsigned long for 64-bit registers and use uint32_t instead of + unsigned int for 32-bit registers. + +2016-07-26 Pedro Alves + + * linux-x86-low.c (x86_siginfo_fixup): Rename 'native' parameter + to 'ptrace'. + +2016-07-21 Tom Tromey + + * configure: Rebuild. + +2016-07-21 Yao Qi + + * mem-break.c (find_gdb_breakpoint): Cast bp to + 'struct gdb_breakpoint *' rather than 'gdb_breakpoint *'. + +2016-07-21 Yao Qi + + * server.c (handle_v_requests): Support s and S actions + if target_supports_software_single_step return true. + +2016-07-21 Yao Qi + + * linux-low.c (resume_stopped_resumed_lwps): If resume request + is resume_step, call maybe_hw_step. + (linux_wait_1): Stop all threads, remove reinsert breakpoints, + and unstop them. + (linux_resume_one_lwp_throw): Don't assert the thread has reinsert + breakpoints or not. + (proceed_one_lwp): If resume request is resume_step, install + reinsert breakpoints and call maybe_hw_step. + +2016-07-21 Yao Qi + + * linux-low.c (proceed_one_lwp): Declare. + (linux_resume_one_thread): Remove local variable 'step'. + Lift code enqueue signal. Call proceed_one_lwp instead of + linux_resume_one_lwp. + +2016-07-21 Yao Qi + + * linux-low.c (linux_resume_one_thread): Call + enqueue_pending_signal. + +2016-07-21 Yao Qi + + * gdbthread.h (make_cleanup_restore_current_thread): Declare. + * inferiors.c (do_restore_current_thread_cleanup): New function. + (make_cleanup_restore_current_thread): Likewise. + * linux-low.c (install_software_single_step_breakpoints): Call + make_cleanup_restore_current_thread. Switch current_thread to + thread. + +2016-07-21 Yao Qi + + * mem-break.c (struct reinsert_breakpoint) : New field. + (set_reinsert_breakpoint): New parameter ptid. Callers updated. + (clone_one_breakpoint): Likewise. + (delete_reinsert_breakpoints): Change parameter to thread. + Callers updated. + (has_reinsert_breakpoints): Likewise. + (uninsert_reinsert_breakpoints): Likewise. + (reinsert_reinsert_breakpoints): Likewise. + * mem-break.h (set_reinsert_breakpoint): Update declaration. + (delete_reinsert_breakpoints): Likewise. + (reinsert_reinsert_breakpoints): Likewise. + (uninsert_reinsert_breakpoints): Likewise. + (has_reinsert_breakpoints): Likewise. + +2016-07-21 Yao Qi + + * inferiors.c (get_thread_process): Make parameter const. + * inferiors.h (get_thread_process): Update declaration. + * mem-break.c (clone_all_breakpoints): Remove all parameters. + Add new parameters child_thread and parent_thread. Callers + updated. + * mem-break.h (clone_all_breakpoints): Update declaration. + +2016-07-21 Yao Qi + + * mem-break.c (struct breakpoint) : Remove. + : Remove. + (struct gdb_breakpoint): New. + (struct other_breakpoint): New. + (struct reinsert_breakpoint): New. + (is_gdb_breakpoint): New function. + (any_persistent_commands): Update command_list if + is_gdb_breakpoint returns true. + (set_breakpoint): Create breakpoints according to their types. + (find_gdb_breakpoint): Return 'struct gdb_breakpoint *'. + (set_gdb_breakpoint_1): Likewise. + (set_gdb_breakpoint): Likewise. + (clear_breakpoint_conditions): Change parameter type to + 'struct gdb_breakpoint *'. + (clear_breakpoint_commands): Likewise. + (clear_breakpoint_conditions_and_commands): Likewise. + (add_condition_to_breakpoint): Likewise. + (add_breakpoint_condition): Likewise. + (add_commands_to_breakpoint): Likewise. + (check_breakpoints): Check other_breakpoint. + (clone_one_breakpoint): Clone breakpopint according to its type. + * mem-break.h (struct gdb_breakpoint): Declare. + (set_gdb_breakpoint): Update declaration. + (clear_breakpoint_conditions_and_commands): Likewise. + (add_breakpoint_condition): Likewise. + (add_breakpoint_commands): Likewise. + * server.c (process_point_options): Change parameter type to + 'struct gdb_breakpoint *'. + +2016-07-21 Yao Qi + + * mem-break.c (set_breakpoint_at): Rename it to ... + (set_breakpoint_type_at): ... it. + (set_breakpoint_at): Call set_breakpoint_type_at. + (set_reinsert_breakpoint): Call set_breakpoint_type_at. + * mem-break.h (set_breakpoint_at): Update comments. + +2016-07-12 Chung-Lin Tang + + * linux-nios2-low.c (nios2_fill_gregset): Add type cast + to buf parameter. + (nios2_store_gregset): Likewise. + +2016-07-01 Pedro Alves + Antoine Tremblay + + * linux-low.c: Change interface to take the target lwp_info + pointer directly and return void. Handle detaching from a zombie + thread. + (linux_detach_lwp_callback): New function. + (linux_detach): Detach from the leader thread after detaching from + the clone threads. + +2016-06-28 Yao Qi + + * linux-aarch64-low.c (aarch64_ftrace_insn_reloc_b): Use int64_t + for variable new_offset. + (aarch64_ftrace_insn_reloc_b_cond): Likewise. + (aarch64_ftrace_insn_reloc_cb): Likewise. + (aarch64_ftrace_insn_reloc_tb): Likewise. + (aarch64_install_fast_tracepoint_jump_pad): Likewise. Use + PRIx64 instead of PRIx32. + +2016-06-28 Yao Qi + + * linux-arm-low.c (arm_get_syscall_trapinfo): New function. + (the_low_target): Install arm_get_syscall_trapinfo. + +2016-06-28 Yao Qi + + * linux-aarch64-low.c (aarch64_get_syscall_trapinfo): New + function. + (the_low_target): Install aarch64_get_syscall_trapinfo. + +2016-06-28 Yao Qi + + * linux-low.c (get_syscall_trapinfo): Remove parameter sysret. + Callers updated. + * linux-low.h (struct linux_target_ops) : + Remove parameter sysno. + * linux-x86-low.c (x86_get_syscall_trapinfo): Remove parameter + sysret. + +2016-06-21 Andreas Arnez + + * linux-s390-low.c (s390_emit_eq_goto): Mark function static. + (s390_emit_ne_goto): Likewise. + (s390_emit_lt_goto): Likewise. + (s390_emit_le_goto): Likewise. + (s390_emit_gt_goto): Likewise. + (s390_emit_ge_goto): Likewise. + (s390x_emit_eq_goto): Likewise. + (s390x_emit_ne_goto): Likewise. + (s390x_emit_lt_goto): Likewise. + (s390x_emit_le_goto): Likewise. + (s390x_emit_gt_goto): Likewise. + (s390x_emit_ge_goto): Likewise. + (s390_emit_ops_impl): Mark variable static. + (s390x_emit_ops): Likewise. + +2016-06-17 Yao Qi + + * linux-low.c (handle_extended_wait): Call + uninsert_reinsert_breakpoints for the parent process. Remove + reinsert breakpoints from the child process. Reinsert them to + the parent process when vfork is done. + * mem-break.c (uninsert_reinsert_breakpoints): New function. + (reinsert_reinsert_breakpoints): New function. + * mem-break.h (uninsert_reinsert_breakpoints): Declare + (reinsert_reinsert_breakpoints): Declare. + +2016-06-17 Yao Qi + + * linux-low.c (handle_extended_wait): If the parent is doing + step-over, remove the reinsert breakpoints from the forked child. + +2016-06-17 Yao Qi + + * linux-low.c (unsuspend_all_lwps): Declare. + (linux_low_filter_event): If thread exited, call finish_step_over. + If step-over is finished, unsuspend other threads. + +2016-06-17 Yao Qi + + * linux-low.c (linux_resume_one_lwp_throw): Assert + has_reinsert_breakpoints returns false. + * mem-break.c (delete_disabled_breakpoints): Assert + bp type isn't reinsert_breakpoint. + +2016-06-17 Yao Qi + + * linux-low.c (maybe_hw_step): New function. + (linux_resume_one_lwp_throw): Call maybe_hw_step. + (finish_step_over): Switch current_thread to lwp temporarily, + and assert has_reinsert_breakpoints returns true. + (proceed_one_lwp): Call maybe_hw_step. + * mem-break.c (has_reinsert_breakpoints): New function. + * mem-break.h (has_reinsert_breakpoints): Declare. + +2016-06-02 Jon Turney + + * win32-low.c (win32_create_inferior): Add pointer casts for C++. + +2016-05-17 Yao Qi + + * linux-low.c (linux_stabilize_threads): Call unsuspend_all_lwps + instead of find_inferior. + +2016-05-05 Yao Qi + + * linux-arm-low.c (get_next_pcs_read_memory_unsigned_integer): + Initialize res to zero. + +2016-05-05 Yao Qi + + * linux-arm-low.c (arm_sigreturn_next_pc): Change type of cpsr + to uint32_t. + +2016-05-04 Ulrich Weigand + + * spu-low.c (fetch_ppc_register): Cast PowerPC-Linux-specific value + used as first ptrace argument to PTRACE_TYPE_ARG1 for C++. + (fetch_ppc_memory_1, store_ppc_memory_1): Likewise. + +2016-04-28 Par Olsson + Simon Marchi + + * tracepoint.c (write_inferior_int8): New function. + (cmd_qtenable_disable): Write enable flag using + write_inferior_int8. + +2016-04-25 Yao Qi + + * linux-low.c (lwp_signal_can_be_delivered): Adjust. + (need_step_over_p): Return zero if the LWP has pending signals + can be delivered on software single step target. + +2016-04-25 Yao Qi + + * linux-low.c (reinsert_raw_breakpoint): If bp->inserted is true + return instead of error. + +2016-04-22 Yao Qi + + * linux-aarch32-low.c (arm_store_gregset): Clear CPSR bits 20 + to 23. + +2016-04-22 Yao Qi + + * linux-low.c (lwp_signal_can_be_delivered): Don't deliver + signal when stepping over breakpoint with software single + step. + +2016-04-21 Pedro Alves + + * linux-s390-low.c (s390_collect_ptrace_register) + (s390_supply_ptrace_register, s390_get_hwcap): Use gdb_byte * and + add casts. + (s390_check_regset): Use void * instead of gdb_byte *. + +2016-04-20 Pedro Alves + + * configure: Renegerate. + +2016-04-20 Yao Qi + + * linux-aarch32-low.c: Include "arch/arm-linux.h". + (arm_fill_gregset): Use ARM_CPSR_GREGNUM rather than magic + number 16. + (arm_store_gregset): Likewise. + +2016-04-16 Walfred Tedeschi + + * Makefile.in (clean): Add removal for i386-avx-mpx.c, + i386-avx-mpx-linux.c, amd64-avx-mpx.c and amd64-avx-mpx-linux.c. + (i386-avx-mpx.c, i386-avx-mpx-linux.c, amd64-avx-mpx.c) + (amd64-avx-mpx-linux.c): New rules. + (amd64-avx-mpx-linux-ipa.o, i386-avx-mpx-linux-ipa.o): New rule. + * configure.srv (srv_i386_regobj): Add i386-avx-mpx.o. + (srv_i386_linux_regobj): Add i386-avx-mpx-linux.o. + (srv_amd64_regobj): Add amd64-avx-mpx.o. + (srv_amd64_linux_regobj): Add amd64-avx-mpx-linux.o. + (srv_i386_xmlfiles): Add i386/i386-avx-mpx.xml. + (srv_amd64_xmlfiles): Add i386/amd64-avx-mpx.xml. + (srv_i386_linux_xmlfiles): Add i386/i386-avx-mpx-linux.xml. + (srv_amd64_linux_xmlfiles): Add i386/amd64-avx-mpx-linux.xml. + (ipa_i386_linux_regobj): Add i386-avx-mpx-linux-ipa.o. + (ipa_amd64_linux_regobj): Add amd64-avx-mpx-linux-ipa.o. + * linux-x86-low.c (x86_linux_read_description): Add case for + X86_XSTATE_AVX_MPX_MASK. + (x86_get_ipa_tdesc_idx): Add cases for avx_mpx. + (initialize_low_arch): Call init_registers_amd64_avx_mpx_linux and + init_registers_i386_avx_mpx_linux. + * linux-i386-ipa.c (get_ipa_tdesc): Add case for avx_mpx. + (initialize_low_tracepoint): Call + init_registers_i386_avx_mpx_linux. + * linux-amd64-ipa.c (get_ipa_tdesc): Add case for avx_mpx. + (initialize_low_tracepoint): Call + init_registers_amd64_avx_mpx_linux. + * linux-x86-tdesc.h (X86_TDESC_AVX_MPX): New enum value. + (init_registers_amd64_avx_mpx_linux, tdesc_amd64_avx_mpx_linux) + (init_registers_i386_avx_mpx_linux, tdesc_i386_avx_mpx_linux): New + declarations. + +2016-04-18 Pedro Alves + + * configure: Regenerate. + +2016-04-13 Antoine Tremblay + + * linux-aarch64-low.c (aarch64_emit_add): Switch x1 and x0. + (aarch64_emit_sub): Likewise. + +2016-04-12 Pedro Alves + + * utils.c (prepare_to_throw_exception): Delete. + +2016-04-05 Simon Marchi + + * Makefile.in ($(IPA_LIB)): Set SONAME of the IPA lib. + +2016-04-05 Marcin Kościelnicki + + * tracepoint.c (getauxval): Move to #ifdef IN_PROCESS_AGENT. + +2016-04-03 Marcin Kościelnicki + + * linux-aarch64-ipa.c: Add include. + * linux-ppc-ipa.c: Add include. + * linux-s390-ipa.c: Add include. + +2016-03-31 Marcin Kościelnicki + + * tracepoint.c (gdb_collect_ptr): Remove const qualifier. + (get_raw_reg_ptr): Likewise. + (get_trace_state_variable_value_ptr): Likewise. + (set_trace_state_variable_value_ptr): Likewise. + (initialize_tracepoint): Cast alloc_jump_pad_buffer result to + char *. + +2016-03-31 Wei-cheng Wang + Marcin Kościelnicki + + PR/17221 + * linux-ppc-low.c (emit_insns): New function. + (__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros. + (ppc_emit_prologue): New function. + (ppc_emit_epilogue): New function. + (ppc_emit_add): New function. + (ppc_emit_sub): New function. + (ppc_emit_mul): New function. + (ppc_emit_lsh): New function. + (ppc_emit_rsh_signed): New function. + (ppc_emit_rsh_unsigned): New function. + (ppc_emit_ext): New function. + (ppc_emit_zero_ext): New function. + (ppc_emit_log_not): New function. + (ppc_emit_bit_and): New function. + (ppc_emit_bit_or): New function. + (ppc_emit_bit_xor): New function. + (ppc_emit_bit_not): New function. + (ppc_emit_equal): New function. + (ppc_emit_less_signed): New function. + (ppc_emit_less_unsigned): New function. + (ppc_emit_ref): New function. + (ppc_emit_const): New function. + (ppc_emit_reg): New function. + (ppc_emit_pop): New function. + (ppc_emit_stack_flush): New function. + (ppc_emit_swap): New function. + (ppc_emit_stack_adjust): New function. + (ppc_emit_call): New function. + (ppc_emit_int_call_1): New function. + (ppc_emit_void_call_2): New function. + (ppc_emit_if_goto): New function. + (ppc_emit_goto): New function. + (ppc_emit_eq_goto): New function. + (ppc_emit_ne_goto): New function. + (ppc_emit_lt_goto): New function. + (ppc_emit_le_goto): New function. + (ppc_emit_gt_goto): New function. + (ppc_emit_ge_goto): New function. + (ppc_write_goto_address): New function. + (ppc_emit_ops_impl): New static variable. + (ppc64v1_emit_prologue): New function. + (ppc64v2_emit_prologue): New function. + (ppc64_emit_epilogue): New function. + (ppc64_emit_add): New function. + (ppc64_emit_sub): New function. + (ppc64_emit_mul): New function. + (ppc64_emit_lsh): New function. + (ppc64_emit_rsh_signed): New function. + (ppc64_emit_rsh_unsigned): New function. + (ppc64_emit_ext): New function. + (ppc64_emit_zero_ext): New function. + (ppc64_emit_log_not): New function. + (ppc64_emit_bit_and): New function. + (ppc64_emit_bit_or): New function. + (ppc64_emit_bit_xor): New function. + (ppc64_emit_bit_not): New function. + (ppc64_emit_equal): New function. + (ppc64_emit_less_signed): New function. + (ppc64_emit_less_unsigned): New function. + (ppc64_emit_ref): New function. + (ppc64_emit_const): New function. + (ppc64v1_emit_reg): New function. + (ppc64v2_emit_reg): New function. + (ppc64_emit_pop): New function. + (ppc64_emit_stack_flush): New function. + (ppc64_emit_swap): New function. + (ppc64v1_emit_call): New function. + (ppc64v2_emit_call): New function. + (ppc64v1_emit_int_call_1): New function. + (ppc64v2_emit_int_call_1): New function. + (ppc64v1_emit_void_call_2): New function. + (ppc64v2_emit_void_call_2): New function. + (ppc64_emit_if_goto): New function. + (ppc64_emit_eq_goto): New function. + (ppc64_emit_ne_goto): New function. + (ppc64_emit_lt_goto): New function. + (ppc64_emit_le_goto): New function. + (ppc64_emit_gt_goto): New function. + (ppc64_emit_ge_goto): New function. + (ppc64v1_emit_ops_impl): New static variable. + (ppc64v2_emit_ops_impl): New static variable. + (ppc_emit_ops): New function. + (linux_low_target): Wire in ppc_emit_ops. + +2016-03-31 Wei-cheng Wang + Marcin Kościelnicki + + PR/17221 + * Makefile.in: Add powerpc-*-ipa.o + * configure.srv: Add ipa_obj for powerpc*-linux. + * linux-ppc-ipa.c: New file. + * linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h, tracepoint.h + includes. + (PPC_FIELD): New macro. + (PPC_SEXT): New macro. + (PPC_OP6): New macro. + (PPC_BO): New macro. + (PPC_LI): New macro. + (PPC_BD): New macro. + (init_registers_*): Move prototype to linux-ppc-tdesc.h. + (tdesc_*): Move declaration to linux-ppc-tdesc.h. + (ppc_get_hwcap): Rename to ppc_get_auxv and add type parameter. + (ppc_get_thread_area): New function. + (is_elfv2_inferior): New function. + (gen_ds_form): New function. + (GEN_STD): New macro. + (GEN_STDU): New macro. + (GEN_LD): New macro. + (GEN_LDU): New macro. + (gen_d_form): New function. + (GEN_ADDI): New macro. + (GEN_ADDIS): New macro. + (GEN_LI): New macro. + (GEN_LIS): New macro. + (GEN_ORI): New macro. + (GEN_ORIS): New macro. + (GEN_LWZ): New macro. + (GEN_STW): New macro. + (GEN_STWU): New macro. + (gen_xfx_form): New function. + (GEN_MFSPR): New macro. + (GEN_MTSPR): New macro. + (GEN_MFCR): New macro. + (GEN_MTCR): New macro. + (GEN_SYNC): New macro. + (GEN_LWSYNC): New macro. + (gen_x_form): New function. + (GEN_OR): New macro. + (GEN_MR): New macro. + (GEN_LWARX): New macro. + (GEN_STWCX): New macro. + (GEN_CMPW): New macro. + (gen_md_form): New function. + (GEN_RLDICL): New macro. + (GEN_RLDICR): New macro. + (gen_i_form): New function. + (GEN_B): New macro. + (GEN_BL): New macro. + (gen_b_form): New function. + (GEN_BNE): New macro. + (GEN_LOAD): New macro. + (GEN_STORE): New macro. + (gen_limm): New function. + (gen_atomic_xchg): New function. + (gen_call): New function. + (ppc_relocate_instruction): New function. + (ppc_install_fast_tracepoint_jump_pad): New function. + (ppc_get_min_fast_tracepoint_insn_len): New function. + (ppc_get_ipa_tdesc_idx): New function. + (the_low_target): Wire in the new functions. + (initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit + tdescs. + * linux-ppc-tdesc.h: New file. + +2016-03-31 Marcin Kościelnicki + + * linux-aarch64-ipa.c: Add and includes. + (alloc_jump_pad_buffer): New function. + * linux-amd64-ipa.c: Add include. + (alloc_jump_pad_buffer): New function. + * linux-i386-ipa.c (alloc_jump_pad_buffer): New function. + * linux-s390-ipa.c: Add and includes. + (alloc_jump_pad_buffer): New function. + * tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function. + (initialize_tracepoint): Delegate to alloc_jump_pad_buffer. + * tracepoint.h (alloc_jump_pad_buffer): New prototype. + (getauxval) [!HAVE_GETAUXVAL]: New prototype. + +2016-03-30 Marcin Kościelnicki + + * linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg. + * linux-amd64-ipa.c: Likewise. + * linux-i386-ipa.c: Likewise. + * linux-s390-ipa.c: Likewise. + * tracepoint.c: IPA-export gdb_collect_ptr instead of gdb_collect, + ditto for get_raw_reg_ptr, get_trace_state_variable_value_ptr, + set_trace_state_variable_value_ptr. + (struct ipa_sym_addresses): Likewise. + (symbol_list): Likewise. + (install_fast_tracepoint): Dereference gdb_collect_ptr instead of + accessing gdb_collect directly. + (gdb_collect_ptr_type): New typedef. + (get_raw_reg_ptr_type): New typedef. + (get_trace_state_variable_value_ptr_type): New typedef. + (set_trace_state_variable_value_ptr_type): New typedef. + (gdb_collect_ptr): New global. + (get_raw_reg_ptr): New global. + (get_trace_state_variable_value_ptr): New global. + (set_trace_state_variable_value_ptr): New global. + (get_raw_reg_func_addr): Dereference get_raw_reg_ptr instead of + accessing get_raw_reg directly. + (get_get_tsv_func_addr): Likewise for + get_trace_state_variable_value_ptr. + (get_set_tsv_func_addr): Likewise for + set_trace_state_variable_value_ptr. + * tracepoint.h: Rename gdb_agent_get_raw_reg to get_raw_reg. + +2016-03-30 Simon Marchi + + * tracepoint.c (cmd_qtenable_disable): Remove whitespace. + +2016-03-30 Marcin Kościelnicki + + * remote-utils.c (look_up_one_symbol): Remove own_buf, handle 'v' + packets. + (relocate_instruction): Remove own_buf. + * server.c (own_buf): Make global. + (handle_v_requests): Make global. + * server.h (own_buf): New declaration. + (handle_v_requests): New prototype. + +2016-03-29 Marcin Kościelnicki + + PR 18377 + * linux-s390-low.c (add_insns): New function. + (s390_emit_prologue): New function. + (s390_emit_epilogue): New function. + (s390_emit_add): New function. + (s390_emit_sub): New function. + (s390_emit_mul): New function. + (s390_emit_lsh): New function. + (s390_emit_rsh_signed): New function. + (s390_emit_rsh_unsigned): New function. + (s390_emit_ext): New function. + (s390_emit_log_not): New function. + (s390_emit_bit_and): New function. + (s390_emit_bit_or): New function. + (s390_emit_bit_xor): New function. + (s390_emit_bit_not): New function. + (s390_emit_equal): New function. + (s390_emit_less_signed): New function. + (s390_emit_less_unsigned): New function. + (s390_emit_ref): New function. + (s390_emit_if_goto): New function. + (s390_emit_goto): New function. + (s390_write_goto_address): New function. + (s390_emit_litpool): New function. + (s390_emit_const): New function. + (s390_emit_call): New function. + (s390_emit_reg): New function. + (s390_emit_pop): New function. + (s390_emit_stack_flush): New function. + (s390_emit_zero_ext): New function. + (s390_emit_swap): New function. + (s390_emit_stack_adjust): New function. + (s390_emit_set_r2): New function. + (s390_emit_int_call_1): New function. + (s390_emit_void_call_2): New function. + (s390_emit_eq_goto): New function. + (s390_emit_ne_goto): New function. + (s390_emit_lt_goto): New function. + (s390_emit_le_goto): New function. + (s390_emit_gt_goto): New function. + (s390_emit_ge_goto): New function. + (s390x_emit_prologue): New function. + (s390x_emit_epilogue): New function. + (s390x_emit_add): New function. + (s390x_emit_sub): New function. + (s390x_emit_mul): New function. + (s390x_emit_lsh): New function. + (s390x_emit_rsh_signed): New function. + (s390x_emit_rsh_unsigned): New function. + (s390x_emit_ext): New function. + (s390x_emit_log_not): New function. + (s390x_emit_bit_and): New function. + (s390x_emit_bit_or): New function. + (s390x_emit_bit_xor): New function. + (s390x_emit_bit_not): New function. + (s390x_emit_equal): New function. + (s390x_emit_less_signed): New function. + (s390x_emit_less_unsigned): New function. + (s390x_emit_ref): New function. + (s390x_emit_if_goto): New function. + (s390x_emit_const): New function. + (s390x_emit_call): New function. + (s390x_emit_reg): New function. + (s390x_emit_pop): New function. + (s390x_emit_stack_flush): New function. + (s390x_emit_zero_ext): New function. + (s390x_emit_swap): New function. + (s390x_emit_stack_adjust): New function. + (s390x_emit_int_call_1): New function. + (s390x_emit_void_call_2): New function. + (s390x_emit_eq_goto): New function. + (s390x_emit_ne_goto): New function. + (s390x_emit_lt_goto): New function. + (s390x_emit_le_goto): New function. + (s390x_emit_gt_goto): New function. + (s390x_emit_ge_goto): New function. + (s390_emit_ops): New function. + (struct linux_target_ops): Fill in emit_ops hook. + +2016-03-29 Marcin Kościelnicki + + PR 18377 + * Makefile.in: Add s390 IPA files. + * configure.srv: Build IPA for s390. + * linux-s390-ipa.c: New file. + * linux-s390-low.c: New includes - inttypes.h and linux-s390-tdesc.h. + (init_registers_s390_linux32): Move declaration to linux-s390-tdesc.h. + (tdesc_s390_linux32): Likewise. + (init_registers_s390_linux32v1): Likewise. + (tdesc_s390_linux32v1): Likewise. + (init_registers_s390_linux32v2): Likewise. + (tdesc_s390_linux32v2): Likewise. + (init_registers_s390_linux64): Likewise. + (tdesc_s390_linux64): Likewise. + (init_registers_s390_linux64v1): Likewise. + (tdesc_s390_linux64v1): Likewise. + (init_registers_s390_linux64v2): Likewise. + (tdesc_s390_linux64v2): Likewise. + (init_registers_s390_te_linux64): Likewise. + (tdesc_s390_te_linux64): Likewise. + (init_registers_s390_vx_linux64): Likewise. + (tdesc_s390_vx_linux64): Likewise. + (init_registers_s390_tevx_linux64): Likewise. + (tdesc_s390_tevx_linux64): Likewise. + (init_registers_s390x_linux64): Likewise. + (tdesc_s390x_linux64): Likewise. + (init_registers_s390x_linux64v1): Likewise. + (tdesc_s390x_linux64v1): Likewise. + (init_registers_s390x_linux64v2): Likewise. + (tdesc_s390x_linux64v2): Likewise. + (init_registers_s390x_te_linux64): Likewise. + (tdesc_s390x_te_linux64): Likewise. + (init_registers_s390x_vx_linux64): Likewise. + (tdesc_s390x_vx_linux64): Likewise. + (init_registers_s390x_tevx_linux64): Likewise. + (tdesc_s390x_tevx_linux64): Likewise. + (have_hwcap_s390_vx): New static variable. + (s390_arch_setup): Fill have_hwcap_s390_vx. + (s390_get_thread_area): New function. + (s390_ft_entry_gpr_esa): New const. + (s390_ft_entry_gpr_zarch): New const. + (s390_ft_entry_misc): New const. + (s390_ft_entry_fr): New const. + (s390_ft_entry_vr): New const. + (s390_ft_main_31): New const. + (s390_ft_main_64): New const. + (s390_ft_exit_fr): New const. + (s390_ft_exit_vr): New const. + (s390_ft_exit_misc): New const. + (s390_ft_exit_gpr_esa): New const. + (s390_ft_exit_gpr_zarch): New const. + (append_insns): New function. + (s390_relocate_instruction): New function. + (s390_install_fast_tracepoint_jump_pad): New function. + (s390_get_min_fast_tracepoint_insn_len): New function. + (s390_get_ipa_tdesc_idx): New function. + (struct linux_target_ops): Wire in the above functions. + (initialize_low_arch) [!__s390x__]: Don't initialize s390x tdescs. + * linux-s390-tdesc.h: New file. + +2016-03-29 Marcin Kościelnicki + + * linux-s390-low.c (s390_supports_tracepoints): New function. + (struct linux_target_ops): Fill supports_tracepoints hook. + +2016-03-18 Yao Qi + + * linux-low.c (lwp_signal_can_be_delivered): New function. + (linux_resume_one_lwp_throw): Use lwp_signal_can_be_delivered. + +2016-03-18 Yao Qi + + * linux-low.c (linux_resume_one_lwp_throw): Set 'signal' to + 0 if signal is enqueued. Remove 'signal' from one debugging + message. Move one debugging message to some lines below. + Remove code setting 'signal' to 0. + +2016-03-18 Yao Qi + + * linux-low.c (linux_low_filter_event): Remove redundant + WIFSTOPPED check together with linux_wstatus_maybe_breakpoint. + +2016-03-09 Marcin Kościelnicki + + * linux-ppc-low.c (ppc_supports_tracepoints): New function. + (struct linux_target_ops): Wire in the above. + +2016-03-03 Yao Qi + + * linux-low.c: Update comments to start_step_over. + +2016-03-03 Yao Qi + + PR server/19736 + * linux-low.c (handle_extended_wait): Set child suspended + if event_lwp->bp_reinsert isn't zero. + +2016-03-02 Yao Qi + + * linux-low.c (linux_resume_one_lwp_throw): Replace code with + enqueue_pending_signal. + +2016-03-02 Marcin Kościelnicki + + * tracepoint.c (cmd_qtstart): Only set ipa_tdesc_idx if agent + is actually loaded. + +2016-02-25 Marcin Kościelnicki + + * linux-s390-low.c (s390_num_regs_3264): Define on 31-bit too. + (s390_regmap_3264) [!__s390x__]: New global. + (s390_collect_ptrace_register): Skip map entries containing -1. + (s390_supply_ptrace_register): Ditto. + (s390_fill_gprs_high): New function. + (s390_store_gprs_high): New function. + (s390_regsets): Add NT_S390_HIGH_GPRS. + (s390_get_hwcap): Enable on 31-bit. + (have_hwcap_s390_high_gprs): Enable on 31-bit. + (s390_arch_setup): Enable detection of high GPRs, TDB, VX on 31-bit. + Detect NT_S390_HIGH_GPRS. + (s390_usrregs_info_3264): Enable on 31-bit. + (s390_regs_info): Enable regs_info_3264 on 31-bit. + (initialize_low_arch): Initialize s390_regsets_info_3264 on 31-bit. + +2016-02-25 Marcin Kościelnicki + + PR gdb/13808 + * Makefile.in: Add i386-*-linux-ipa.o and amd64-*-linux-ipa.o. + * configure.srv: Ditto. + * linux-aarch64-ipa.c (get_ipa_tdesc): New function. + (initialize_low_tracepoint): Remove ipa_tdesc assignment. + * linux-amd64-ipa.c: Add "linux-x86-tdesc.h" include. + (init_registers_amd64_linux): Remove prototype. + (tdesc_amd64_linux): Remove declaration. + (get_ipa_tdesc): New function. + (initialize_low_tracepoint): Remove ipa_tdesc assignment, + initialize remaining tdescs. + * linux-i386-ipa.c: Add "linux-x86-tdesc.h" include. + (init_registers_i386_linux): Remove prototype. + (tdesc_i386_linux): Remove declaration. + (get_ipa_tdesc): New function. + (initialize_low_tracepoint): Remove ipa_tdesc assignment, + initialize remaining tdescs. + * linux-low.c (linux_get_ipa_tdesc_idx): New function. + (linux_target_ops): wire in linux_get_ipa_tdesc_idx. + * linux-low.h (struct linux_target_ops): Add get_ipa_tdesc_idx. + * linux-x86-low.c: Move tdesc declarations to linux-x86-tdesc.h. + (x86_get_ipa_tdesc_idx): New function. + (the_low_target): Wire in x86_get_ipa_tdesc_idx. + * linux-x86-tdesc.h: New file. + * target.h (struct target_ops): Add get_ipa_tdesc_idx. + (target_get_ipa_tdesc_idx): New macro. + * tracepoint.c (ipa_tdesc_idx): New macro. + (struct ipa_sym_addresses): Add addr_ipa_tdesc_idx. + (symbol_list): Add ipa_tdesc_idx. + (cmd_qtstart): Write ipa_tdesc_idx in the target. + (ipa_tdesc): Remove. + (ipa_tdesc_idx): New variable. + (get_context_regcache): Use get_ipa_tdesc. + (gdb_collect): Ditto. + (gdb_probe): Ditto. + * tracepoint.h (get_ipa_tdesc): New prototype. + (ipa_tdesc): Remove. + +2016-02-24 Pedro Alves + + * linux-low.c (check_stopped_by_breakpoint): Rename to ... + (save_stop_reason): ... this. Use GDB_ARCH_IS_TRAP_HWBKPT and + handle ambiguous GDB_ARCH_IS_TRAP_BRKPT / GDB_ARCH_IS_TRAP_HWBKPT. + Factor out common code between the USE_SIGTRAP_SIGINFO and + !USE_SIGTRAP_SIGINFO blocks. + (linux_low_filter_event): Call save_stop_reason instead of + check_stopped_by_breakpoint and check_stopped_by_watchpoint. + Update comments. + (linux_wait_1): Update comments. + +2016-02-24 Wei-cheng Wang + + * linux-ppc-low.c (ppc_supports_z_point_type): New function: + (ppc_insert_point, ppc_remove_point): Insert/remove z-packet breakpoints. + (ppc64_emit_ops_vector): Add target ops - ppc_supports_z_point_type, + ppc_insert_point, ppc_remove_point. + +2016-02-17 Marcin Kościelnicki + + * linux-s390-low.c (s390_supports_z_point_type): New function. + (struct linux_target_ops): Wire s390_supports_z_point_type in. + +2016-02-16 Yao Qi + + * linux-arm-low.c (get_next_pcs_syscall_next_pc): Remove argument + PC. Get pc from regcache_read_pc. + +2016-02-12 Yao Qi + + * linux-aarch64-low.c (aarch64_get_pc): Call linux_get_pc_64bit + or linux_get_pc_32bit. + (aarch64_set_pc): Call linux_set_pc_64bit or linux_set_pc_32bit. + +2016-02-12 Yao Qi + + * linux-arm-low.c (get_next_pcs_ops): Initialize it with + arm_linux_get_next_pcs_fixup. + +2016-02-12 Marcin Kościelnicki + + * tracepoint.c (x_tracepoint_action_download): Change + write_inferior_data_ptr to write_inferior_data_pointer. + (cmd_qtstart): Likewise. + (write_inferior_data_ptr): Remove. + (download_agent_expr): Change write_inferior_data_ptr to + write_inferior_data_pointer. + (download_tracepoint_1): Likewise. + (download_tracepoint): Likewise. + (download_trace_state_variables): Likewise. + +2016-02-11 Wei-cheng Wang + Marcin Kościelnicki + + * tracepoint.c (struct tracepoint_action_ops): Remove. + (struct tracepoint_action): Remove ops. + (m_tracepoint_action_download, r_tracepoint_action_download) + (x_tracepoint_action_download, l_tracepoint_action_download): Adjust + size and offset accordingly. + (m_tracepoint_action_ops, r_tracepoint_action_ops) + (x_tracepoint_action_ops, l_tracepoint_action_ops): Remove. + (tracepoint_action_send, tracepoint_action_download): New functions. + Helpers for trace action handlers. + (add_tracepoint_action): Remove setup actions ops. + (download_tracepoint_1, tracepoint_send_agent): Call helper functions. + +2016-02-10 Yao Qi + + * regcache.c (regcache_raw_read_unsigned): Clear *VAL. + +2016-02-09 Simon Marchi + + * configure.ac: Use AC_CONFIG_FILES instead of passing arguments + to AC_OUTPUT. + * configure: Regenerate. + +2016-02-09 Simon Marchi + + * linux-aarch64-low.c (aarch64_linux_siginfo_fixup): Change + void * to gdb_byte *. + * linux-low.c (siginfo_fixup): Likewise. + (linux_xfer_siginfo): Likewise. + * linux-low.h (struct linux_target_ops) : + Likewise. + * linux-x86-low.c (x86_siginfo_fixup): Likewise. + +2016-02-02 Walfred Tedeschi + + * configure.srv (x86_64-*-linux*): Add amd64-linux-siginfo.o + to srv_tgtobj. + (i[34567]86-*-linux*): Add amd64-linux-siginfo.o + to srv_tgtobj. + * linux-x86-low.c [__x86_64__]: Include + "nat/amd64-linux-siginfo.h". + (compat_siginfo_from_siginfo, siginfo_from_compat_siginfo) + (compat_x32_siginfo_from_siginfo, siginfo_from_compat_x32_siginfo) + (compat_timeval, compat_sigval, compat_x32_clock, cpt_si_pid) + (cpt_si_uid, cpt_si_timerid, cpt_si_overrun, cpt_si_status) + (cpt_si_utime, cpt_si_stime, cpt_si_ptr, cpt_si_addr, cpt_si_band) + (cpt_si_fd, si_timerid, si_overrun): Move from + nat/amd64-linux-siginfo.c. + * Makefile.in (amd64-linux-siginfo.o:): New rule. + +2016-01-28 Simon Marchi + + * server.c (skip_to_semicolon): Remove. + (process_point_options): Use strchrnul instead of + skip_to_semicolon. + +2016-01-26 Yao Qi + + * linux-arm-low.c (arm_gdbserver_get_next_pcs): Remove argument pc. + * linux-low.c (install_software_single_step_breakpoints): Don't + call regcache_read_pc. + * linux-low.h (struct linux_target_ops) : Remove + argument pc. + +2016-01-26 Yao Qi + + * linux-low.c (install_software_single_step_breakpoints): Call + regcache_read_pc instead of get_pc. + +2016-01-26 Yao Qi + + * remote-utils.c (remote_close) [!USE_WIN32API]: Ignore SIGIO. + (unblock_async_io): Rename to ... + (block_unblock_async_io): ... it. New function. + (enable_async_io): Don't install SIGIO handler. Unblock it + instead. + (disable_async_io): Don't ignore SIGIO. Block it instead. + (initialize_async_io): Install SIGIO handler. Don't call + unblock_async_io. + +2016-01-26 Yao Qi + + * remote-utils.c (getpkt): If the buffer isn't empty, and the + first character is '\003', call *the_target->request_interrupt. + +2016-01-25 Yao Qi + + * remote-utils.c (new_thread_notify): Remove. + (dead_thread_notify): Likewise. + * remote-utils.h (new_thread_notify): Remove declaration. + (dead_thread_notify): Likewise. + +2016-01-23 Marcin Kościelnicki + + * gdb.trace/pending.exp: Fix expected message on continue. + +2016-01-22 Marcin Kościelnicki + + * tracepoint.c (write_inferior_data_ptr): Cast to uintptr_t, so that + it works properly on big-endian machines where sizeof (CORE_ADDR) + != sizeof (void *). + +2016-01-21 Pedro Alves + + * Makefile.in (COMPILER_CFLAGS, CXXFLAGS): New. + (INTERNAL_CFLAGS_BASE): Use COMPILER_CFLAGS instead of CFLAGS. + * configure: Regenerate. + +2016-01-21 Yao Qi + + * linux-arm-low.c (arm_sigreturn_next_pc): Add parameter + is_thumb and set it according to CPSR saved on the stack. + (get_next_pcs_syscall_next_pc): Pass is_thumb to + arm_sigreturn_next_pc. + +2016-01-18 Yao Qi + + * linux-low.c (linux_set_pc_64bit): New function. + (linux_get_pc_64bit): New function. + * linux-low.h (linux_set_pc_64bit, linux_get_pc_64bit): + Declare. + * linux-sparc-low.c (debug_threads): Remove declaration. + (sparc_get_pc): Remove. + (the_low_target): Use linux_get_pc_64bit instead of + sparc_get_pc. + * linux-tile-low.c (tile_get_pc, tile_set_pc): Remove. + (the_low_target): Use linux_get_pc_64bit and + linux_set_pc_64bit. + +2016-01-18 Yao Qi + + * linux-arm-low.c (debug_threads): Remove declaration. + (arm_get_pc, arm_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-bfin-low.c (bfin_get_pc, bfin_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-cris-low.c (debug_threads): Remove declaration. + (cris_get_pc, cris_set_pc,): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-crisv32-low.c (debug_threads): Remove declaration. + (cris_get_pc, cris_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-low.c: Include inttypes.h. + (linux_get_pc_32bit, linux_set_pc_32bit): New functions. + * linux-low.h (linux_get_pc_32bit, linux_set_pc_32bit): Declare. + * linux-m32r-low.c (m32r_get_pc, m32r_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-m68k-low.c (m68k_get_pc, m68k_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-nios2-low.c (nios2_get_pc, nios2_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-sh-low.c (sh_get_pc, sh_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + * linux-xtensa-low.c (xtensa_get_pc, xtensa_set_pc): Remove. + (the_low_target): Use linux_get_pc_32bit and + linux_set_pc_32bit. + +2016-01-18 Gary Benson + + * configure.ac (AC_FUNC_FORK): New check. + * config.in: Regenerate. + * configure: Likewise. + +2016-01-14 Yao Qi + + * linux-aarch32-low.c (thumb2_breakpoint): Make it static. + * linux-aarch32-low.h (thumb2_breakpoint): Remove declaration. + * linux-arm-low.c (arm_gdbserver_get_next_pcs): Pass 1 to + arm_get_next_pcs_ctor. + +2016-01-12 Josh Stone + Philippe Waroquiers + + * inferiors.h: Include "gdb_vecs.h". + (struct process_info): Add syscalls_to_catch. + * inferiors.c (remove_process): Free syscalls_to_catch. + * remote-utils.c (prepare_resume_reply): Report syscall_entry and + syscall_return stops. + * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. + * server.c (handle_general_set): Handle QCatchSyscalls. + (handle_query): Report support for QCatchSyscalls. + * target.h (struct target_ops): Add supports_catch_syscall. + (target_supports_catch_syscall): New macro. + * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. + (struct lwp_info): Add syscall_state. + * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. + Maintain syscall_state and syscalls_to_catch across exec. + (get_syscall_trapinfo): New function, proxy to the_low_target. + (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. + (linux_low_filter_event): Toggle syscall_state entry/return for + syscall traps, and set it ignored for all others. + (gdb_catching_syscalls_p): New function. + (gdb_catch_this_syscall_p): New function. + (linux_wait_1): Handle SYSCALL_SIGTRAP. + (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. + (linux_supports_catch_syscall): New function. + (linux_target_ops): Install it. + * linux-x86-low.c (x86_get_syscall_trapinfo): New function. + (the_low_target): Install it. + +2016-01-12 Mike Frysinger + + * acinclude.m4: Include new ../warning.m4 file. + * configure: Regenerated. + * configure.ac: Replace all warning logic with AM_GDB_WARNINGS. + +2016-01-12 Mike Frysinger + + * ax.c (is_goto_target): Mark static. + * linux-low.c (register_addr): Likewise. + (linux_fetch_registers, linux_store_registers): Likewise. + * mem-break.c (any_persistent_commands): Fix old prototype. + (add_commands_to_breakpoint): Mark static. + * regcache.c (find_register_by_name): Delete unused func. + * remote-utils.c (hex_or_minus_one): Mark static. + * server.c (monitor_show_help): Mark static. + (handle_query, handle_v_cont, handle_v_attach, handle_v_kill, + handle_v_requests): Likewise. + +2016-01-12 Pedro Alves + + Remove use of the registered trademark symbol throughout. + +2016-01-08 Yao Qi + + * remote-utils.c (getpkt): If c is '\003', call target hook + request_interrupt. + +2016-01-06 Yao Qi + + * linux-aarch32-low.h (arm_abi_breakpoint): Move to + linux-aarch32-low.c. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint_len): Likewise. + (thumb2_breakpoint, thumb2_breakpoint_len): Likewise. + (thumb2_breakpoint): Declare. + * linux-aarch32-low.c (arm_abi_breakpoint): Moved from + linux-aarch32-low.h. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint_len): Likewise. + (thumb2_breakpoint, thumb2_breakpoint_len): Likewise. + +2016-01-01 Joel Brobecker + + * gdbreplay.c (gdbreplay_version): Change copyright year in + version message. + * server.c (gdbserver_version): Likewise. + +2015-12-28 Patrick Palka + + * server.c (crc32_table): Delete. + (crc32): Use libiberty's xcrc32 function. + +2015-12-22 Joel Brobecker + + * lynx-low.c (lynx_delete_thread_callback): New function. + (lynx_mourn): Properly delete our process and all of its + threads. Remove call to clear_inferiors. + +2015-12-22 Joel Brobecker + + * target.c (thread_search_callback): Add check that + the thread_stopped target callback is not NULL before + calling it. + +2015-12-21 Yao Qi + + * linux-aarch32-low.h [__aarch64__]: Use arm_abi_breakpoint + arm breakpoint. + +2015-12-18 Antoine Tremblay + + * server.c (handle_query): Call target_supports_software_single_step. + +2015-12-18 Antoine Tremblay + + * linux-low.c (single_step): New function. + (linux_resume_one_lwp_throw): Call single_step. + (start_step_over): Likewise. + +2015-12-18 Antoine Tremblay + + * Makefile.in (SFILES): Append arch/arm-linux.c, + arch/arm-get-next-pcs.c. + (arm-linux.o): New rule. + (arm-get-next-pcs.o): New rule. + * configure.srv (arm*-*-linux*): Add arm-get-next-pcs.o, + arm-linux.o. + * linux-aarch32-low.c (arm_abi_breakpoint): Remove macro. Moved + to linux-aarch32-low.c. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint): Likewise. + (thumb_breakpoint_len, thumb2_breakpoint): Likewise. + (thumb2_breakpoint_len): Likewise. + (arm_is_thumb_mode): Make non-static. + * linux-aarch32-low.h (arm_abi_breakpoint): New macro. Moved + from linux-aarch32-low.c. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint): Likewise. + (thumb_breakpoint_len, thumb2_breakpoint): Likewise. + (thumb2_breakpoint_len): Likewise. + (arm_is_thumb_mode): New declaration. + * linux-arm-low.c: Include arch/arm-linux.h + aarch/arm-get-next-pcs.h, sys/syscall.h. + (get_next_pcs_ops): New struct. + (get_next_pcs_addr_bits_remove): New function. + (get_next_pcs_is_thumb): New function. + (get_next_pcs_read_memory_unsigned_integer): Likewise. + (arm_sigreturn_next_pc): Likewise. + (get_next_pcs_syscall_next_pc): Likewise. + (arm_gdbserver_get_next_pcs): Likewise. + (struct linux_target_ops) : + Initialize. + * linux-low.h: Move CORE_ADDR vector definition to gdb_vecs.h. + * server.h: Include gdb_vecs.h. + +2015-12-18 Antoine Tremblay + + * Makefile.in (SFILES): Append common/common-regcache.c. + (OBS): Append common-regcache.o. + (common-regcache.o): New rule. + * regcache.c (init_register_cache): Initialize cache to + REG_UNAVAILABLE. + (regcache_raw_read_unsigned): New function. + * regcache.h (REG_UNAVAILABLE, REG_VALID): Replaced by shared + register_status enum. + +2015-12-18 Antoine Tremblay + + * linux-aarch64-low.c (the_low_targets): Rename + breakpoint_reinsert_addr to get_next_pcs. + * linux-arm-low.c (the_low_targets): Likewise. + * linux-bfin-low.c (the_low_targets): Likewise. + * linux-cris-low.c (the_low_targets): Likewise. + * linux-crisv32-low.c (the_low_targets): Likewise. + * linux-low.c (can_software_single_step): Likewise. + (install_software_single_step_breakpoints): New function. + (start_step_over): Use install_software_single_step_breakpoints. + * linux-low.h: New CORE_ADDR vector. + (struct linux_target_ops) Rename breakpoint_reinsert_addr to + get_next_pcs. + * linux-mips-low.c (the_low_targets): Likewise. + * linux-nios2-low.c (the_low_targets): Likewise. + * linux-sparc-low.c (the_low_targets): Likewise. + +2015-12-17 Pedro Alves + + * linux-low.c (linux_kill_one_lwp): Remove references to + LinuxThreads. + (kill_lwp): Remove HAVE_TKILL_SYSCALL check. No longer fall back + to 'kill'. + (linux_init_signals): Delete. + (initialize_low): Adjust. + * thread-db.c (thread_db_init): Remove LinuxThreads reference. + +2015-12-16 Pedro Alves + + * configure.ac (compiler warning flags): When testing a + -Wno-foo option, check whether -Wfoo works instead. + * configure: Regenerate. + +2015-12-11 Don Breazeal + + * server.c (process_serial_event): Don't exit from gdbserver + in remote mode if there are still active inferiors. + +2015-12-11 Yao Qi + + * linux-aarch64-low.c (aarch64_breakpoint_at): Call + arm_breakpoint_at if the process is 32-bit. + +2015-12-11 Yao Qi + + * linux-aarch32-low.c [__aarch64__]: Use arm_abi_breakpoint + arm breakpoint. + +2015-12-07 Yao Qi + + * configure.srv: Append arm.o to srv_tgtobj for + aarch64*-*-linux* target. + * linux-aarch32-low.c (arm_abi_breakpoint): New macro. Moved + from linux-arm-low.c. + (arm_eabi_breakpoint, arm_breakpoint): Likewise. + (arm_breakpoint_len, thumb_breakpoint): Likewise. + (thumb_breakpoint_len, thumb2_breakpoint): Likewise. + (thumb2_breakpoint_len): Likewise. + (arm_is_thumb_mode, arm_breakpoint_at): Likewise. + (arm_breakpoint_kinds): Likewise. + (arm_breakpoint_kind_from_pc): Likewise. + (arm_sw_breakpoint_from_kind): Likewise. + (arm_breakpoint_kind_from_current_state): Likewise. + * linux-aarch32-low.h (arm_breakpoint_kind_from_pc): Declare. + (arm_sw_breakpoint_from_kind): Declare. + (arm_breakpoint_kind_from_current_state): Declare. + (arm_breakpoint_at): Declare. + * linux-aarch64-low.c (aarch64_sw_breakpoint_from_kind): Call + arm_sw_breakpoint_from_kind if process is 32-bit. + (aarch64_breakpoint_kind_from_pc): New function. + (aarch64_breakpoint_kind_from_current_state): New function. + (the_low_target): Initialize fields breakpoint_kind_from_pc + and breakpoint_kind_from_current_state. + * linux-arm-low.c (arm_breakpoint_kinds): Move to + linux-aarch32-low.c. + (arm_abi_breakpoint, arm_eabi_breakpoint): Likewise. + (arm_breakpoint, arm_breakpoint_len): Likewise. + (thumb_breakpoint, thumb_breakpoint_len): Likewise. + (thumb2_breakpoint, thumb2_breakpoint_len): Likewise. + (arm_is_thumb_mode): Likewise. + (arm_breakpoint_at): Likewise. + (arm_breakpoint_kind_from_pc): Likewise. + (arm_sw_breakpoint_from_kind): Likewise. + (arm_breakpoint_kind_from_current_state): Likewise. + + Revert: + 2015-08-04 Yao Qi + + * linux-aarch64-low.c (aarch64_supports_z_point_type): Return + 0 for Z_PACKET_SW_BP if it may be used in multi-arch debugging. + * server.c (extended_protocol): Remove "static". + * server.h (extended_protocol): Declare it. + +2015-12-04 Josh Stone + + * target.h (struct target_ops) : Rename to ... + (struct target_ops) : ... this. + (target_arch_setup): Rename to ... + (target_post_create_inferior): ... this, calling post_create_inferior. + * server.c (start_inferior): Update target_arch_setup calls to + target_post_create_inferior. + * linux-low.c (linux_low_ptrace_options): Forward declare. + (linux_arch_setup): Update its comment for general use. + (linux_post_create_inferior): New, run arch_setup and setup ptrace. + (struct linux_target_ops): Use linux_post_create_inferior. + * lynx-low.c (struct lynx_target_ops): Update arch_setup stub comment + to post_create_inferior. + * nto-low.c (struct nto_target_ops): Likewise. + * spu-low.c (struct spu_target_ops): Likewise. + * win32-low.c (struct win32_target_ops): Likewise. + +2015-12-03 Antoine Tremblay + + * linux-arm-low.c: Remove duplicate arch/arm.h include. + +2015-11-30 Antoine Tremblay + + * linux-arm-low.c (arm_reinsert_addr): Remove function. + (struct linux_target_ops : Set to NULL. + * linux-cris-low.c (cris_reinsert_addr> Remove function. + (struct linux_target_ops) : Set to NULL. + * linux-crisv32-low.c (cris_reinsert_addr): Remove function. + (struct linux_target_ops) : Set to NULL. + * linux-mips-low.c (mips_reinsert_addr): Remove function. + (struct linux_target_ops) : Set to NULL. + * linux-nios2-low.c (nios2_reinsert_addr): Remove function. + (struct linux_target_ops) : Set to NULL. + * linux-sparc-low.c (sparc_reinsert_addr): Remove function. + (struct linux_target_ops) : Set to NULL. + +2015-11-30 Antoine Tremblay + + * linux-low.c (linux_look_up_symbols): Don't call + linux_supports_traceclone. + * linux-low.h (thread_db_init): Remove use_events argument. + * thread-db.c (thread_db_use_event): Remove global variable. + (struct thread_db) : Remove field. + (struct thread_db) : Remove field. + (thread_db_create_event): Remove function. + (thread_db_enable_reporting): Likewise. + (find_one_thread): Don't check for thread_db_use_events. + (attach_thread): Likewise. + (thread_db_load_search): Remove td_thr_event_enable_p initialization. + (try_thread_db_load_1): Don't check for thread_db_use_events. + (thread_db_init): Remove use_events argument and thread events + handling. + (remove_thread_event_breakpoints): Remove function. + (thread_db_detach): Remove call to remove_thred_event_breakpoints. + +2015-11-30 Antoine Tremblay + + * linux-aarch64-low.c (aarch64_supports_hardware_single_step): + New function. + (struct linux_target_ops) : Initialize. + * linux-arm-low.c (arm_supports_hardware_single_step): New function. + (struct linux_target_ops) : Initialize. + * linux-bfin-low.c (bfin_supports_hardware_single_step): New function. + (struct linux_target_ops) : + Initialize. + * linux-crisv32-low.c (cris_supports_hardware_single_step): + New function. + (struct linux_target_ops) : Initialize. + * linux-low.c (can_hardware_single_step): Use + supports_hardware_single_step. + (can_software_single_step): New function. + (start_step_over): Call can_software_single_step. + (linux_supports_hardware_single_step): New function. + (struct target_ops) : Initialize. + * linux-low.h (struct linux_target_ops) + : Initialize. + * linux-m32r-low.c (m32r_supports_hardware_single_step): New function. + (struct linux_target_ops) : Initialize. + * linux-ppc-low.c (ppc_supports_hardware_single_step): New function. + (struct linux_target_ops) Initialize. + * linux-s390-low.c (s390_supports_hardware_single_step): New function. + (struct linux_target_ops) : Initialize. + * linux-sh-low.c (sh_supports_hardware_single_step): New function. + (struct linux_target_ops) : Initialize. + * linux-tic6x-low.c (tic6x_supports_hardware_single_step): New function. + (struct linux_target_ops) : + Initialize. + * linux-tile-low.c (tile_supports_hardware_single_step): New function. + (struct linux_target_ops) : + Initialize. + * linux-x86-low.c (x86_supports_hardware_single_step) New function. + (struct linux_target_ops) : Initialize. + * linux-xtensa-low.c (xtensa_supports_hardware_single_step): + New function. + (struct linux_target_ops) : Initialize. + * target.h (struct target_ops): : + New field. + (target_supports_software_single_step): New macro. + +2015-11-30 Antoine Tremblay + + * linux-low.c (linux_wait_1): Fix pc advance condition. + * mem-break.c (reinsert_breakpoint_inserted_here): New function. + * mem-break.h (reinsert_breakpoint_inserted_here): New declaration. + +2015-11-30 Antoine Tremblay + + * linux-arm-low.c (arm_is_thumb_mode): New function. + (arm_breakpoint_at): Use arm_is_thumb_mode. + (arm_breakpoint_kind_from_current_state): New function. + (struct linux_target_ops) : + Initialize. + * linux-low.c (linux_wait_1): Call breakpoint_kind_from_current_state. + (linux_breakpoint_kind_from_current_state): New function. + (struct target_ops : Initialize. + * linux-low.h (struct linux_target_ops) + : New field. + * target.h (struct target_ops): Likewise. + (target_breakpoint_kind_from_current_state): New macro. + +2015-11-30 Pedro Alves + + * linux-low.c (linux_resume): Wake up the event loop before + returning. + +2015-11-30 Pedro Alves + + * mem-break.c (check_gdb_bp_preconditions): Remove current_thread + check. + (set_gdb_breakpoint): If prepare_to_access_memory fails, set *ERR + to -1. + * target.c (struct thread_search): New structure. + (thread_search_callback): New function. + (prev_general_thread): New global. + (prepare_to_access_memory, done_accessing_memory): New functions. + * target.h (prepare_to_access_memory, done_accessing_memory): + Replace macros with function declarations. + +2015-11-30 Pedro Alves + + PR 14618 + * linux-low.c (linux_wait_1): If the last resumed thread is gone, + report TARGET_WAITKIND_NO_RESUMED. + * remote-utils.c (prepare_resume_reply): Handle + TARGET_WAITKIND_NO_RESUMED. + * server.c (report_no_resumed): New global. + (handle_query) : Handle "no-resumed+". Report + "no-resumed+" support. + (resume): When the target reports TARGET_WAITKIND_NO_RESUMED, only + return error if the client doesn't support no-resumed events. + (push_stop_notification): New function. + (handle_target_event): Use it. Report TARGET_WAITKIND_NO_RESUMED + events if the client supports them. + +2015-11-30 Pedro Alves + + * linux-low.c (thread_still_has_status_pending_p): Don't check + vCont;t here. + (lwp_resumed): New function. + (status_pending_p_callback): Return early if the LWP is not + supposed to be resumed. + +2015-11-30 Pedro Alves + + * linux-low.c (handle_extended_wait): Assert that the LWP's + waitstatus is TARGET_WAITKIND_IGNORE. If GDB wants to hear about + thread create events, leave the new child's status pending. + (linux_low_filter_event): If GDB wants to hear about thread exit + events, leave the LWP marked dead and don't delete it. + (linux_wait_for_event_filtered): Don't check for thread exit. + (filter_exit_event): New function. + (linux_wait_1): Use it, when returning an exit event. + (linux_resume_one_lwp_throw): Assert that the LWP's + waitstatus is TARGET_WAITKIND_IGNORE. + * remote-utils.c (prepare_resume_reply): Handle + TARGET_WAITKIND_THREAD_CREATED and TARGET_WAITKIND_THREAD_EXITED. + * server.c (report_thread_events): New global. + (handle_general_set): Handle QThreadEvents. + (handle_query) : Handle and report QThreadEvents+; + (handle_target_event): Handle TARGET_WAITKIND_THREAD_CREATED and + TARGET_WAITKIND_THREAD_EXITED. + * server.h (report_thread_events): Declare. + +2015-11-30 Pedro Alves + + * linux-low.c (resume_stopped_resumed_lwps): Don't check whether + the thread's last_resume_kind was resume_stop. + +2015-11-30 Pedro Alves + + * linux-low.c (linux_attach): In non-stop mode, wait for one stop + before returning. + +2015-11-30 Pedro Alves + + * server.c (handle_v_requests): Handle vCtrlC. + +2015-11-30 Pedro Alves + + * gdbthread.h (find_any_thread_of_pid): Declare. + * inferiors.c (thread_of_pid, find_any_thread_of_pid): New + functions. + * server.c (handle_query): If current_thread is NULL, look for + another thread of the selected process. + +2015-11-26 Daniel Colascione + Simon Marchi + + * linux-low.c (linux_target_ops): Use linux_proc_tid_get_name. + * server.c (handle_qxfer_threads_worker): Refactor to include thread + name in reply. + * target.h (struct target_ops) : New field. + (target_thread_name): New macro. + +2015-11-23 Joel Brobecker + + * regcache.h (regcache_invalidate_pid): Add declaration. + * regcache.c (regcache_invalidate_pid): New function, extracted + from regcache_invalidate. + (regcache_invalidate): Reimplement using regcache_invalidate_pid. + Add trivial documentation comment. + * lynx-low.c: Use regcache_invalidate_pid instead of + regcache_invalidate. + +2015-11-23 Joel Brobecker + + * configure.ac: Do not call AC_CHECK_TYPES for Elf32_auxv_t + and Elf64_auxv_t if the target is Android. + +2015-11-22 Doug Evans + + * target.h: #include . + +2015-11-19 Pedro Alves + + * linux-low.c (linux_process_qsupported): Change prototype. + Adjust. + * linux-low.h (struct linux_target_ops) : + Change prototype. + * linux-x86-low.c (x86_linux_process_qsupported): Change prototype + and adjust to loop over all features. + * server.c (handle_query) : Adjust to call + target_process_qsupported once, passing it a vector of unprocessed + features. + * target.h (struct target_ops) : Change + prototype. + (target_process_qsupported): Adjust. + +2015-11-19 Pedro Alves + + * configure.ac (ERROR_ON_WARNING): Don't check whether in C++ + mode. + * configure: Regenerate. + +2015-11-19 Pedro Alves + + * configure: Regenerate. + +2015-11-19 Yao Qi + + * linux-aarch64-low.c (emit_data_processing_reg): Change opcode + type to uint32_t. + +2015-11-19 Yao Qi + + * linux-aarch64-low.c (enum aarch64_operand_type): New. + (struct aarch64_operand): Move enum out. + +2015-11-19 Yao Qi + + * linux-aarch64-low.c (aarch64_fill_fpregset): Cast buf to + struct user_fpsimd_state *. + (aarch64_store_fpregset): Likewise. + +2015-11-19 Yao Qi + + * linux-aarch64-low.c (aarch64_fill_gregset): Cast buf to + struct user_pt_regs *. + (aarch64_store_gregset): Likewise. + +2015-11-18 Pedro Alves + + * Makefile.in (all_object_files): Add $IPA_OBJS. + +2015-11-17 Pedro Alves + + * win32-low.c (win32_resume): Use gdb_signal_from_host, + GDB_SIGNAL_0 and gdb_signal_to_string. + +2015-11-17 Pedro Alves + + * win32-low.c (handle_output_debug_string): Remove parameter. + (win32_kill): Remove our_status local and adjust call to + handle_output_debug_string. + (get_child_debug_event): Adjust call to + handle_output_debug_string. + +2015-11-03 Simon Marchi + + * linux-mips-low.c (mips_fill_gregset): Add cast. + (mips_store_gregset): Likewise. + (mips_fill_fpregset): Likewise. + (mips_store_fpregset): Likewise. + +2015-11-03 Simon Marchi + + * linux-mips-low.c (mips_add_watchpoint): Rename private to + priv. + +2015-11-03 Simon Marchi + + * linux-mips-low.c (mips_linux_new_thread): Change type of + watch_type to enum target_hw_bp_type. + +2015-11-03 Simon Marchi + + * linux-arm-low.c (raw_bkpt_type_to_arm_hwbp_type): + Change return type to arm_hwbp_type. + +2015-11-03 Simon Marchi + + * linux-aarch32-low.c (arm_fill_gregset): Add cast. + (arm_store_gregset): Likewise. + * linux-arm-low.c (arm_get_hwcap): Likewise. + (arm_read_description): Likewise. + +2015-11-03 Simon Marchi + + * linux-aarch32-low.c (aarch32_regsets): Use NULL_REGSET. + +2015-11-03 Simon Marchi + + * linux-ppc-low.c (ppc_get_hwcap): Add cast. + (ppc_fill_vsxregset): Likewise. + (ppc_store_vsxregset): Likewise. + (ppc_fill_vrregset): Likewise. + (ppc_store_vrregset): Likewise. + (ppc_fill_evrregset): Likewise. + (ppc_store_evrregset): Likewise. + +2015-11-03 Simon Marchi + + * linux-ppc-low.c (ppc_usrregs_info): Remove + forward-declaration. + (ppc_arch_setup): Move lower in file. + +2015-10-30 Simon Marchi + + * proc-service.c (ps_pdread): Change CORE_ADDR cast to uintptr_t. + (ps_pdwrite): Likewise. + +2015-10-29 Henrik Wallin + + * linux-arm-low.c (arm_new_thread): Move pointer dereference + to after assert checks. + +2015-10-29 Simon Marchi + + * proc-service.c (ps_pdread): Add/adjust casts. + (ps_pdwrite): Add/adjust casts. + +2015-10-29 Simon Marchi + + * server.c (handle_search_memory_1): Cast return value of + memmem. + +2015-10-29 Simon Marchi + + * server.c (write_qxfer_response): Change type of data to + gdb_byte *. + +2015-10-29 Pedro Alves + + * mem-break.c (Z_packet_to_bkpt_type): Add cast. + +2015-10-29 Pedro Alves + + * tracepoint.c (clear_installed_tracepoints): Add casts. + +2015-10-29 Pedro Alves + + * server.c (handle_v_cont, process_serial_event): Add enum + gdb_signal casts to signal parsing code. + +2015-10-29 Pedro Alves + + * linux-low.h (NULL_REGSET): Define. + * linux-aarch64-low.c (aarch64_regsets): Use NULL_REGSET. + * linux-arm-low.c (arm_regsets): Likewise. + * linux-crisv32-low.c (cris_regsets): Likewise. + * linux-m68k-low.c (m68k_regsets): Likewise. + * linux-mips-low.c (mips_regsets): Likewise. + * linux-nios2-low.c (nios2_regsets): Likewise. + * linux-ppc-low.c (ppc_regsets): Likewise. + * linux-s390-low.c (s390_regsets): Likewise. + * linux-sh-low.c (sh_regsets): Likewise. + * linux-sparc-low.c (sparc_regsets): Likewise. + * linux-tic6x-low.c (tic6x_regsets): Likewise. + * linux-tile-low.c (tile_regsets): Likewise. + * linux-x86-low.c (x86_regsets): Likewise. + * linux-xtensa-low.c (xtensa_regsets): Likewise. + +2015-10-29 Pedro Alves + + * linux-low.h (NULL_REGSET): Define. + * linux-aarch64-low.c (aarch64_regsets): Use NULL_REGSET. + * linux-arm-low.c (arm_regsets): Likewise. + * linux-crisv32-low.c (cris_regsets): Likewise. + * linux-m68k-low.c (m68k_regsets): Likewise. + * linux-mips-low.c (mips_regsets): Likewise. + * linux-nios2-low.c (nios2_regsets): Likewise. + * linux-ppc-low.c (ppc_regsets): Likewise. + * linux-s390-low.c (s390_regsets): Likewise. + * linux-sh-low.c (sh_regsets): Likewise. + * linux-sparc-low.c (sparc_regsets): Likewise. + * linux-tic6x-low.c (tic6x_regsets): Likewise. + * linux-tile-low.c (tile_regsets): Likewise. + * linux-x86-low.c (x86_regsets): Likewise. + * linux-xtensa-low.c (xtensa_regsets): Likewise. + +2015-10-26 Doug Evans + + * linux-low.c (__SIGRTMIN): Move to nat/linux-nat.h. + +2015-10-26 Doug Evans + + * linux-low.c (W_STOPCODE): Moved to common/gdb_wait.h. + +2015-10-26 Doug Evans + + * thread-db.c (find_one_thread): Cast ti.ti_tid to unsigned long + for debug_printf. + (attach_thread, find_new_threads_callback): Ditto. + +2015-10-23 Antoine Tremblay + + * mem-break.h (set_breakpoint_data): Remove. + +2015-10-23 Antoine Tremblay + + * nto-low.c (nto_sw_breakpoint_from_kind): New function. + (struct target_ops) : Initialize. + (initialize_low): Remove set_breakpoint_data call. + * spu-low.c (spu_sw_breakpoint_from_kind): New function. + (struct target_ops) : Iniitalize. + (initialize_low): Remove set_breakpoint_data call. + * win32-low.c (win32_sw_breakpoint_from_kind): New function. + (struct target_ops) : Initialize. + (initialize_low): Remove set_breakpoint_data call. + +2015-10-23 Antoine Tremblay + + * linux-low.c (default_breakpoint_kind_from_pc): Move to target.c. + * mem-break.c (set_breakpoint_at): Use target_breakpoint_kind_from_pc. + * target.c (default_breakpoint_kind_from_pc): Moved from linux-low.c + * target.h (target_breakpoint_kind_from_pc): New macro. + +2015-10-22 Antoine Tremblay + + * linux-low.c (default_breakpoint_kind_from_pc): New function. + (linux_breakpoint_kind_from_pc): Use default_breakpoint_kind_from_pc for + the default breakpoint kind. + +2015-10-21 Antoine Tremblay + + * linux-arm-low.c (arm_supports_z_point_type): Add software + breakpoint support. + +2015-10-21 Antoine Tremblay + + * linux-arm-low.c: Refactor breakpoint definitions. + (arm_breakpoint_at): Adjust for arm_abi_breakpoint. + (arm_sw_breakpoint_from_kind): Adjust for arm_breakpoint. + +2015-10-21 Antoine Tremblay + + * Makefile.in: Add arm.c/o. + * configure.srv: Likewise. + * linux-arm-low.c (arm_breakpoint_kinds): New enum. + (arm_breakpoint_kind_from_pc): New function. + (arm_sw_breakpoint_from_kind): Return proper kind. + (struct linux_target_ops) : Initialize. + +2015-10-21 Antoine Tremblay + + * linux-low.c (initialize_low): Ajdust for breakpoint global variables + removal. + * mem-break.c : Remove breakpoint_data/breakpoint_len global variables. + (struct raw_breakpoint) : Remove. + (struct raw_breakpoint) : Add. + (bp_size): New function. + (bp_opcode): Likewise. + (find_raw_breakpoint_at): Adjust for kind. + (insert_memory_breakpoint): Adjust for kind call bp_size,bp_opcode. + (remove_memory_breakpoint): Adjust for kind call bp_size. + (set_raw_breakpoint_at): Adjust for kind. + (set_breakpoint): Likewise. + (set_breakpoint_at): Call breakpoint_kind_from_pc. + (delete_raw_breakpoint): Adjust for kind. + (delete_breakpoint): Likewise. + (find_gdb_breakpoint): Likewise. + (set_gdb_breakpoint_1): Likewise. + (set_gdb_breakpoint): Likewise. + (delete_gdb_breakpoint_1): Likewise. + (delete_gdb_breakpoint): Likewise. + (uninsert_raw_breakpoint): Likewise. + (reinsert_raw_breakpoint): Likewise. + (set_breakpoint_data): Remove. + (validate_inserted_breakpoint): Adjust for kind call bp_size,bp_opcode. + (check_mem_read): Adjust for kind call bp_size. + (check_mem_write): Adjust for kind call bp_size,bp_opcode. + (clone_one_breakpoint): Adjust for kind. + * mem-break.h (set_gdb_breakpoint): Likewise. + (delete_gdb_breakpoint): Likewise. + * server.c (process_serial_event): Likewise. + +2015-10-21 Antoine Tremblay + + * linux-aarch64-low.c (aarch64_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-arm-low.c (arm_breakpoint_kind_from_pc): New function. + (arm_sw_breakpoint_from_kind): New function. + * linux-bfin-low.c (bfin_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-cris-low.c (cris_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-crisv32-low.c (cris_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-low.c (linux_wait_1): Call breakpoint_kind_from_pc + and sw_breakpoint_from_kind to increment the pc. + (linux_breakpoint_kind_from_pc): New function. + (linux_sw_breakpoint_from_kind): New function. + (struct target_ops) : Initialize field. + (initialize_low): Call breakpoint_kind_from_pc and + sw_breakpoint_from_kind to replace breakpoint_data/len. + * linux-low.h (struct linux_target_ops) : + New field. + (struct linux_target_ops) : Likewise. + * linux-m32r-low.c (m32r_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-m68k-low.c (m68k_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-mips-low.c (mips_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-nios2-low.c (nios2_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-ppc-low.c (ppc_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-s390-low.c (s390_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-sh-low.c (sh_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-sparc-low.c (sparc_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-tic6x-low.c (tic6x_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-tile-low.c (tile_sw_breakpoint_from_kind): New function. + * linux-x86-low.c (x86_sw_breakpoint_from_kind): New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + * linux-xtensa-low.c (xtensa_sw_breakpoint_from_kind) New function. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Remove. + (struct linux_target_ops) : Initialize field. + (struct linux_target_ops) : Initialize field. + +2015-10-21 Antoine Tremblay + + * linux-cris-low.c (cris_get_pc): Remove void arg. + +2015-10-16 Aleksandar Ristovski + + * gdbserver/nto-low.c (nto_insert_point, nto_remove_point): Fix + variable name. + +2015-10-16 Aleksandar Ristovski + + * inferiors.c (thread_pid_matches_callback): New function. + (find_thread_process): New function. + (remove_thread): Reset current_thread. + (remove_process): Assert threads have been removed first. + +2015-10-15 Yao Qi + + * linux-aarch64-low.c (aarch64_insert_point): Set len to 2 + if it is 3. + (aarch64_remove_point): Likewise. + * regcache.c (regcache_register_size): New function. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c: Update all callers as emit_load_store + is renamed to aarch64_emit_load_store. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c: Update all callers of function renaming + from emit_insn to aarch64_emit_insn. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c (enum aarch64_opcodes): Move to + arch/aarch64-insn.h. + (struct aarch64_memory_operand): Likewise. + (ENCODE): Likewise. + (emit_insn): Move to arch/aarch64-insn.c. + (emit_b, emit_bcond, emit_cb, emit_tb): Remove. + (emit_load_store): Move to arch/aarch64-insn.c. + (emit_ldr, emit_ldrb, emit_ldrsw, emit_nop): Remove. + (can_encode_int32): Remove. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c (extract_signed_bitfield): Remove. + (aarch64_decode_ldr_literal): Move to gdb/arch/aarch64-insn.c. + (aarch64_relocate_instruction): Likewise. + (struct aarch64_insn_data): Move to gdb/arch/aarch64-insn.h. + (struct aarch64_insn_visitor): Likewise. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c (struct aarch64_insn_data): New. + (struct aarch64_insn_visitor): New. + (struct aarch64_insn_relocation_data): New. + (aarch64_ftrace_insn_reloc_b): New function. + (aarch64_ftrace_insn_reloc_b_cond): Likewise. + (aarch64_ftrace_insn_reloc_cb): Likewise. + (aarch64_ftrace_insn_reloc_tb): Likewise. + (aarch64_ftrace_insn_reloc_adr): Likewise. + (aarch64_ftrace_insn_reloc_ldr_literal): Likewise. + (aarch64_ftrace_insn_reloc_others): Likewise. + (visitor): New. + (aarch64_relocate_instruction): Use visitor. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c (aarch64_relocate_instruction): Return + int. Add argument buf. + (aarch64_install_fast_tracepoint_jump_pad): Pass buf to + aarch64_relocate_instruction. + +2015-10-12 Yao Qi + + * linux-aarch64-low.c (aarch64_relocate_instruction): Add + argument insn. Remove local variable insn. Don't call + target_read_uint32. + (aarch64_install_fast_tracepoint_jump_pad): Call + target_read_uint32. + +2015-09-30 Yao Qi + + * linux-aarch64-low.c (emit_movk): Shorten a long line. + (emit_load_store_pair): Likewise. + +2015-09-25 Simon Marchi + + * dll.c (match_dll): Add cast(s). + (unloaded_dll): Likewise. + * linux-low.c (second_thread_of_pid_p): Likewise. + (delete_lwp_callback): Likewise. + (count_events_callback): Likewise. + (select_event_lwp_callback): Likewise. + (linux_set_resume_request): Likewise. + * server.c (accumulate_file_name_length): Likewise. + (emit_dll_description): Likewise. + (handle_qxfer_threads_worker): Likewise. + (visit_actioned_threads): Likewise. + * thread-db.c (any_thread_of): Likewise. + * tracepoint.c (same_process_p): Likewise. + (match_blocktype): Likewise. + (build_traceframe_info_xml): Likewise. + +2015-09-25 Simon Marchi + + * ax.c (gdb_parse_agent_expr): Add cast to allocation result + assignment. + (gdb_unparse_agent_expr): Likewise. + * hostio.c (require_data): Likewise. + (handle_pread): Likewise. + * linux-low.c (disable_regset): Likewise. + (fetch_register): Likewise. + (store_register): Likewise. + (get_dynamic): Likewise. + (linux_qxfer_libraries_svr4): Likewise. + * mem-break.c (delete_fast_tracepoint_jump): Likewise. + (set_fast_tracepoint_jump): Likewise. + (uninsert_fast_tracepoint_jumps_at): Likewise. + (reinsert_fast_tracepoint_jumps_at): Likewise. + (validate_inserted_breakpoint): Likewise. + (clone_agent_expr): Likewise. + * regcache.c (init_register_cache): Likewise. + * remote-utils.c (putpkt_binary_1): Likewise. + (decode_M_packet): Likewise. + (decode_X_packet): Likewise. + (look_up_one_symbol): Likewise. + (relocate_instruction): Likewise. + (monitor_output): Likewise. + * server.c (handle_search_memory): Likewise. + (handle_qxfer_exec_file): Likewise. + (handle_qxfer_libraries): Likewise. + (handle_qxfer): Likewise. + (handle_query): Likewise. + (handle_v_cont): Likewise. + (handle_v_run): Likewise. + (captured_main): Likewise. + * target.c (write_inferior_memory): Likewise. + * thread-db.c (try_thread_db_load_from_dir): Likewise. + * tracepoint.c (init_trace_buffer): Likewise. + (add_tracepoint_action): Likewise. + (add_traceframe): Likewise. + (add_traceframe_block): Likewise. + (cmd_qtdpsrc): Likewise. + (cmd_qtdv): Likewise. + (cmd_qtstatus): Likewise. + (response_source): Likewise. + (response_tsv): Likewise. + (cmd_qtnotes): Likewise. + (gdb_collect): Likewise. + (initialize_tracepoint): Likewise. + +2015-09-21 Pierre Langlois + + * linux-aarch64-low-.c: Include ax.h and tracepoint.h. + (enum aarch64_opcodes) , , , , , + , , , , , , , , + : New. + (enum aarch64_condition_codes): New enum. + (w0): New static global. + (fp): Likewise. + (lr): Likewise. + (struct aarch64_memory_operand) : New + MEMORY_OPERAND_POSTINDEX type. + (postindex_memory_operand): New helper function. + (emit_ret): New function. + (emit_load_store_pair): New function, factored out of emit_stp + with support for MEMORY_OPERAND_POSTINDEX. + (emit_stp): Rewrite using emit_load_store_pair. + (emit_ldp): New function. + (emit_load_store): Likewise. + (emit_ldr): Mention post-index instruction in comment. + (emit_ldrh): New function. + (emit_ldrb): New function. + (emit_ldrsw): Mention post-index instruction in comment. + (emit_str): Likewise. + (emit_subs): New function. + (emit_cmp): Likewise. + (emit_and): Likewise. + (emit_orr): Likewise. + (emit_orn): Likewise. + (emit_eor): Likewise. + (emit_mvn): Likewise. + (emit_lslv): Likewise. + (emit_lsrv): Likewise. + (emit_asrv): Likewise. + (emit_mul): Likewise. + (emit_sbfm): Likewise. + (emit_sbfx): Likewise. + (emit_ubfm): Likewise. + (emit_ubfx): Likewise. + (emit_csinc): Likewise. + (emit_cset): Likewise. + (emit_nop): Likewise. + (emit_ops_insns): New helper function. + (emit_pop): Likewise. + (emit_push): Likewise. + (aarch64_emit_prologue): New function. + (aarch64_emit_epilogue): Likewise. + (aarch64_emit_add): Likewise. + (aarch64_emit_sub): Likewise. + (aarch64_emit_mul): Likewise. + (aarch64_emit_lsh): Likewise. + (aarch64_emit_rsh_signed): Likewise. + (aarch64_emit_rsh_unsigned): Likewise. + (aarch64_emit_ext): Likewise. + (aarch64_emit_log_not): Likewise. + (aarch64_emit_bit_and): Likewise. + (aarch64_emit_bit_or): Likewise. + (aarch64_emit_bit_xor): Likewise. + (aarch64_emit_bit_not): Likewise. + (aarch64_emit_equal): Likewise. + (aarch64_emit_less_signed): Likewise. + (aarch64_emit_less_unsigned): Likewise. + (aarch64_emit_ref): Likewise. + (aarch64_emit_if_goto): Likewise. + (aarch64_emit_goto): Likewise. + (aarch64_write_goto_address): Likewise. + (aarch64_emit_const): Likewise. + (aarch64_emit_call): Likewise. + (aarch64_emit_reg): Likewise. + (aarch64_emit_pop): Likewise. + (aarch64_emit_stack_flush): Likewise. + (aarch64_emit_zero_ext): Likewise. + (aarch64_emit_swap): Likewise. + (aarch64_emit_stack_adjust): Likewise. + (aarch64_emit_int_call_1): Likewise. + (aarch64_emit_void_call_2): Likewise. + (aarch64_emit_eq_goto): Likewise. + (aarch64_emit_ne_goto): Likewise. + (aarch64_emit_lt_goto): Likewise. + (aarch64_emit_le_goto): Likewise. + (aarch64_emit_gt_goto): Likewise. + (aarch64_emit_ge_got): Likewise. + (aarch64_emit_ops_impl): New static global variable. + (aarch64_emit_ops): New target function, return + &aarch64_emit_ops_impl. + (struct linux_target_ops): Install it. + +2015-09-21 Pierre Langlois + + * Makefile.in (linux-aarch64-ipa.o, aarch64-ipa.o): New rules. + * configure.srv (aarch64*-*-linux*): Add linux-aarch64-ipa.o and + aarch64-ipa.o. + * linux-aarch64-ipa.c: New file. + * linux-aarch64-low.c: Include arch/aarch64-insn.h, inttypes.h + and endian.h. + (aarch64_get_thread_area): New target method. + (extract_signed_bitfield): New helper function. + (aarch64_decode_ldr_literal): New function. + (enum aarch64_opcodes): New enum. + (struct aarch64_register): New struct. + (struct aarch64_operand): New struct. + (x0): New static global. + (x1): Likewise. + (x2): Likewise. + (x3): Likewise. + (x4): Likewise. + (w2): Likewise. + (ip0): Likewise. + (sp): Likewise. + (xzr): Likewise. + (aarch64_register): New helper function. + (register_operand): Likewise. + (immediate_operand): Likewise. + (struct aarch64_memory_operand): New struct. + (offset_memory_operand): New helper function. + (preindex_memory_operand): Likewise. + (enum aarch64_system_control_registers): New enum. + (ENCODE): New macro. + (emit_insn): New helper function. + (emit_b): New function. + (emit_bcond): Likewise. + (emit_cb): Likewise. + (emit_tb): Likewise. + (emit_blr): Likewise. + (emit_stp): Likewise. + (emit_ldp_q_offset): Likewise. + (emit_stp_q_offset): Likewise. + (emit_load_store): Likewise. + (emit_ldr): Likewise. + (emit_ldrsw): Likewise. + (emit_str): Likewise. + (emit_ldaxr): Likewise. + (emit_stxr): Likewise. + (emit_stlr): Likewise. + (emit_data_processing_reg): Likewise. + (emit_data_processing): Likewise. + (emit_add): Likewise. + (emit_sub): Likewise. + (emit_mov): Likewise. + (emit_movk): Likewise. + (emit_mov_addr): Likewise. + (emit_mrs): Likewise. + (emit_msr): Likewise. + (emit_sevl): Likewise. + (emit_wfe): Likewise. + (append_insns): Likewise. + (can_encode_int32_in): New helper function. + (aarch64_relocate_instruction): New function. + (aarch64_install_fast_tracepoint_jump_pad): Likewise. + (aarch64_get_min_fast_tracepoint_insn_len): Likewise. + (struct linux_target_ops): Install aarch64_get_thread_area, + aarch64_install_fast_tracepoint_jump_pad and + aarch64_get_min_fast_tracepoint_insn_len. + +2015-09-21 Pierre Langlois + + * Makefile.in (aarch64-insn.o): New rule. + * configure.srv (aarch64*-*-linux*): Add aarch64-insn.o. + +2015-09-21 Yao Qi + + * ax.c [!IN_PROCESS_AGENT] (gdb_agent_op_sizes): Define it. + +2015-09-21 Yao Qi + + * tracepoint.c (max_jump_pad_size): Remove. + +2015-09-18 Yao Qi + + * linux-aarch64-low.c: Don't include sys/uio.h. + (ps_get_thread_area): Call aarch64_ps_get_thread_area. + +2015-09-16 Wei-cheng Wang + + * tracepoint.c (eval_result_type): Change prototype. + (condition_true_at_tracepoint): Fix argument to compiled_cond. + +2015-09-15 Pedro Alves + + * remote-utils.c (prepare_resume_reply) : + Check whether to report exec events instead of checking whether + multiprocess is enabled. + +2015-09-15 Pedro Alves + + PR remote/18965 + * remote-utils.c (prepare_resume_reply): Merge + TARGET_WAITKIND_VFORK_DONE switch case with the + TARGET_WAITKIND_FORKED case. + +2015-09-15 Yao Qi + + * server.c (handle_query): Check string comparison using + "else if" instead of "if". + +2015-09-15 Yao Qi + + * server.c (vCont_supported): New global variable. + (handle_query): Set vCont_supported to 1 if "vContSupported+" + matches. Append ";vContSupported+" to own_buf. + (handle_v_requests): Append ";s;S" to own_buf if target supports + hardware single step or vCont_supported is false. + (capture_main): Set vCont_supported to zero. + +2015-09-15 Yao Qi + + * linux-low.c (linux_supports_conditional_breakpoints): Rename + it to ... + (linux_supports_hardware_single_step): ... New function. + (linux_target_ops): Update. + * lynx-low.c (lynx_target_ops): Set field + supports_hardware_single_step to target_can_do_hardware_single_step. + * nto-low.c (nto_target_ops): Likewise. + * spu-low.c (spu_target_ops): Likewise. + * win32-low.c (win32_target_ops): Likewise. + * target.c (target_can_do_hardware_single_step): New function. + * target.h (struct target_ops) : + Remove. : New field. + (target_supports_conditional_breakpoints): Remove. + (target_supports_hardware_single_step): New macro. + (target_can_do_hardware_single_step): Declare. + * server.c (handle_query): Use target_supports_hardware_single_step + instead of target_supports_conditional_breakpoints. + +2015-09-15 Yao Qi + + * linux-aarch64-low.c (aarch64_linux_siginfo_fixup): New + function. + (struct linux_target_ops the_low_target): Install + aarch64_linux_siginfo_fixup. + +2015-09-11 Don Breazeal + Luis Machado + + * linux-low.c (linux_mourn): Static declaration. + (linux_arch_setup): Move in front of + handle_extended_wait. + (linux_arch_setup_thread): New function. + (handle_extended_wait): Handle exec events. Call + linux_arch_setup_thread. Make event_lwp argument a + pointer-to-a-pointer. + (check_zombie_leaders): Do not check stopped threads. + (linux_low_ptrace_options): Add PTRACE_O_TRACEEXEC. + (linux_low_filter_event): Add lwp and thread for exec'ing + non-leader thread if leader thread has been deleted. + Refactor code into linux_arch_setup_thread and call it. + Pass child lwp pointer by reference to handle_extended_wait. + (linux_wait_for_event_filtered): Update comment. + (linux_wait_1): Prevent clobbering exec event status. + (linux_supports_exec_events): New function. + (linux_target_ops) : Initialize new member. + * lynx-low.c (lynx_target_ops) : Initialize + new member. + * remote-utils.c (prepare_resume_reply): New stop reason 'exec'. + * server.c (report_exec_events): New global variable. + (handle_query): Handle qSupported query for exec-events feature. + (captured_main): Initialize report_exec_events. + * server.h (report_exec_events): Declare new global variable. + * target.h (struct target_ops) : New + member. + (target_supports_exec_events): New macro. + * win32-low.c (win32_target_ops) : + Initialize new member. + +2015-09-09 Markus Metzger + + * linux-low.c (linux_low_enable_btrace): Remove. + (linux_target_ops): Replace linux_low_enable_btrace with + linux_enable_btrace. + +2015-09-03 Yao Qi + + * linux-aarch64-low.c (aarch64_insert_point): Call + aarch64_handle_watchpoint if aarch64_linux_region_ok_for_watchpoint + returns true. + +2015-08-27 Ulrich Weigand + + * linux-low.c (check_stopped_by_breakpoint): Use + GDB_ARCH_IS_TRAP_BRKPT instead of GDB_ARCH_TRAP_BRKPT. + +2015-08-27 Pedro Alves + + * proc-service.c (ps_pdwrite): Return PS_ERR/PS_OK explicily. + +2015-08-26 Simon Marchi + + * ax.c (gdb_parse_agent_expr): Replace xmalloc-family function with + the XNEW-family equivalent. + (compile_bytecodes): Likewise. + * dll.c (loaded_dll): Likewise. + * event-loop.c (append_callback_event): Likewise. + (create_file_handler): Likewise. + (create_file_event): Likewise. + * hostio.c (handle_open): Likewise. + * inferiors.c (add_thread): Likewise. + (add_process): Likewise. + * linux-aarch64-low.c (aarch64_linux_new_process): Likewise. + * linux-arm-low.c (arm_new_process): Likewise. + (arm_new_thread): Likewise. + * linux-low.c (add_to_pid_list): Likewise. + (linux_add_process): Likewise. + (handle_extended_wait): Likewise. + (add_lwp): Likewise. + (enqueue_one_deferred_signal): Likewise. + (enqueue_pending_signal): Likewise. + (linux_resume_one_lwp_throw): Likewise. + (linux_resume_one_thread): Likewise. + (linux_read_memory): Likewise. + (linux_write_memory): Likewise. + * linux-mips-low.c (mips_linux_new_process): Likewise. + (mips_linux_new_thread): Likewise. + (mips_add_watchpoint): Likewise. + * linux-x86-low.c (initialize_low_arch): Likewise. + * lynx-low.c (lynx_add_process): Likewise. + * mem-break.c (set_raw_breakpoint_at): Likewise. + (set_breakpoint): Likewise. + (add_condition_to_breakpoint): Likewise. + (add_commands_to_breakpoint): Likewise. + (clone_agent_expr): Likewise. + (clone_one_breakpoint): Likewise. + * regcache.c (new_register_cache): Likewise. + * remote-utils.c (look_up_one_symbol): Likewise. + * server.c (queue_stop_reply): Likewise. + (start_inferior): Likewise. + (queue_stop_reply_callback): Likewise. + (handle_target_event): Likewise. + * spu-low.c (fetch_ppc_memory): Likewise. + (store_ppc_memory): Likewise. + * target.c (set_target_ops): Likewise. + * thread-db.c (thread_db_load_search): Likewise. + (try_thread_db_load_1): Likewise. + * tracepoint.c (add_tracepoint): Likewise. + (add_tracepoint_action): Likewise. + (create_trace_state_variable): Likewise. + (cmd_qtdpsrc): Likewise. + (cmd_qtro): Likewise. + (add_while_stepping_state): Likewise. + * win32-low.c (child_add_thread): Likewise. + (get_image_name): Likewise. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (aarch64_linux_new_thread): Remove. + +2015-08-25 Yao Qi + + * Makefile.in (aarch64-linux.o): New rule. + * configure.srv (aarch64*-*-linux*): Append aarch64-linux.o to + srv_tgtobj. + * linux-aarch64-low.c: Include nat/aarch64-linux.h. + (aarch64_init_debug_reg_state): Make it extern. + (aarch64_linux_prepare_to_resume): Remove. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (aarch64_linux_prepare_to_resume): Use + lwp_arch_private_info and ptid_of_lwp. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (aarch64_get_debug_reg_state): Add argument pid. + Find proc_info by find_process_pid. All callers updated. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (struct arch64_dr_update_callback_param): + Remove. + (debug_reg_change_callback): Remove. + (aarch64_notify_debug_reg_change): Remove. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (aarch64_notify_debug_reg_change): + Call current_lwp_ptid. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (debug_reg_change_callback): Use + debug_printf. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (debug_reg_change_callback): Use phex. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (debug_reg_change_callback): Remove comments. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (debug_reg_change_callback): Re-indent + the code. + +2015-08-25 Yao Qi + + * linux-aarch64-low.c (aarch64_dr_update_callback_param) : + Remove. + (debug_reg_change_callback): Remove argument entry and add argument + lwp. Remove local variable thread. Don't print thread id in the + debugging output. Don't check whether pid of thread equals to pid. + (aarch64_notify_debug_reg_change): Don't set param.pid. Call + iterate_over_lwps instead find_inferior. + +2015-08-24 Pedro Alves + + * inferiors.c (get_first_process): New function. + * inferiors.h (get_first_process): New declaration. + * remote-utils.c (read_ptid): Default to the first process in the + list, instead of to the current thread's process. + +2015-08-24 Pedro Alves + + * debug.c: Include gdb_sys_time.h instead of sys/time.h. + * event-loop.c: Likewise. + * remote-utils.c: Likewise. + * tracepoint.c: Likewise. + +2015-08-24 Pedro Alves + + * spu-low.c (spu_request_interrupt): Use lwpid_of instead of + ptid_get_lwp. + +2015-08-21 Pedro Alves + + * ax.c (gdb_eval_agent_expr): Return expr_eval_unhandled_opcode + instead of literal 1. + +2015-08-21 Pedro Alves + + * tdesc.c (default_description): Explicitly zero-initialize. + +2015-08-21 Pedro Alves + + PR gdb/18749 + * inferiors.c (remove_thread): Discard any pending stop reply for + this thread. + * server.c (remove_all_on_match_pid): Rename to ... + (remove_all_on_match_ptid): ... this. Work with a filter ptid + instead of a pid. + (discard_queued_stop_replies): Change parameter to a ptid. Now + extern. + (handle_v_kill, kill_inferior_callback, captured_main) + (process_serial_event): Adjust. + * server.h (discard_queued_stop_replies): Declare. + +2015-08-21 Pedro Alves + + * linux-low.c (wait_for_sigstop): Always switch to no thread + selected if the previously current thread dies. + * lynx-low.c (lynx_request_interrupt): Use the first thread's + process instead of the current thread's. + * remote-utils.c (input_interrupt): Don't check if there's no + current thread. + * server.c (gdb_read_memory, gdb_write_memory): If setting the + current thread to the general thread fails, error out. + (handle_qxfer_auxv, handle_qxfer_libraries) + (handle_qxfer_libraries_svr4, handle_qxfer_siginfo) + (handle_qxfer_spu, handle_qxfer_statictrace, handle_qxfer_fdpic) + (handle_query): Check if there's a thread selected instead of + checking whether there's any thread in the thread list. + (handle_qxfer_threads, handle_qxfer_btrace) + (handle_qxfer_btrace_conf): Don't error out early if there's no + thread in the thread list. + (handle_v_cont, myresume): Don't set the current thread to the + continue thread. + (process_serial_event) : Also set thread_id if the + previous general thread is still alive. + (process_serial_event) : If setting the current + thread to the general thread fails, error out. + * spu-low.c (spu_resume, spu_request_interrupt): Use the first + thread's lwp instead of the current thread's. + * target.c (set_desired_thread): If the desired thread was not + found, leave the current thread pointing to NULL. Return an int + (boolean) indicating success. + * target.h (set_desired_thread): Change return type to int. + +2015-08-20 Max Filippov + + * configure.srv (xtensa*-*-linux*): Add srv_linux_thread_db=yes. + * linux-xtensa-low.c (arch/xtensa.h gdb_proc_service.h): New + #includes. + (ps_get_thread_area): New function. + +2015-08-19 Gary Benson + + * hostio.c (handle_pread): Do not attempt to read more data + than hostio_reply_with_data can fit in a packet. + +2015-08-18 Joel Brobecker + + * linux-aarch32-low.c (NT_ARM_VFP): Define if not already defined. + +2015-08-14 Matthew Fortune + + * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP_REL. + +2015-08-06 Pedro Alves + + * tracepoint.c (expr_eval_result): Now an int. + +2015-08-06 Pedro Alves + + * gdbthread.h (struct regcache): Forward declare. + (struct thread_info) : Now a struct regcache + pointer. + * inferiors.c (inferior_regcache_data) + (set_inferior_regcache_data): Now work with struct regcache + pointers. + * inferiors.h (struct regcache): Forward declare. + (inferior_regcache_data, set_inferior_regcache_data): Now work + with struct regcache pointers. + * regcache.c (get_thread_regcache, regcache_invalidate_thread) + (free_register_cache_thread): Remove struct regcache pointer + casts. + +2015-08-06 Pedro Alves + + * server.c (captured_main): On error, print the exception message + to stderr, and if run_once is set, throw a quit. + +2015-08-06 Pedro Alves + + * linux-low.c (move_out_of_jump_pad_callback): Temporarily switch + the current thread. + +2015-08-06 Pedro Alves + + * linux-low.c (linux_write_memory): Rewrite debug output to avoid + reading beyond the passed in buffer length. + +2015-08-06 Pierre Langlois + + * tracepoint.c (symbol_list) : Remove. + +2015-08-06 Pedro Alves + + * linux-low.c (handle_extended_wait): Set the fork child's suspend + count if stopping and suspending threads. + (check_stopped_by_breakpoint): If stopped by trace, set the LWP's + stop reason to TARGET_STOPPED_BY_SINGLE_STEP. + (linux_detach): Complete an ongoing step-over. + (lwp_suspended_inc, lwp_suspended_decr): New functions. Use + throughout. + (resume_stopped_resumed_lwps): Don't resume a suspended thread. + (linux_wait_1): If passing a signal to the inferior after + finishing a step-over, unsuspend and re-resume all lwps. If we + see a single-step event but the thread should be continuing, don't + pass the trap to gdb. + (stuck_in_jump_pad_callback, move_out_of_jump_pad_callback): Use + internal_error instead of gdb_assert. + (enqueue_pending_signal): New function. + (check_ptrace_stopped_lwp_gone): Add debug output. + (start_step_over): Use internal_error instead of gdb_assert. + (complete_ongoing_step_over): New function. + (linux_resume_one_thread): Don't resume a suspended thread. + (proceed_one_lwp): If the LWP is stepping over a breakpoint, reset + it stepping. + +2015-08-06 Pedro Alves + + * linux-low.c (add_lwp): Set waitstatus to TARGET_WAITKIND_IGNORE. + (linux_thread_alive): Use lwp_is_marked_dead. + (extended_event_reported): Delete. + (linux_wait_1): Check if waitstatus is TARGET_WAITKIND_IGNORE + instead of extended_event_reported. + (mark_lwp_dead): Don't set the 'dead' flag. Store the waitstatus + as well. + (lwp_is_marked_dead): New function. + (lwp_running): Use lwp_is_marked_dead. + * linux-low.h: Delete 'dead' field, and update 'waitstatus's + comment. + +2015-08-06 Pedro Alves + + * linux-low.c (linux_wait_1): Move fork event output out of the + !report_to_gdb check. Pass event_child->waitstatus to + target_waitstatus_to_string instead of ourstatus. + +2015-08-04 Yao Qi + + * linux-aarch64-low.c (aarch64_supports_tracepoints): Return 0 + if current_thread is 32 bit. + +2015-08-04 Yao Qi + + * linux-aarch64-low.c (aarch64_supports_z_point_type): Return + 0 for Z_PACKET_SW_BP if it may be used in multi-arch debugging. + * server.c (extended_protocol): Remove "static". + * server.h (extended_protocol): Declare it. + +2015-08-04 Yao Qi + + * linux-aarch64-low.c (aarch64_get_pc): Get PC register on + both aarch64 and aarch32. + (aarch64_set_pc): Likewise. + +2015-08-04 Yao Qi + + * configure.srv (case aarch64*-*-linux*): Append arm-with-neon.o + to srv_regobj and append arm-core.xml arm-vfpv3.xml and + arm-with-neon.xml to srv_xmlfiles. + * linux-aarch64-low.c: Include linux-aarch32-low.h. + (is_64bit_tdesc): New function. + (aarch64_linux_read_description): New function. + (aarch64_arch_setup): Call aarch64_linux_read_description. + (regs_info): Rename to regs_info_aarch64. + (aarch64_regs_info): Return right regs_info. + (initialize_low_arch): Call initialize_low_arch_aarch32. + +2015-08-04 Yao Qi + + * configure.srv (srv_tgtobj): Add linux-aarch32-low.o. + * linux-aarch32-low.c: New file. + * linux-aarch32-low.h: New file. + * linux-arm-low.c (arm_fill_gregset): Move it to + linux-aarch32-low.c. + (arm_store_gregset): Likewise. + (arm_fill_vfpregset): Call arm_fill_vfpregset_num + (arm_store_vfpregset): Call arm_store_vfpregset_num. + (arm_arch_setup): Check if PTRACE_GETREGSET works. + (regs_info): Rename to regs_info_arm. + (arm_regs_info): Return regs_info_aarch32 if + have_ptrace_getregset is 1 and target description is + arm_with_neon or arm_with_vfpv3. + (initialize_low_arch): Don't call init_registers_arm_with_neon. + Call initialize_low_arch_aarch32 instead. + +2015-08-04 Yao Qi + + * linux-x86-low.c (have_ptrace_getregset): Move it to ... + * linux-low.c: ... here. + * linux-low.h (have_ptrace_getregset): Declare it. + +2015-08-04 Pedro Alves + + * thread-db.c (struct thread_db): Use new typedefs. + (try_thread_db_load_1): Define local TDB_DLSYM macro and use it in + CHK calls. + (disable_thread_event_reporting): Cast result of dlsym to + destination function pointer type. + (thread_db_mourn): Use td_ta_delete_ftype. + +2015-08-03 Sandra Loosemore + + * linux-nios2-low.c (NIOS2_BREAKPOINT): Conditionalize for + arch variant. + (CDX_BREAKPOINT): Define for R2. + (nios2_breakpoint_at): Check for CDX_BREAKPOINT when R2. + (the_low_target): Add comments. + +2015-07-30 Yao Qi + + * linux-arm-low.c (arm_hwcap): Remove it. + (arm_read_description): New local variable arm_hwcap. Don't + set arm_hwcap to zero. + +2015-07-30 Yao Qi + + * linux-arm-low.c (arm_fill_wmmxregset): Don't use arm_hwcap. + Use regcache->tdesc instead. + (arm_store_wmmxregset): Likewise. + (arm_fill_vfpregset): Likewise. + (arm_store_vfpregset): Likewise. + +2015-07-30 Yao Qi + + * linux-arm-low.c: Include arch/arm.h. + (arm_fill_gregset): Don't use arm_num_regs and arm_regmap. + (arm_store_gregset): Likewise. + +2015-07-29 Simon Marchi + + * linux-mips-low.c (mips_linux_prepare_to_resume): Add NULL as + ptrace's 4th parameter. + +2015-07-27 Yao Qi + + * configure.srv (case aarch64*-*-linux*): Don't set + srv_linux_usrregs. + +2015-07-24 Pedro Alves + + * linux-aarch64-low.c: Include nat/gdb_ptrace.h instead of + sys/ptrace.h. + * linux-arm-low.c: Likewise. + * linux-cris-low.c: Likewise. + * linux-crisv32-low.c: Likewise. + * linux-low.c: Likewise. + * linux-m68k-low.c: Likewise. + * linux-mips-low.c: Likewise. + * linux-nios2-low.c: Likewise. + * linux-s390-low.c: Likewise. + * linux-sparc-low.c: Likewise. + * linux-tic6x-low.c: Likewise. + * linux-tile-low.c: Likewise. + * linux-x86-low.c: Likewise. + +2015-07-24 Pedro Alves + + * config.in: Regenerate. + * configure: Regenerate. + +2015-07-24 Pedro Alves + + * acinclude.m4: Include ../ptrace.m4. + * configure.ac: Call GDB_AC_PTRACE. + * config.in, configure: Regenerate. + +2015-07-24 Yao Qi + + * linux-low.c (linux_create_inferior): Remove setting to + proc->priv->new_inferior. + (linux_attach): Likewise. + (linux_low_filter_event): Likewise. + * linux-low.h (struct process_info_private) : Remove. + +2015-07-24 Yao Qi + + * linux-low.c (linux_arch_setup): New function. + (linux_low_filter_event): If proc->tdesc is NULL and + proc->attached is true, call the_low_target.arch_setup. + Otherwise, keep status pending, and return. + (linux_resume_one_lwp_throw): Don't call get_pc if + thread->while_stepping isn't NULL. Don't call + get_thread_regcache if proc->tdesc is NULL. + (need_step_over_p): Return 0 if proc->tdesc is NULL. + (linux_target_ops): Install arch_setup. + * server.c (start_inferior): Call the_target->arch_setup. + * target.h (struct target_ops) : New field. + (target_arch_setup): New marco. + * lynx-low.c (lynx_target_ops): Update. + * nto-low.c (nto_target_ops): Update. + * spu-low.c (spu_target_ops): Update. + * win32-low.c (win32_target_ops): Update. + +2015-07-24 Yao Qi + + * linux-low.c (linux_add_process): Don't set + proc->priv->new_inferior. + (linux_create_inferior): Set proc->priv->new_inferior to 1. + (linux_attach): Likewise. + +2015-07-24 Yao Qi + + * server.c (start_inferior): Code refactor. + +2015-07-24 Yao Qi + + * server.c (process_serial_event): Set general_thread. + +2015-07-21 Yao Qi + + * linux-aarch64-low.c (aarch64_arch_setup): Remove code and call + aarch64_linux_get_debug_reg_capacity. + +2015-07-17 Yao Qi + + * Makefile.in (aarch64-linux-hw-point.o): New rule. + * configure.srv (srv_tgtobj): Append aarch64-linux-hw-point.o. + * linux-aarch64-low.c: Include nat/aarch64-linux-hw-point.h. + (AARCH64_HBP_MAX_NUM): Move to nat/aarch64-linux-hw-point.h. + (AARCH64_HWP_MAX_NUM, AARCH64_HBP_ALIGNMENT): Likewise. + (AARCH64_HWP_ALIGNMENT): Likewise. + (AARCH64_HWP_MAX_LEN_PER_REG): Likewise. + (AARCH64_DEBUG_NUM_SLOTS, AARCH64_DEBUG_ARCH): Likewise. + (aarch64_num_bp_regs, aarch64_num_wp_regs): Likewise. + (AARCH64_DEBUG_ARCH_V8, DR_MARK_ALL_CHANGED): Likewise. + (DR_MARK_N_CHANGED, DR_CLEAR_CHANGED): Likewise. + (DR_HAS_CHANGED, DR_N_HAS_CHANGE): Likewise. + (struct aarch64_debug_reg_state): Likewise. + (struct arch_lwp_info): Likewise. + (aarch64_align_watchpoint): Likewise. + (DR_CONTROL_ENABLED, DR_CONTROL_LENGTH): Likewise. + (aarch64_watchpoint_length): Likewise. + (aarch64_point_encode_ctrl_reg): Likewise + (aarch64_point_is_aligned): Likewise. + (aarch64_align_watchpoint): Likewise. + (aarch64_linux_set_debug_regs): + (aarch64_dr_state_insert_one_point): Likewise. + (aarch64_dr_state_remove_one_point): Likewise. + (aarch64_handle_breakpoint): Likewise. + (aarch64_handle_aligned_watchpoint): Likewise. + (aarch64_handle_unaligned_watchpoint): Likewise. + (aarch64_handle_watchpoint): Likewise. + +2015-07-17 Yao Qi + + * linux-aarch64-low.c (aarch64_handle_breakpoint): Add argument state + and don't aarch64_get_debug_reg_state. All callers update. + (aarch64_handle_aligned_watchpoint): Likewise. + (aarch64_handle_unaligned_watchpoint): Likewise. + (aarch64_handle_watchpoint): Likewise. + (aarch64_insert_point): Call aarch64_get_debug_reg_state earlier. + (aarch64_remove_point): Likewise. + +2015-07-17 Yao Qi + + * linux-aarch64-low.c (aarch64_show_debug_reg_state): Use + debug_printf. + (aarch64_handle_unaligned_watchpoint): Likewise. + +2015-07-15 Jan Kratochvil + + Revert the previous 3 commits: + Move gdb_regex* to common/ + Move linux_find_memory_regions_full & co. + gdbserver build-id attribute generator + +2015-07-15 Aleksandar Ristovski + + gdbserver build-id attribute generator. + * linux-low.c (nat/linux-maps.h, search.h, rsp-low.h): Include. + (ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New. + (ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New. + (find_phdr): New. + (get_dynamic): Use find_pdhr to traverse program headers. + (struct mapping_entry, mapping_entry_s, free_mapping_entry_vec) + (compare_mapping_entry_range, struct find_memory_region_callback_data) + (read_build_id, find_memory_region_callback, lrfind_mapping_entry) + (get_hex_build_id): New. + (linux_qxfer_libraries_svr4): Add optional build-id attribute + to reply XML document. + +2015-07-15 Aleksandar Ristovski + + * target.c: Include target/target-utils.h and fcntl.h. + (target_fileio_read_stralloc_1_pread, target_fileio_read_stralloc_1) + (target_fileio_read_stralloc): New functions. + +2015-07-15 Jan Kratochvil + + * Makefile.in (OBS): Add gdb_regex.o. + (gdb_regex.o): New. + * config.in: Rebuilt. + * configure: Rebuilt. + +2015-07-15 Aleksandar Ristovski + + Create empty nat/linux-maps.[ch] and common/target-utils.[ch]. + * Makefile.in (OBS): Add target-utils.o. + (linux-maps.o, target-utils.o): New. + * configure.srv (srv_linux_obj): Add linux-maps.o. + +2015-07-15 Pierre Langlois + + * linux-aarch64-low.c (aarch64_supports_range_stepping): New + function, return 1. + (the_low_target): Install it. + +2015-07-14 Pedro Alves + + * linux-low.c (kill_wait_lwp): Don't assert if waitpid fails. + Instead, ignore ECHILD, and throw an error for other errnos. + +2015-07-10 Pedro Alves + + * event-loop.c (struct callback_event) : Change type to + gdb_client_data instance instead of gdb_client_data pointer. + (append_callback_event): Adjust. + +2015-07-10 Pierre Langlois + + * linux-aarch64-low.c: Add comments for each linux_target_ops + method. Remove comments already covered in target_ops and + linux_target_ops definitions. + (the_low_target): Add comments for each unimplemented method. + +2015-07-09 Yao Qi + + * linux-aarch64-low.c (aarch64_regmap): Remove. + (aarch64_usrregs_info): Remove. + (regs_info): Set field usrregs to NULL. + +2015-07-02 Markus Metzger + + * linux-low.c: Include "rsp-low.h" + (linux_low_encode_pt_config, linux_low_encode_raw): New. + (linux_low_read_btrace): Support BTRACE_FORMAT_PT. + (linux_low_btrace_conf): Support BTRACE_FORMAT_PT. + (handle_btrace_enable_pt): New. + (handle_btrace_general_set): Support "pt". + (handle_btrace_conf_general_set): Support "pt:size". + +2015-06-29 Pierre Langlois + + * linux-aarch64-low.c (aarch64_supports_z_point_type): Enable for + Z_PACKET_SW_BP. + +2015-06-29 Pierre Langlois + + * linux-aarch64-low.c: Remove comment about endianness. + (aarch64_breakpoint): Change type to gdb_byte[]. Set to "brk #0". + (aarch64_breakpoint_at): Change type of insn to gdb_byte[]. Use + memcmp. + +2015-06-24 Gary Benson + + * linux-i386-ipa.c (stdint.h): Do not include. + * lynx-i386-low.c (stdint.h): Likewise. + * lynx-ppc-low.c (stdint.h): Likewise. + * mem-break.c (stdint.h): Likewise. + * thread-db.c (stdint.h): Likewise. + * tracepoint.c (stdint.h): Likewise. + * win32-low.c (stdint.h): Likewise. + +2015-06-18 Simon Marchi + + * server.c (write_qxfer_response): Update call to + remote_escape_output. + +2015-06-15 Aleksandar Ristovski + + Merge multiple hex conversions. + * gdbreplay.c (tohex): Rename to 'fromhex'. + (logchar): Use fromhex. + +2015-06-10 Jan Kratochvil + + * server.c (handle_qxfer_libraries): Set `version' attribute for + . + +2015-06-10 Gary Benson + + * target.h (struct target_ops) : New field. + : Likewise. + : Likewise. + * linux-low.c (nat/linux-namespaces.h): New include. + (linux_target_ops): Initialize the_target->multifs_open, + the_target->multifs_unlink and the_target->multifs_readlink. + * hostio.h (hostio_handle_new_gdb_connection): New declaration. + * hostio.c (hostio_fs_pid): New static variable. + (hostio_handle_new_gdb_connection): New function. + (handle_setfs): Likewise. + (handle_open): Use the_target->multifs_open as appropriate. + (handle_unlink): Use the_target->multifs_unlink as appropriate. + (handle_readlink): Use the_target->multifs_readlink as + appropriate. + (handle_vFile): Handle vFile:setfs packets. + * server.c (handle_query): Call hostio_handle_new_gdb_connection + after target_handle_new_gdb_connection. + +2015-06-10 Gary Benson + + * configure.ac (AC_CHECK_FUNCS): Add setns. + * config.in: Regenerate. + * configure: Likewise. + * Makefile.in (SFILES): Add nat/linux-namespaces.c. + (linux-namespaces.o): New rule. + * configure.srv (srv_linux_obj): Add linux-namespaces.o. + +2015-06-09 Gary Benson + + * hostio.c (handle_open): Process mode argument with + fileio_to_host_mode. + +2015-06-01 Yao Qi + + * linux-s390-low.c (PTRACE_GETREGSET, PTRACE_SETREGSET): Remove. + * linux-x86-low.c: Likewise. + +2015-05-28 Don Breazeal + + * linux-low.c (handle_extended_wait): Initialize + thread_info.last_resume_kind for new fork children. + +2015-05-15 Pedro Alves + + * target.h (target_handle_new_gdb_connection): Rewrite using if + wrapped in do/while. + +2015-05-14 Joel Brobecker + + * configure.ac: Add prfpregset_t BFD_HAVE_SYS_PROCFS_TYPE check. + * configure, config.in: Regenerate. + * gdb_proc_service.h [HAVE_PRFPREGSET_T] (prfpregset_t): + Declare typedef. + +2015-05-12 Don Breazeal + + * linux-low.c (handle_extended_wait): Handle PTRACE_EVENT_FORK and + PTRACE_EVENT_VFORK_DONE. + (linux_low_ptrace_options, extended_event_reported): Add vfork + events. + * remote-utils.c (prepare_resume_reply): New stop reasons "vfork" + and "vforkdone" for RSP 'T' Stop Reply Packet. + * server.h (report_vfork_events): Declare + global variable. + +2015-05-12 Don Breazeal + + * linux-aarch64-low.c (aarch64_linux_new_fork): New function. + (the_low_target) : Initialize new member. + * linux-arm-low.c (arm_new_fork): New function. + (the_low_target) : Initialize new member. + * linux-low.c (handle_extended_wait): Call new target function + new_fork. + * linux-low.h (struct linux_target_ops) : New member. + * linux-mips-low.c (mips_add_watchpoint): New function + extracted from mips_insert_point. + (the_low_target) : Initialize new member. + (mips_linux_new_fork): New function. + (mips_insert_point): Call mips_add_watchpoint. + * linux-x86-low.c (x86_linux_new_fork): New function. + (the_low_target) : Initialize new member. + +2015-05-12 Don Breazeal + + * linux-low.c (handle_extended_wait): Implement return value, + rename argument 'event_child' to 'event_lwp', handle + PTRACE_EVENT_FORK, call internal_error for unrecognized event. + (linux_low_ptrace_options): New function. + (linux_low_filter_event): Call linux_low_ptrace_options, + use different argument fo linux_enable_event_reporting, + use return value from handle_extended_wait. + (extended_event_reported): New function. + (linux_wait_1): Call extended_event_reported and set + status to report fork events. + (linux_write_memory): Add pid to debug message. + (reset_lwp_ptrace_options_callback): New function. + (linux_handle_new_gdb_connection): New function. + (linux_target_ops): Initialize new structure member. + * linux-low.h (struct lwp_info) : New member. + * lynx-low.c: Initialize new structure member. + * remote-utils.c (prepare_resume_reply): Implement stop reason + "fork" for "T" stop message. + * server.c (handle_query): Call handle_new_gdb_connection. + * server.h (report_fork_events): Declare global flag. + * target.h (struct target_ops) : + New member. + (target_handle_new_gdb_connection): New macro. + * win32-low.c: Initialize new structure member. + +2015-05-12 Don Breazeal + + * mem-break.c (APPEND_TO_LIST): Define macro. + (clone_agent_expr): New function. + (clone_one_breakpoint): New function. + (clone_all_breakpoints): New function. + * mem-break.h: Declare new functions. + +2015-05-12 Don Breazeal + + * linux-low.c (linux_supports_fork_events): New function. + (linux_supports_vfork_events): New function. + (linux_target_ops): Initialize new structure members. + (initialize_low): Call linux_check_ptrace_features. + * lynx-low.c (lynx_target_ops): Initialize new structure + members. + * server.c (report_fork_events, report_vfork_events): + New global flags. + (handle_query): Add new features to qSupported packet and + response. + (captured_main): Initialize new global variables. + * target.h (struct target_ops) : + New member. + : New member. + (target_supports_fork_events): New macro. + (target_supports_vfork_events): New macro. + * win32-low.c (win32_target_ops): Initialize new structure + members. + +2015-05-12 Gary Benson + + * server.c (handle_qxfer_exec_file): Use current process + if annex is empty. + +2015-05-08 Sandra Loosemore + + * linux-nios2-low.c: Include elf/common.h. Adjust comments. + Remove HAVE_PTRACE_GETREGS conditionals. + (nios2_regsets): Use PTRACE_GETREGSET and PTRACE_SETREGSET + instead of PTRACE_GETREGS and PTRACE_SETREGS. + +2015-05-08 Yao Qi + + * linux-low.c (linux_supports_conditional_breakpoints): New + function. + (linux_target_ops): Install new target method. + * lynx-low.c (lynx_target_ops): Install NULL hook for + supports_conditional_breakpoints. + * nto-low.c (nto_target_ops): Likewise. + * spu-low.c (spu_target_ops): Likewise. + * win32-low.c (win32_target_ops): Likewise. + * server.c (handle_query): Check + target_supports_conditional_breakpoints. + * target.h (struct target_ops) : + New field. + (target_supports_conditional_breakpoints): New macro. + +2015-05-06 Pedro Alves + + PR server/18081 + * server.c (start_inferior): If the process exits, mourn it. + +2015-04-21 Gary Benson + + * hostio.c (fileio_open_flags_to_host): Factored out to + fileio_to_host_openflags in common/fileio.c. Single use + updated. + +2015-04-17 Max Filippov + + * linux-xtensa-low.c (xtensa_fill_gregset) + (xtensa_store_gregset): Check XCHAL_HAVE_LOOPS instead of + XCHAL_HAVE_LOOP. + +2015-04-17 Max Filippov + + * linux-xtensa-low.c (xtensa_usrregs_info): Remove. + (regs_info): Replace usrregs pointer with NULL. + +2015-04-17 Gary Benson + + * target.h (struct target_ops) : New field. + * linux-low.c (linux_target_ops): Initialize pid_to_exec_file. + * server.c (handle_qxfer_exec_file): New function. + (qxfer_packets): Add exec-file entry. + (handle_query): Report qXfer:exec-file:read as supported packet. + +2015-04-14 Romain Naour (tiny change) + + * linux-low.c (linux_read_offsets): Remove get_thread_lwp. + +2015-04-09 Gary Benson + + * hostio-errno.c (errno_to_fileio_error): Remove function. + Update caller to use remote_fileio_to_fio_error. + +2015-04-09 Yao Qi + + * linux-low.c (linux_insert_point): Call + insert_memory_breakpoint if TYPE is raw_bkpt_type_sw. + (linux_remove_point): Call remove_memory_breakpoint if type is + raw_bkpt_type_sw. + * linux-x86-low.c (x86_insert_point): Don't call + insert_memory_breakpoint. + (x86_remove_point): Don't call remove_memory_breakpoint. + +2015-04-01 Pedro Alves + Cleber Rosa + + * server.c (gdbserver_usage): Reorganize and extend the usage + message. + +2015-03-24 Pedro Alves + + * linux-low.c (check_stopped_by_breakpoint): Tweak debug log + output. Also dump TRAP_TRACE. + (linux_low_filter_event): In debug output, distinguish a + resume_stop SIGSTOP from a delayed SIGSTOP. + +2015-03-24 Gary Benson + + * linux-x86-low.c (x86_linux_new_thread): Moved to + nat/x86-linux.c. + (x86_linux_prepare_to_resume): Likewise. + +2015-03-24 Gary Benson + + * Makefile.in (x86-linux-dregs.o): New rule. + * configure.srv: Add x86-linux-dregs.o to relevant targets. + * linux-x86-low.c: Include nat/x86-linux-dregs.h. + (u_debugreg_offset): Moved to nat/x86-linux-dregs.c. + (x86_linux_dr_get): Likewise. + (x86_linux_dr_set): Likewise. + (update_debug_registers_callback): Likewise. + (x86_linux_dr_set_addr): Likewise. + (x86_linux_dr_get_addr): Likewise. + (x86_linux_dr_set_control): Likewise. + (x86_linux_dr_get_control): Likewise. + (x86_linux_dr_get_status): Likewise. + (x86_linux_update_debug_registers): Likewise. + +2015-03-24 Gary Benson + + * linux-x86-low.c (x86_linux_update_debug_registers): + New function, factored out from... + (x86_linux_prepare_to_resume): ...this. + +2015-03-24 Gary Benson + + * linux-x86-low.c (x86_linux_dr_get): Update comments. + (x86_linux_dr_set): Likewise. + (update_debug_registers_callback): Likewise. + (x86_linux_dr_set_addr): Likewise. + (x86_linux_dr_get_addr): Likewise. + (x86_linux_dr_set_control): Likewise. + (x86_linux_dr_get_control): Likewise. + (x86_linux_dr_get_status): Likewise. + (x86_linux_prepare_to_resume): Likewise. + +2015-03-24 Gary Benson + + * linux-x86-low.c (x86_linux_dr_get): Add assertion. + Use perror_with_name. Pass string through gettext. + (x86_linux_dr_set): Likewise. + +2015-03-24 Gary Benson + + * linux-x86-low.c (x86_dr_low_set_addr): Rename to... + (x86_linux_dr_set_addr): ...this. + (x86_dr_low_get_addr): Rename to... + (x86_linux_dr_get_addr): ...this. + (x86_dr_low_set_control): Rename to... + (x86_linux_dr_set_control): ...this. + (x86_dr_low_get_control): Rename to... + (x86_linux_dr_get_control): ...this. + (x86_dr_low_get_status): Rename to... + (x86_linux_dr_get_status): ...this. + (x86_dr_low): Update with new function names. + +2015-03-24 Gary Benson + + * Makefile.in (x86-linux.o): New rule. + * configure.srv: Add x86-linux.o to relevant targets. + * linux-low.c (lwp_set_arch_private_info): New function. + (lwp_arch_private_info): Likewise. + * linux-x86-low.c: Include nat/x86-linux.h. + (arch_lwp_info): Removed structure. + (update_debug_registers_callback): + Use lwp_set_debug_registers_changed. + (x86_linux_prepare_to_resume): Use lwp_debug_registers_changed + and lwp_set_debug_registers_changed. + (x86_linux_new_thread): Use lwp_set_debug_registers_changed. + +2015-03-24 Gary Benson + + * linux-low.h (linux_target_ops) : Changed signature. + * linux-arm-low.c (arm_new_thread): Likewise. + * linux-aarch64-low.c (aarch64_linux_new_thread): Likewise. + * linux-mips-low.c (mips_linux_new_thread): Likewise. + * linux-x86-low.c (x86_linux_new_thread): Likewise. + * linux-low.c (add_lwp): Update the_low_target.new_thread call. + +2015-03-24 Gary Benson + + * linux-low.c (ptid_of_lwp): New function. + (lwp_is_stopped): Likewise. + (lwp_stop_reason): Likewise. + * linux-x86-low.c (update_debug_registers_callback): + Use lwp_is_stopped. + (x86_linux_prepare_to_resume): Use ptid_of_lwp and + lwp_stop_reason. + +2015-03-24 Gary Benson + + * linux-low.h (linux_stop_lwp): Remove declaration. + +2015-03-24 Gary Benson + + * linux-low.h: Include nat/linux-nat.h. + * linux-low.c (iterate_over_lwps_args): New structure. + (iterate_over_lwps_filter): New function. + (iterate_over_lwps): Likewise. + * linux-x86-low.c (update_debug_registers_callback): + Update signature to what iterate_over_lwps expects. + Remove PID check that iterate_over_lwps now performs. + (x86_dr_low_set_addr): Use iterate_over_lwps. + (x86_dr_low_set_control): Likewise. + +2015-03-24 Gary Benson + + * linux-x86-low.c (x86_debug_reg_state): New function. + (x86_linux_prepare_to_resume): Use the above. + +2015-03-24 Gary Benson + + * linux-low.c (current_lwp_ptid): New function. + * linux-x86-low.c: Include nat/linux-nat.h. + (x86_dr_low_get_addr): Use current_lwp_ptid. + (x86_dr_low_get_control): Likewise. + (x86_dr_low_get_status): Likewise. + +2015-03-20 Pedro Alves + + * tracepoint.c (cmd_qtstatus): Make "str" const. + +2015-03-20 Pedro Alves + + * server.c (handle_general_set): Make "req_str" const. + +2015-03-19 Pedro Alves + + * linux-low.c (linux_resume_one_lwp): Rename to ... + (linux_resume_one_lwp_throw): ... this. Don't handle ESRCH here, + instead call perror_with_name. + (check_ptrace_stopped_lwp_gone): New function. + (linux_resume_one_lwp): Reimplement as wrapper around + linux_resume_one_lwp_throw that swallows errors if the LWP is + gone. + +2015-03-19 Pedro Alves + + * linux-low.c (count_events_callback, select_event_lwp_callback): + No longer check whether the thread has resume_stop as last resume + kind. + +2015-03-19 Pedro Alves + + * linux-low.c (count_events_callback, select_event_lwp_callback): + Use the lwp's status_pending_p field, not the thread's. + +2015-03-19 Pedro Alves + + * linux-low.c (select_event_lwp_callback): Update comments to + no longer mention SIGTRAP. + +2015-03-18 Gary Benson + + * server.c (handle_query): Do not report vFile:fstat as supported. + +2015-03-11 Gary Benson + + * hostio.c (sys/types.h): New include. + (sys/stat.h): Likewise. + (common-remote-fileio.h): Likewise. + (handle_fstat): New function. + (handle_vFile): Handle vFile:fstat packets. + +2015-03-11 Gary Benson + + * configure.ac (AC_CHECK_MEMBERS): Add checks for + struct stat.st_blocks and struct stat.st_blksize. + * configure: Regenerate. + * config.in: Likewise. + * Makefile.in (SFILES): Add common/common-remote-fileio.c. + (OBS): Add common-remote-fileio.o. + (common-remote-fileio.o): New rule. + +2015-03-09 Pedro Alves + + * tracepoint.c (gdb_agent_helper_thread): Cast '&sockaddr' to + 'struct sockaddr' pointer in 'accept' call. + +2015-03-09 Pedro Alves + + Revert: + 2015-03-07 Pedro Alves + * gdbreplay.c: No longer include , , + or here. Instead include "gdb_socket.h". + (remote_open): Use union gdb_sockaddr_u. + * remote-utils.c: No longer include , + or here. Instead include "gdb_socket.h". + (handle_accept_event, remote_prepare): Use union gdb_sockaddr_u. + * tracepoint.c: Include "gdb_socket.h" instead of + or . + (init_named_socket, gdb_agent_helper_thread): Use union + gdb_sockaddr_u. + +2015-03-07 Pedro Alves + + * configure.ac (build_warnings): Move + -Wdeclaration-after-statement to the C-specific set. + * configure: Regenerate. + +2015-03-07 Pedro Alves + + * gdbreplay.c: No longer include , , + or here. Instead include "gdb_socket.h". + (remote_open): Use union gdb_sockaddr_u. + * remote-utils.c: No longer include , + or here. Instead include "gdb_socket.h". + (handle_accept_event, remote_prepare): Use union gdb_sockaddr_u. + * tracepoint.c: Include "gdb_socket.h" instead of + or . + (init_named_socket, gdb_agent_helper_thread): Use union + gdb_sockaddr_u. + +2015-03-07 Pedro Alves + + Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH + instead. + +2015-03-06 Yao Qi + + * linux-aarch64-low.c (aarch64_insert_point): Use + show_debug_regs as a boolean. + (aarch64_remove_point): Likewise. + +2015-03-05 Pedro Alves + + * lynx-low.c (lynx_target_ops): Install NULL hooks for + stopped_by_sw_breakpoint, supports_stopped_by_sw_breakpoint, + stopped_by_hw_breakpoint, supports_stopped_by_hw_breakpoint. + * nto-low.c (nto_target_ops): Likewise. + * spu-low.c (spu_target_ops): Likewise. + * win32-low.c (win32_target_ops): Likewise. + +2015-03-04 Pedro Alves + + * linux-low.c (check_stopped_by_breakpoint) [USE_SIGTRAP_SIGINFO]: + Decide whether a breakpoint triggered based on the SIGTRAP's + siginfo.si_code. + (thread_still_has_status_pending_p) [USE_SIGTRAP_SIGINFO]: Don't check whether a + breakpoint is inserted if relying on SIGTRAP's siginfo.si_code. + (linux_low_filter_event): Check for breakpoints before checking + watchpoints. + (linux_wait_1): Don't re-increment the PC if relying on SIGTRAP's + siginfo.si_code. + (linux_stopped_by_sw_breakpoint) + (linux_supports_stopped_by_sw_breakpoint) + (linux_stopped_by_hw_breakpoint) + (linux_supports_stopped_by_hw_breakpoint): New functions. + (linux_target_ops): Install new target methods. + +2015-03-04 Pedro Alves + + * remote-utils.c (prepare_resume_reply): Report swbreak/hbreak. + * server.c (swbreak_feature, hwbreak_feature): New globals. + (handle_query) : Handle "swbreak+" and "hwbreak+". + (captured_main): Clear swbreak_feature and hwbreak_feature. + * server.h (swbreak_feature, hwbreak_feature): Declare. + * target.h (struct target_ops) : New fields. + (target_supports_stopped_by_sw_breakpoint) + (target_stopped_by_sw_breakpoint) + (target_supports_stopped_by_hw_breakpoint) + (target_stopped_by_hw_breakpoint): Declare. + +2015-03-04 Pedro Alves + + enum lwp_stop_reason -> enum target_stop_reason + * linux-low.c (check_stopped_by_breakpoint): Adjust. + (thread_still_has_status_pending_p, check_stopped_by_watchpoint) + (linux_wait_1, stuck_in_jump_pad_callback) + (move_out_of_jump_pad_callback, linux_resume_one_lwp) + (linux_stopped_by_watchpoint): + * linux-low.h (enum lwp_stop_reason): Delete. + (struct lwp_info) : Now an enum target_stop_reason. + * linux-x86-low.c (x86_linux_prepare_to_resume): Adjust. + +2015-03-04 Yao Qi + + * Makefile.in (SFILES): Add linux-aarch64-low.c. + +2015-03-03 Gary Benson + + * hostio.c (handle_vFile): Fix prefix lengths. + +2015-03-03 Markus Metzger + + * linux-low.c (linux_low_enable_btrace): Do not overwrite non-zero + ptr_bits. + +2015-03-02 Andreas Arnez + + * Makefile.in (s390-vx-linux64.c, s390-tevx-linux64.c) + (s390x-vx-linux64.c, s390x-tevx-linux64.c): New rules. + (clean): Add "rm -f" for above C files. + * configure.srv (srv_regobj): Add s390-vx-linux64.o, + s390-tevx-linux64.o, s390x-vx-linux64.o, and s390x-tevx-linux64.o. + (srv_xmlfiles): Add s390-vx-linux64.xml, s390-tevx-linux64.xml, + s390x-vx-linux64.xml, s390x-tevx-linux64.xml, and s390-vx.xml. + * linux-s390-low.c (HWCAP_S390_VX): New macro. + (init_registers_s390_vx_linux64, init_registers_s390_tevx_linux64) + (init_registers_s390x_vx_linux64) + (init_registers_s390x_tevx_linux64) + (tdesc_s390_vx_linux64, tdesc_s390_tevx_linux64) + (tdesc_s390x_vx_linux64, tdesc_s390x_tevx_linux64): New extern + declarations. + (s390_fill_vxrs_low, s390_store_vxrs_low, s390_fill_vxrs_high) + (s390_store_vxrs_high): New functions. + (s390_regsets): Add entries for NT_S390_VXRS_LOW and + NT_S390_VXRS_HIGH. + (s390_arch_setup): Add logic for selecting one of the new target + descriptions. Activate the new vector regsets if applicable. + (initialize_low_arch): Also invoke init_registers_s390_vx_linux64, + init_registers_s390_tevx_linux64, init_registers_s390x_vx_linux64, + and init_registers_s390x_tevx_linux64. + +2015-03-01 Pedro Alves + + * linux-i386-ipa.c (gdb_agent_get_raw_reg): Constify 'raw_regs' + parameter. + +2015-02-27 Pedro Alves + + * linux-x86-low.c (u_debugreg_offset): New function. + (x86_linux_dr_get, x86_linux_dr_set): Use it. + +2015-02-27 Pedro Alves + + * gdb_proc_service.h: Wrap with EXTERN_C_PUSH/EXTERN_C_POP. + [!HAVE_PROC_SERVICE_H] (struct ps_prochandle): Forward declare. + [!HAVE_PROC_SERVICE_H] (ps_pdread, ps_pdwrite, ps_ptread) + ps_ptwrite, ps_lgetregs, ps_lsetregs, ps_lgetfpregs) + (ps_lsetfpregs, ps_getpid) + (ps_get_thread_area, ps_pglobal_lookup, ps_pstop, ps_pcontinue) + (ps_lstop, ps_lcontinue, ps_lgetxregsize, ps_lgetxregs) + (ps_lsetxregs, ps_plog): Declare. + +2015-02-27 Pedro Alves + + * linux-amd64-ipa.c (gdb_agent_get_raw_reg): Use + IP_AGENT_EXPORT_FUNC. + * linux-i386-ipa.c (gdb_agent_get_raw_reg): Use + IP_AGENT_EXPORT_FUNC. + * tracepoint.c (ATTR_USED, ATTR_NOINLINE, ATTR_CONSTRUCTOR) + (IP_AGENT_EXPORT): Delete. + (gdb_tp_heap_buffer, gdb_jump_pad_buffer, gdb_jump_pad_buffer_end) + (gdb_trampoline_buffer, gdb_trampoline_buffer_end) + (gdb_trampoline_buffer_error, collecting, gdb_collect) + (stop_tracing, flush_trace_buffer, about_to_request_buffer_space) + (trace_buffer_is_full, stopping_tracepoint, expr_eval_result) + (error_tracepoint, tracepoints, tracing, trace_buffer_ctrl) + (trace_buffer_ctrl_curr, trace_buffer_lo, trace_buffer_hi) + (traceframe_read_count, traceframe_write_count) + (traceframes_created, trace_state_variables, get_raw_reg) + (get_trace_state_variable_value, set_trace_state_variable_value) + (ust_loaded, helper_thread_id, cmd_buf): Use + IPA_SYM_EXPORTED_NAME. + (stop_tracing, flush_trace_buffer): Use IP_AGENT_EXPORT_FUNC. + (tracepoints) Use IP_AGENT_EXPORT_VAR. + (stopping_tracepoint, trace_buffer_is_full, expr_eval_result): Use + IP_AGENT_EXPORT_VAR and wrap in EXTERN_C_PUSH/EXTERN_C_POP. + (last_tracepoint): Move into !IN_PROCESS_AGENT block. + (error_tracepoint): Use IP_AGENT_EXPORT_VAR and wrap in + EXTERN_C_PUSH/EXTERN_C_POP. + (trace_state_variables): Use IP_AGENT_EXPORT_VAR. + (trace_buffer_lo, trace_buffer_hi): Use IP_AGENT_EXPORT_VAR and + wrap in EXTERN_C_PUSH/EXTERN_C_POP. + (trace_buffer_ctrl, trace_buffer_ctrl_curr) + (traceframe_write_count, traceframe_read_count) + (traceframes_created, tracing): Use IP_AGENT_EXPORT_VAR. + (about_to_request_buffer_space, get_trace_state_variable_value) + (set_trace_state_variable_value): Use IP_AGENT_EXPORT_FUNC. + (collecting): Use IP_AGENT_EXPORT_VAR and wrap in + EXTERN_C_PUSH/EXTERN_C_POP. + (gdb_collect): Use IP_AGENT_EXPORT_FUNC. + (ust_loaded, cmd_buf): Use IP_AGENT_EXPORT_VAR. + (helper_thread_id, gdb_agent_capability): Use IP_AGENT_EXPORT_VAR + and wrap in EXTERN_C_PUSH/EXTERN_C_POP. + (gdb_tp_heap_buffer, gdb_jump_pad_buffer, gdb_jump_pad_buffer_end) + (gdb_trampoline_buffer, gdb_trampoline_buffer_end) + (gdb_trampoline_buffer_error): Use IP_AGENT_EXPORT_VAR. + * tracepoint.h (ATTR_USED, ATTR_NOINLINE, EXPORTED_SYMBOL): + Define. + (IP_AGENT_EXPORT_FUNC, IP_AGENT_EXPORT_VAR) + (IP_AGENT_EXPORT_VAR_DECL): Define. + (tracing): Declare. + (gdb_agent_get_raw_reg): Declare. + +2015-02-27 Tom Tromey + Pedro Alves + + Rename symbols whose names are reserved C++ keywords throughout. + +2015-02-27 Pedro Alves + + * Makefile.in (COMPILER): New, get it from autoconf. + (CXX): Get from autoconf instead. + (COMPILE.pre): Use COMPILER. + (CC-LD): Rename to ... + (CC_LD): ... this. Use COMPILER. + (gdbserver$(EXEEXT), gdbreplay$(EXEEXT), $(IPA_LIB)): Adjust. + (CXX_FOR_TARGET): Default to g++ instead of gcc. + * acinclude.m4: Include build-with-cxx.m4. + * configure.ac: Call AC_PROG_CXX and GDB_AC_BUILD_WITH_CXX. + Disable -Werror by default if building in C++ mode. + (build_warnings): Add -Wno-sign-compare, -Wno-write-strings and + -Wno-narrowing in C++ mode. Run supported-warning-flags tests with + the C++ compiler. Save/restore CXXFLAGS too. + * configure: Regenerate. + +2015-02-27 Pedro Alves + + * acinclude.m4: Include libiberty.m4. + * configure.ac: Call libiberty_INIT. + * config.in, configure: Regenerate. + +2015-02-26 Pedro Alves + + * linux-low.c (linux_wait_1): When incrementing the PC past a + program breakpoint always use the_low_target.breakpoint_len as + increment, rather than the maximum between that and + the_low_target.decr_pc_after_break. + +2015-02-23 Pedro Alves + + * linux-low.c (check_stopped_by_breakpoint): Don't check if the + thread was doing a step-over; always adjust the PC if + we stepped over a permanent breakpoint. + (linux_wait_1): If we stepped over breakpoint that was on top of a + permanent breakpoint, manually advance the PC past it. + +2015-02-23 Pedro Alves + + * linux-x86-low.c (REGSIZE): Define in both 32-bit and 64-bit + modes. + (x86_fill_gregset, x86_store_gregset): Use it when handling + $orig_eax. + +2015-02-20 Pedro Alves + + * thread-db.c: Include "nat/linux-procfs.h". + (thread_db_init): Skip listing new threads if the kernel supports + PTRACE_EVENT_CLONE and /proc/PID/task/ is accessible. + +2015-02-20 Pedro Alves + + * linux-low.c (status_pending_p_callback): Use ptid_match. + +2015-02-19 Antoine Tremblay + + PR breakpoints/16812 + * linux-low.c (wstatus_maybe_breakpoint): Remove. + (linux_low_filter_event): Update wstatus_maybe_breakpoint name. + (linux_wait_1): Report SIGTRAP,SIGILL,SIGSEGV. + +2015-02-10 Antoine Tremblay + + PR breakpoints/15956 + * tracepoint.c (cmd_qtinit): Add check for current_thread. + +2015-02-09 Markus Metzger + + * linux-low.c (linux_low_btrace_conf): Print size. + * server.c (handle_btrace_conf_general_set): New. + (hanle_general_set): Call handle_btrace_conf_general_set. + (handle_query): Report Qbtrace-conf:bts:size as supported. + +2015-02-09 Markus Metzger + + * linux-low.c (linux_low_enable_btrace): Update parameters. + (linux_low_btrace_conf): New. + (linux_target_ops): Initialize. + * server.c (current_btrace_conf): New. + (handle_btrace_enable): Rename to ... + (handle_btrace_enable_bts): ... this. Pass ¤t_btrace_conf + to target_enable_btrace. Update comment. Update users. + (handle_qxfer_btrace_conf): New. + (qxfer_packets): Add btrace-conf entry. + (handle_query): Report qXfer:btrace-conf:read as supported packet. + * target.h (target_ops): Update parameters and comment. + (target_ops): New. + (target_enable_btrace): Update parameters. + (target_read_btrace_conf): New. + +2015-02-09 Markus Metzger + + * server.c (handle_btrace_general_set): Remove call to + target_supports_btrace. + (supported_btrace_packets): New. + (handle_query): Call supported_btrace_packets. + * target.h: include btrace-common.h. + (btrace_target_info): Removed. + (supports_btrace, target_supports_btrace): Update parameters. + +2015-02-09 Markus Metzger + + * Makefile.in (SFILES): Add common/btrace-common.c. + (OBS): Add common/btrace-common.o. + (btrace-common.o): Add build rules. + * linux-low: Include btrace-common.h. + (linux_low_read_btrace): Use struct btrace_data. Call + btrace_data_init and btrace_data_fini. + +2015-02-06 Pedro Alves + + * thread-db.c (find_new_threads_callback): Add debug output. + +2015-02-04 Pedro Alves + + * linux-low.c (handle_extended_wait): Don't resume LWPs here. + (resume_stopped_resumed_lwps): New function. + (linux_wait_for_event_filtered): Use it. + +2015-01-15 Sergio Durigan Junior + + * Makefile.in (SFILES): Add linux-personality.c. + (linux-personality.o): New rule. + * configure.srv (srv_linux_obj): Add linux-personality.o to the + list of objects to be built. + * linux-low.c: Include nat/linux-personality.h. + (linux_create_inferior): Remove code to disable address space + randomization (moved to ../nat/linux-personality.c). Create + cleanup to disable address space randomization. + +2015-01-15 Sergio Durigan Junior + + * Makefile.in (posix-strerror.o): New rule. + (mingw-strerror.o): Likewise. + * configure: Regenerated. + * configure.ac: Source file ../common/common.host. Initialize new + variable srv_host_obs. Add srv_host_obs to GDBSERVER_DEPFILES. + +2015-01-14 Yao Qi + + * Makefile.in (SFILES): Add nat/ppc-linux.c. + (ppc-linux.o): New rule. + * configure.srv (powerpc*-*-linux*): Add ppc-linux.o. + * configure.ac: AC_CHECK_FUNCS(getauxval). + * config.in: Re-generated. + * configure: Re-generated. + * linux-ppc-low.c (ppc_arch_setup) [__powerpc64__]: Call + ppc64_64bit_inferior_p + +2015-01-14 Yao Qi + + * linux-ppc-low.c: Include "nat/ppc-linux.h". + (PPC_FEATURE_HAS_VSX): Move to nat/ppc-linux.h. + (PPC_FEATURE_HAS_ALTIVEC, PPC_FEATURE_HAS_SPE): Likewise. + (PT_ORIG_R3, PT_TRAP): Likewise. + (PTRACE_GETVSXREGS, PTRACE_SETVSXREGS): Likewise. + (PTRACE_GETVRREGS, PTRACE_SETVRREGS): Likewise. + (PTRACE_GETEVRREGS, PTRACE_SETEVRREGS): Likewise. + +2015-01-10 Joel Brobecker + + * i387-fp.c (i387_cache_to_xsave): In look over + num_avx512_zmmh_high_registers, replace use of struct i387_xsave + zmmh_low_space field by use of zmmh_high_space. + +2015-01-09 Pedro Alves + + * linux-low.c (step_over_bkpt): Move higher up in the file. + (handle_extended_wait): Don't store the stop_pc here. + (get_stop_pc): Adjust comments and rename to ... + (check_stopped_by_breakpoint): ... this. Record whether the LWP + stopped for a software breakpoint or hardware breakpoint. + (thread_still_has_status_pending_p): New function. + (status_pending_p_callback): Use + thread_still_has_status_pending_p. If the event is no longer + interesting, resume the LWP. + (handle_tracepoints): Add assert. + (maybe_move_out_of_jump_pad): Remove cancel_breakpoints call. + (wstatus_maybe_breakpoint): New function. + (cancel_breakpoint): Delete function. + (check_stopped_by_watchpoint): New function, factored out from + linux_low_filter_event. + (lp_status_maybe_breakpoint): Delete function. + (linux_low_filter_event): Remove filter_ptid argument. + Leave thread group exits pending here. Store the LWP's stop PC. + Always leave events pending. + (linux_wait_for_event_filtered): Pull all events out of the + kernel, and leave them all pending. + (count_events_callback, select_event_lwp_callback): Consider all + events. + (cancel_breakpoints_callback, linux_cancel_breakpoints): Delete. + (select_event_lwp): Only give preference to the stepping LWP in + all-stop mode. Adjust comments. + (ignore_event): New function. + (linux_wait_1): Delete 'retry' label. Use ignore_event. Remove + references to cancel_breakpoints. Adjust to renames. Also give + equal priority to all LWPs that have had events in non-stop mode. + If reporting a software breakpoint event, unadjust the LWP's PC. + (linux_wait): If linux_wait_1 returned an ignored event, retry. + (stuck_in_jump_pad_callback, move_out_of_jump_pad_callback): + Adjust. + (linux_resume_one_lwp): Store the LWP's PC. Adjust. + (resume_status_pending_p): Use thread_still_has_status_pending_p. + (linux_stopped_by_watchpoint): Adjust. + (linux_target_ops): Remove reference to linux_cancel_breakpoints. + * linux-low.h (enum lwp_stop_reason): New. + (struct lwp_info) : Adjust comment. + : Delete field. + : New field. + * linux-x86-low.c (x86_linux_prepare_to_resume): Adjust. + * mem-break.c (software_breakpoint_inserted_here) + (hardware_breakpoint_inserted_here): New function. + * mem-break.h (software_breakpoint_inserted_here) + (hardware_breakpoint_inserted_here): Declare. + * target.h (struct target_ops) : Remove field. + (cancel_breakpoints): Delete. + * tracepoint.c (clear_installed_tracepoints, stop_tracing) + (upload_fast_traceframes): Remove references to + cancel_breakpoints. + +2015-01-09 Pedro Alves + + * thread-db.c (find_new_threads_callback): Ignore thread if the + kernel thread ID is -1. + +2015-01-09 Pedro Alves + + * linux-low.c (linux_attach_fail_reason_string): Move to + nat/linux-ptrace.c, and rename. + (linux_attach_lwp): Update comment. + (attach_proc_task_lwp_callback): New function. + (linux_attach): Adjust to rename and use + linux_proc_attach_tgid_threads. + (linux_attach_fail_reason_string): Delete declaration. + +2015-01-01 Joel Brobecker + + * gdbreplay.c (gdbreplay_version): Update copyright year to 2015. + * server.c (gdbserver_version): Likewise. + +2014-12-29 Sergio Durigan Junior + + * remote-utils.c: Include ctype.h. + (input_interrupt): Explicitly handle the case when the char + received is the NUL byte. Improve the printing of non-ASCII + characters. + +2014-12-16 Joel Brobecker + + * linux-low.c (linux_low_filter_event): Update call to + linux_enable_event_reporting following the addition of + a new parameter to that function. + +2014-12-16 Catalin Udma + + PR server/17457 + * linux-aarch64-low.c (AARCH64_FPSR_REGNO): New define. + (AARCH64_FPCR_REGNO): Likewise. + (AARCH64_NUM_REGS): Update to include fpsr/fpcr registers. + (aarch64_fill_fpregset): Add missing fpsr/fpcr registers. + (aarch64_store_fpregset): Likewise. + +2014-12-15 Joel Brobecker + + * lynx-low.c (lynx_resume): Use PTRACE_SINGLESTEP_ONE if N == 1. + Remove FIXME comment about assumption about N. + +2014-12-13 Joel Brobecker + + * configure.ac: If large-file support is disabled in GDBserver, + pass --disable-largefile to ACX_CONFIGURE_DIR call for "gnulib". + * configure: Regenerate. + +2014-12-12 Andreas Arnez + + * linux-low.c (regsets_fetch_inferior_registers): Suppress the + warning upon ENODATA from ptrace. + * linux-s390-low.c (s390_store_tdb): New. + (s390_regsets): Add regset for NT_S390_TDB. + +2014-12-12 Andreas Arnez + + * linux-low.c (regsets_store_inferior_registers): Skip regsets + without a fill_function. + * linux-s390-low.c (s390_fill_last_break): Remove. + (s390_regsets): Set fill_function to NULL for NT_S390_LAST_BREAK. + (s390_arch_setup): Use regset's size instead of fill_function for + loop end condition. + +2014-12-12 Andreas Arnez + + * linux-low.c (regsets_fetch_inferior_registers): Do not invoke + the regset's store function when ptrace returned an error. + * regcache.c (get_thread_regcache): Invalidate register cache + before fetching inferior's registers. + +2014-12-12 Andreas Arnez + + * linux-low.c (regsets_fetch_inferior_registers): Rephrase + while-loop as for-loop. + (regsets_store_inferior_registers): Likewise. + +2014-11-28 Yao Qi + + * configure.ac(AC_CHECK_FUNCS): Remove readlink. + * config.in, configure: Re-generate. + * hostio.c (handle_unlink): Remove code checking HAVE_READLINK + is defined. + +2014-11-21 Yao Qi + + * configure.ac: Don't invoke AC_FUNC_ALLOCA. + (AC_CHECK_HEADERS): Remove malloc.h. + * configure: Re-generated. + * config.in: Re-generated. + * server.h: Don't include alloca.h and malloc.h. + * gdbreplay.c: Don't check HAVE_ALLOCA_H is defined. + Don't include malloc.h. + +2014-11-17 Joel Brobecker + + * lynx-low.c (lynx_write_memory): Put lynx_read_memory and + corresponding ERRNO check in same block. + +2014-11-12 Pedro Alves + + * server.c (cont_thread): Update comment. + (start_inferior, attach_inferior): No longer clear cont_thread. + (handle_v_cont): No longer set cont_thread. + (captured_main): Clear cont_thread each time a GDB connects. + +2014-11-12 Pedro Alves + + * linux-low.c (linux_wait_1): Don't force a wait for the Hc + thread, and don't resume all threads if the Hc thread has exited. + +2014-11-12 Pedro Alves + + * linux-low.c (linux_request_interrupt): Always send a SIGINT to + the process group instead of to a specific LWP. + +2014-10-15 Pedro Alves + + PR server/17487 + * win32-arm-low.c (arm_set_thread_context): Remove current_event + parameter. + (arm_set_thread_context): Delete. + (the_low_target): Adjust. + * win32-i386-low.c (debug_registers_changed) + (debug_registers_used): Delete. + (update_debug_registers_callback): New function. + (x86_dr_low_set_addr, x86_dr_low_set_control): Mark all threads as + needing to update their debug registers. + (win32_get_current_dr): New function. + (x86_dr_low_get_addr, x86_dr_low_get_control) + (x86_dr_low_get_status): Fetch the debug register from the thread + record's context. + (i386_initial_stuff): Adjust. + (i386_get_thread_context): Remove current_event parameter. Don't + clear debug_registers_changed nor copy DR values to + debug_reg_state. + (i386_set_thread_context): Delete. + (i386_prepare_to_resume): New function. + (i386_thread_added): Mark the thread as needing to update irs + debug registers. + (the_low_target): Remove i386_set_thread_context and install + i386_prepare_to_resume. + * win32-low.c (win32_get_thread_context): Adjust. + (win32_set_thread_context): Use SetThreadContext + directly. + (win32_prepare_to_resume): New function. + (win32_require_context): New function, factored out from ... + (thread_rec): ... this. + (continue_one_thread): Call win32_prepare_to_resume on each thread + we're about to continue. + (win32_resume): Call win32_prepare_to_resume on the event thread. + * win32-low.h (struct win32_thread_info) + : New field. + (struct win32_target_ops): Change prototype of set_thread_context, + delete set_thread_context and add prepare_to_resume. + (win32_require_context): New declaration. + +2014-10-08 Gary Benson + + * server.h: Do not include common-exceptions.h. + +2014-10-08 Gary Benson + + * server.h: Do not include cleanups.h. + +2014-09-30 James Hogan + + * Makefile.in (clean): Add rm -f commands for mips-dsp-linux.c and + mips64-dsp-linux.c. + +2014-09-23 Yao Qi + + * linux-low.c (lp_status_maybe_breakpoint): New function. + (linux_low_filter_event): Call lp_status_maybe_breakpoint. + (count_events_callback): Likewise. + (select_event_lwp_callback): Likewise. + (cancel_breakpoints_callback): Likewise. + +2014-09-19 Don Breazeal + + * linux-low.c (handle_extended_wait): Call + linux_ptrace_get_extended_event. + (get_stop_pc, get_detach_signal, linux_low_filter_event): Call + linux_is_extended_waitstatus. + +2014-09-16 Joel Brobecker + + * Makefile.in (CPPFLAGS): Define. + (INTERNAL_CFLAGS_BASE): Add ${CPPFLAGS}. + (IPAGENT_CFLAGS): Remove ${CPPFLAGS}. + +2014-09-16 Gary Benson + + * inferiors.h (current_inferior): Renamed as... + (current_thread): New variable. All uses updated. + * linux-low.c (get_pc): Renamed saved_inferior as saved_thread. + (maybe_move_out_of_jump_pad): Likewise. + (cancel_breakpoint): Likewise. + (linux_low_filter_event): Likewise. + (wait_for_sigstop): Likewise. + (linux_resume_one_lwp): Likewise. + (need_step_over_p): Likewise. + (start_step_over): Likewise. + (linux_stabilize_threads): Renamed save_inferior as saved_thread. + * linux-x86-low.c (x86_linux_update_xmltarget): Likewise. + * proc-service.c (ps_lgetregs): Renamed reg_inferior as reg_thread + and save_inferior as saved_thread. + * regcache.c (get_thread_regcache): Renamed saved_inferior as + saved_thread. + (regcache_invalidate_thread): Likewise. + * remote-utils.c (prepare_resume_reply): Likewise. + * thread-db.c (thread_db_get_tls_address): Likewise. + (disable_thread_event_reporting): Likewise. + (remove_thread_event_breakpoints): Likewise. + * tracepoint.c (gdb_agent_about_to_close): Renamed save_inferior + as saved_thread. + * target.h (set_desired_inferior): Renamed as... + (set_desired_thread): New declaration. All uses updated. + * server.c (myresume): Updated comment to reference thread instead + of inferior. + (handle_serial_event): Likewise. + (handle_target_event): Likewise. + +2014-09-12 Tom Tromey + Gary Benson + + * regcache.h: Include common-regcache.h. + (regcache_read_pc): Don't declare. + * regcache.c (get_thread_regcache_for_ptid): New function. + +2014-09-11 Tom Tromey + Gary Benson + + * symbol.c: New file. + * Makefile.in (SFILES): Add symbol.c. + (OBS): Add symbol.o. + +2014-09-11 Gary Benson + + * target.c (target_stop_ptid, target_continue_ptid): New + functions. + +2014-09-11 Tom Tromey + Gary Benson + + * target.h: Include target/target.h. + * target.c (target_read_memory, target_read_uint32) + (target_write_memory): New functions. + +2014-09-11 Gary Benson + + * server.h (debug_hw_points): Don't declare. + * server.c (debug_hw_points): Don't define. Replace all uses + with show_debug_regs. + * linux-aarch64-low.c (debug_hw_points): Don't define. Replace + all uses with show_debug_regs. + +2014-09-08 Edjunior Barbosa Machado + + * linux-ppc-low.c (ppc_collect_ptrace_register): Adjust routine to take + endianness into account. + (ppc_supply_ptrace_register): Likewise. + +2014-09-03 James Hogan + + * linux-mips-low.c (mips_read_description): Reset errno to 0 prior + to reading DSP_CONTROL with PTRACE_PEEKUSER ptrace call. + +2014-09-03 Gary Benson + + * linux-x86-low.c (x86_linux_prepare_to_resume): Use + ALL_DEBUG_ADDRESS_REGISTERS. + +2014-09-02 Gary Benson + + * i386-low.h: Renamed as... + * x86-low.h: New file. All type, function and variable name + prefixes changed from "i386_" to "x86_". All references updated. + * i386-low.c: Renamed as... + * x86-low.c: New file. All type, function and variable name + prefixes changed from "i386_" to "x86_". All references updated. + +2014-09-02 Gary Benson + + * linux-x86-low.c (x86_linux_new_process): Use XCNEW. + (x86_linux_new_thread): Likewise. + +2014-08-29 Gary Benson + + * server.h (setjmp.h): Do not include. + (toplevel): Do not declare. + (common-exceptions.h): Include. + (cleanups.h): Likewise. + * server.c (toplevel): Do not define. + (exit_code): New static global. + (detach_or_kill_for_exit_cleanup): New function. + (main): New function. Original main renamed to... + (captured_main): New function. + * utils.c (verror) [!IN_PROCESS_AGENT]: Use throw_verror. + +2014-08-29 Gary Benson + + * Makefile.in (SFILES): Add common/common-exceptions.c. + (OBS): Add common-exceptions.o. + (common-exceptions.o): New rule. + * utils.c (prepare_to_throw_exception): New function. + +2014-08-29 Gary Benson + + * config.in: Regenerate. + * configure: Likewise. + +2014-08-29 Gary Benson + + * Makefile.in (SFILES): Add common/cleanups.c. + (OBS): cleanups.o. + (cleanups.o): New rule. + +2014-08-29 Gary Benson + + * utils.c (internal_vwarning): New function. + +2014-08-28 Gary Benson + + * utils.h (fatal): Remove declaration. + * utils.c (fatal): Remove function. + +2014-08-28 Gary Benson + + * tracepoint.c (gdb_agent_init): Replace fatal with + perror_with_name. + (initialize_tracepoint): Likewise. + +2014-08-28 Gary Benson + + * remote-utils.c (remote_prepare): Replace fatal with error. + +2014-08-28 Gary Benson + + * linux-low.c (linux_async): Replace fatal with warning. + Tidy up and return. + (linux_start_non_stop): Return -1 if linux_async failed. + +2014-08-28 Gary Benson + + * linux-x86-low.c (i386_dr_low_set_addr): Replace check with + gdb_assert. + (i386_dr_low_get_addr): Remove vague comment. + * win32-i386-low.c (i386_dr_low_set_addr): Replace check with + gdb_assert. + +2014-08-28 Gary Benson + + * inferiors.c (get_thread_process): Replace check with gdb_assert. + * linux-low.c (linux_wait_for_event_filtered): Replace fatal with + internal_error. + (linux_resume_one_lwp): Likewise. + * linux-x86-low.c (x86_siginfo_fixup): Replace checks with + gdb_assert. + * mem-break.c (raw_bkpt_type_to_target_hw_bp_type): Replace fatal + with internal_error. + * regcache.c (get_thread_regcache): Replace check with gdb_assert. + (init_register_cache): Replace fatal with gdb_assert_not_reached. + (find_register_by_name): Replace fatal with internal_error. + (find_regno): Likewise. + * tdesc.c (init_target_desc): Replace check with gdb_assert. + * thread-db.c (thread_db_create_event): Likewise. + (thread_db_load_search): Likewise. + (try_thread_db_load_1): Likewise. + * tracepoint.c (get_jump_space_head): Replace fatal with + internal_error. + (claim_trampoline_space): Likewise. + (have_fast_tracepoint_trampoline_buffer): Likewise. + (cmd_qtstart): Likewise. + (stop_tracing): Likewise. + (fast_tracepoint_collecting): Likewise. + (target_malloc): Likewise. + (download_tracepoint): Likewise. + (download_trace_state_variables): Replace check with gdb_assert. + (upload_fast_traceframes): Replace fatal with internal_error. + +2014-08-19 Tom Tromey + Gary Benson + + * Makefile.in (SFILES): Add common/common-debug.c. + (OBS): Add common-debug.o. + (common-debug.o): New rule. + * debug.h (debug_printf): Don't declare. + * debug.c (debug_printf): Renamed and rewritten as... + (debug_vprintf): New function. + +2014-08-19 Gary Benson + + * utils.h: Do not include print-utils.h. + +2014-08-19 Tom Tromey + Gary Benson + + * server.h: Add static assertion. + (gdb_byte, CORE_ADDR, LONGEST, ULONGEST): Remove. + +2014-08-19 Tom Tromey + Gary Benson + + * Makefile.in (SFILES): Add common/errors.c. + (OBS): Add errors.o. + (IPA_OBS): Add errors-ipa.o. + (errors.o): New rule. + (errors-ipa.o): Likewise. + * utils.h (perror_with_name, error, warning): Don't declare. + * utils.c (warning): Renamed and rewritten as... + (vwarning): New function. + (error): Renamed and rewritten as... + (verror): New function. + (internal_error): Renamed and rewritten as... + (internal_verror): New function. + +2014-08-07 Gary Benson + + * configure.ac (AC_CHECK_HEADERS): Remove errno.h. + * configure: Regenerate. + * config.in: Likewise. + * server.h: Do not include errno.h. + * event-loop.c: Likewise. + * hostio-errno.c: Likewise. + * linux-low.c: Likewise. + * remote-utils.c: Likewise. + * spu-low.c: Likewise. + * utils.c: Likewise. + * gdbreplay.c: Unconditionally include errno.h. + +2014-08-07 Gary Benson + + * server.h: Do not include string.h. + * event-loop.c: Likewise. + * linux-low.c: Likewise. + * regcache.c: Likewise. + * remote-utils.c: Likewise. + * spu-low.c: Likewise. + * utils.c: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include gdb_assert.h. + +2014-08-07 Gary Benson + + * server.h: Do not include common-utils.h. + +2014-08-07 Gary Benson + + * server.h: Do not include ptid.h. + * notif.h: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include gdb_locale.h. + +2014-08-07 Gary Benson + + * server.h: Do not include gdb/signals.h. + * win32-low.c: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include pathmax.h. + +2014-08-07 Gary Benson + + * server.h: Do not include libiberty.h. + * linux-bfin-low.c: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include ansidecl.h. + +2014-08-07 Gary Benson + + * linux-x86-low.c: Do not include stddef.h. + * lynx-ppc-low.c: Likewise. + * tracepoint.c: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include stdarg.h. + * nto-low.c: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include stdlib.h. + * inferiors.c: Likewise. + * linux-low.c: Likewise. + * regcache.c: Likewise. + * spu-low.c: Likewise. + * tracepoint.c: Likewise. + * utils.c: Likewise. + +2014-08-07 Gary Benson + + * server.h: Do not include stdio.h. + * linux-low.c: Likewise. + * remote-utils.c: Likewise. + * spu-low.c: Likewise. + * utils.c: Likewise. + * wincecompat.c: Likewise. + +2014-08-06 Gary Benson + + * regcache.c (init_register_cache): Move conditionals inside if. + +2014-08-06 Gary Benson + + * linux-low.c (linux_supports_non_stop): Use target_is_async_p. + +2014-07-31 Gary Benson + + * ax.h: Do not include server.h. + * gdbthread.h: Likewise. + * lynx-low.h: Likewise. + * notif.h: Likewise. + +2014-07-30 Gary Benson + + * server.h: Include common-defs.h. + Do not include config.h or build-gnulib-gdbserver/config.h. + +2014-07-30 Gary Benson + + * hostio-errno.c: Move server.h to top of includes list. + * inferiors.c: Likewise. + * linux-x86-low.c: Likewise. + * notif.c: Include server.h. + +2014-07-24 Tom Tromey + Gary Benson + + * server.h (CORE_ADDR): Now unsigned. + +2014-07-16 Pedro Alves + + * linux-low.c (linux_kill_one_lwp): Use kill_lwp, not kill. + +2014-07-15 Pedro Alves + + * linux-low.c (linux_kill_one_lwp): Save errno and work with saved + copy. + +2014-07-11 Pedro Alves + + * linux-low.c (kill_wait_lwp): New function, based on + kill_one_lwp_callback, but use my_waitpid directly. + (kill_one_lwp_callback, linux_kill): Use it. + +2014-06-23 Pedro Alves + + * linux-x86-low.c (x86_linux_prepare_to_resume): Clear DR_CONTROL + before setting DR0..DR3. + +2014-06-20 Gary Benson + + * configure.ac (AC_REPLACE_FUNCS) : Removed. + * configure: Regenerated. + * config.in: Likewise. + +2014-06-20 Gary Benson + + * Makefile.in (SFILES): Update locations for files moved + from common to nat. + (object file files): Reordered. + +2014-06-20 Gary Benson + + * i386-low.h (i386_dr_low_can_set_addr): Removed. + (i386_dr_low_set_addr): Likewise. + (i386_dr_low_get_addr): Likewise. + (i386_dr_low_can_set_control): Likewise. + (i386_dr_low_set_control): Likewise. + (i386_dr_low_get_control): Likewise. + (i386_dr_low_get_status): Likewise. + (i386_get_debug_register_length): Likewise. + * linux-x86-low.c (i386_dr_low_set_addr): + Changed signature. Made static. + (i386_dr_low_get_addr): Likewise. + (i386_dr_low_set_control): Likewise. + (i386_dr_low_get_control): Likewise. + (i386_dr_low_get_status): Likewise. + (i386_dr_low): New global variable. + * win32-i386-low.c (i386_dr_low_set_addr): + Changed signature. Made static. + (i386_dr_low_get_addr): Likewise. + (i386_dr_low_set_control): Likewise. + (i386_dr_low_get_control): Likewise. + (i386_dr_low_get_status): Likewise. + (i386_dr_low): New global variable. + +2014-06-20 Marcus Shawcroft + + * configure.ac: Invoke. AC_CHECK_TOOL(AR, ar). + * Makefile.in (AR, AR_FLAGS): Define. + * configure: Regenerate. + +2014-06-19 Gary Benson + + * Makefile.in (i386-dregs.o): New rule. + * configure.srv: Add i386-dregs.o to all targets using i386-low.o. + * i386-low.c (target.h): Remove include. + (TARGET_HAS_DR_LEN_8): Now in i386-dregs.c. + (DR_CONTROL_SHIFT): Likewise. + (DR_CONTROL_SIZE): Likewise. + (DR_RW_EXECUTE): Likewise. + (DR_RW_WRITE): Likewise. + (DR_RW_READ): Likewise. + (DR_RW_IORW): Likewise. + (DR_LEN_1): Likewise. + (DR_LEN_2): Likewise. + (DR_LEN_4): Likewise. + (DR_LEN_8): Likewise. + (DR_LOCAL_ENABLE_SHIFT): Likewise. + (DR_GLOBAL_ENABLE_SHIFT): Likewise. + (DR_ENABLE_SIZE): Likewise. + (DR_LOCAL_SLOWDOWN): Likewise. + (DR_GLOBAL_SLOWDOWN): Likewise. + (DR_CONTROL_RESERVED): Likewise. + (I386_DR_CONTROL_MASK): Likewise. + (I386_DR_VACANT): Likewise. + (I386_DR_LOCAL_ENABLE): Likewise. + (I386_DR_GLOBAL_ENABLE): Likewise. + (I386_DR_DISABLE): Likewise. + (I386_DR_SET_RW_LEN): Likewise. + (I386_DR_GET_RW_LEN): Likewise. + (I386_DR_WATCH_HIT): Likewise. + (i386_wp_op_t): Likewise. + (i386_show_dr): Likewise. + (i386_length_and_rw_bits): Likewise. + (i386_insert_aligned_watchpoint): Likewise. + (i386_remove_aligned_watchpoint): Likewise. + (i386_handle_nonaligned_watchpoint): Likewise. + i386_update_inferior_debug_regs(): Likewise. + (i386_dr_insert_watchpoint): Likewise. + (i386_dr_remove_watchpoint): Likewise. + (i386_dr_region_ok_for_watchpoint): Likewise. + (i386_dr_stopped_data_address): Likewise. + (i386_dr_stopped_by_watchpoint): Likewise. + +2014-06-19 Gary Benson + + * i386-low.c (i386_dr_show): Renamed to + i386_show_dr and made static. All uses updated. + (i386_dr_length_and_rw_bits): Renamed to + i386_length_and_rw_bits and made static. + All uses updated. + (i386_dr_insert_aligned_watchpoint): Renamed to + i386_insert_aligned_watchpoint and made static. + All uses updated. + (i386_dr_remove_aligned_watchpoint): Renamed to + i386_remove_aligned_watchpoint and made static. + All uses updated. + (i386_dr_update_inferior_debug_regs): Renamed to + i386_update_inferior_debug_regs and made static. + All uses updated. + +2014-06-18 Gary Benson + + * i386-low.h (i386_dr_low_can_set_addr): New macro. + (i386_dr_low_can_set_control): Likewise. + (i386_get_debug_register_length): Likewise. + * i386-low.c (i386_dr_low_can_set_addr): Now in i386-low.h. + (i386_dr_low_can_set_control): Likewise. + (i386_get_debug_register_length): Likewise. + +2014-06-17 Gary Benson + + * i386-low.h (i386-dregs.h): New include. + (DR_FIRSTADDR): Now in i386-dregs.h. + (DR_LASTADDR): Likewise. + (DR_NADDR): Likewise. + (DR_STATUS): Likewise. + (DR_CONTROL): Likewise. + (i386_debug_reg_state): Likewise. + (i386_dr_insert_watchpoint): Likewise. + (i386_dr_remove_watchpoint): Likewise. + (i386_dr_region_ok_for_watchpoint): Likewise. + (i386_dr_stopped_data_address): Likewise. + (i386_dr_stopped_by_watchpoint): Likewise. + * i386-low.c (ALL_DEBUG_REGISTERS): Likewise. + +2014-06-18 Gary Benson + + * i386-low.h (i386_low_insert_watchpoint): Renamed to + i386_dr_insert_watchpoint. + (i386_low_remove_watchpoint): Renamed to + i386_dr_remove_watchpoint. + (i386_low_region_ok_for_watchpoint): Renamed to + i386_dr_region_ok_for_watchpoint. + (i386_low_stopped_data_address): Renamed to + i386_dr_stopped_data_address. + (i386_low_stopped_by_watchpoint): Renamed to + i386_dr_stopped_by_watchpoint. + * i386-low.c (i386_show_dr): Renamed to + i386_dr_show and made nonstatic. All uses updated. + (i386_length_and_rw_bits): Renamed to + i386_dr_length_and_rw_bits and made nonstatic. + All uses updated. + (i386_insert_aligned_watchpoint): Renamed to + i386_dr_insert_aligned_watchpoint and made nonstatic. + All uses updated. + (i386_remove_aligned_watchpoint): Renamed to + i386_dr_remove_aligned_watchpoint and made nonstatic. + All uses updated. + (i386_update_inferior_debug_regs): Renamed to + i386_dr_update_inferior_debug_regs and made nonstatic. + All uses updated. + (i386_low_insert_watchpoint): Renamed to + i386_dr_insert_watchpoint. All uses updated. + (i386_low_remove_watchpoint): Renamed to + i386_dr_remove_watchpoint. All uses updated. + (i386_low_region_ok_for_watchpoint): Renamed to + i386_dr_region_ok_for_watchpoint. All uses updated. + (i386_low_stopped_data_address): Renamed to + i386_dr_stopped_data_address. All uses updated. + (i386_low_stopped_by_watchpoint): Renamed to + i386_dr_stopped_by_watchpoint. All uses updated. + +2014-06-18 Gary Benson + + * i386-low.c (i386_dr_low_can_set_addr): New macro. + (i386_dr_low_can_set_control): Likewise. + (i386_insert_aligned_watchpoint): New check. + +2014-06-18 Gary Benson + + * i386-low.c (i386_update_inferior_debug_regs) : + Renamed to state. + +2014-06-18 Gary Benson + + * i386-low.c (i386_length_and_rw_bits): Use internal_error + instead of fatal and error. + (i386_handle_nonaligned_watchpoint): Likewise. + +2014-06-18 Gary Benson + + * i386-low.c (i386_get_debug_register_length): New macro. + (TARGET_HAS_DR_LEN_8): Remove conditional. Use above macro. + (i386_show_dr): Use debug_printf instead of fprintf. Use + phex to format values. + +2014-06-18 Gary Benson + + * i386-low.h: Comment changes. + * i386-low.c: Likewise. + +2014-06-18 Gary Benson + + * i386-low.c: Whitespace changes. + +2014-06-12 Tom Tromey + + * utils.c (freeargv): Remove. + +2014-06-12 Tom Tromey + + * debug.c (debug_printf): Remove HAVE_GETTIMEOFDAY checks. + * server.c (monitor_show_help): Remove HAVE_GETTIMEOFDAY check. + (parse_debug_format_options): Likewise. + (gdbserver_usage): Likewise. + * Makefile.in (LIBIBERTY_BUILDDIR, LIBIBERTY): New variables. + (SUBDIRS, REQUIRED_SUBDIRS): Add libiberty. + (gdbserver$(EXEEXT), gdbreplay$(EXEEXT)): Depend on and link + against libiberty. + ($(LIBGNU)): Depend on libiberty. + (all-lib): Recurse into all subdirs. + (install-only): Invoke "install" target in subdirs. + (vasprintf.o, vsnprintf.o, safe-ctype.o, lbasename.o): Remove + targets. + * configure: Rebuild. + * configure.ac: Add ACX_CONFIGURE_DIR for libiberty. Don't check + for vasprintf, vsnprintf, or gettimeofday. + * configure.srv: Don't add safe-ctype.o or lbasename.o to + srv_tgtobj. + +2014-06-05 Joel Brobecker + + * development.sh: Delete. + * Makefile.in (config.status): Adjust dependency on development.sh. + * configure.ac: Adjust development.sh source call. + * configure: Regenerate. + +2014-06-02 Pedro Alves + + * ax.c (gdb_free_agent_expr): New function. + * ax.h (gdb_free_agent_expr): New declaration. + * mem-break.c (delete_gdb_breakpoint_1): Also clear the commands + list. + (clear_breakpoint_conditions, clear_breakpoint_commands): Make + static. + (clear_breakpoint_conditions_and_commands): New function. + * mem-break.h (clear_breakpoint_conditions): Delete declaration. + (clear_breakpoint_conditions_and_commands): New declaration. + +2014-05-23 Ramana Radhakrishnan + + * linux-aarch64-low.c (asm/ptrace.h): Include. + +2014-05-21 Jan Kratochvil + + Fix TLS access for -static -pthread. + * gdbserver/thread-db.c (struct thread_db): Add td_thr_tlsbase_p. + (thread_db_get_tls_address): Call it if LOAD_MODULE is zero. + (thread_db_load_search, try_thread_db_load_1): Initialize it. + +2014-05-20 Pedro Alves + + * linux-aarch64-low.c (aarch64_insert_point) + (aarch64_remove_point): No longer check whether the type is + supported here. Adjust to new interface. + (the_low_target): Install aarch64_supports_z_point_type as + supports_z_point_type method. + * linux-arm-low.c (raw_bkpt_type_to_arm_hwbp_type): New function. + (arm_linux_hw_point_initialize): Take an enum raw_bkpt_type + instead of a Z packet char. Adjust. + (arm_supports_z_point_type): New function. + (arm_insert_point, arm_remove_point): Adjust to new interface. + (the_low_target): Install arm_supports_z_point_type. + * linux-crisv32-low.c (cris_supports_z_point_type): New function. + (cris_insert_point, cris_remove_point): Adjust to new interface. + Don't check whether the type is supported here. + (the_low_target): Install cris_supports_z_point_type. + * linux-low.c (linux_supports_z_point_type): New function. + (linux_insert_point, linux_remove_point): Adjust to new interface. + * linux-low.h (struct linux_target_ops) : Take an enum raw_bkpt_type instead of a char. Add + raw_breakpoint pointer parameter. + : New method. + * linux-mips-low.c (mips_supports_z_point_type): New function. + (mips_insert_point, mips_remove_point): Adjust to new interface. + Use mips_supports_z_point_type. + (the_low_target): Install mips_supports_z_point_type. + * linux-ppc-low.c (the_low_target): Install NULL as + supports_z_point_type method. + * linux-s390-low.c (the_low_target): Install NULL as + supports_z_point_type method. + * linux-sparc-low.c (the_low_target): Install NULL as + supports_z_point_type method. + * linux-x86-low.c (x86_supports_z_point_type): New function. + (x86_insert_point): Adjust to new insert_point interface. Use + insert_memory_breakpoint. Adjust to new + i386_low_insert_watchpoint interface. + (x86_remove_point): Adjust to remove_point interface. Use + remove_memory_breakpoint. Adjust to new + i386_low_remove_watchpoint interface. + (the_low_target): Install x86_supports_z_point_type. + * lynx-low.c (lynx_target_ops): Install NULL as + supports_z_point_type callback. + * nto-low.c (nto_supports_z_point_type): New. + (nto_insert_point, nto_remove_point): Adjust to new interface. + (nto_target_ops): Install nto_supports_z_point_type. + * mem-break.c: Adjust intro comment. + (struct raw_breakpoint) : New fields. + : Update comment. + : Delete field. + (enum bkpt_type) : Delete value. + : New values. + (raw_bkpt_type_to_target_hw_bp_type): New function. + (find_enabled_raw_code_breakpoint_at): New function. + (find_raw_breakpoint_at): New type and size parameters. Use them. + (insert_memory_breakpoint): New function, based off + set_raw_breakpoint_at. + (remove_memory_breakpoint): New function. + (set_raw_breakpoint_at): Reimplement. + (set_breakpoint): New, based on set_breakpoint_at. + (set_breakpoint_at): Reimplement. + (delete_raw_breakpoint): Go through the_target->remove_point + instead of assuming memory breakpoints. + (find_gdb_breakpoint_at): Delete. + (Z_packet_to_bkpt_type, Z_packet_to_raw_bkpt_type): New functions. + (find_gdb_breakpoint): New function. + (set_gdb_breakpoint_at): Delete. + (z_type_supported): New function. + (set_gdb_breakpoint_1): New function, loosely based off + set_gdb_breakpoint_at. + (check_gdb_bp_preconditions, set_gdb_breakpoint): New functions. + (delete_gdb_breakpoint_at): Delete. + (delete_gdb_breakpoint_1): New function, loosely based off + delete_gdb_breakpoint_at. + (delete_gdb_breakpoint): New function. + (clear_gdb_breakpoint_conditions): Rename to ... + (clear_breakpoint_conditions): ... this. Don't handle a NULL + breakpoint. + (add_condition_to_breakpoint): Make static. + (add_breakpoint_condition): Take a struct breakpoint pointer + instead of an address. Adjust. + (gdb_condition_true_at_breakpoint): Rename to ... + (gdb_condition_true_at_breakpoint_z_type): ... this, and add + z_type parameter. + (gdb_condition_true_at_breakpoint): Reimplement. + (add_breakpoint_commands): Take a struct breakpoint pointer + instead of an address. Adjust. + (gdb_no_commands_at_breakpoint): Rename to ... + (gdb_no_commands_at_breakpoint_z_type): ... this. Add z_type + parameter. Return true if no breakpoint was found. Change debug + output. + (gdb_no_commands_at_breakpoint): Reimplement. + (run_breakpoint_commands): Rename to ... + (run_breakpoint_commands_z_type): ... this. Add z_type parameter, + and change return type to boolean. + (run_breakpoint_commands): New function. + (gdb_breakpoint_here): Also check for Z1 breakpoints. + (uninsert_raw_breakpoint): Don't try to reinsert a disabled + breakpoint. Go through the_target->remove_point instead of + assuming memory breakpoint. + (uninsert_breakpoints_at, uninsert_all_breakpoints): Uninsert + software and hardware breakpoints. + (reinsert_raw_breakpoint): Go through the_target->insert_point + instead of assuming memory breakpoint. + (reinsert_breakpoints_at, reinsert_all_breakpoints): Reinsert + software and hardware breakpoints. + (check_breakpoints, breakpoint_here, breakpoint_inserted_here): + Check both software and hardware breakpoints. + (validate_inserted_breakpoint): Assert the breakpoint is a + software breakpoint. Set the inserted flag to -1 instead of + setting shlib_disabled. + (delete_disabled_breakpoints): Adjust. + (validate_breakpoints): Only validate software breakpoints. + Adjust to inserted flag change. + (check_mem_read, check_mem_write): Skip breakpoint types other + than software breakpoints. Adjust to inserted flag change. + * mem-break.h (enum raw_bkpt_type): New enum. + (raw_breakpoint, struct process_info): Forward declare. + (Z_packet_to_target_hw_bp_type): Delete declaration. + (raw_bkpt_type_to_target_hw_bp_type, Z_packet_to_raw_bkpt_type) + (set_gdb_breakpoint, delete_gdb_breakpoint) + (clear_breakpoint_conditions): New declarations. + (set_gdb_breakpoint_at, clear_gdb_breakpoint_conditions): Delete. + (breakpoint_inserted_here): Update comment. + (add_breakpoint_condition, add_breakpoint_commands): Replace + address parameter with a breakpoint pointer parameter. + (gdb_breakpoint_here): Update comment. + (delete_gdb_breakpoint_at): Delete. + (insert_memory_breakpoint, remove_memory_breakpoint): Declare. + * server.c (process_point_options): Take a struct breakpoint + pointer instead of an address. Adjust. + (process_serial_event) : Use set_gdb_breakpoint and + delete_gdb_breakpoint. + * spu-low.c (spu_target_ops): Install NULL as + supports_z_point_type method. + * target.h: Include mem-break.h. + (struct target_ops) : Update comment. + : New field. + : Take an enum raw_bkpt_type argument + instead of a char. Also take a raw breakpoint pointer. + * win32-arm-low.c (the_low_target): Install NULL as + supports_z_point_type. + * win32-i386-low.c (i386_supports_z_point_type): New function. + (i386_insert_point, i386_remove_point): Adjust to new interface. + (the_low_target): Install i386_supports_z_point_type. + * win32-low.c (win32_supports_z_point_type): New function. + (win32_insert_point, win32_remove_point): Adjust to new interface. + (win32_target_ops): Install win32_supports_z_point_type. + * win32-low.h (struct win32_target_ops): + : New method. + : Take an enum raw_bkpt_type argument + instead of a char. Also take a raw breakpoint pointer. + +2014-05-20 Pedro Alves + + * mem-break.h: Include break-common.h. + (Z_PACKET_SW_BP, Z_PACKET_HW_BP, Z_PACKET_WRITE_WP) + (Z_PACKET_READ_WP, Z_PACKET_ACCESS_WP): New defines. + (Z_packet_to_target_hw_bp_type): New declaration. + * mem-break.c (Z_packet_to_target_hw_bp_type): New function. + * i386-low.c (Z_PACKET_HW_BP, Z_PACKET_WRITE_WP, Z_PACKET_READ_WP) + (Z_PACKET_ACCESS_WP): Delete macros. + (Z_packet_to_hw_type): Delete function. + * i386-low.h: Don't include break-common.h here. + (Z_packet_to_hw_type): Delete declaration. + * linux-x86-low.c (x86_insert_point, x86_insert_point): Call + Z_packet_to_target_hw_bp_type instead of Z_packet_to_hw_type. + * win32-i386-low.c (i386_insert_point, i386_remove_point): Call + Z_packet_to_target_hw_bp_type instead of Z_packet_to_hw_type. + * linux-aarch64-low.c: Don't include break-common.h here. + (Z_PACKET_SW_BP, Z_PACKET_HW_BP, Z_PACKET_WRITE_WP) + (Z_PACKET_READ_WP, Z_PACKET_ACCESS_WP): Delete macros. + (Z_packet_to_target_hw_bp_type): Delete function. + * linux-mips-low.c (rsp_bp_type_to_target_hw_bp_type): Delete + function. + (mips_insert_point, mips_remove_point): Use + Z_packet_to_target_hw_bp_type. + +2014-05-20 Pedro Alves + + * linux-aarch64-low.c: Include break-common.h. + (enum target_point_type): Delete. + (Z_packet_to_point_type): Rename to ... + (Z_packet_to_target_hw_bp_type): ... this, and return a + target_hw_bp_type instead. + (aarch64_show_debug_reg_state): Take an enum target_hw_bp_type + instead of an enum target_point_type. + (aarch64_point_encode_ctrl_reg): Likewise. Compute type mask from + breakpoint type. + (aarch64_dr_state_insert_one_point) + (aarch64_dr_state_remove_one_point, aarch64_handle_breakpoint) + (aarch64_handle_aligned_watchpoint) + (aarch64_handle_unaligned_watchpoint, aarch64_handle_watchpoint): + Take an enum target_hw_bp_type instead of an enum + target_point_type. + (aarch64_supports_z_point_type): New function. + (aarch64_insert_point, aarch64_remove_point): Use it. Adjust to + use Z_packet_to_target_hw_bp_type. + +2014-05-20 Joel Brobecker + + * configure.ac: Only use -Werror by default when DEVELOPMENT + is true. + * configure: Regenerate. + +2014-05-19 Jan Kratochvil + + Fix gdbserver qGetTLSAddr for x86_64 -m32. + * linux-x86-low.c (X86_64_USER_REGS): New. + (x86_fill_gregset): Call memset for BUF first in x86_64 -m32 case. + +2014-04-28 Yao Qi + + * Makefile.in (i386-avx512.c): Fix the typo of generated file + name. + +2014-04-25 Pedro Alves + + PR server/16255 + * linux-low.c (linux_attach_fail_reason_string): New function. + (linux_attach_lwp): Delete. + (linux_attach_lwp_1): Rename to ... + (linux_attach_lwp): ... this. Take a ptid instead of a pid as + argument. Remove "initial" parameter. Return int instead of + void. Don't error or warn here. + (linux_attach): Adjust to call linux_attach_lwp. Call error on + failure to attach to the tgid. Call warning when failing to + attach to an lwp. + * linux-low.h (linux_attach_lwp): Take a ptid instead of a pid as + argument. Remove "initial" parameter. Return int instead of + void. Don't error or warn here. + (linux_attach_fail_reason_string): New declaration. + * thread-db.c (attach_thread): Adjust to linux_attach_lwp's + interface change. Use linux_attach_fail_reason_string. + +2014-04-24 Michael Sturm + Walfred Tedeschi + + * Makefile.in: Added rules to handle new files + i386-avx512.c i386-avx512-linux.c amd64-avx512.c + amd64-avx512-linux.c x32-avx512.c x32-avx512-linux.c. + * configure.srv (srv_i386_regobj): Add i386-avx512.o. + (srv_i386_linux_regobj): Add i386-avx512-linux.o. + (srv_amd64_regobj): Add amd64-avx512.o and x32-avx512.o. + (srv_amd64_linux_regobj): Add amd64-avx512-linux.o and + x32-avx512-linux.o. + (srv_i386_32bit_xmlfiles): Add i386/32bit-avx512.xml. + (srv_i386_64bit_xmlfiles): Add i386/64bit-avx512.xml. + (srv_amd64_xmlfiles): Add i386/amd64-avx512.xml and + i386/x32-avx512.xml. + (srv_i386_linux_xmlfiles): Add i386/i386-avx512-linux.xml. + (srv_amd64_linux_xmlfiles): Add i386/amd64-avx512-linux.xml and + i386/x32-avx512-linux.xml. + * i387-fp.c (num_avx512_k_registers): New constant for number + of K registers. + (num_avx512_zmmh_low_registers): New constant for number of + lower ZMM registers (0-15). + (num_avx512_zmmh_high_registers): New constant for number of + higher ZMM registers (16-31). + (num_avx512_ymmh_registers): New contant for number of higher + YMM registers (ymm16-31 added by avx521 on x86_64). + (num_avx512_xmm_registers): New constant for number of higher + XMM registers (xmm16-31 added by AVX512 on x86_64). + (struct i387_xsave): Add space for AVX512 registers. + (i387_cache_to_xsave): Change raw buffer size to 64 characters. + Add code to handle AVX512 registers. + (i387_xsave_to_cache): Add code to handle AVX512 registers. + * linux-x86-low.c (init_registers_amd64_avx512_linux): New + prototypei from generated file. + (tdesc_amd64_avx512_linux): Likewise. + (init_registers_x32_avx512_linux): Likewise. + (tdesc_x32_avx512_linux): Likewise. + (init_registers_i386_avx512_linux): Likewise. + (tdesc_i386_avx512_linux): Likewise. + (x86_64_regmap): Add AVX512 registers. + (x86_linux_read_description): Add code to handle AVX512 XSTATE + mask. + (initialize_low_arch): Add code to initialize AVX512 registers. + +2014-04-23 Pedro Alves + + * mem-break.c (find_gdb_breakpoint_at): Make static. + * mem-break.h (find_gdb_breakpoint_at): Delete declaration. + +2014-04-23 Pedro Alves + + * i386-low.c: Don't include break-common.h here. + (i386_low_insert_watchpoint, i386_low_remove_watchpoint): Change + prototype to take target_hw_bp_type as argument instead of a Z + packet char. + * i386-low.h: Include break-common.h here. + (Z_packet_to_hw_type): Declare. + (i386_low_insert_watchpoint, i386_low_remove_watchpoint): Change + prototypes. + * linux-x86-low.c (x86_insert_point): Convert the packet number to + a target_hw_bp_type before calling i386_low_insert_watchpoint. + (x86_remove_point): Convert the packet number to a + target_hw_bp_type before calling i386_low_remove_watchpoint. + * win32-i386-low.c (i386_insert_point): Convert the packet number + to a target_hw_bp_type before calling i386_low_insert_watchpoint. + (i386_remove_point): Convert the packet number to a + target_hw_bp_type before calling i386_low_remove_watchpoint. + +2014-04-23 Pedro Alves + + * utils.h (perror_with_name): Add ATTRIBUTE_NORETURN. + +2014-04-10 Pedro Alves + + * mem-break.c (add_breakpoint_condition, add_breakpoint_commands): + Check if the condition or command is NULL before checking if the + breakpoint is known. On success, return true. + * mem-break.h (add_breakpoint_condition): Document return. + (add_breakpoint_commands): Add describing comment. + * server.c (skip_to_semicolon): New function. + (process_point_options): Use it. + +2014-04-09 Pedro Alves + + * linux-low.c (linux_read_loadmap): Pass current_inferior directly + to lwpid_of. + +2014-02-27 Pedro Alves + + PR 12702 + * inferiors.h (A_I_NEXT, ALL_INFERIORS_TYPE, ALL_PROCESSES): New + macros. + * linux-low.c (delete_lwp, handle_extended_wait): Add debug + output. + (last_thread_of_process_p): Take a PID argument instead of a + thread pointer. + (linux_wait_for_lwp): Delete. + (num_lwps, check_zombie_leaders, not_stopped_callback): New + functions. + (linux_low_filter_event): New function, party factored out from + linux_wait_for_event. + (linux_wait_for_event): Rename to ... + (linux_wait_for_event_filtered): ... this. Add new filter ptid + argument. Partly rewrite. Always use waitpid(-1, WNOHANG) and + sigsuspend. Check for zombie leaders. + (linux_wait_for_event): Reimplement as wrapper around + linux_wait_for_event_filtered. + (linux_wait_1): Handle TARGET_WAITKIND_NO_RESUMED. Assume that if + a normal or signal exit is seen, it's the whole process exiting. + (wait_for_sigstop): No longer a for_each_inferior callback. + Rewrite on top of linux_wait_for_event_filtered. + (stop_all_lwps): Call wait_for_sigstop directly. + * server.c (resume, handle_target_event): Handle + TARGET_WAITKIND_NO_RESUMED. + +2014-02-26 Joel Brobecker + + * win32-low.c (psapi_get_dll_name, + * win32_CreateToolhelp32Snapshot): Delete. + (win32_CreateToolhelp32Snapshot, win32_Module32First) + (win32_Module32Next, load_toolhelp, toolhelp_get_dll_name): + Delete. + (handle_load_dll): Add function description. + Remove code using psapi_get_dll_name and toolhelp_get_dll_name. + +2014-02-26 Joel Brobecker + + * win32-low.c (win32_add_one_solib): Add 0x1000 to load_addr. + Add comment. + (win32_add_all_dlls): Remove 0x1000 offset applied to DLL + base address when calling win32_add_one_solib. + (handle_load_dll): Delete local variable load_addr. + Remove 0x1000 offset applied to DLL base address when calling + win32_add_one_solib. + (handle_unload_dll): Add comment. + +2014-02-26 Joel Brobecker + + * win32-low.c (win32_add_all_dlls): Renames + win32_ensure_ntdll_loaded. Rewrite function documentation. + Adjust implementation to always load all DLLs. + Add 0x1000 offset to DLL base address when calling + win32_add_one_solib. + (child_initialization_done): New static global. + (do_initial_child_stuff): Set child_initialization_done to + zero during child initialization, and 1 after. Replace call + to win32_ensure_ntdll_loaded by call to win32_add_all_dlls. + Add comment. + (match_dll_by_basename, dll_is_loaded_by_basename): Delete. + (handle_unload_dll): Add function documentation. + (get_child_debug_event): Ignore load and unload DLL events + during child initialization. + +2014-02-20 Doug Evans + + Remove global all_lwps. + * inferiors.h (ptid_of): Move here from linux-low.h. + (pid_of, lwpid_of): Ditto. + * linux-aarch64-low.c (debug_reg_change_callback): Update, "entry" + parameter is a struct thread_info * now. + (aarch64_notify_debug_reg_change): Fetch pid from current_inferior + directly. Pass &all_threads to find_inferior instead of &all_lwps. + (aarch64_stopped_data_address): Fetch lwpid from current_inferior + directly. + (aarch64_linux_prepare_to_resume): Fetch ptid from thread. + (aarch64_arch_setup): Fetch lwpid from current_inferior directly. + * linux-arm-low.c (update_registers_callback): Update, "entry" + parameter is a struct thread_info * now. + Fetch lwpid from current_inferior directly. + (arm_insert_point): Pass &all_threads to find_inferior instead of + &all_lwps. + (arm_remove_point): Ditto. + (arm_stopped_by_watchpoint): Fetch lwp from current_inferior. + (arm_prepare_to_resume): Fetch pid from thread. + (arm_read_description): Fetch lwpid from current_inferior directly. + * linux-low.c (all_lwps): Delete. + (delete_lwp): Delete call to remove_inferior. + (handle_extended_wait): Fetch lwpid from thread. + (add_lwp): Don't set lwp->entry.id. Remove call to + add_inferior_to_list. + (linux_attach_lwp_1): Fetch pid from current_inferior directly. + (linux_kill_one_lwp): Fetch ptid,lwpid from thread. + (kill_one_lwp_callback): Ditto. + (linux_kill): Don't dereference NULL pointer. + Fetch ptid,lwpid from thread. + (get_detach_signal): Fetch ptid from thread. + (linux_detach_one_lwp): Fetch ptid,lwpid from thread. + Simplify call to regcache_invalidate_thread. + (delete_lwp_callback): Update, "entry" parameter is a + struct thread_info * now. Fetch pid from thread. + (linux_mourn): Pass &all_threads to find_inferior instead of &all_lwps. + (status_pending_p_callback): Update, "entry" parameter is a + struct thread_info * now. Fetch ptid from thread. + (find_lwp_pid): Update, "entry" parameter is a + struct thread_info * now. + (linux_wait_for_lwp): Fetch pid from thread. + (linux_fast_tracepoint_collecting): Fetch lwpid from thread. + (maybe_move_out_of_jump_pad): Fetch lwpid from current_inferior. + (enqueue_one_deferred_signal): Fetch lwpid from thread. + (dequeue_one_deferred_signal): Ditto. + (cancel_breakpoint): Fetch ptid from current_inferior. + (linux_wait_for_event): Pass &all_threads to find_inferior, + not &all_lwps. Fetch ptid, lwpid from thread. + (count_events_callback): Update, "entry" parameter is a + struct thread_info * now. + (select_singlestep_lwp_callback): Ditto. + (select_event_lwp_callback): Ditto. + (cancel_breakpoints_callback): Ditto. + (linux_cancel_breakpoints): Pass &all_threads to find_inferior, + not &all_lwps. + (select_event_lwp): Ditto. Fetch ptid from event_thread. + (unsuspend_one_lwp): Update, "entry" parameter is a + struct thread_info * now. + (unsuspend_all_lwps): Pass &all_threads to find_inferior, + not &all_lwps. + (linux_stabilize_threads): Ditto. And for for_each_inferior. + Fetch lwpid from thread, not lwp. + (linux_wait_1): Fetch ptid, lwpid from current_inferior. + Pass &all_threads to find_inferior, not &all_lwps. + (send_sigstop): Fetch lwpid from thread, not lwp. + (send_sigstop_callback): Update, "entry" parameter is a + struct thread_info * now. + (suspend_and_send_sigstop_callback): Ditto. + (wait_for_sigstop): Ditto. Fetch ptid, lwpid from thread, lwp. + (stuck_in_jump_pad_callback): Update, "entry" parameter is a + struct thread_info * now. + (move_out_of_jump_pad_callback): Ditto. Fetch ptid, lwpid + from thread, lwp. + (lwp_running): Update, "entry" parameter is a + struct thread_info * now. + (stop_all_lwps): Fetch ptid from thread. + Pass &all_threads to find_inferior, for_each_inferior, not &all_lwps. + (linux_resume_one_lwp): Fetch lwpid from thread. + (linux_set_resume_request): Update, "entry" parameter is a + struct thread_info * now. Fetch pid, lwpid from thread. + (resume_status_pending_p): Update, "entry" parameter is a + struct thread_info * now. + (need_step_over_p): Ditto. Fetch lwpid from thread. + (start_step_over): Fetch lwpid from thread. + (linux_resume_one_thread): Update, "entry" parameter is a + struct thread_info * now. Fetch lwpid from thread. + (linux_resume): Pass &all_threads to find_inferior, not &all_lwps. + (proceed_one_lwp): Update, "entry" parameter is a + struct thread_info * now. Fetch lwpid from thread. + (unsuspend_and_proceed_one_lwp): Update, "entry" parameter is a + struct thread_info * now. + (proceed_all_lwps): Pass &all_threads to find_inferior, not &all_lwps. + (unstop_all_lwps): Ditto. Fetch lwpid from thread. + (regsets_fetch_inferior_registers): Fetch lwpid from current_inferior + directly. + (regsets_store_inferior_registers): Ditto. + (fetch_register, store_register): Ditto. + (linux_read_memory, linux_write_memory): Ditto. + (linux_request_interrupt): Ditto. + (linux_read_auxv): Ditto. + (linux_xfer_siginfo): Ditto. + (linux_qxfer_spu): Ditto. + (linux_qxfer_libraries_svr4): Ditto. + * linux-low.h (ptid_of, pid_of, lwpid_of): Delete, + moved to inferiors.h. + (get_lwp): Delete. + (get_thread_lwp): Update. + (struct lwp_info): Delete member "entry". Simplify comment for + member "thread". + (all_lwps): Delete. + * linux-mips-low.c (mips_read_description): Fetch lwpid from + current_inferior directly. + (update_watch_registers_callback): Update, "entry" parameter is a + struct thread_info * now. Fetch pid from thread. + (mips_linux_prepare_to_resume): Fetch ptid from thread. + (mips_insert_point): Fetch lwpid from current_inferior. + Pass &all_threads to find_inferior, not &all_lwps. + (mips_remove_point): Pass &all_threads to find_inferior, not &all_lwps. + (mips_stopped_by_watchpoint): Fetch lwpid from current_inferior + directly. + (mips_stopped_data_address): Ditto. + * linux-s390-low.c (s390_arch_setup): Fetch pid from current_inferior + directly. + * linux-tile-low.c (tile_arch_setup): Ditto. + * linux-x86-low.c (x86_get_thread_area): Fetch lwpid from thread. + (update_debug_registers_callback): Update, "entry" parameter is a + struct thread_info * now. Fetch pid from thread. + (i386_dr_low_set_addr): Fetch pid from current_inferior directly. + Pass &all_threads to find_inferior, not &all_lwps. + (i386_dr_low_get_addr): Fetch ptid from current_inferior directly. + (i386_dr_low_set_control): Fetch pid from current_inferior directly. + Pass &all_threads to find_inferior, not &all_lwps. + (i386_dr_low_get_control): Fetch ptid from current_inferior directly. + (i386_dr_low_get_status): Ditto. + (x86_linux_prepare_to_resume): Fetch ptid from thread. + (x86_siginfo_fixup): Fetch lwpid from current_inferior directly. + (x86_linux_read_description): Ditto. + * proc-service.c (ps_getpid): Fetch pid from current_inferior directly. + +2014-02-20 Doug Evans + + * inferiors.c (get_first_inferior): Fix buglet. + +2014-02-19 Doug Evans + + * gdbthread.h (add_thread): Change result type to struct thread_info *. + * inferiors.c (add_thread): Change result type to struct thread_info *. + All callers updated. + (add_lwp): Call add_thread here instead of in callers. + All callers updated. + * linux-low.h (get_lwp_thread): Rewrite. + (struct lwp_info): New member "thread". + +2014-02-19 Doug Evans + + * linux-low.c (add_lwp): Change result to struct lwp_info *. + All callers updated. + +2014-02-19 Doug Evans + + * inferiors.c (add_thread): Fix whitespace. + +2014-02-19 Doug Evans + + * dll.c (clear_dlls): Replace accessing list implemention details + with API function. + * gdbthread.h (get_first_thread): Declare. + * inferiors.c (for_each_inferior_with_data): New function. + (get_first_thread): New function. + (find_thread_ptid): Simplify. + (get_first_inferior): New function. + (clear_list): Delete. + (one_inferior_p): New function. + (clear_inferior_list): New function. + (clear_inferiors): Update. + * inferiors.h (for_each_inferior_with_data): Declare. + (clear_inferior_list): Declare. + (one_inferior_p): Declare. + (get_first_inferior): Declare. + * linux-low.c (linux_wait_for_event): Replace accessing list + implemention details with API function. + * server.c (target_running): Ditto. + (accumulate_file_name_length): New function. + (emit_dll_description): New function. + (handle_qxfer_libraries): Replace accessing list implemention + details with API function. + (handle_qxfer_threads_worker): New function. + (handle_qxfer_threads_proper): Replace accessing list implemention + details with API function. + (handle_query): Ditto. + (visit_actioned_threads_callback_ftype): New typedef. + (visit_actioned_threads_data): New struct. + (visit_actioned_threads): Rewrite to be find_inferior callback. + (resume): Call find_inferior. + (handle_status): Replace accessing list implemention + details with API function. + (process_serial_event): Replace accessing list implemention details + with API function. + * target.c (set_desired_inferior): Replace accessing list implemention + details with API function. + * tracepoint.c (same_process_p): New function. + (gdb_agent_about_to_close): Replace accessing list implemention + details with API function. + * win32-low.c (child_delete_thread): Replace accessing list + implemention details with API function. + (match_dll_by_basename): New function. + (dll_is_loaded_by_basename): New function. + (win32_ensure_ntdll_loaded): Replace accessing list implemention + details call to dll_is_loaded_by_basename. + +2014-02-19 Doug Evans + + * dll.h (struct dll_info): Add comment. + * gdbthread.h (struct thread_info): Add comment. + (current_ptid): Simplify. + * inferiors.c (add_process): Update. + (remove_process): Update. + * inferiors.h (struct process_info): Rename member "head" to "entry". + * linux-low.c (delete_lwp): Update. + (add_lwp): Update. + (last_thread_of_process_p): Update. + (kill_one_lwp_callback, linux_kill): Update. + (status_pending_p_callback): Update. + (wait_for_sigstop): Update. Simplify read of ptid. + (start_step_over): Update. + * linux-low.h (ptid_of, pid_of, lwpid_of): Update. + (get_lwp_thread): Update. + (struct lwp_info): Rename member "head" to "entry". + * regcache.h (inferior_list_entry): Delete. + * server.c (kill_inferior_callback): Update. + (detach_or_kill_inferior_callback): Update. + (print_started_pid): Update. + (print_attached_pid): Update. + (process_serial_event): Simplify read of ptid. + * thread-db.c (thread_db_create_event): Update. + (thread_db_get_tls_address): Update. + * win32-low.c (current_inferior_ptid): Simplify. + +2014-02-19 Tom Tromey + + * target.h (struct target_ops) : Add target_ops + argument. + (target_supports_btrace): Update. + +2014-02-14 Yao Qi + + * Makefile.in (IPA_OBJS): Append rsp-low-ipa.o. + (rsp-low-ipa.o): New target. + +2014-02-12 Tom Tromey + + * ax.c (gdb_parse_agent_expr): Use hex2bin, not + convert_ascii_to_int. + * regcache.c (registers_to_string): Likewise. + * remote-utils.c (decode_M_packet): Likewise. + * server.c (process_serial_event): Likewise. + +2014-02-12 Tom Tromey + + * server.c (handle_query, handle_v_run): Use hex2bin, not + unhexify. + * tracepoint.c (cmd_qtdpsrc, cmd_qtdv, cmd_qtnotes): Likewise. + +2014-02-12 Tom Tromey + + * ax.c (gdb_unparse_agent_expr): Use bin2hex, not + convert_int_to_ascii. + * regcache.c (registers_to_string, collect_register_as_string): + Likewise. + * remote-utils.c (look_up_one_symbol, relocate_instruction): + Likewise. + * server.c (process_serial_event): Likewise. + * tracepoint.c (cmd_qtstatus, response_source, response_tsv) + (cmd_qtbuffer, cstr_to_hexstr): Likewise. + +2014-02-12 Tom Tromey + + * remote-utils.c (look_up_one_symbol, monitor_output): Use + bin2hex, not hexify. + * tracepoint.c (cmd_qtstatus): Likewise. + +2014-02-12 Tom Tromey + + * remote-utils.c (monitor_output): Pass explicit length to + hexify. + +2014-02-12 Tom Tromey + + * tracepoint.c: Include rsp-low.h. + * server.c: Include rsp-low.h. + * remote-utils.h (convert_ascii_to_int, convert_int_to_ascii) + (unhexify, hexify, remote_escape_output, unpack_varlen_hex): Don't + declare. + * remote-utils.c: Include rsp-low.h. + (fromhex, hexchars, ishex, unhexify, tohex, hexify) + (remote_escape_output, remote_unescape_input, unpack_varlen_hex) + (convert_int_to_ascii, convert_ascii_to_int): Move to + common/rsp-low.c. + * regcache.c: Include rsp-low.h. + * ax.c: Include rsp-low.h. + * Makefile.in (SFILES): Add common/rsp-low.c. + (OBS): Add rsp-low.o. + (rsp-low.o): New target. + +2014-02-12 Tom Tromey + + * utils.h (pulongest, plongest, phex_nz): Don't declare. + Include print-utils.h. + * utils.c (NUMCELLS, CELLSIZE, get_cell, decimal2str, pulongest) + (plongest, thirty_two, phex_nz): Remove. + * Makefile.in (SFILES): Add common/print-utils.c. + (OBS): Add print-utils.o. + (print-utils-ipa.o): New target. + (print-utils.o): New target. + (IPA_OBJS): Add print-utils-ipa.o. + +2014-02-06 Tom Tromey + + * Makefile.in (SFILES): Fix indentation. + +2014-02-05 Doug Evans + + * linux-low.c (linux_wait_for_event): Improve comment. + (linux_wait_1): Keep current_inferior in sync with event_child. + +2014-01-22 Doug Evans + + * gdbthread.h (gdb_id_to_thread): Delete, unused. + +2014-01-22 Doug Evans + + * configure.ac (AC_CHECK_FUNCS): Add test for gettimeofday. + * configure: Regenerate. + * config.in: Regenerate. + * Makefile.in (SFILES): Add debug.c. + (OBS): Add debug.o. + * debug.c: New file. + * debug.h: New file. + * linux-aarch64-low.c (*): Update all debugging printfs to use + debug_printf instead of fprintf. + * linux-arm-low.c (*): Ditto. + * linux-cris-low.c (*): Ditto. + * linux-crisv32-low.c (*): Ditto. + * linux-m32r-low.c (*): Ditto. + * linux-sparc-low.c (*): Ditto. + * linux-x86.c (*): Ditto. + * linux-low.c (*): Ditto. + (linux_wait_1): Add calls to debug_enter, debug_exit. + (linux_wait): Remove redundant debugging printf. + (stop_all_lwps): Add calls to debug_enter, debug_exit. + (linux_resume, unstop_all_lwps): Ditto. + * mem-break.c (*): Update all debugging printfs to use + debug_printf instead of fprintf. + * remote-utils.c (*): Ditto. + * thread-db.c (*): Ditto. + * server.c #include , "gdb_vecs.h". + (debug_threads): Moved to debug.c. + (*): Update all debugging printfs to use debug_printf instead of + fprintf. + (start_inferior): Replace call to fflush with call to debug_flush. + (monitor_show_help): Mention set debug-format. + (parse_debug_format_options): New function. + (handle_monitor_command): Handle "monitor set debug-format". + (gdbserver_usage): Mention --debug-format. + (main): Parse --debug-format. + * server.h (debug_threads): Declaration moved to debug.h. + #include "debug.h". + * tracepoint.c (trace_debug_1) [!IN_PROCESS_AGENT]: Add version of + trace_debug_1 that uses debug_printf. + (tracepoint_look_up_symbols): Update all debugging printfs to use + debug_printf instead of fprintf. + +2014-01-20 Baruch Siach + + * linux-xtensa-low.c: Include asm/ptrace.h instead of + sys/ptrace.h. + +2014-01-17 Pedro Alves + + PR build/16445 + * linux-x86-low.c: Don't include elf/common.h if ELFMAG0 is + defined after including gdb_proc_service.h. + +2014-01-16 Doug Evans + + * dll.c (UNSPECIFIED_CORE_ADDR): New macro. + (match_dll): Use it. + +2014-01-16 Markus Metzger + + * target.h (target_ops) : Change parameters and + return type to allow error reporting. + * server.c (handle_qxfer_btrace): Support delta reads. Pass + trace reading errors on. + * linux-low.c (linux_low_read_btrace): Pass trace reading + errors on. + (linux_low_disable_btrace): New. + +2014-01-15 Doug Evans + + * inferiors.c (thread_id_to_gdb_id): Delete. + * inferiors.h (thread_id_to_gdb_id): Delete. + +2014-01-13 Eli Zaretskii + + * Makefile.in (INCLUDE_CFLAGS): Remove trailing slash from + "-I$(srcdir)/../". Fixes MinGW compilation errors with old GCC + versions. + +2014-01-08 Pedro Alves + + * server.c (handle_status): Don't discard previous queued stop + replies or thread's pending status here. + (main) : Do it here instead. + +2014-01-08 Pedro Alves + + * gdbthread.h (struct thread_info) : New field. + * server.c (visit_actioned_threads, handle_pending_status): New + function. + (handle_v_cont): Factor out parts to ... + (resume): ... this new function. If in all-stop, and a thread + being resumed has a pending status, report it without actually + resuming. + (myresume): Adjust to use the new 'resume' function. + (clear_pending_status_callback, set_pending_status_callback) + (find_status_pending_thread_callback): New functions. + (handle_status): Handle the case of multiple threads having + interesting statuses to report. Report threads' real last signal + instead of always reporting GDB_SIGNAL_TRAP. Look for a thread + with an interesting thread to report the status for, instead of + always reporting the status of the first thread. + +2014-01-01 Joel Brobecker + + * gdbserver.c (gdbserver_version): Set copyright year to 2014. + * gdbreplay.c (gdbreplay_version): Likewise. + +2013-12-18 Yufeng Zhang + + * linux-aarch64-low.c (aarch64_linux_set_debug_regs): Set + iov.iov_len with the real length in use. + +2013-12-13 Joel Brobecker + + * Makefile.in (safe-ctype.o, lbasename.o): New rules. + * configure.srv: Add safe-ctype.o and lbasename.o to srv_tgtobj + for all targets that use win32-low.c. + * win32-low.c (win32_ensure_ntdll_loaded): New function. + (do_initial_child_stuff): Add call to win32_ensure_ntdll_loaded. + +2013-12-13 Pedro Alves + + * target.c (mywait): Set OURSTATUS->KIND to TARGET_WAITKIND_STOPPED + if equal to TARGET_WAITKIND_LOADED. + * win32-low.c (cached_status): New static global. + (win32_wait): Add declaration. + (do_initial_child_stuff): Flush all initial pending debug events + up to the initial breakpoint. + (win32_wait): If CACHED_STATUS was set, return that instead + of doing a real wait. Remove the code resuming the execution + of the inferior after receiving a TARGET_WAITKIND_LOADED event + during the initial phase. Also remove the code changing + OURSTATUS->KIND from TARGET_WAITKIND_LOADED to + TARGET_WAITKIND_STOPPED. + +2013-12-11 Yao Qi + + * notif.c (handle_notif_ack): Return 0 if no notification + matches. + +2013-11-20 Doug Evans + + * linux-low.c (linux_set_resume_request): Fix comment. + +2013-11-20 Doug Evans + + * linux-low.c (resume_status_pending_p): Tweak comment. + +2013-11-20 Walfred Tedeschi + + * Makefile.in: Add i386-mpx.c, i386-mpx-linux.c, amd64-mpx.c, + amd64-mpx-linux.c, x32-mpx.c and x32-mpx-linux.c generation. + * configure.srv (srv_i386_regobj): Add i386-mpx.o. + (srv_i386_linux_regobj): Add i386-mpx-linux.o. + (srv_amd64_regobj): Add amd64-mpx.o. + (srv_amd64_linux_regobj): Add amd64-mpx-linux.o. + (srv_i386_32bit_xmlfiles): Add i386/32bit-mpx.xml. + (srv_i386_64bit_xmlfiles): Add i386/64bit-mpx.xml. + * i387-fp.c (num_pl_bnd_register) Added constant. + (num_pl_bnd_cfg_registers) Added constant. + (struct i387_xsave) Added reserved area and MPX fields. + (i387_cache_to_xsave, i387_xsave_to_cache) Add MPX. + * linux-x86-low.c (init_registers_i386_mpx_linux): Declare new + function. + (tdesc_i386_mpx_linux): Add MPX amd64 target. + (init_registers_amd64_mpx_linux): Declare new function. + (tdesc_amd64_mpx_linux): Add MPX amd64 target. + (x86_64_regmap): Add MPX registers. + (x86_linux_read_description): Add MPX case. + (initialize_low_arch): Initialize MPX targets. + +2013-11-18 Tom Tromey + + * configure: Rebuild. + * configure.ac: Don't check for stdlib.h. + * gdbreplay.c: Unconditionally include stdlib.h. + +2013-11-18 Tom Tromey + + * config.in: Rebuild. + * configure: Rebuild. + * configure.ac: Don't use AC_HEADER_DIRENT. + +2013-11-18 Tom Tromey + + * server.h: Don't check HAVE_STRING_H. + * gdbreplay.c: Don't check HAVE_STRING_H. + * configure: Rebuild. + +2013-11-18 Tom Tromey + + * Makefile.in (gdbreplay$(EXEEXT)): Depend on and link against + LIBGNU. + +2013-11-08 Tom Tromey + + * configure, config.in: Rebuild. + * configure.ac: Remove unused configury. + +2013-11-08 Tom Tromey + + * acinclude.m4: Include common.m4, codeset.m4. + * configure, config.in: Rebuild. + * configure.ac: Use GDB_AC_COMMON. + +2013-11-06 Andreas Arnez + + * linux-s390-low.c (HWCAP_S390_TE): New define. + (s390_arch_setup): Consider the TE field in the HWCAP for + determining 'have_regset_tdb'. + +2013-10-16 Sergio Durigan Junior + + PR gdb/16014 + * tracepoint.c (download_tracepoint_1): Remove unnecessary double + call to sizeof. + +2013-10-02 Pedro Alves + + * server.c (process_serial_event): Don't output "GDBserver + exiting" if GDB is connected through stdio. + * target.c (mywait): Likewise, be silent if GDB is connected + through stdio. + +2013-10-01 Joel Brobecker + + * lynx-low.c (lynx_add_threads_after_attach): New function. + (lynx_attach): Remove call to add_thread. Add call to + lynx_add_threads_after_attach instead. + +2013-09-28 Mike Frysinger + + * configure.ac (AC_CHECK_HEADERS): Add sys/syscall.h + * config.in, configure: Regenerated. + +2013-09-18 Yao Qi + + PR server/15959 + * server.c (start_inferior): Clear 'resume_info'. + +2013-09-16 Jiong Wang + + * linux-tile-low.c (tile_regsets): Modify the size field to 64-bit + for each register. + +2013-09-16 Jiong Wang + + * configure.srv : Remove linux-osdata.o from and add + linux-tile-low.o to srv_tgtobj. + +2013-09-16 Will Newton + + * linux-aarch64-low.c (aarch64_linux_set_debug_regs): Zero + out regs. + +2013-09-06 Pedro Alves + + * Makefile.in (gdb_proc_service_h, regdef_h, regcache_h) + (signals_def, signals_h, ptid_h, ax_h, agent_h, linux_btrace_h) + (linux_osdata_h, vec_h, gdb_vecs_h, host_defs_h, libiberty_h) + (server_h, gdbthread_h, linux_low_h, linux_ptrace_h) + (gdb_thread_db_h, linux_procfs_h, lynx_low_h, nto_low_h) + (mips_linux_watch_h, i386_low_h, win32_low_h): Delete. + +2013-09-06 Pedro Alves + + * Makefile.in (linux-btrace.o, mips-linux-watch.o): Remove + explicit header dependencies and use $COMPILE/$POSTCOMPILE. + +2013-09-06 Pedro Alves + + * linux-amd64-ipa.c: Include tracepoint.h. + * linux-i386-ipa.c: Include tracepoint.h. + +2013-09-06 Ricard Wanderlof + + * linux-crisv32-low.c (PTRACE_GET_THREAD_AREA): New macro. + (ps_get_thread_area): New function. + +2013-09-06 Ricard Wanderlof + + * linux-crisv32-low.c (elf_gregset_t): Delete typedef. + (initialize_low_arch): Call init_registers_crisv32 rather than + init_register_crisv32. + +2013-09-05 Pedro Alves + + * server.h (handle_vFile, hostio_last_error_from_errno): Move + to ... + * hostio.h: ... this new file. + * hostio.c, server.c, linux-low.c, nto-low.c, spu-low, + win32-low.c: Include hostio.h. + +2013-09-05 Pedro Alves + + * server.h (gdb_client_data, handler_func, callback_handler_func) + (delete_file_handler, add_file_handler, append_callback_event) + (delete_callback_event, start_event_loop, initialize_event_loop): + Move to event-loop.h and include it. + * event-loop.h: New file. + +2013-09-05 Pedro Alves + + * dll.c, inferiors.c, remote-utils.c, server.c: Include "dll.h". + * server.h (struct dll_info, all_dlls, dlls_changed, clear_dlls) + (loaded_dll, unloaded_dll): Move to ... + * dll.h: ... this new file. + * inferiors.c, remote-utils.c, win32-low.c: Include "dll.h". + +2013-09-05 Pedro Alves + + * server.h (current_process, get_thread_process, all_processes) + (add_inferior_to_list, for_each_inferior, current_inferior) + (remove_inferior, add_process, remove_process, find_process_pid) + (have_started_inferiors_p, have_attached_inferiors_p) + (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id) + (clear_inferiors, find_inferior, find_inferior_id) + (inferior_target_data, set_inferior_target_data) + (inferior_regcache_data, set_inferior_regcache_data): Move to + inferiors.h, and include it. + * inferiors.h: New file. + +2013-09-05 Pedro Alves + + * server.h (struct emit_ops, current_insn_ptr, emit_error): + Move ... + * ax.h: ... here. + +2013-09-05 Pedro Alves + + * ax.c, linux-low.c, linux-x86-low.c, server.c: Include + tracepoint.h. + * server.h (IPA_BUFSIZ, initialize_tracepoint, tracing) + (disconnected_tracing, tracepoint_look_up_symbols, stop_tracing + (handle_tracepoint_general_set, handle_tracepoint_query) + (tracepoint_finished_step, tracepoint_was_hit) + (release_while_stepping_state_list, current_traceframe) + (in_readonly_region, traceframe_read_mem) + (fetch_traceframe_registers, traceframe_read_sdata) + (traceframe_read_info, struct fast_tpoint_collect_status) + (fast_tracepoint_collecting, force_unlock_trace_buffer) + (handle_tracepoit_bkpts, initialize_low_tracepoint) + (supply_fast_tracepoint_registers) + (supply_static_tracepoint_registers, set_trampoline_buffer_space) + (ipa_tdesc, claim_trampoline_space) + (have_fast_tracepoint_trampoline_buffer, gdb_agent_about_to_close) + (agent_mem_read, agent_get_trace_state_variable_value) + (agent_set_trace_state_variable_value, agent_tsv_read) + (agent_mem_read_string, get_raw_reg_func_addr) + (get_get_tsv_func_addr, get_set_tsv_func_addr): Move to ... + * tracepoint.h: ... this new file. + +2013-09-05 Pedro Alves + + * server.h (perror_with_name, error, fatal, warning, paddress) + (pulongest, plongest, phex_nz, pfildes): Move to utils.h, and + include it. + * utils.h: New file. + +2013-09-05 Pedro Alves + + * server.h (remote_debug, noack_mode, transport_is_reliable) + (gdb_connected, STDIO_CONNECTION_NAME, remote_connection_is_stdio) + (read_ptid, write_ptid, putpkt, putpkt_binary, putpkt_notif) + (getpkt, remote_prepare, remote_open, remote_close, write_ok) + (write_enn, initialize_async_io, enable_async_io) + (disable_async_io, check_remote_input_interrupt_request) + (convert_ascii_to_int, convert_int_to_ascii, new_thread_notify) + (dead_thread_notify, prepare_resume_reply) + (decode_address_to_semicolon, decode_address, decode_m_packet) + (decode_M_packet, decode_X_packet, decode_xfer_write) + (decode_search_memory_packet, unhexify, hexify) + (remote_escape_output, unpack_varlen_hex, clear_symbol_cache) + (look_up_one_symbol, relocate_instruction) + (monitor_output): Move to remote-utils.h, and include it. + * remote-utils.h: New file. + +2013-09-05 Pedro Alves + + * server.h (_): Delete. + +2013-09-02 Pedro Alves + + * tracepoint.c (TRACEFRAME_EOB_MARKER_SIZE): New macro. + (init_trace_buffer): Ensure at least TRACEFRAME_EOB_MARKER_SIZE is + allocated. + (trace_buffer_alloc): Use TRACEFRAME_EOB_MARKER_SIZE. + +2013-09-02 Pierre Muller + + * win32-low.c (child_xfer_memory): Check if ReadProcessMemory + or WriteProcessMemory complete successfully and handle + ERROR_PARTIAL_COPY error. + +2013-09-02 Pedro Alves + + * server.c (gdb_read_memory): Return -1 on traceframe memory read + error instead of EIO. + +2013-08-28 Jan Kratochvil + + PR server/15604 + * linux-low.c: Include filestuff.h. + (linux_create_inferior) : Call close_most_fds. + * lynx-low.c: Include filestuff.h. + (lynx_create_inferior) : Call close_most_fds. + * server.c: Include filestuff.h. + (main): Call notice_open_fds. + * spu-low.c: Include filestuff.h. + (spu_create_inferior) : Call close_most_fds. + +2013-08-22 Luis Machado + + * Makefile.in: Explain why ../target and ../nat are not + listed as include file search paths. + (linux-waitpid.o): New object file rule. + * configure.srv (srv_native_linux_obj): New variable. + Replace all occurrences of linux native object files with + $srv_native_linux_obj. + * linux-low.c: Include nat/linux-nat.h and nat/linux-waitpid.h. + (HAS_NOMMU): Move defining logic to common/linux-ptrace.c. + (linux_enable_event_reporting): Remove declaration. + (my_waitpid): Moved to common/linux-waitpid.c. + (linux_wait_for_event): Pass ptid when calling + linux_enable_event_reporting. + (linux_supports_tracefork_flag): Remove. + (linux_enable_event_reporting): Likewise. + (linux_tracefork_grandchild): Remove. + (STACK_SIZE): Moved to common/linux-ptrace.c. + (linux_tracefork_child): Remove. + (linux_test_for_tracefork): Remove. + (linux_look_up_symbols): Call linux_supports_traceclone. + (initialize_low): Remove call to linux_test_for_tracefork. + * linux-low.h (PTRACE_TYPE_ARG3): Move to + common/linux-ptrace.h. + (PTRACE_TYPE_ARG4): Likewise. + Include linux-ptrace.h. + +2013-08-21 Pedro Alves + + * config.in: Renegerate. + +2013-08-19 Luis Machado + + * Makefile.in (INCLUDE_CFLAGS): Include -I$(srcdir)/../. + (SFILES): Remove $(srcdir)/common/target-common.c and + add $(srcdir)/target/waitstatus.c. + (OBS): Remove target-common.o and add waitstatus.o. + (server_h): Remove $(srcdir)/../common/target-common.h and + add $(srcdir)/../target/resume.h, $(srcdir)/../target/wait.h + and $(srcdir)/../target/waitstatus.h. + (target-common.o): Remove. + (waitstatus.o): New target object file. + * target.h: Do not include target-common.h and + include target/resume.h, target/wait.h and + target/waitstatus.h. + +2013-08-13 Luis Machado + + * linux-arm-low.c: Rename all occurrences of PTRACE_ARG3_TYPE + to PTRACE_TYPE_ARG3. + * linux-low.c: Rename all occurrences of PTRACE_ARG3_TYPE + to PTRACE_TYPE_ARG3 and PTRACE_ARG4_TYPE to + PTRACE_TYPE_ARG4. + * linux-low.h (PTRACE_ARG3_TYPE): Rename to PTRACE_TYPE_ARG3. + (PTRACE_ARG4_TYPE): Rename to PTRACE_TYPE_ARG4. + +2013-07-27 Jie Zhang + Daniel Jacobowitz + Yao Qi + + * Makefile.in (SFILES): Add common/mips-linux-watch.c. + (mips-linux-watch.o): New rule. + (mips_linux_watch_h): New variable. + * configure.srv : Add mips-linux-watch.o to + srv_tgtobj. + * linux-mips-low.c: Include mips-linux-watch.h. + (struct arch_process_info, struct arch_lwp_info): New. + (update_watch_registers_callback): New function. + (mips_linux_new_process, mips_linux_new_thread) New functions. + (mips_linux_prepare_to_resume, mips_insert_point): New + functions. + (mips_remove_point, mips_stopped_by_watchpoint): New + functions. + (rsp_bp_type_to_target_hw_bp_type): New function. + (mips_stopped_data_address): New function. + (the_low_target): Add watchpoint support functions. + +2013-07-27 Yao Qi + + * i386-low.c: Include break-common.h. + (enum target_hw_bp_type): Remove. + +2013-07-24 Luis Machado + + * Makefile.in (SFILES): /common/target-common.c. + (OBS): Add target-common.o. + (server_h): Add $(srcdir)/../common/target-common.h. + (target-common.o): New target. + * server.c (queue_stop_reply_callback): Free + status string after use. + * target.c (target_waitstatus_to_string): Remove. + * target.h: Include target-common.h. + (resume_kind): Likewise. + (target_waitkind): Likewise. + (target_waitstatus): Likewise. + (TARGET_WNOHANG): Likewise. + +2013-07-04 Yao Qi + + * Makefile.in (host_alias): Use @host_noncanonical@. + (target_alias): Use @target_noncanonical@. + * configure.ac: Use ACX_NONCANONICAL_TARGET and + ACX_NONCANONICAL_HOST. + * configure: Regenerated. + + Revert: + 2013-06-28 Mircea Gherzan + + * configure.ac (version_host, version_target): Set and AC_SUBST them. + * configure: Rebuild. + * Makefile.in (version_host, version_target): Get from configure. + (version.c): Use $(version_host) and $(version_target). + +2013-07-03 Pedro Alves + + * Makefile.in (config.status): Depend on development.sh. + * acinclude.m4: Include libmcheck.m4. + * configure: Regenerate. + +2013-07-02 Mircea Gherzan + + * win32-low.c (winapi_DebugActiveProcessStop): Move the WINAPI + attribute inside the parentheses. + (winapi_DebugSetProcessKillOnExit): Ditto. + (winapi_DebugBreakProcess): Ditto. + (winapi_GenerateConsoleCtrlEvent): Ditto. + +2013-07-02 Mircea Gherzan + + * notif.h (notif_event): Add a dummy member to avoid compiler + errors. + +2013-07-01 Pedro Alves + + * hostio.c (HOSTIO_PATH_MAX): Define. + (require_filename, handle_open, handle_unlink, handle_readlink): + Use it. + +2013-07-01 Pedro Alves + + * server.h: Include "pathmax.h". + * linux-low.c: Don't include sys/param.h. + (linux_pid_exe_is_elf_64_file): Use PATH_MAX instead of + MAXPATHLEN. + * win32-low.c: Don't include sys/param.h. + (win32_create_inferior): Use PATH_MAX instead of MAXPATHLEN. + +2013-07-01 Pedro Alves + + * event-loop.c: Don't check HAVE_UNISTD_H before including + . + * gdbreplay.c: Likewise. + * remote-utils.c: Likewise. + * server.c: Likewise. + * configure.ac: Don't check for unistd.h. + * configure: Regenerate. + +2013-06-28 Tom Tromey + + * Makefile.in (version.c): Use version.in, not + common/version.in. + +2013-06-28 Mircea Gherzan + + * configure.ac (version_host, version_target): Set and AC_SUBST them. + * configure: Rebuild. + * Makefile.in (version_host, version_target): Get from configure. + (version.c): Use $(version_host) and $(version_target). + +2013-06-10 Dmitry Kozlov + + Fix trace-status to output user name without trailing colon. + * tracepoint.c (cmd_qtstatus): Remove unnecessary colon from user name. + +2013-06-10 Dmitry Kozlov + + Fix trace-status to output proper start-time and stop-time. + * tracepoint.c (cmd_qtstatus): Modify trace-status output to + output start time and stop time in hex as gdb expects. + +2013-06-26 Pedro Alves + + * tracepoint.c (build_traceframe_info_xml): Output trace state + variables present in the trace buffer. + +2013-06-24 Tom Tromey + + * Makefile.in (version.c): Use bfd/version.h, common/version.in, + create-version.sh. + (version.o): Remove. + * gdbreplay.c: Include version.h. + (version, host_name): Don't declare. + * server.h: Include version.h. + (version, host_name): Don't declare. + +2013-06-12 Pedro Alves + + * linux-x86-low.c (linux_is_elf64): Delete global. + (x86_siginfo_fixup): Replace reference to `linux_is_elf64' global + with local linux_pid_exe_is_elf_64_file use. + +2013-06-11 Pedro Alves + + * linux-low.c (regset_disabled, disable_regset): New functions. + (regsets_fetch_inferior_registers) + (regsets_store_inferior_registers): Use them. + (initialize_regsets_info); Don't allocate the disabled_regsets + array here. + * linux-low.h (struct regsets_info) : Extend + comment. + +2013-06-11 Pedro Alves + + * linux-low.c (initialize_regsets_info): Use xcalloc instead of + xmalloc. + +2013-06-11 Pedro Alves + + * linux-x86-low.c (initialize_low_arch): Call + init_registers_x32_avx_linux. + +2013-06-09 Jan Kratochvil + + Fix compatibility with Android Bionic. + * linux-low.c (linux_qxfer_libraries_svr4): Ignore first entry even if + it is not empty. + +2013-06-07 Pedro Alves + + PR server/14823 + * Makefile.in (OBS): Add tdesc.o. + (IPA_OBJS): Add tdesc-ipa.o. + (tdesc-ipa.o): New rule. + * ax.c (gdb_eval_agent_expr): Adjust register_size call to new + interface. + * linux-low.c (new_inferior): Delete. + (disabled_regsets, num_regsets): Delete. + (linux_add_process): Adjust to set the new per-process + new_inferior flag. + (linux_detach_one_lwp): Adjust to call regcache_invalidate_thread. + (linux_wait_for_lwp): Adjust. Only call arch_setup if the event + was a stop. When calling arch_setup, switch the current inferior + to the thread that got an event. + (linux_resume_one_lwp): Adjust to call regcache_invalidate_thread. + (regsets_fetch_inferior_registers) + (regsets_store_inferior_registers): New regsets_info parameter. + Adjust to use it. + (linux_register_in_regsets): New regs_info parameter. Adjust to + use it. + (register_addr, fetch_register, store_register): New usrregs_info + parameter. Adjust to use it. + (usr_fetch_inferior_registers, usr_store_inferior_registers): New + parameter regs_info. Adjust to use it. + (linux_fetch_registers): Get the current inferior's regs_info, and + adjust to use it. + (linux_store_registers): Ditto. + [HAVE_LINUX_REGSETS] (initialize_regsets_info): New. + (initialize_low): Don't initialize the target_regsets here. Call + initialize_low_arch. + * linux-low.h (target_regsets): Delete declaration. + (struct regsets_info): New. + (struct usrregs_info): New. + (struct regs_info): New. + (struct process_info_private) : New field. + (struct linux_target_ops): Delete the num_regs, regmap, and + regset_bitmap fields. New field regs_info. + [HAVE_LINUX_REGSETS] (initialize_regsets_info): Declare. + * i387-fp.c (num_xmm_registers): Delete. + (i387_cache_to_fsave, i387_fsave_to_cache): Adjust find_regno + calls to new interface. + (i387_cache_to_fxsave, i387_cache_to_xsave, i387_fxsave_to_cache) + (i387_xsave_to_cache): Adjust find_regno calls to new interface. + Infer the number of xmm registers from the regcache's target + description. + * i387-fp.h (num_xmm_registers): Delete. + * inferiors.c (add_thread): Don't install the thread's regcache + here. + * proc-service.c (gregset_info): Fetch the current inferior's + regs_info. Adjust to use it. + * regcache.c: Include tdesc.h. + (register_bytes, reg_defs, num_registers) + (gdbserver_expedite_regs): Delete. + (get_thread_regcache): If the thread doesn't have a regcache yet, + create one, instead of aborting gdbserver. + (regcache_invalidate_one): Rename to ... + (regcache_invalidate_thread): ... this. + (regcache_invalidate_one): New. + (regcache_invalidate): Only invalidate registers of the current + process. + (init_register_cache): Add target_desc parameter, and use it. + (new_register_cache): Ditto. Assert the target description has a + non zero registers_size. + (regcache_cpy): Add assertions. Adjust. + (realloc_register_cache, set_register_cache): Delete. + (registers_to_string, registers_from_string): Adjust. + (find_register_by_name, find_regno, find_register_by_number) + (register_cache_size): Add target_desc parameter, and use it. + (free_register_cache_thread, free_register_cache_thread_one) + (regcache_release, register_cache_size): New. + (register_size): Add target_desc parameter, and use it. + (register_data, supply_register, supply_register_zeroed) + (supply_regblock, supply_register_by_name, collect_register) + (collect_register_as_string, collect_register_by_name): Adjust. + * regcache.h (struct target_desc): Forward declare. + (struct regcache) : New field. + (init_register_cache, new_register_cache): Add target_desc + parameter. + (regcache_invalidate_thread): Declare. + (regcache_invalidate_one): Delete declaration. + (regcache_release): Declare. + (find_register_by_number, register_cache_size, register_size) + (find_regno): Add target_desc parameter. + (gdbserver_expedite_regs, gdbserver_xmltarget): Delete + declarations. + * remote-utils.c: Include tdesc.h. + (outreg, prepare_resume_reply): Adjust. + * server.c: Include tdesc.h. + (gdbserver_xmltarget): Delete declaration. + (get_features_xml, process_serial_event): Adjust. + * server.h [IN_PROCESS_AGENT] (struct target_desc): Forward + declare. + (struct process_info) : New field. + (ipa_tdesc): Declare. + * tdesc.c: New file. + * tdesc.h: New file. + * tracepoint.c: Include tdesc.h. + [IN_PROCESS_AGENT] (ipa_tdesc): Define. + (get_context_regcache): Adjust to pass ipa_tdesc down. + (do_action_at_tracepoint): Adjust to get the register cache size + from the context regcache's description. + (traceframe_walk_blocks): Adjust to get the register cache size + from the current trace frame's description. + (traceframe_get_pc): Adjust to get current trace frame's + description and pass it down. + (gdb_collect): Adjust to get the register cache size from the + IPA's description. + * linux-amd64-ipa.c (tdesc_amd64_linux): Declare. + (gdbserver_xmltarget): Delete. + (initialize_low_tracepoint): Set the ipa's target description. + * linux-i386-ipa.c (tdesc_i386_linux): Declare. + (initialize_low_tracepoint): Set the ipa's target description. + * linux-x86-low.c: Include tdesc.h. + [__x86_64__] (is_64bit_tdesc): New. + (ps_get_thread_area, x86_get_thread_area): Use it. + (i386_cannot_store_register): Rename to ... + (x86_cannot_store_register): ... this. Use is_64bit_tdesc. + (i386_cannot_fetch_register): Rename to ... + (x86_cannot_fetch_register): ... this. Use is_64bit_tdesc. + (x86_fill_gregset, x86_store_gregset): Adjust register_size calls + to new interface. + (target_regsets): Rename to ... + (x86_regsets): ... this. + (x86_get_pc, x86_set_pc): Adjust register_size calls to new + interface. + (x86_siginfo_fixup): Use is_64bit_tdesc. + [__x86_64__] (tdesc_amd64_linux, tdesc_amd64_avx_linux) + (tdesc_x32_avx_linux, tdesc_x32_linux) + (tdesc_i386_linux, tdesc_i386_mmx_linux, tdesc_i386_avx_linux): + Declare. + (x86_linux_update_xmltarget): Delete. + (I386_LINUX_XSAVE_XCR0_OFFSET): Define. + (have_ptrace_getfpxregs, have_ptrace_getregset): New. + (AMD64_LINUX_USER64_CS): New. + (x86_linux_read_description): New, based on + x86_linux_update_xmltarget. + (same_process_callback): New. + (x86_arch_setup_process_callback): New. + (x86_linux_update_xmltarget): New. + (x86_regsets_info): New. + (amd64_linux_regs_info): New. + (i386_linux_usrregs_info): New. + (i386_linux_regs_info): New. + (x86_linux_regs_info): New. + (x86_arch_setup): Reimplement. + (x86_install_fast_tracepoint_jump_pad): Use is_64bit_tdesc. + (x86_emit_ops): Ditto. + (the_low_target): Adjust. Install x86_linux_regs_info, + x86_cannot_fetch_register, and x86_cannot_store_register. + (initialize_low_arch): New. + * linux-ia64-low.c (tdesc_ia64): Declare. + (ia64_fetch_register): Adjust. + (ia64_usrregs_info, regs_info): New globals. + (ia64_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-sparc-low.c (tdesc_sparc64): Declare. + (sparc_fill_gregset_to_stack, sparc_store_gregset_from_stack): + Adjust. + (sparc_arch_setup): New function. + (sparc_regsets_info, sparc_usrregs_info, regs_info): New globals. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-ppc-low.c (tdesc_powerpc_32l, tdesc_powerpc_altivec32l) + (tdesc_powerpc_cell32l, tdesc_powerpc_vsx32l) + (tdesc_powerpc_isa205_32l, tdesc_powerpc_isa205_altivec32l) + (tdesc_powerpc_isa205_vsx32l, tdesc_powerpc_e500l) + (tdesc_powerpc_64l, tdesc_powerpc_altivec64l) + (tdesc_powerpc_cell64l, tdesc_powerpc_vsx64l) + (tdesc_powerpc_isa205_64l, tdesc_powerpc_isa205_altivec64l) + (tdesc_powerpc_isa205_vsx64l): Declare. + (ppc_cannot_store_register, ppc_collect_ptrace_register) + (ppc_supply_ptrace_register, parse_spufs_run, ppc_get_pc) + (ppc_set_pc, ppc_get_hwcap): Adjust. + (ppc_usrregs_info): Forward declare. + (!__powerpc64__) ppc_regmap_adjusted: New global. + (ppc_arch_setup): Adjust to the current process'es target + description. + (ppc_fill_vsxregset, ppc_store_vsxregset, ppc_fill_vrregset) + (ppc_store_vrregset, ppc_fill_evrregset, ppc_store_evrregse) + (ppc_store_evrregset): Adjust. + (target_regsets): Rename to ... + (ppc_regsets): ... this, and make static. + (ppc_usrregs_info, ppc_regsets_info, regs_info): New globals. + (ppc_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-s390-low.c (tdesc_s390_linux32, tdesc_s390_linux32v1) + (tdesc_s390_linux32v2, tdesc_s390_linux64, tdesc_s390_linux64v1) + (tdesc_s390_linux64v2, tdesc_s390x_linux64, tdesc_s390x_linux64v1) + (tdesc_s390x_linux64v2): Declare. + (s390_collect_ptrace_register, s390_supply_ptrace_register) + (s390_fill_gregset, s390_store_last_break): Adjust. + (target_regsets): Rename to ... + (s390_regsets): ... this, and make static. + (s390_get_pc, s390_set_pc): Adjust. + (s390_get_hwcap): New target_desc parameter, and use it. + [__s390x__] (have_hwcap_s390_high_gprs): New global. + (s390_arch_setup): Adjust to set the current process'es target + description. Don't adjust the regmap. + (s390_usrregs_info, s390_regsets_info, regs_info): New globals. + [__s390x__] (s390_usrregs_info_3264, s390_regsets_info_3264) + (regs_info_3264): New globals. + (s390_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-mips-low.c (tdesc_mips_linux, tdesc_mips_dsp_linux) + (tdesc_mips64_linux, tdesc_mips64_dsp_linux): Declare. + [__mips64] (init_registers_mips_linux) + (init_registers_mips_dsp_linux): Delete defines. + [__mips64] (tdesc_mips_linux, tdesc_mips_dsp_linux): New defines. + (have_dsp): New global. + (mips_read_description): New, based on mips_arch_setup. + (mips_arch_setup): Reimplement. + (get_usrregs_info): New function. + (mips_cannot_fetch_register, mips_cannot_store_register) + (mips_get_pc, mips_set_pc, mips_fill_gregset, mips_store_gregset) + (mips_fill_fpregset, mips_store_fpregset): Adjust. + (target_regsets): Rename to ... + (mips_regsets): ... this, and make static. + (mips_regsets_info, mips_dsp_usrregs_info, mips_usrregs_info) + (dsp_regs_info, regs_info): New globals. + (mips_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-arm-low.c (tdesc_arm, tdesc_arm_with_iwmmxt) + (tdesc_arm_with_vfpv2, tdesc_arm_with_vfpv3, tdesc_arm_with_neon): + Declare. + (arm_fill_vfpregset, arm_store_vfpregset): Adjust. + (arm_read_description): New, with bits factored from + arm_arch_setup. + (arm_arch_setup): Reimplement. + (target_regsets): Rename to ... + (arm_regsets): ... this, and make static. + (arm_regsets_info, arm_usrregs_info, regs_info): New globals. + (arm_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-m68k-low.c (tdesc_m68k): Declare. + (target_regsets): Rename to ... + (m68k_regsets): ... this, and make static. + (m68k_regsets_info, m68k_usrregs_info, regs_info): New globals. + (m68k_regs_info): New function. + (m68k_arch_setup): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-sh-low.c (tdesc_sharch): Declare. + (target_regsets): Rename to ... + (sh_regsets): ... this, and make static. + (sh_regsets_info, sh_usrregs_info, regs_info): New globals. + (sh_regs_info, sh_arch_setup): New functions. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-bfin-low.c (tdesc_bfin): Declare. + (bfin_arch_setup): New function. + (bfin_usrregs_info, regs_info): New globals. + (bfin_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-cris-low.c (tdesc_cris): Declare. + (cris_arch_setup): New function. + (cris_usrregs_info, regs_info): New globals. + (cris_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-cris-low.c (tdesc_crisv32): Declare. + (cris_arch_setup): New function. + (cris_regsets_info, cris_usrregs_info, regs_info): New globals. + (cris_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-m32r-low.c (tdesc_m32r): Declare. + (m32r_arch_setup): New function. + (m32r_usrregs_info, regs_info): New globals. + (m32r_regs_info): Adjust. + (initialize_low_arch): New function. + * linux-tic6x-low.c (tdesc_tic6x_c64xp_linux) + (tdesc_tic6x_c64x_linux, tdesc_tic6x_c62x_linux): Declare. + (tic6x_usrregs_info): Forward declare. + (tic6x_read_description): New function, based on ... + (tic6x_arch_setup): ... this. Reimplement. + (target_regsets): Rename to ... + (tic6x_regsets): ... this, and make static. + (tic6x_regsets_info, tic6x_usrregs_info, regs_info): New globals. + (tic6x_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-xtensa-low.c (tdesc_xtensa): Declare. + (xtensa_fill_gregset, xtensa_store_gregset): Adjust. + (target_regsets): Rename to ... + (xtensa_regsets): ... this, and make static. + (xtensa_regsets_info, xtensa_usrregs_info, regs_info): New + globals. + (xtensa_arch_setup, xtensa_regs_info): New functions. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-nios2-low.c (tdesc_nios2_linux): Declare. + (nios2_arch_setup): Set the current process'es tdesc. + (target_regsets): Rename to ... + (nios2_regsets): ... this. + (nios2_regsets_info, nios2_usrregs_info, regs_info): New globals. + (nios2_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-aarch64-low.c (tdesc_aarch64): Declare. + (aarch64_arch_setup): Set the current process'es tdesc. + (target_regsets): Rename to ... + (aarch64_regsets): ... this. + (aarch64_regsets_info, aarch64_usrregs_info, regs_info): New globals. + (aarch64_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-tile-low.c (tdesc_tilegx, tdesc_tilegx32): Declare + globals. + (target_regsets): Rename to ... + (tile_regsets): ... this. + (tile_regsets_info, tile_usrregs_info, regs_info): New globals. + (tile_regs_info): New function. + (tile_arch_setup): Set the current process'es tdesc. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * spu-low.c (tdesc_spu): Declare. + (spu_create_inferior, spu_attach): Set the new process'es tdesc. + * win32-arm-low.c (tdesc_arm): Declare. + (arm_arch_setup): New function. + (the_low_target): Install arm_arch_setup instead of + init_registers_arm. + * win32-i386-low.c (tdesc_i386, tdesc_amd64): Declare. + (init_windows_x86): Rename to ... + (i386_arch_setup): ... this. Set `win32_tdesc'. + (the_low_target): Adjust. + * win32-low.c (win32_tdesc): New global. + (child_add_thread): Don't create the thread cache here. + (do_initial_child_stuff): Set the new process'es tdesc. + * win32-low.h (struct target_desc): Forward declare. + (win32_tdesc): Declare. + * lynx-i386-low.c (tdesc_i386): Declare global. + (lynx_i386_arch_setup): Set `lynx_tdesc'. + * lynx-low.c (lynx_tdesc): New global. + (lynx_add_process): Set the new process'es tdesc. + * lynx-low.h (struct target_desc): Forward declare. + (lynx_tdesc): Declare global. + * lynx-ppc-low.c (tdesc_powerpc_32): Declare global. + (lynx_ppc_arch_setup): Set `lynx_tdesc'. + * nto-low.c (nto_tdesc): New global. + (do_attach): Set the new process'es tdesc. + * nto-low.h (struct target_desc): Forward declare. + (nto_tdesc): Declare. + * nto-x86-low.c (tdesc_i386): Declare. + (nto_x86_arch_setup): Set `nto_tdesc'. + +2013-06-04 Gary Benson + + * server.c (handle_query): Add "augmented-libraries-svr4-read+" + to qSupported response when appropriate. + (handle_qxfer_libraries_svr4): Allow qXfer:libraries-svr4:read + with nonzero-length annex. + * linux-low.c (linux_qxfer_libraries_svr4): Parse and handle + arguments supplied in annex. + +2013-05-31 Doug Evans + + PR server/15594 + * linux-x86-low.c (ps_get_thread_area): Properly extend address to + 64 bits in 64-cross-32 environment. + +2013-05-28 Pedro Alves + + * Makefile.in (clean): Remove reference to aarch64-without-fpu.c. + (aarch64-without-fpu.c): Delete rule. + * configure.srv (aarch64*-*-linux*): Remove references to + aarch64-without-fpu.o and aarch64-without-fpu.xml. + * linux-aarch64-low.c (init_registers_aarch64_without_fpu): Remove + declaration. + +2013-05-24 Pedro Alves + + * server.c (handle_v_cont) : Use unpack_varlen_hex + instead of strchr/decode_address. Error if the range isn't split + with a ','. Don't assume there's be a ':' in the action. + +2013-05-23 Yao Qi + Pedro Alves + + * linux-low.c (lwp_in_step_range): New function. + (linux_wait_1): If the thread was range stepping and stopped + outside the stepping range, report the stop to GDB. Otherwise, + continue stepping. Add range stepping debug output. + (linux_set_resume_request): Copy the step range from the resume + request to the lwp. + (linux_supports_range_stepping): New. + (linux_target_ops) : Set to + linux_supports_range_stepping. + * linux-low.h (struct linux_target_ops) + : New field. + (struct lwp_info) : New fields. + * linux-x86-low.c (x86_supports_range_stepping): New. + (the_low_target) : Set to + x86_supports_range_stepping. + * server.c (handle_v_cont): Handle 'r' action. + (handle_v_requests): Append ";r" if the target supports range + stepping. + * target.h (struct thread_resume) : New fields. + (struct target_ops) : + New field. + (target_supports_range_stepping): New macro. + +2013-05-17 Joel Brobecker + + * lynx-low.c (lynx_resume): Fix null_ptid/minus_one_ptid + confusion in comment. + +2013-05-17 Joel Brobecker + + * lynx-low.c (struct process_info_private): New type. + (lynx_add_process): New function. + (lynx_create_inferior, lynx_attach): Replace calls to + add_process by calls to lynx_add_process. + (lynx_resume): If PTID is null, then try using + current_process()->private->last_wait_event_ptid. + Add comments. + (lynx_clear_inferiors): Delete. The contents of that function + has been inlined in lynx_mourn; + (lynx_wait_1): Save the ptid in the process's private data. + (lynx_mourn): Free the process' private data. Replace call + to lynx_clear_inferiors by call to clear_inferiors. + +2013-05-17 Yao Qi + + * i386-low.c (i386_length_and_rw_bits): Move the comment to + the right place. + +2013-05-16 Luis Machado + + * linux-low.c: Move definition checks upwards for PT_TEXT_ADDR, + PT_DATA_ADDR and PT_TEXT_END_ADDR. Update comments. + (linux_read_offsets): Remove PT_TEXT_ADDR, PT_DATA_ADDR and + PT_TEXT_END_ADDR guards. Update comments. + (linux_target_op) : Conditionally define to + linux_read_offsets if the target is UCLIBC and if it defines + PT_TEXT_ADDR, PT_DATA_ADDR and PT_TEXT_END_ADDR. + +2013-05-06 Sandra Loosemore + Andrew Jenner + + * Makefile.in (SFILES): Add linux-nios2-low.c. + (clean): Add action to delete nios2-linux.c. + (nios2-linux.c): New rule. + * configure.srv: Add nios2*-*-linux*. + * linux-nios2-low.c: New. + +2013-05-03 Hafiz Abid Qadeer + + * tracepoint.c (cmd_qtinit): Call 'stop_tracing'. + +2013-04-25 Hui Zhu + + PR gdb/15186 + * ax.c (ax_printf): Add fflush. + +2013-04-22 Tom Tromey + + * Makefile.in (SFILES): Add filestuff.c. + (OBS): Add filestuff.o. + (filestuff.o): New target. + * config.in, configure: Rebuild. + * configure.ac: Check for fdwalk, pipe2. + +2013-04-17 Pedro Alves + + * configure.ac (USE_THREAD_DB): Delete variable. + (if test "$srv_linux_thread_db" = "yes"): AC_DEFINE USE_THREAD_DB. + Don't AC_SUBST USE_THREAD_DB. + * Makefile.in (INTERNAL_CFLAGS): Remove @USE_THREAD_DB@. + * config.in, configure: Regenerate. + +2013-04-16 Pedro Alves + + * linux-low.h (struct lwp_info) : Move under + the USE_THREAD_DB #ifdef. + +2013-04-16 Pedro Alves + + * Makefile.in (INTERNAL_CFLAGS): Add @USE_THREAD_DB@. + (linux-low.o): Delete rule. + * linux-low.h: Always include "gdb_thread_db.h" instead of + conditionally including thread_db.h. + (struct lwp_info) : Guard with #ifdef USE_THREAD_DB instead of + HAVE_THREAD_DB_H. + +2013-04-07 Jan Kratochvil + + * Makefile.in (install-only): Fix make install regression. + +2013-04-05 Jan Kratochvil + + Convert man pages to texinfo, new gdbinit.5 texinfo page. + * Makefile.in (install-only): Remove $(man1dir) and gdbserver.1 + installation. + * gdbserver.1: Remove. + +2013-03-22 Pedro Alves + + * linux-low.c (handle_extended_wait): Don't call + linux_enable_event_reporting. + +2013-03-15 Tony Theodore + + PR build/9098: + * Makefile.in (SHELL): Use @SHELL@. + +2013-03-14 Sergio Durigan Junior + + * tracepoint.c (cmd_qtv): Initialize `val' with zero, silencing + compiler warning. + +2013-03-13 Joel Brobecker + + * linux-low.c (linux_target_ops) [!HAVE_LINUX_BTRACE]: + Remove extraneous NULL element. + +2013-03-13 Yao Qi + + * tracepoint.c (traceframe_read_tsv): Look for the last matched + 'V' block in trace frame. + +2013-03-11 Markus Metzger + + * target.h (struct target_ops): Add btrace ops. + (target_supports_btrace): New macro. + (target_enable_btrace): New macro. + (target_disable_btrace): New macro. + (target_read_btrace): New macro. + * gdbthread.h (struct thread_info): Add btrace field. + * server.c: Include btrace-common.h. + (handle_btrace_general_set): New function. + (handle_btrace_enable): New function. + (handle_btrace_disable): New function. + (handle_general_set): Call handle_btrace_general_set. + (handle_qxfer_btrace): New function. + (struct qxfer qxfer_packets[]): Add btrace entry. + * inferiors.c (remove_thread): Disable btrace. + * linux-low: Include linux-btrace.h. + (linux_low_enable_btrace): New function. + (linux_low_read_btrace): New function. + (linux_target_ops): Add btrace ops. + * configure.srv (i[34567]86-*-linux*): Add linux-btrace.o. + Add srv_linux_btrace=yes. + (x86_64-*-linux*): Add linux-btrace.o. + Add srv_linux_btrace=yes. + * configure.ac: Define HAVE_LINUX_BTRACE. + * config.in: Regenerated. + * configure: Regenerated. + +2013-03-11 Markus Metzger + + * server.c (handle_qxfer): Preserve error message if -3 is + returned. + (qxfer): Document the -3 return value. + +2013-03-11 Markus Metzger + + * Makefile.in (SFILES): Add $(srcdir)/common/linux-btrace.c. + (linux_btrace_h): New variable. + (linux-btrace.o): New rule. + +2013-03-08 Stan Shebs + Hafiz Abid Qadeer + + * tracepoint.c (trace_buffer_size): New global. + (DEFAULT_TRACE_BUFFER_SIZE): New define. + (init_trace_buffer): Change to one-argument function. Allocate + trace buffer memory. + (handle_tracepoint_general_set): Call cmd_bigqtbuffer_size to + handle QTBuffer:size packet. + (cmd_bigqtbuffer_size): New function. + (initialize_tracepoint): Call init_trace_buffer with + DEFAULT_TRACE_BUFFER_SIZE. + * server.c (handle_query): Add QTBuffer:size in the + supported packets. + +2013-03-07 Yao Qi + + * tracepoint.c (cur_action, cur_step_action): Make them unsigned. + (cmd_qtfp): Initialize cur_action and cur_step_action 0 instead + of -1. + (cmd_qtsp): Adjust condition. Do post increment. + Set cur_action and cur_step_action back to 0. + +2013-03-07 Jeremy Bennett + + PR server/15236 + * linux-low.c (linux_write_memory): Return early success if LEN is + zero. + +2013-03-05 Corinna Vinschen + + * configure.srv: Add x86_64-*-cygwin* as target. + +2013-02-28 Tom Tromey + + * configure.ac: Invoke AC_SYS_LARGEFILE. + * configure, config.in: Rebuild. + +2013-02-28 Corinna Vinschen + + * win32-low.c: Throughout, fix format strings and casts of + printf-like functions to avoid type related warnings on all + platforms. + (get_child_debug_event): Print dwDebugEventCode as hex since + that's how it's usually documented. + +2013-02-28 Yao Qi + + * tracepoint.c (cmd_qtbuffer): Call phex_nz instead of + pulongest. + +2013-02-27 Jiong Wang + + * Makefile.in (clean): Remove reg-tilegx.c, reg-tilegx32.c. + (reg-tilegx32.c): New rule. + * configure.srv (tilegx-*-linux*): Add reg-tilegx32.o to srv_regobj. + * linux-tile-low.c (tile_arch_setup): New function. Invoke + different register info initializer according to elf class. + (init_registers_tilgx32): New function. The tilegx32 register info + initializer. + (tile_fill_gregset): Use "uint_reg_t" to represent register size. + (tile_store_gregset): Likewise. + +2013-02-27 Yao Qi + + * server.c (process_point_options): Print debug message when + debug_threads is true. + +2013-02-26 Yao Qi + + * tracepoint.c (cmd_qtbuffer): Don't set '\0' in OWN_BUF. + +2013-02-19 Pedro Alves + Kai Tietz + + PR gdb/15161 + + * server.c (handle_query) : Use unpack_varlen_hex + instead of strtoul to extract address from packet. + (process_serial_event) <'z'>: Likewise. + +2013-02-18 Yao Qi + + * linux-bfin-low.c (the_low_target): Use NULL instead of 0. + +2013-02-14 Pedro Alves + + Plug memory leak. + + * tracepoint.c (cmd_qtnotes): Free TRACING_USER_NAME, + TRACING_NOTES and TRACING_STOP_NOTE before clobbering. + +2013-02-14 Pedro Alves + + * tracepoint.c (cmd_qtdpsrc): Use savestring. + +2013-02-14 Pedro Alves + + * tracepoint.c (save_string): Delete. + (add_tracepoint_action): Use savestring instead of save_string. + +2013-02-12 Pedro Alves + + * linux-xtensa-low.c: Ditto. + * xtensa-xtregs.c: Ditto. + +2013-02-12 Sanimir Agovic + + * thread-db.c (thread_db_get_tls_address): NULL pointer check + thread_db. + +2013-02-07 Marcus Shawcroft + + * linux-aarch64-low.c (aarch64_arch_setup): Clamp + aarch64_num_wp_regs and aarch64_num_bp_regs to + AARCH64_HWP_MAX_NUM and AARCH64_HBP_MAX_NUM respectively. + +2013-02-07 Marcus Shawcroft + + * linux-aarch64-low.c (ps_get_thread_area): Replace + PTRACE_GET_THREAD_AREA with PTRACE_GETREGSET. + +2013-02-04 Jim MacArthur + Marcus Shawcroft + Nigel Stephens + Yufeng Zhang + + * Makefile.in (clean): Remove aarch64.c and aarch64-without-fpu.c. + (aarch64.c, aarch64-without-fpu.c): New targets. + * configure.srv (aarch64*-*-linux*): New. + * linux-aarch64-low.c: New file. + +2013-02-04 Marcus Shawcroft + + * linux-low.c (handle_extended_wait, linux_create_inferior) + (linux_attach_lwp_1, linux_kill_one_lwp, linux_attach_one_lwp) + (dequeue_one_deferred_signal, linux_resume_one_thread) + (fetch_register, linux_write_memory, linux_enable_event_reporting) + (linux_tracefork_grandchild, linux_test_for_tracefork) + (linux_read_offsets, linux_xfer_siginfo, linux_xfer_siginfo): Add + PTRACE_ARG3_TYPE and PTRACE_ARG4_TYPE cast to ptrace arguments + where the argument is 0. + +2013-01-25 Yao Qi + + * event-loop.c: Include "queue.h". + (gdb_event_p): New typedef. + (struct gdb_event) : Remove. + (event_queue): Change to QUEUE(gdb_event_p). + (async_queue_event): Remove. + (gdb_event_xfree): New. + (initialize_event_loop): New. + (process_event): Use API from QUEUE. + (wait_for_event): Likewise. + * server.c (main): Call initialize_event_loop. + * server.h (initialize_event_loop): Declare. + +2013-01-18 Yao Qi + + * ax.h (struct eval_agent_expr_context): New. + (gdb_eval_agent_expr): Update declaration. + * ax.c (gdb_eval_agent_expr): Remove argument REGCACHE and + TFRAME. Add new argument CTX. + * server.h (struct eval_agent_expr_context): Declare. + (agent_mem_read, agent_tsv_read): Update declaration. + (agent_mem_read_string): Likewise. + * tracepoint.c (eval_tracepoint_agent_expr): Remove. + (add_traceframe_block): Add new argument TPOINT. + Increase TPOINT->traceframe_usage. + (do_action_at_tracepoint): Call gdb_eval_agent_expr instead of + eval_tracepoint_agent_expr. + (condition_true_at_tracepoint): Likewise. + (agent_mem_read): Remove argument TFRAME. Add argument CTX. + (agent_mem_read_string, agent_tsv_read): Likewise. + +2013-01-16 Yao Qi + + * linux-low.c (linux_resume_one_lwp): Don't check + 'lwp->bp_reinsert != 0'. + +2013-01-07 Joel Brobecker + Pedro Alves + + * lynx-low.c (ptrace_request_to_str): Define a temporary + macro and use it to simplify this function's implementation. + +2013-01-07 Joel Brobecker + + * lynx-low.c (lynx_resume): Call perror_with_name if lynx_ptrace + sets errno. + +2013-01-07 Joel Brobecker + + * configure.srv (i[34567]86-*-lynxos*): Set srv_xmlfiles. + +2013-01-07 Joel Brobecker + + * configure.srv (powerpc-*-lynxos*): Set srv_xmlfiles. + +2013-01-07 Joel Brobecker + + * lynx-low.c (lynx_resume): Use the resume_info parameter + to determine the ptid for the lynx_ptrace call, unless + it is equal to minus_one_ptid, in which case we use the + ptid of the current_inferior. + (lynx_wait_1): After having received a thread create/exit + event, resume the inferior's execution using the signaling + thread's ptid, rather than the old ptid. + +2013-01-07 Joel Brobecker + + * lynx-low.c (lynx_resume): Delete variable ret. + +2013-01-01 Joel Brobecker + + * gdbreplay.c (gdbreplay_version): Update copyright year. + * server.c (gdbserver_version): Likewise. + +2012-12-17 Joel Brobecker + + * lynx-low.c (lynx_wait_1): Add debug trace before adding + new thread. + +2012-12-17 Joel Brobecker + + * lynx-low.c (ptrace_request_to_str): Add handling for + PTRACE_GETTRACESIG. + +2012-12-17 Joel Brobecker + + * lynx-low.c (lynx_attach): Delete variable new_process. + +2012-12-17 Joel Brobecker + + * lynx-low.c (lynx_create_inferior): Delete variable + new_process. + +2012-12-17 Joel Brobecker + + * lynx-low.c (ptrace_request_to_str): Do not handle + PTRACE_GETTHREADLIST if this macro does not exist. + +2012-12-15 Yao Qi + + * Makefile.in (OBS): Add notif.o. + * notif.c, notif.h: New. + * server.c: Include "notif.h". + (struct vstop_notif) : Remove. + : New field. + (queue_stop_reply): Update. + (push_event, send_next_stop_reply): Remove. + (discard_queued_stop_replies): Update. + (notif_stop): New variable. + (handle_v_stopped): Remove. + (handle_v_requests): Don't call handle_v_stopped. Call + handle_ack_notif instead. + (queue_stop_reply_callback): Call notif_event_enque instead + of queue_stop_reply. + (handle_status): Don't call send_next_stop_reply, call + notif_write_event instead. + (kill_inferior_callback): Likewise. + (detach_or_kill_inferior_callback): Likewise. + (main): Call initialize_notif. + (process_serial_event): Call QUEUE_is_empty. + (handle_target_event): Call notif_push instead of push event. + * server.h (push_event): Remove declaration. + +2012-12-10 Tom Tromey + + * Makefile.in (DEPMODE, DEPDIR, depcomp, COMPILE.pre) + (COMPILE.post, COMPILE, POSTCOMPILE, IPAGENT_COMPILE): New + macros. + (.c.o): Rewrite. + (ax-ipa.o, tracepoint-ipa.o, utils-ipa.o, format-ipa.o) + (common-utils-ipa.o, remote-utils-ipa.o, regcache-ipa.o) + (i386-linux-ipa.o, linux-i386-ipa.o, linux-amd64-ipa.o) + (amd64-linux-ipa.o, ax.o): Rewrite. + (event-loop.o, hostio.o, hostio-errno.o, inferiors.o, mem-break.o) + (proc-service.o, regcache.o, remote-utils.o, server.o, target.o) + (thread-db.o, tracepoint.o, utils.o, gdbreplay.o, dll.o): Remove. + (signals.o, linux-procfs.o, linux-ptrace.o, common-utils.o, vec.o) + (gdb_vecs.o, xml-utils.o, linux-osdata.o, ptid.o, buffer.o) + (format.o, agent.o, vasprintf.o, vsnprintf.o): Rewrite. + (i386-low.o, i387-fp.o, linux-low.o, linux-arm-low.o) + (linux-bfin-low.o, linux-cris-low.o, linux-crisv32-low.o) + (linux-ia64-low.o, linux-m32r-low.o, linux-mips-low.o) + (linux-ppc-low.o, linux-s390-low.o, linux-sh-low.o) + (linux-tic6x-low.o, linux-x86-low.o, linux-xtensa-low.o) + (linux-tile-low.o, lynx-low.o, lynx-ppc-low.o, nto-low.o) + (nto-x86-low.o, linux-low.o, win32-low.o, win32-arm-low.o) + (win32-i386-low.o, spu-low.o, reg-arm.o, arm-with-iwmmxt.o) + (arm-with-vfpv2.o, arm-with-vfpv3.o, arm-with-neon.o, reg-bfin.o) + (reg-cris.o, reg-crisv32.o, i386.o, i386-linux.o, i386-avx.o) + (i386-avx-linux.o, i386-mmx.o, i386-mmx-linux.o, reg-ia64.o) + (reg-m32r.o, reg-m68k.o, reg-cf.o, mips-linux.o, mips-dsp-linux.o) + (mips64-linux.o, mips64-dsp-linux.o, powerpc-32.o, powerpc-32l.o) + (powerpc-altivec32l.o, powerpc-cell32l.o, powerpc-vsx32l.o) + (powerpc-isa205-32l.o, powerpc-isa205-altivec32l.o) + (powerpc-isa205-vsx32l.o, powerpc-e500l.o, powerpc-64l.o) + (powerpc-altivec64l.o, powerpc-cell64l.o, powerpc-vsx64l.o) + (powerpc-isa205-64l.o, powerpc-isa205-altivec64l.o) + (powerpc-isa205-vsx64l.o, s390-linux32.o, s390-linux32v1.o) + (s390-linux32v2.o, s390-linux64.o, s390-linux64v1.o) + (s390-linux64v2.o, s390x-linux64.o, s390x-linux64v1.o) + (s390x-linux64v2.o, tic6x-c64xp-linux.o, tic6x-c64x-linux.o) + (tic6x-c62x-linux.o, reg-sh.o, reg-sparc64.o, reg-spu.o, amd64.o) + (amd64-linux.o, amd64-avx.o, amd64-avx-linux.o, x32.o) + (x32-linux.o, x32-avx.o, x32-avx-linux.o, reg-xtensa.o) + (reg-tilegx.o): Remove. + (all_object_files): New macro. + Include .deps files. + * aclocal.m4, configure: Rebuild. + * acinclude.m4: Include depstand.m4, lead-dot.m4. + * configure.ac: Invoke ZW_CREATE_DEPDIR, + ZW_PROG_COMPILER_DEPENDENCIES. Compute GMAKE condition. + +2012-12-05 Tom Tromey + + PR gdb/14917: + * server.h (current_insn_ptr, emit_error): Declare 'extern'. + +2012-11-28 Markus Metzger + + * configure.ac: Check for linux/perf_event.h. + * config.in: Regenerated. + * configure: Regenerated. + +2012-11-26 Maxime Villard + + * hostio.c (handle_readlink): Decrease buffer size + parameter passed to readlink by one byte. + +2012-11-26 Yao Qi + + * configure.ac (build_warnings): Append '-Wempty-body'. + * configure: Regenerated. + * linux-low.c (linux_create_inferior): Use braces for empty 'if' + body. + +2012-11-15 Pierre Muller + + * configure.ac (AC_CHECK_HEADERS): Add wait.h header. + * config.in: Regenerate. + * configure: Regenerate. + * linux-low.c: Use "gdb_stat.h" header instead of header. + Use "gdb_wait.h" header instead of header. + * lynx-low.c: Use "gdb_wait.h" header instead of header. + * remote-utils.c: Use "gdb_stat.h" header instead of + header. + * server.c: Remove HAVE_WAIT_H conditional. Use "gdb_wait.h" header + instead of header. + * spu-low.c: Use "gdb_wait.h" header instead of header. + +2012-11-13 Markus Metzger + + * Makefile.in: (INTERNAL_CFLAGS): Add -DGDBSERVER + (various make rules): Remove -DGDBSERVER + +2012-11-09 Yao Qi + + * spu-low.c (current_ptid): Move it to .. + * gdbthread.h: ... here. New. + * remote-utils.c (read_ptid): Use macro 'current_ptid'. + * server.c (myresume, process_serial_event): Likewise. + * thread-db.c (thread_db_find_new_threads): Likewise. + * tracepoint.c (run_inferior_command): Likewise. + +2012-10-01 Andrew Burgess + + * server.c (handle_search_memory_1): Include access length in + warning message. + +2012-09-05 Michael Brandt + + * linux-crisv32-low.c: Fix compile errors. + +2012-09-04 Yao Qi + + * tracepoint.c (cmd_qtsv): Adjust debug message. + Don't check CUR_TPOINT. + +2012-08-28 Yao Qi + + * ax.c, tracepoint.c: Replace ATTR_FORMAT with ATTRIBUTE_PRINTF. + * server.h: Include 'libiberty.h' and 'ansidecl.h'. + (ATTR_NORETURN, ATTR_FORMAT, ATTR_MALLOC): Remove. + Remove declarations of xmalloc, xreallloc, xstrdup and + freeargv. + * Makefile.in (libiberty_h): New. + (server_h): Append dependencies 'libiberty.h' and 'ansidecl.h'. + (linux-bfin-low.o): Append dependency 'libiberty.h'. + +2012-08-23 Yao Qi + + * server.h: Remove declaration of 'xsnprintf'. + +2012-08-22 Keith Seitz + + * server.h: Include build-gnulib-gbserver/config.h. + * gdbreplay.c: Likewise. + +2012-08-08 Doug Evans + + * Makefile.in (SFILES): Add gdb_vecs.c. + (OBS): Add gdb_vecs.o. + (gdb_vecs_h, host_defs_h): New variables. + (thread-db.o): Add $(gdb_vecs_h) dependency. + (gdb_vecs.o): New rule. + * thread-db.c: #include "gdb_vecs.h". + (thread_db_load_search): Use a vector to iterate over path elements. + Handle text appearing after "$pdir". + + * configure.ac: Add check for strstr. + * config.in: Regenerate. + * configure: Regenerate. + +2012-08-02 Ulrich Weigand + + * hostio.c (handle_pread): If pread fails, fall back to attempting + lseek/read. + (handle_pwrite): Likewise for pwrite. + +2012-08-01 Ulrich Weigand + + * linux-arm-low.c (arm_linux_hw_point_initialize): Distinguish + between unsupported TYPE and unimplementable ADDR/LEN combination. + (arm_insert_point): Act on new return value. + +2012-07-31 Pedro Alves + + * server.c (process_point_options): Only skip tokens if we find + one that is unrecognized. Don't treat 'X' specially while + skipping unrecognized tokens. + +2012-07-30 Ulrich Weigand + + * linux-arm-low.c (arm_linux_hw_point_initialize): Do not attempt + to 4-byte-align HW breakpoint addresses for Thumb. + +2012-07-27 Yao Qi + + PR remote/14161. + + * server.h: Declare gdb_agent_about_to_close. + * target.c (kill_inferior): Include "agent.h". + New. Send command 'kill'. + * target.h (kill_inferior): Removed macro. + * tracepoint.c (gdb_agent_about_to_close): New. + (gdb_agent_helper_thread): Handle command 'close'. + Wait endlessly until the inferior stops. + Install gdb_agent_remove_socket to atexit hook. + (agent_socket_name): New static variable. + (gdb_agent_socket_init): Replace local variable 'name' with + 'agent_socket_name'. + (gdb_agent_remove_socket): New. + +2012-07-27 Yao Qi + + * server.c (process_point_options): Stop at 'X' when parsing. + +2012-07-19 Michael Eager + + * i386-low.c (Z_packet_to_hw_type): Add Z_PACKET_HW_BP, translate + to hw_execute. + * linux-x86-low.c (x86_insert_point, x86_remove_point): + Call i386_low_insert_watchpoint, i386_low_remove_watchpoint to add/del + hardware breakpoint. + +2012-07-07 Jan Kratochvil + + * gdbserver/linux-low.c (initialize_low): Call + linux_ptrace_init_warnings. + +2012-07-02 Doug Evans + + * mem-break.c (gdb_no_commands_at_breakpoint): Fix cast from + pointer to int. + +2012-07-02 Stan Shebs + + * Makefile.in (WARN_CFLAGS_NO_FORMAT): Define. + (ax.o): Add it to build rule. + (ax-ipa.o): Ditto. + (OBS): Add format.o. + (IPA_OBS): Add format.o. + * server.c (handle_query): Claim support for breakpoint commands. + (process_point_options): Add command case. + (process_serial_event): Leave running if there are printfs in + effect. + * mem-break.h (any_persistent_commands): Declare. + (add_breakpoint_commands): Declare. + (gdb_no_commands_at_breakpoint): Declare. + (run_breakpoint_commands): Declare. + * mem-break.c (struct point_command_list): New struct. + (struct breakpoint): New field command_list. + (any_persistent_commands): New function. + (add_commands_to_breakpoint): New function. + (add_breakpoint_commands): New function. + (gdb_no_commands_at_breakpoint): New function. + (run_breakpoint_commands): New function. + * linux-low.c (linux_wait_1): Test for and run breakpoint commands + locally. + * ax.c: Include format.h. + (ax_printf): New function. + (gdb_eval_agent_expr): Add printf opcode. + +2012-06-13 Yao Qi + + * server.c (start_inferior): Remove duplicated writes to fields + 'last_resume_kind' and 'last_status' of 'current_inferior'. + +2012-06-12 Yao Qi + Pedro Alves + + * linux-low.c (linux_set_resume_request): Simplify predicate. Add + comment. + * server.c (handle_v_cont): Extend comment. + +2012-06-11 Yao Qi + + * linux-low.c (linux_attach): Add 'static'. + +2012-06-06 Yao Qi + + * ax.c (gdb_eval_agent_expr): Print `top' in hex. + +2012-06-01 Jan Kratochvil + + Fix gcc -flto compilation warning. + * server.c (main): Make variable multi_mode and attach volatile. + +2012-05-30 Thiago Jung Bauermann + + * linux-low.c (get_r_debug): Disable code using DT_MIPS_RLD_MAP + if the platform doesn't know about it. + +2012-05-30 Jeff Kenton + + * Makefile.in (SFILES): Add linux-tile-low.c. + (linux-tile-low.o, reg-tilegx.o, reg-tilegx.c): New rules. + * configure.srv: Handle tilegx-*-linux*. + * linux-tile-low.c: New file. + +2012-05-28 Jan Kratochvil + + * linux-low.c (linux_qxfer_libraries_svr4): Return -1 if R_DEBUG is -1. + +2012-05-24 Pedro Alves + + PR gdb/7205 + + Replace TARGET_SIGNAL_ with GDB_SIGNAL_ throughout. + +2012-05-24 Pedro Alves + + PR gdb/7205 + + Replace target_signal with gdb_signal throughout. + +2012-05-22 Maciej W. Rozycki + + * linux-low.c (linux_store_registers): Avoid the copying sequence + when no data has been retrieved by ptrace. + +2012-05-22 Will Deacon + + * linux-low (__UCLIBC__ && !(__UCLIBC_HAS_MMU__ || __ARCH_HAS_MMU__)): + Include asm/ptrace.h. + (PT_TEXT_ADDR, PT_DATA_ADDR, PT_TEXT_END_ADDR): Define only if not + already defined. + +2012-05-21 Maciej W. Rozycki + + * linux-low.c (linux_store_registers): Don't re-retrieve data + with ptrace that has already been obtained from /proc. Always + copy any data retrieved with ptrace to the buffer supplied. + +2012-05-11 Yao Qi + Pedro Alves + + * linux-low.c (enum stopping_threads_kind): New. + (stopping_threads): Change type to `enum stopping_threads_kind'. + (handle_extended_wait): If stopping and suspending threads, leave + the new_lwp suspended too. + (linux_wait_for_event): Adjust. + (stop_all_lwps): Set `stopping_threads' to + STOPPING_AND_SUSPENDING_THREADS or STOPPING_THREADS depending on + whether we're suspending threads or just stopping them. Assert no + recursion happens. + +2012-04-29 Yao Qi + + * server.h: Move some code to ... + * gdbthread.h: ... here. New. + * Makefile.in (inferiors.o, regcache.o): Depends on gdbthread.h + (remote-utils.o, server.o, target.o tracepoint.o): Likewise. + (nto-low.o, win32-low.o): Likewise. + * inferiors.c, linux-low.h, nto-low.c: Include gdbthread.h. + * regcache.c, remote-utils.c, server.c: Likewise. + * target.c, tracepoint.c, win32-low.c: Likewise. + +2012-04-24 Thiago Jung Bauermann + + * linux-low.h (PTRACE_ARG3_TYPE): Move macro from linux-low.c. + (PTRACE_ARG4_TYPE): Likewise. + (PTRACE_XFER_TYPE): Likewise. + * linux-arm-low.c (arm_prepare_to_resume): Cast third argument of + ptrace to PTRACE_ARG3_TYPE. + * linux-low.c (PTRACE_ARG3_TYPE): Move macro to linux-low.h. + (PTRACE_ARG4_TYPE): Likewise. + (PTRACE_XFER_TYPE): Likewise. + (linux_detach_one_lwp): Cast fourth argument of + ptrace to long then PTRACE_ARG4_TYPE. + (regsets_fetch_inferior_registers): Cast third argument of + ptrace to long then PTRACE_ARG3_TYPE. + (regsets_store_inferior_registers): Likewise. + +2012-04-20 Pedro Alves + + * configure: Regenerate. + +2012-04-19 Pedro Alves + + * Makefile.in (GNULIB_BUILDDIR): New. + (LIBGNU, INCGNU, GNULIB_H): Adjust. + (SUBDIRS, CLEANDIRS, REQUIRED_SUBDIRS): New. + (all, install-only, uninstall, clean-info, all-lib, clean): No + longer pass GNULIB_FLAGS_TO_PASS. Use subdir_do. + (maintainer-clean realclean distclean): Use subdir_do. + (subdir_do): New. + (gnulib/import/Makefile): Adjust. Replace gnulib/import with + $(GNULIB_BUILDDIR). Don't pass argument to config.status. + * acinclude.m4: Include acx_configure_dir.m4. + * configure.ac: Remove gl_EARLY, gl_INIT, and AM_INIT_AUTOMAKE + calls. Call AC_PROG_RANLIB. Configure gnulib using + ACX_CONFIGURE_DIR. + (GNULIB): New. + (GNULIB_STDINT_H): Adjust. + (AC_OUTPUT): Don't output gnulib/Makefile anymore. + * gdbreplay.c: Include build-gnulib/config.h. + * server.h: Likewise. + * aclocal.m4: Regenerate. + * config.in: Regenerate. + * configure: Regenerate. + +2012-04-19 Pedro Alves + + * Makefile.in (LIBGNU, INCGNU): Adjust. + (GNULIB_FLAGS_TO_PASS, GNULIB_H): Adjust. + (all, install-only, uninstall, clean-info, all-lib, clean) + (maintainer-clean, Makefile, gnulib/Makefile): Adjust. + * configure.ac: Adjust AC_OUTPUT output. + * aclocal.m4: Regenerate. + * configure: Regenerate. + +2012-04-19 Pedro Alves + + * Makefile.in (generated_files): New. + (server_h): Remove the explicit dependency on config.h, and depend + on $generated_files. + +2012-04-19 Pedro Alves + + * Makefile.in (INCGNU): Add -Ignulib. + +2012-04-19 Pedro Alves + + * Makefile.in (GNULIB_INCLUDE_DIR): Rename to ... + (INCGNU): ... this, and spell out -I here. + (GNULIB_LIB): Rename to ... + (LIBGNU): ... this. + (INCLUDE_CFLAGS, gdbserver$(EXEEXT), $(GNULIB_LIB) rule): Adjust. + +2012-04-19 Pedro Alves + + * config.in: Regenerate. + +2012-04-19 Pedro Alves + + * configure.ac: Remove AC_CHECK_DECLS check for memmem. + * server.h (memmem): Remove declaration. + * config.in: Regenerate. + * configure: Regenerate. + +2012-04-19 Yao Qi + + * Makefile.in (SFILES): Add common/vec.c. + (OBS): Add vec.o. + (vec.o): New rule. + +2012-04-19 Yao Qi + + * remote-utils.c (prepare_resume_reply): Replace with macro + target_core_of_thread. + * server.c (handle_qxfer_threads_proper): Likewise. + * target.h (traget_core_of_thread): New macro. + +2012-04-18 Pedro Alves + + * aclocal.m4: Regenerate. + * configure: Regenerate. + +2012-04-16 Yao Qi + + * tracepoint.c (cmd_qtstart): Download tracepoints even when they are + duplicated on address. + +2012-04-16 Yao Qi + + * tracepoint.c (COPY_FIELD_TO_BUF): New macro. + (struct tracepoint_action_ops) : New field. + (m_tracepoint_action_send, r_tracepoint_action_send): New. + (agent_expr_send, x_tracepoint_action_send): New. + (l_tracepoint_action_send): New. + (cmd_qtdp): Download and install tracepoint + according to `use_agent'. + (run_inferior_command): Add one more parameter `len'. + Update callers. + (tracepoint_send_agent): New. + (cmd_qtdp, cmd_qtstart): Call tracepoint_send_agent. + +2012-04-16 Yao Qi + + * tracepoint.c (download_tracepoints): Moved to ... + (cmd_qtstart): ... here. + +2012-04-14 Yao Qi + + * tracepoint.c: Include inttypes.h. + (struct collect_memory_action): Use sized types. + (struct tracepoint): Likewise. + (cmd_qtdp, stop_tracing): Update print specifiers. + (cmd_qtp, response_tracepoint): Likewise. + (collect_data_at_tracepoint): Likewise. + (collect_data_at_step): Likewise. + +2012-04-14 Yao Qi + + Import gnulib module inttypes. + * aclocal.m4, config.in, configure: Regenerated. + +2012-04-14 Yao Qi + + * Makefile.in (maintainer-clean, realclean, distclean): Remove + Makefile and config.status at last. + +2012-04-13 Yao Qi + + * tracepoint.c: Include stdint.h unconditionally. + +2012-04-13 Thiago Jung Bauermann + + * acinclude.m4 (GDBSERVER_HAVE_THREAD_DB_TYPE): New macro based + on BFD_HAVE_SYS_PROCFS_TYPE. + * configure.ac: Look for lwpid_t and psaddr_t in libthread_db.h. + * configure: Regenerate. + * config.in: Likewise. + +2012-04-13 H.J. Lu + + * Makefile.in (clean): Also remove x32.c x32-linux.c + x32-avx.c x32-avx-linux.c. + (x32.o): New target. + (x32.c): Likewise. + (x32-linux.o): Likewise. + (x32-linux.c): Likewise. + (x32-avx.o): Likewise. + (x32-avx.c): Likewise. + (x32-avx-linux.o): Likewise. + (x32-avx-linux.c): Likewise. + + * configure.srv (srv_amd64_regobj): Add x32.o x32-avx.o. + (srv_amd64_linux_regobj): Add x32-linux.o x32-avx-linux.o. + (srv_i386_64bit_xmlfiles): Add i386/x32-core.xml. + (srv_amd64_xmlfiles): Add i386/x32.xml i386/x32-avx.xml. + (srv_amd64_linux_xmlfiles): Add i386/x32-linux.xml + i386/x32-avx-linux.xml. + + * linux-x86-low.c (init_registers_x32_linux): New prototype. + (init_registers_x32_avx_linux): Likwise. + (x86_linux_update_xmltarget): Call init_registers_x32_linux + or init_registers_x32_avx_linux if linux_is_elf64 is false. + +2012-04-13 Pedro Alves + + * Makefile.in (GNULIB_FLAGS_TO_PASS): New. + (FLAGS_TO_PASS): Don't change or set $top_srcdir, $srcdir and VPATH. + (all, uninstall, clean-info, all-lib, clean, maintainer-clean) + (realclean, distclean): Explicitly pass $GNULIB_FLAGS_TO_PASS to + the sub-make. + +2012-04-12 H.J. Lu + + * linux-x86-low.c (compat_x32_clock_t): New. + (compat_x32_siginfo_t): Likewise. + (compat_x32_siginfo_from_siginfo): Likewise. + (siginfo_from_compat_x32_siginfo): Likewise. + (linux_is_elf64): Likewise. + (x86_siginfo_fixup): Call compat_x32_siginfo_from_siginfo + and siginfo_from_compat_x32_siginfo for x32. + (x86_arch_setup): Set linux_is_elf64. + +2012-04-12 H.J. Lu + + PR gdb/13969 + * linux-low.c (linux_pid_exe_is_elf_64_file): Also return the + e_machine field. + (linux_qxfer_libraries_svr4): Update call to elf_64_file_p. + * linux-low.h (linux_pid_exe_is_elf_64_file): Updated. + * linux-x86-low.c (x86_arch_setup): Check if GDBserver is + compatible with process. + +2012-04-12 Yao Qi + + * Makefile.in: Define abs_top_srcdir and abs_srcdir. + (INCLUDE_CFLAGS): Append GNULIB_INCLUDE_DIR. + (install-only, install-info, clean): Handle sub dir gnulib. + (all-lib, am--refresh): New targets. + (memmem.o): Remove target. + * configure.ac: Remove AC_CONFIG_LIBOBJ_DIR. + Invoke gl_EARLY. Invoke AC_CHECK_PROGS for make. + (AC_REPLACE_FUNCS): Remove memmem. + Invoke gl_INIT and AM_INIT_AUTOMAKE. + (AC_OUTPUT): Generate Makefile in gnulib/. + * aclocal.m4, config.in, configure: Regenerated. + +2012-04-10 Maciej W. Rozycki + + * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP. + +2012-04-05 Pedro Alves + + -Werror=strict-aliasing + + * spu-low.c (parse_spufs_run): Avoid dereferencing type-punned + pointer. + +2012-04-04 Pedro Alves + + * linux-sparc-low.c (sparc_fill_gregset_to_stack) + (sparc_store_gregset_from_stack, sparc_store_gregset) + (sparc_breakpoint_at): Fix formatting. + +2012-03-30 Thiago Jung Bauermann + + * configure.ac: Check whether Elf32_auxv_t and Elf64_auxv_t + are available. + * linux-low.c [HAVE_ELF32_AUXV_T] (Elf32_auxv_t): Add typedef. + [HAVE_ELF64_AUXV_T] (Elf64_auxv_t): Likewise. + * config.in: Regenerate. + * configure: Likewise. + +2012-03-29 Pedro Alves + + * linux-low.c (regsets_store_inferior_registers) [__sparc__]: + Correct ptrace arguments. + +2012-03-28 Pedro Alves + + * linux-ia64-low.c (ia64_regmap): Map IA64_EC_REGNUM to PT_AR_EC. + (IA64_GR0_REGNUM, IA64_FR0_REGNUM) + (IA64_FR1_REGNUM): New defines. + (ia64_fetch_register): New. + (the_low_target): Install it. + * linux-low.h (struct linux_target_ops) : New + field. + * linux-low.c (linux_fetch_registers): Try the + the_low_target.fetch_register hook first. + + * linux-arm-low.c (the_low_target): Adjust. + * linux-bfin-low.c (the_low_target): Adjust. + * linux-cris-low.c (the_low_target): Adjust. + * linux-crisv32-low.c (the_low_target): Adjust. + * linux-m32r-low.c (the_low_target): Adjust. + * linux-m68k-low.c (the_low_target): Adjust. + * linux-mips-low.c (the_low_target): Adjust. + * linux-ppc-low.c (the_low_target): Adjust. + * linux-s390-low.c (the_low_target): Adjust. + * linux-sh-low.c (the_low_target): Adjust. + * linux-sparc-low.c (the_low_target): Adjust. + * linux-tic6x-low.c (the_low_target): Adjust. + * linux-x86-low.c (the_low_target): Adjust. + * linux-xtensa-low.c (the_low_target): Adjust. + +2012-03-26 Pedro Alves + + * server.c (handle_qxfer_libraries): Don't bail early if + the_target->qxfer_libraries_svr4 is not NULL. + +2012-03-26 Pedro Alves + + * linux-low.c (linux_qxfer_libraries_svr4): Fix pasto in comment. + +2012-03-23 Pedro Alves + + * linux-low.c (linux_qxfer_libraries_svr4): Terminate the + "library-list-svr4" element's start tag when the the DSO list is + empty. + +2012-03-23 Pedro Alves + + * linux-low.c (read_one_ptr): Read the inferior's pointer through + a variable whose type size is the same as the inferior's pointer + size. + +2012-03-21 Thomas Schwinge + + * linux-arm-low.c (arm_stopped_by_watchpoint): Use siginfo_t instead of + struct siginfo. + * linux-low.c (siginfo_fixup, linux_xfer_siginfo): Likewise. + * linux-x86-low.c (x86_siginfo_fixup): Likewise. + * linux-low.h: Include . + (struct siginfo): Remove forward declaration. + (struct linux_target_ops) : Use siginfo_t instead of + struct siginfo. + +2012-03-21 Mike Frysinger + + * .gitignore: Ignore more files. + +2012-03-19 Pedro Alves + Jan Kratochvil + + * server.c (cont_thread, general_thread): Add describing comments. + (start_inferior): Clear `cont_thread'. + (handle_v_cont): Don't set `cont_thread' if resuming all threads + of a process. + +2012-03-15 Yao Qi + + * tracepoint.c (install_tracepoint): Move duplicated tracepoint + handling to ... + (cmd_qtdp): ... here. + +2012-03-15 Yao Qi + + * tracepoint.c (struct tracepoint_action_ops): New. + (struct tracepoint_action) [!IN_PROCESS_AGENT] : New field. + (m_tracepoint_action_download): New. + (r_tracepoint_action_download): New. + (x_tracepoint_action_download): New. + (l_tracepoint_action_download): New. + (add_tracepoint_action): Install `action->ops' according type. + (download_tracepoint_1): Move code `download' function pointer + of various tracepoint_action_ops. + +2012-03-13 Jan Kratochvil + + * linux-low.c (linux_attach_lwp_1): New variable buffer. Call + linux_ptrace_attach_warnings. + +2012-03-13 Jan Kratochvil + + * Makefile.in (linux-ptrace.o): New. + * configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*) + (cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*) + (m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*) + (s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux) + (x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ + of these targets. + * linux-low.c (linux_attach_lwp_1): Remove redundent else clause. + +2012-03-08 Yao Qi + Pedro Alves + + Fix PR server/13392. + * linux-x86-low.c (amd64_install_fast_tracepoint_jump_pad): Check + offset of JMP insn. + * tracepoint.c (remove_tracepoint): New. + (cmd_qtdp): Call remove_tracepoint when failed to install. + +2012-03-07 Pedro Alves + + * linux-low.c (get_detach_signal): New. + (linux_detach_one_lwp): Get rid of a pending SIGSTOP with SIGCONT. + Pass on pending signals to PTRACE_DETACH. Check the result of the + ptrace call. + * server.c (program_signals, program_signals_p): New. + (handle_general_set): Handle QProgramSignals. + * server.h (program_signals, program_signals_p): Declare. + +2012-03-05 Pedro Alves + Jan Kratochvil + + * linux-low.c (get_dynamic): Don't warn when PT_PHDR isn't found. + New comment why. + +2012-03-03 Yao Qi + + * tracepoint.c (tracepoint_look_up_symbols): Update call to + agent_look_up_symbols. + +2012-03-03 Yao Qi + + * Makefile.in (linux-low.o): Keep dependence on agent.h. + (linux-x86-low.o): Likewise. + * server.h: Remove in_process_agent_loaded. + * tracepoint.c (in_process_agent_loaded): Removed. Moved it + common/agent.c. + Update callers. + +2012-03-03 Yao Qi + + * tracepoint.c (gdb_agent_capability): New global. + (in_process_agent_loaded_ust): Renamed to + `in_process_agent_supports_ust'. + Update callers. + (in_process_agent_supports_ust): Call agent_capability_check. + (clear_installed_tracepoints): Assert that agent supports + agent. + +2012-03-03 Yao Qi + + * linux-low.c (linux_supports_agent): New. + (linux_target_ops): Initialize field `supports_agent' with + linux_supports_agent. + * target.h (struct target_ops) : New. + (target_supports_agent): New macro. + * server.c (handle_general_set): Handle packet 'QAgent'. + (handle_query): Send `QAgent+'. + * Makefile.in (server.o): Depends on agent.h. + +2012-03-03 Yao Qi + + * Makefile.in (OBS): Add agent.o. + Add new rule for agent.o. + Track dependence of tracepoint.c on agent.h. + * tracepoint.c (run_inferior_command_1): + (run_inferior_command): Call agent_run_command. + (gdb_ust_connect_sync_socket): Deleted. Move it to + common/agent.c. + (resume_thread, stop_thread): Likewise. + (gdb_ust_socket_init): Renamed to ... + (gdb_agent_socket_init): ... New. + (gdb_ust_thread): Renamed to ... + (gdb_agent_helper_thread): ... New. + (gdb_ust_init): Move some code to ... + (gdb_agent_init): ... here. New. + [HAVE_UST]: Call gdb_ust_init. + (initialize_tracepoint_ftlib): Call gdb_agent_init. + * configure.ac: Add `sys/un.h' to AC_CHECK_HEADERS. + * config.in, configure: Regenerated. + +2012-03-02 Pedro Alves + + * inferiors.c (add_pid_to_list, pull_pid_from_list): Delete. + * linux-low.c (struct simple_pid_list): New. + (stopped_pids): New a struct simple_pid_list pointer. + (add_to_pid_list, pull_pid_from_list): New. + (handle_extended_wait): Don't assume the first signal new children + report is SIGSTOP. Adjust call to pull_pid_from_list. + (linux_wait_for_lwp): Adjust. + +2012-03-02 Yao Qi + + * tracepoint.c (do_action_at_tracepoint): Write `stop_pc' in + debug log. + +2012-03-02 Yao Qi + + * tracepoint.c (collect_ust_data_at_tracepoint): Remove parameters + `stop_pc' and `tpoint'. Update caller. + +2012-03-01 Maciej W. Rozycki + + * linux-low.h (linux_target_ops): Add regset_bitmap member. + * linux-low.c (use_linux_regsets): New macro. + [!HAVE_LINUX_REGSETS] (regsets_fetch_inferior_registers): Likewise. + [!HAVE_LINUX_REGSETS] (regsets_store_inferior_registers): Likewise. + (linux_register_in_regsets): New function. + (usr_fetch_inferior_registers): Skip registers covered by + regsets. + (usr_store_inferior_registers): Likewise. + (usr_fetch_inferior_registers): New macro. + (usr_store_inferior_registers): Likewise. + (linux_fetch_registers): Handle mixed regset/non-regset targets. + (linux_store_registers): Likewise. + * linux-mips-low.c (init_registers_mips_dsp_linux): New + prototype. + (init_registers_mips64_dsp_linux): Likewise. + (init_registers_mips_linux): New macro. + (init_registers_mips_dsp_linux): Likewise. + (mips_dsp_num_regs): Likewise. + (DSP_BASE, DSP_CONTROL): New fallback macros. + (mips_base_regs): New macro. + (mips_regmap): Use it. Fix the size. + (mips_dsp_regmap): New variable. + (mips_dsp_regset_bitmap): Likewise. + (mips_arch_setup): New function. + (mips_cannot_fetch_register): Use the_low_target.regmap rather + than mips_regmap. + (mips_cannot_store_register): Likewise. + (the_low_target): Update .arch_setup, .num_regs and .regmap + initializers. Add .regset_bitmap initializer. + * linux-arm-low.c (the_low_target): Add .regset_bitmap + initializer. + * linux-bfin-low.c (the_low_target): Likewise. + * linux-cris-low.c (the_low_target): Likewise. + * linux-crisv32-low.c (the_low_target): Likewise. + * linux-ia64-low.c (the_low_target): Likewise. + * linux-m32r-low.c (the_low_target): Likewise. + * linux-m68k-low.c (the_low_target): Likewise. + * linux-ppc-low.c (the_low_target): Likewise. + * linux-s390-low.c (the_low_target): Likewise. + * linux-sh-low.c (the_low_target): Likewise. + * linux-sparc-low.c (the_low_target): Likewise. + * linux-tic6x-low.c (the_low_target): Likewise. + * linux-x86-low.c (the_low_target): Likewise. + * linux-xtensa-low.c (the_low_target): Likewise. + * configure.srv : Add mips-dsp-linux.o and + mips64-dsp-linux.o to srv_regobj. Add mips-dsp-linux.xml, + mips64-dsp-linux.xml, mips-dsp.xml and mips64-dsp.xml to + srv_xmlfiles. + * Makefile.in (mips-dsp-linux.o, mips-dsp-linux.c): New targets. + (mips64-dsp-linux.o, mips64-dsp-linux.c): Likewise. + +2012-02-29 Yao Qi + Pedro Alves + + * linux-low.c: (linux_wait_1): Call unsuspend_all_lwps when + `step_over_finished' is true. + +2012-02-27 Pedro Alves + + * linux-low.c (pid_is_stopped): Delete, moved to common/. + (linux_attach_lwp_1): Adjust to use linux_proc_pid_is_stopped. + +2012-02-27 Pedro Alves + + PR server/9684 + * linux-low.c (pid_is_stopped): New. + (linux_attach_lwp_1): Handle attaching to 'T (stopped)' processes. + +2012-02-25 Luis Machado + + * mem-break.c (clear_gdb_breakpoint_conditions): Fix de-allocation + of conditions. + +2012-02-24 Maciej W. Rozycki + + * linux-mips-low.c (mips_regmap): Correct the index of $f9. + +2012-02-24 Luis Machado + + * server.c (handle_query): Advertise support for target-side + breakpoint condition evaluation. + (process_point_options): New function. + (process_serial_event): When inserting a breakpoint, check for + a target-side condition that should be evaluated. + + * mem-break.c: Include regcache.h and ax.h. + (point_cond_list_t): New data structure. + (breakpoint) : New field. + (find_gdb_breakpoint_at): Make non-static. + (delete_gdb_breakpoint_at): Clear any target-side + conditions. + (clear_gdb_breakpoint_conditions): New function. + (add_condition_to_breakpoint): Likewise. + (add_breakpoint_condition): Likewise. + (gdb_condition_true_at_breakpoint): Likewise. + (gdb_breakpoint_here): Return result directly instead + of going through a local variable. + + * mem-break.h (find_gdb_breakpoint_at): New prototype. + (clear_gdb_breakpoint_conditions): Likewise. + (add_breakpoint_condition): Likewise. + (gdb_condition_true_at_breakpoint): Likewise. + + * linux-low.c (linux_wait_1): Evaluate target-side breakpoint condition. + (need_step_over_p): Take target-side breakpoint condition into + consideration. + +2012-02-24 Luis Machado + + * server.h: Include tracepoint.h. + (agent_mem_read, agent_get_trace_state_variable_value, + agent_set_trace_state_variable_value, + agent_tsv_read, agent_mem_read_string, get_get_tsv_func_addr, + get_set_tsv_func_addr): New prototypes. + + * ax.h: New include file. + * ax.c: New source file. + + * tracepoint.c: Include ax.h. + (gdb_agent_op, gdb_agent_op_names, gdb_agent_op_sizes, + agent_expr, eval_result_type): Move to ax.h. + (parse_agent_expr): Rename to ... + (gdb_parse_agent_expr): ... this, make it non-static and move + to ax.h. + (unparse_agent_expr) Rename to ... + (gdb_unparse_agent_expr): ... this, make it non-static and move + to ax.h. + (eval_agent_expr): Rename to ... + (eval_tracepoint_agent_expr): ... this. + (agent_mem_read, agent_mem_read_string, agent_tsv_read): Remove + forward declarations. + (add_tracepoint_action): Call gdb_parse_agent_expr (...). + (agent_get_trace_state_variable_value): New function. + (agent_set_trace_state_variable_value): New function. + (cmd_qtdp): Call gdb_parse_agent_expr (...). + (response_tracepoint): Call gdb_unparse_agent_expr (...). + (do_action_at_tracepoint): Call eval_tracepoint_agent_expr (...). + (condition_true_at_tracepoint): Likewise. + (parse_agent_expr): Rename to ... + (gdb_parse_agent_expr): ... this and move to ax.c. + (unparse_agent_expr): Rename to ... + (gdb_unparse_agent_expr): ... this and move to ax.c. + (gdb_agent_op_name): Move to ax.c. + (eval_agent_expr): Rename to ... + (gdb_eval_agent_expr): ... this, use regcache passed as parameter + and move to ax.c. + (eval_tracepoint_agent_expr): New function. + (agent_mem_read, agent_mem_read_string, agent_tsv_read): Make + non-static. + (current_insn_ptr, emit_error, struct bytecode_address): Move to + ax.c. + (emit_prologue, emit_epilogue, emit_add, emit_sub, emit_mul, emit_lsh, + emit_rsh_signed, emit_rsh_unsigned, emit_ext, emit_log_not, + emit_bit_and, emit_bit_or, emit_bit_xor, emit_bit_not, emit_equal, + emit_less_signed, emit_less_unsigned, emit_ref, emit_if_goto, + emit_goto, write_goto_address, emit_const, emit_reg, emit_pop, + emit_stack, emit_zero_ext, emit_swap, emit_stack_adjust, + emit_int_call_1, emit_void_call_2, emit_eq_goto, emit_ne_goto, + emit_lt_goto, emit_ge_goto, emit_gt_goto, emit_le_goto): Move to ax.c. + (get_get_tsv_func_addr, get_set_tsv_func_addr): New functions. + (compile_bytecodes): Remove forward declaration. + (is_goto_target): Move to ax.c. + (compile_bytecodes): Move to ax.c and call + agent_get_trace_state_variable_value (...) and + agent_set_trace_state_variable_value (...). + + * Makefile.in: Update ax.c and IPA dependencies. + +2012-02-24 Pedro Alves + + * tracepoint.c (cmd_bigqtbuffer): Rename as ... + (cmd_bigqtbuffer_circular): ... this. Only handle + 'QTBuffer:circular:'. + (handle_tracepoint_general_set): Adjust. + +2012-02-16 Yao Qi + + * inferiors.c: Move code to ... + * dll.c: .... here. New. + * server.h: Declare clear_dlls. + * Makefile.in (SFILES): Add dll.c. + (OBS): Add dll.o + (dll.o): New rule. + +2012-02-11 Yao Qi + + * server.c: (handle_monitor_command): Add a new parameter + `own_buf'. + (handle_query): Update caller. + +2012-02-09 Joel Brobecker + + * configure.ac: Add readlink to AC_CHECK_FUNCS list. + * configure, config.in: Regenerate. + * hostio.c: Provide an alternate implementation if HAVE_READLINK + is not defined. + +2012-02-02 Pedro Alves + + Try SIGKILL first, then PTRACE_KILL. + * linux-low.c (linux_kill_one_lwp): New. + (linux_kill_one_lwp): Rename to ... + (kill_one_lwp_callback): ... this. Use the new + linux_kill_one_lwp. + +2012-02-02 Pedro Alves + + * tracepoint.c (cmd_qtminftpilen): Return 0 if there's no current + inferior. + +2012-01-27 Pedro Alves + + * linux-low.c (linux_child_pid_to_exec_file): Delete. + (elf_64_file_p): Make static. + (linux_pid_exe_is_elf_64_file): New. + * linux-low.h (linux_child_pid_to_exec_file, elf_64_file_p): + Delete declarations. + (linux_pid_exe_is_elf_64_file): Declare. + * linux-x86-low.c (x86_arch_setup): Use + linux_pid_exe_is_elf_64_file. + +2012-01-25 Jan Kratochvil + + * linux-low.c (linux_wait_for_event_1): Rename to ... + (linux_wait_for_event): ... here and merge it with former + linux_wait_for_event - new variable wait_ptid, use it. + (linux_wait_for_event): Remove - merge it to linux_wait_for_event_1. + +2012-01-23 Pedro Alves + + * server.c (main): Avoid yet another case of infinite loop while + detaching/killing after a longjmp. + +2012-01-20 Jan Kratochvil + + Code cleanup. + * linux-low.c (linux_wait_for_event_1): Use ptid_is_pid. + +2012-01-20 Ulrich Weigand + + * hostio.c (handle_readlink): New function. + (handle_vFile): Call it to handle "vFile:readlink" packets. + +2012-01-20 Pedro Alves + Ulrich Weigand + + * server.c (handle_v_requests): Only support vAttach and vRun to + start multiple processes when in extended protocol mode. + +2012-01-17 Pedro Alves + + * tracepoint.c (initialize_tracepoint): Use mmap instead of + memalign plus mprotect to allocate the scratch buffer. + +2012-01-13 Pedro Alves + + * server.c (attach_inferior): Clear `cont_thread'. + +2012-01-13 Pedro Alves + + * server.c (main): Avoid infinite loop while detaching/killing + after a longjmp. + +2012-01-09 Doug Evans + + * server.c (start_inferior): Set last_ptid in --wrapper case. + +2012-01-06 Yao Qi + + * tracepoint.c [IN_PROCESS_AGENT] (debug_threads): Macro + defined. + [IN_PROCESS_AGENT] (debug_agent): New global variable. + +2012-01-04 Yao Qi + + * tracepoint.c (cmd_qtdp): Print debug message + for static tracepoint. + +2012-01-04 Yao Qi + + * tracepoint.c (trace_vdebug): Differentiate debug message + between gdbserver and IPA. + +2012-01-03 Yao Qi + + * tracepoint.c (tracepoint_was_hit): Don't collect for + static tracepoint. + +2012-01-02 Joel Brobecker + + * terminal.h: Reformat copyright header. + +2012-01-02 Joel Brobecker + + * server.c (gdbserver_version): Update copyright year. + * gdbreplay.c (gdbreplay_version): Likewise. + +2011-12-18 Jan Kratochvil + + * linux-low.c (linux_create_inferior): Put empty if clause for write. + + Revert: + 2011-12-18 Hui Zhu + * linux-low.c (linux_create_inferior): Save return value to ret. + +2011-12-18 Hui Zhu + + * linux-low.c (linux_create_inferior): Save return value to ret. + +2011-12-16 Doug Evans + + * linux-low.c (linux_create_inferior): If stdio connection, + redirect stdin from /dev/null, stdout to stderr. + * remote-utils.c (remote_is_stdio): New static global. + (remote_connection_is_stdio): New function. + (remote_prepare): Handle stdio connection. + (remote_open): Ditto. + (remote_close): Don't close stdin for stdio connections. + (read_prim,write_prim): New functions. Replace all calls to + read/write to these. + * server.c (main): Watch for "-" argument. Move call to + remote_prepare before start_inferior. + * server.h (STDIO_CONNECTION_NAME): New macro. + (remote_connection_is_stdio): Declare. + + * remote-utils.c (prepare_resume_reply): Remove extraneous \n + in debugging output. + +2011-12-15 Yao Qi + + * tracepoint.c: Include sys/syscall.h. + (gdb_ust_thread): Remove preprocessor conditional. + +2011-12-14 Pedro Alves + + * linux-low.c (linux_detach_one_lwp): Call + the_low_target.prepare_to_resume before detaching. + +2011-12-14 Yao Qi + + * tracepoint.c (gdb_ust_thread): Don't ignore return value + of write. + +2011-12-14 Yao Qi + + * i386-low.c (i386_low_stopped_data_address): Initialize local + variable `control'. + +2011-12-13 Pedro Alves + + PR remote/13492 + + * i386-low.c (i386_low_stopped_data_address): Avoid fetching + DR_CONTROL unless necessary. Extend comments. + * linux-x86-low.c (x86_linux_prepare_to_resume): Don't write to + DR0-3 if not used. If any watchpoint was set, clear DR_STATUS. + +2011-12-13 Yao Qi + + * tracepoint.c (trace_buffer_alloc): Replace magic numbers with + macros. + (upload_fast_traceframes, upload_fast_traceframes): Likewise. + +2011-12-08 Jan Kratochvil + + * linux-low.c (linux_kill): Skip PTRACE_KILL if LWP does not exist. + Print new debug message for such case. + +2011-12-06 Jan Kratochvil + + Fix overlapping memcpy. + * mem-break.c (set_raw_breakpoint_at): New variable buf. Use it for + the read_inferior_memory transfer. + (delete_fast_tracepoint_jump): New variable buf. Use it for the + write_inferior_memory transfer. + (set_fast_tracepoint_jump): New variable buf. Use it for the + read_inferior_memory and write_inferior_memory transfers. + (uninsert_fast_tracepoint_jumps_at, reinsert_fast_tracepoint_jumps_at) + (delete_raw_breakpoint, uninsert_raw_breakpoint): New variable buf. + Use it for the write_inferior_memory transfer. + (check_mem_read, check_mem_write): New gdb_asserts for overlapping + buffers. + +2011-12-06 Maciej W. Rozycki + + * linux-low.c (fetch_register, store_register): Make code + consistent, fix formatting. + +2011-12-06 Maciej W. Rozycki + + * linux-low.c (usr_store_inferior_registers): Factor out code + to handle individual registers into... + (store_register): ... this new function. + +2011-12-06 Ulrich Weigand + + * Makefile.in (s390-linux32v1.o, s390-linux32v1.c): New rules. + (s390-linux32v2.o, s390-linux32v2.c): Likewise. + (s390-linux64v1.o, s390-linux64v1.c): Likewise. + (s390-linux64v2.o, s390-linux64v2.c): Likewise. + (s390x-linux64v1.o, s390x-linux64v1.c): Likewise. + (s390x-linux64v2.o, s390x-linux64v2.c): Likewise. + * configure.srv [s390*-*-linux*] (srv_regobj): Add new objects. + (srv_xmlfiles): Add new XML files. + + * linux-s390-low.c: Include "elf/common.h", , + and . + (PTRACE_GETREGSET, PTRACE_SETREGSET): Define if undefined. + (init_registers_s390_linux32v1): Add prototype. + (init_registers_s390_linux32v2): Likewise. + (init_registers_s390_linux64v1): Likewise. + (init_registers_s390_linux64v2): Likewise. + (init_registers_s390x_linux64v1): Likewise. + (init_registers_s390x_linux64v2): Likewise. + (s390_num_regs): Increment to 52. + (s390_regmap): Add orig_r2 register. + (s390_num_regs_3264): Increment to 68. + (s390_regmap_3264): Add orig_r2 register. + (s390_collect_ptrace_register): Handle orig_r2 register. + (s390_supply_ptrace_register): Likewise. + (s390_fill_last_break): New function. + (s390_store_last_break): Likewise. + (s390_fill_system_call): New function. + (s390_store_system_call): Likewise. + (target_regsets): Handle NT_S390_LAST_BREAK and NT_S390_SYSTEM_CALL + register sets. + (s390_check_regset): New function. + (s390_arch_setup): Check for presence of NT_S390_LAST_BREAK and + NT_S390_SYSTEM_CALL regsets and use appropriate description. + Update target_regsets for available register sets. + +2011-12-02 Paul Pluzhnikov + Jan Kratochvil + + * linux-low.c (get_phdr_phnum_from_proc_auxv, get_dynamic, get_r_debug) + (read_one_ptr, struct link_map_offsets, linux_qxfer_libraries_svr4): + New. + (struct linux_target_ops): Install linux_qxfer_libraries_svr4. + * linux-low.h (struct process_info_private): New member r_debug. + * server.c (handle_qxfer_libraries): Call + the_target->qxfer_libraries_svr4. + (handle_qxfer_libraries_svr4): New function. + (qxfer_packets): New entry "libraries-svr4". + (handle_query): Check QXFER_LIBRARIES_SVR4 and report libraries-svr4. + * target.h (struct target_ops): New member qxfer_libraries_svr4. + * remote.c (remote_xfer_partial): Call add_packet_config_cmd for + PACKET_qXfer_libraries_svr4. + +2011-11-30 Ulrich Weigand + + * linux-s390-low.c (s390_collect_ptrace_register): Fully convert + PSW address/mask between 8-byte and 16-byte formats. + (s390_supply_ptrace_register): Likewise. + (s390_get_pc, s390_set_pc): 4-byte PSW address always includes + basic addressing mode bit. + +2011-11-24 Stan Shebs + + * tracepoint.c (cmd_qtstatus): Use plongest instead of %llx. + +2011-11-17 Stan Shebs + + * tracepoint.c (struct tracepoint): New field traceframe_usage. + (tracing_start_time): New global. + (tracing_stop_time): New global. + (tracing_user_name): New global. + (tracing_notes): New global. + (tracing_stop_note): New global. + (cmd_qtstart): Set traceframe_usage, start_time. + (stop_tracing): Set stop_time. + (cmd_qtstatus): Report additional status. + (cmd_qtp): New function. + (handle_tracepoint_query): Call it. + (cmd_qtnotes): New function. + (handle_tracepoint_general_set): Call it. + (get_timestamp): Rename from tsv_get_timestamp. + +2011-11-14 Stan Shebs + Kwok Cheung Yeung + + * linux-x86-low.c (small_jump_insn): New. + (i386_install_fast_tracepoint_jump_pad): Add arguments for + trampoline and error message, build a trampoline and issue a small + jump instruction to it. + (x86_install_fast_tracepoint_jump_pad): Add arguments for + trampoline and error message. + (x86_get_min_fast_tracepoint_insn_len): New. + (the_low_target): Add call to x86_get_min_fast_tracepoint_insn_len. + * linux-low.h (struct linux_target_ops): Add arguments to + install_fast_tracepoint_jump_pad operation, add new operation. + * linux-low.c (linux_install_fast_tracepoint_jump_pad): Add + arguments. + (linux_get_min_fast_tracepoint_insn_len): New function. + (linux_target_op): Add new operation. + * tracepoint.c (gdb_trampoline_buffer): New IPA variable. + (gdb_trampoline_buffer_end): Ditto. + (gdb_trampoline_buffer_error): Ditto. + (struct ipa_sym_addresses): Add fields for new IPA variables. + (symbol_list): Add entries for new IPA variables. + (struct tracepoint): Add fields to hold the address range of the + trampoline used by the tracepoint. + (trampoline_buffer_head): New static variable. + (trampoline_buffer_tail): Ditto. + (claim_trampoline_space): New function. + (have_fast_tracepoint_trampoline_buffer): New function. + (clone_fast_tracepoint): Fill in trampoline fields of tracepoint + structure. + (install_fast_tracepoint): Ditto, also add error buffer argument. + (cmd_qtminftpilen): New function. + (handle_tracepoint_query): Add response to qTMinFTPILen packet. + (fast_tracepoint_from_trampoline_address): New function. + (fast_tracepoint_collecting): Handle trampoline as part of jump + pad space. + (set_trampoline_buffer_space): New function. + (initialize_tracepoint): Initialize new IPA variables. + * target.h (struct target_ops): Add arguments to + install_fast_tracepoint_jump_pad operation, add new + get_min_fast_tracepoint_insn_len operation. + (target_get_min_fast_tracepoint_insn_len): New. + (install_fast_tracepoint_jump_pad): Add arguments. + * server.h (IPA_BUFSIZ): Define. + * linux-i386-ipa.c: Include extra header files. + (initialize_fast_tracepoint_trampoline_buffer): New function. + (initialize_low_tracepoint): Call it. + * server.h (set_trampoline_buffer_space): Declare. + (claim_trampoline_space): Ditto. + (have_fast_tracepoint_trampoline_buffer): Ditto. + +2011-11-14 Yao Qi + + * server.c (handle_query): Handle InstallInTrace for qSupported. + * tracepoint.c (add_tracepoint): Sort list. + (install_tracepoint, download_tracepoint): New. + (cmd_qtdp): Call them to install and download tracepoints. + (sort_tracepoints): Removed. + (cmd_qtstart): Update. + +2011-11-14 Yao Qi + + * mem-break.c (inc_ref_fast_tracepoint_jump): New. + * mem-break.h: Declare. + * tracepoint.c (cmd_qtstart): Move some code to ... + (clone_fast_tracepoint, install_fast_tracepoint): ... here. + New. + (download_tracepoints): Move some code to ... + (download_tracepoint_1): ... here. New. + +2011-11-08 Yao Qi + + * remote-utils.c (relocate_instruction): A comment fix. + +2011-11-07 Joel Brobecker + + * win32-i386-low.c (dr_status_mirror, dr_control_mirror): Delete. + (i386_dr_low_get_control, i386_dr_low_get_status): Use + dr_status_mirror and dr_control_mirror from debug_reg_state. + (i386_dr_low_get_status): Use debug_reg_state.dr_status_mirror + (i386_initial_stuff): Remove use of deleted globals. + (i386_get_thread_context, i386_set_thread_context, + i386_thread_added): Use dr_status_mirror and dr_control_mirror + from debug_reg_state. + +2011-11-05 Yao Qi + + * tracepoint.c (gdb_collect): Loop over tracepoints of same + address as TPOINT's. + +2011-11-02 Stan Shebs + + * tracepoint.c (agent_mem_read_string): New function. + (eval_agent_expr): Call it for tracenz. + * server.c (handle_query): Report support for tracenz. + +2011-11-02 Yao Qi + + * tracepoint.c (cmd_qtstart): Remove unused local variables. + +2011-11-02 Yao Qi + + * target.h: Fix a typo in comment. + +2011-10-31 Pedro Alves + + * mem-break.c (check_mem_write): Add `myaddr' parameter. Don't + clobber the breakpoints' shadows with fast tracepoint jumps. + * mem-break.h (check_mem_write): Add `myaddr' parameter. + * target.c (write_inferior_memory): Also pass MYADDR down to + check_mem_write. + +2011-10-07 Ulrich Weigand + + * configure.ac: Check support for personality routine. + * configure: Regenerate. + * config.in: Likewise. + * linux-low.c: Include . + Define ADDR_NO_RANDOMIZE if necessary. + (linux_create_inferior): Disable address space randomization when + forking inferior, if requested. + (linux_supports_disable_randomization): New function. + (linux_target_ops): Install it. + * server.h (disable_randomization): Declare. + * server.c (disable_randomization): New global variable. + (handle_general_set): Handle QDisableRandomization. + (handle_query): Likewise for qSupported. + (main): Support --disable-randomization and --no-disable-randomization + command line arguments. + * target.h (struct target_ops): Add supports_disable_randomization. + (target_supports_disable_randomization): New macro. + +2011-09-29 Mike Frysinger + + * linux-low.c (target_loadseg): Add defined PTRACE_GETFDPIC to the + ifdef check. + [PT_GETDSBT] (target_loadmap): Wrap in a defined PT_GETDSBT check. + [!PT_GETDSBT] (target_loadmap): New definition. + (LINUX_LOADMAP, LINUX_LOADMAP_EXEC, LINUX_LOADMAP_INTERP): Define. + (linux_read_loadmap): Change PTRACE_GETDSBT_EXEC to + LINUX_LOADMAP_EXEC, PTRACE_GETDSBT_INTERP to LINUX_LOADMAP_INTERP, + and PT_GETDSBT to LINUX_LOADMAP. + [!PT_GETDSBT] (linux_read_loadmap): Define to NULL. + (linux_target_ops): Delete unnecessary ifdef PT_GETDSBT check. + +2011-09-21 Ulrich Weigand + + * linux-arm-low.c (struct arm_linux_hwbp_cap): Remove. + (arm_linux_hwbp_cap): New static variable. + (arm_linux_get_hwbp_cap): Replace by ... + (arm_linux_init_hwbp_cap): ... this new function. + (arm_linux_get_hw_breakpoint_count): Use arm_linux_hwbp_cap. + (arm_linux_get_hw_watchpoint_count): Likewise. + (arm_linux_get_hw_watchpoint_max_length): Likewise. + (arm_arch_setup): Call arm_linux_init_hwbp_cap. + (arm_prepare_to_resume): Use perror_with_name instead of error. + +2011-09-21 Ulrich Weigand + + * linux-arm-low.c: Include . + (PTRACE_GETHBPREGS, PTRACE_SETHBPREGS): Define if necessary. + (struct arm_linux_hwbp_cap): New data type. + (arm_hwbp_type, arm_hwbp_control_t): New typedefs. + (struct arm_linux_hw_breakpoint): New data type. + (MAX_BPTS, MAX_WPTS): Define. + (struct arch_process_info, struct arch_lwp_info): New data types. + (arm_linux_get_hwbp_cap): New function. + (arm_linux_get_hw_breakpoint_count): Likewise. + (arm_linux_get_hw_watchpoint_count): Likewise. + (arm_linux_get_hw_watchpoint_max_length): Likewise. + (arm_hwbp_control_initialize): Likewise. + (arm_hwbp_control_is_enabled): Likewise. + (arm_hwbp_control_is_initialized): Likewise. + (arm_hwbp_control_disable): Likewise. + (arm_linux_hw_breakpoint_equal): Likewise. + (arm_linux_hw_point_initialize): Likewise. + (struct update_registers_data): New data structure. + (update_registers_callback: New function. + (arm_insert_point): Likewise. + (arm_remove_point): Likewise. + (arm_stopped_by_watchpoint): Likewise. + (arm_stopped_data_address): Likewise. + (arm_new_process): Likewise. + (arm_new_thread): Likewise. + (arm_prepare_to_resume): Likewise. + (the_low_target): Register arm_insert_point, arm_remove_point, + arm_stopped_by_watchpoint, arm_stopped_data_address, arm_new_process, + arm_new_thread, and arm_prepare_to_resume. + +2011-09-15 Stan Shebs + + * server.h (struct emit_ops): Add compare-goto fields. + * tracepoint.c (gdb_agent_op_sizes): New table. + (emit_eq_goto): New function. + (emit_ne_goto): New function. + (emit_lt_goto): New function. + (emit_le_goto): New function. + (emit_gt_goto): New function. + (emit_ge_goto): New function. + (is_goto_target): New function. + (compile_bytecodes): Recognize special cases of compare-goto + combinations and call specialized emitters for them. + * linux-x86-low.c (amd64_emit_eq_goto): New function. + (amd64_emit_ne_goto): New function. + (amd64_emit_lt_goto): New function. + (amd64_emit_le_goto): New function. + (amd64_emit_gt_goto): New function. + (amd64_emit_ge_goto): New function. + (amd64_emit_ops): Add the new functions. + (i386_emit_eq_goto): New function. + (i386_emit_ne_goto): New function. + (i386_emit_lt_goto): New function. + (i386_emit_le_goto): New function. + (i386_emit_gt_goto): New function. + (i386_emit_ge_goto): New function. + (i386_emit_ops): Add the new functions. + +2011-09-08 Stan Shebs + + * linux-x86-low.c (i386_emit_prologue): Save %ebx. + (i386_emit_epilogue): Restore %ebx. + +2011-08-31 Jie Zhang + + * server.c (step_thread): Remove definition. + (process_serial_event): Don't handle Hs. + * server.h (step_thread): Remove declaration. + * target.c (set_desired_inferior): Remove use of step_thread. + +2011-08-24 Luis Machado + + * linux-low.c: Include linux-procfs.h. + (linux_attach_lwp_1): Update comments. + (linux_attach): Scan for existing threads when attaching to a + process that is the tgid. + * Makefile.in: Update dependencies. + +2011-08-24 Luis Machado + + * configure.srv: Add linux-procfs.o dependencies. + +2011-08-14 Yao Qi + + * target.h (struct target_ops): Fix indent. + * win32-low.c (win32_target_ops): Fix comment. + +2011-08-14 Andrew Jenner + Yao Qi + + * Makefile.in (clean): Remove tic6x-*.c files. + (linux-tic6x-low.o, tic6x-c62x-linux.o, tic6x-c64x-linux.o): New rules. + (tic6x-c64xp-linux.o, tic6x-c62x-linux.c, tic6x-c64x-linux.c): Likewise. + (tic6x-c64xp-linux.c): Likewise. + * configure.srv: Add support for tic6x-*-uclinux. + * linux-tic6x-low.c: New. + * linux-low.c (PT_TEXT_ADDR, PT_DATA_ADDR, PT_TEXT_END_ADDR): Define. + +2011-08-14 Andrew Stubbs + Yao Qi + + * target.h (struct target_ops): Add read_loadmap. + * linux-low.c (struct target_loadseg): New type. + (struct target_loadmap): New type. + (linux_read_loadmap): New function. + (linux_target_ops): Add linux_read_loadmap. + * server.c (handle_query): Support qXfer:fdpic:read packet. + * win32-low.c (win32_target_ops): Initialize field `read_loadmap' + to NULL. + +2011-08-05 Eli Zaretskii + + * win32-low.c: Include . + +2011-07-22 Pedro Alves + + * i386-low.c (i386_insert_aligned_watchpoint): Don't pass the info + to the inferior here. + (i386_remove_aligned_watchpoint): Ditto. + (i386_handle_nonaligned_watchpoint): Return immediate on fail to + fit part of the watchpoint in the debug registers. + (i386_update_inferior_debug_regs): New. + (i386_low_insert_watchpoint): Work on a local mirror of the debug + registers, and only update the inferior on success. + (i386_low_remove_watchpoint): Ditto. + +2011-07-22 Kwok Cheung Yeung + + * linux-low.c (compare_ints, unique, list_threads, show_process, + linux_core_of_thread): Delete. + (linux_target_ops): Change linux_core_of_thread to + linux_common_core_of_thread. + (linux_qxfer_osdata): Defer to linux_common_xfer_osdata. + * utils.c (malloc_failure): Change type of argument. + (xmalloc, xrealloc, xcalloc, xsnprintf): Delete. + * Makefile.in (SFILES): Add common/common-utils.c, common/xml-utils.c, + common/linux-osdata.c, common/ptid.c and common/buffer.c. + (OBS): Add xml-utils.o, common-utils.o, ptid.o and buffer.o. + (IPA_OBJS): Add common-utils-ipa.o. + (ptid_h, linux_osdata_h): New macros. + (server_h): Add common/common-utils.h, common/xml-utils.h, + common/buffer.h, common/gdb_assert.h, common/gdb_locale.h and + common/ptid.h. + (common-utils-ipa.o, common-utils.o, xml-utils.o, linux-osdata.o, + ptid.o, buffer.o): New rules. + (linux-low.o): Add common/linux-osdata.h as a dependency. + * configure.srv (srv_tgtobj): Add linux-osdata.o to Linux targets. + * configure.ac: Add AC_HEADER_DIRENT check. + * config.in: Regenerate. + * configure: Regenerate. + * remote-utils.c (xml_escape_text): Delete. + (buffer_grow, buffer_free, buffer_init, buffer_finish, + buffer_xml_printf): Move to common/buffer.c. + * server.c (main): Remove call to initialize_inferiors. + * server.h (struct ptid, ptid_t, minus_one_ptid, null_ptid, + ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp, ptid_get_tid, + ptid_equal, ptid_is_pid, initialize_inferiors, xml_escape_text, + internal_error, gdb_assert, gdb_assert_fail): Delete. + (struct buffer, buffer_grow, buffer_free, buffer_init, buffer_finish, + buffer_xml_printf, buffer_grow_str, buffer_grow_str0): Move to + common/buffer.h. + * inferiors.c (null_ptid, minus_one_ptid, ptid_build, pid_to_ptid, + ptid_get_pid, ptid_get_lwp, ptid_get_tid, ptid_equal, ptid_is_pid, + initialize_inferiors): Delete. + +2011-07-20 Pedro Alves + + * tracepoint.c (tracepoint_look_up_symbols): Return upon the first + symbol error. + +2011-05-31 Pedro Alves + + * linux-x86-low.c (i386_dr_low_get_addr): Fix off by one in + assertion. + * win32-i386-low.c (i386_dr_low_get_addr): Ditto. + +2011-05-26 Yao Qi + + * Makefile.in (thread-db.o): Track dependence to + common/gdb_thread_db.h. + * thread-db.c: include gdb_thread_db.h from right place. + +2011-05-16 Adrian Cornish + + * linux-i386-ipa.c (supply_static_tracepoint_registers): Pass + __FILE__ and __LINE__ to internal_error. + +2011-05-13 Doug Evans + + * thread-db.c (try_thread_db_load_from_sdir): New function. + (try_thread_db_load_from_dir): New function. + (thread_db_load_search): Handle $sdir, ignore $pdir. + Remove trying of system directories if search of + libthread-db-search-path fails, that is now done via $sdir. + +2011-05-12 Kwok Cheung Yeung + + * server.c (handle_query): Add EnableDisableTracepoints to the list + of supported features. + * tracepoint.c (clear_installed_tracepoints): Uninstall disabled + tracepoints. + (cmd_qtenable_disable): New. + (cmd_qtstart): Install tracepoints even if disabled. + (handle_tracepoint_general_set): Add call to cmd_qtenable_disable on + receiving a QTEnable or QTDisable packet. + (gdb_collect): Skip data collection if fast tracepoint is disabled. + (ust_marker_to_static_tracepoint): Do not ignore disabled static + tracepoints. + (gdb_probe): Skip data collection if static tracepoint is disabled. + +2011-05-10 Doug Evans + + * thread-db.c (thread_db_handle_monitor_command): Handle elided path. + +2011-05-04 Doug Evans + + * linux-low.c (linux_join): Skip process lookup. + * spu-low.c (spu_join): Ditto. + * server.c (join_inferiors_callback): Delete. + (process_serial_event): For 'D' packet (detach) call join_inferior + directly. + +2011-05-04 Joseph Myers + + * README: Don't mention xscale*-*-linux*. + * configure.srv (xscale*-*-linux*): Don't handle target. + +2011-04-27 Nathan Froyd + + * linux-x86-low.c (amd64_emit_const): Call memcpy instead of + casting pointers. + (amd64_emit_reg, amd64_emit_int_call_1, amd64_emit_void_call_2): + (i386_emit_const, i386_emit_reg, i386_emit_int_call_1): + (i386_emit_void_call_2): Likewise. + +2011-04-26 Yao Qi + + * linux-low.c: Move common macros to linux-ptrace.h. + Include linux-ptrace.h. + * Makefile.in (linux_ptrace_h): New. + (linux-low.o): Depends on linux-ptrace.h. + +2011-04-24 Jan Kratochvil + + * remote-utils.c (handle_accept_event): Close LISTEN_DESC only if + RUN_ONCE. Comment for the LISTEN_DESC delete_file_handler call. + (remote_prepare): New function with most of the TCP code from ... + (remote_open): ... here. Detect PORT here unconditionally. Move also + setting transport_is_reliable. + * server.c (run_once): New variable. + (gdbserver_usage): Document it. + (main): Set run_once for `--once'. Call remote_prepare. Exit after + the first run if RUN_ONCE. + * server.h (run_once, remote_prepare): New declarations. + +2011-04-19 Tom Tromey + + * win32-low.c (handle_load_dll): Remove duplicate "the". + +2011-04-07 Pierre Muller + + Remove support for old Cygwin 1.5 versions. + * win32-low.c (win32_create_inferior): Use new cygwin_path_list + function to avoid warning. + (win32_add_one_solib): Use cygwin_conv_path function to avoid + warning. + +2011-03-18 Pierre Muller + + * gdbserver/server.h (Macro _): Define it if not available. + +2011-03-14 Michael Snyder + + * hostio.c (handle_close): Remove unnecessary null test. + +2011-03-10 Joel Brobecker + + * Makefile.in (maintainer-clean realclean distclean): Remove + "make ... subdir_do" command. + +2011-03-10 Michael Snyder + + * tracepoint.c (tracepoint_finish_step): Fix loop variable. + + * server.c (handle_v_run): Free alloced buffer on early return. + +2011-03-09 Yao Qi + + Revert: + 2011-03-04 Yao Qi + + * Makefile.in: Remove GNU make feature --directory. + + 2011-03-05 Yao Qi + + * Makefile.in (CLEANDIRS, REQUIRED_SUBDIRS): New variable. + (subdir_do): New make target. Copied from gdb/Makefile. + (maintainer-clean, realclean, distclean, clean): Call corresponding + make targets in common/Makefile. + + 2011-02-11 Yao Qi + + * configure.ac: Call AC_PROG_RANLIB. + * Makefile.in: Remove signals.o from OBS. Link libcommon.a. + * configure: Regenerate. + +2011-03-07 Jan Kratochvil + + * remote-utils.c (putpkt_binary_1): Calculate BUF2 size dynamically. + +2011-03-06 Yao Qi + + * Makefile.in (REQUIRED_SUBDIRS): Remove $(LIBCOMMON_DIR). + +2011-03-05 Yao Qi + + * Makefile.in (CLEANDIRS, REQUIRED_SUBDIRS): New variable. + (subdir_do): New make target. Copied from gdb/Makefile. + (maintainer-clean, realclean, distclean, clean): Call corresponding + make targets in common/Makefile. + +2011-03-04 Yao Qi + + * Makefile.in: Remove GNU make feature --directory. + +2011-03-04 Michael Snyder + + * server.c (queue_stop_reply): Call xmalloc not malloc. + +2011-03-02 Michael Snyder + + * linux-arm-low.c (arm_arch_setup): Replace malloc with xmalloc. + +2011-02-28 Michael Snyder + + * tracepoint.c (cmd_qtv): Discard unused value 'packet'. + (cmd_qtframe): Ditto. + (cmd_qtbuffer): Ditto. + (cmd_bigqtbuffer): Ditto. + + * utils.c (decimal2str): Initialize 'width' to nine, then + don't mess with it. + +2011-02-28 Ulrich Weigand + + * hostio.c (require_data): Free *data, not data. + +2011-02-28 Jan Kratochvil + + * hostio.c (require_data): Use free, not xfree. + +2011-02-27 Michael Snyder + + * server.c (handle_query): Discard unused value. + + * hostio.c (require_data): Free malloc memory before returning + error. + +2011-02-26 Michael Snyder + + * linux-low.c (list_threads): Call closedir for dirent. + +2011-02-27 Michael Snyder + + * i386-low.c (i386-length_and_rw_bits): Comment the fact that + a case statement falls through. + + * linux-low.c (linux_xfer_siginfo): Fix fencepost error. + + * linux-amd64-ipa.c (gdb_agent_get_raw_reg): Fix fencepost error + in comparison. + +2011-02-26 Michael Snyder + + * utils.c (decimal2str): Eliminate dead code and dead param. + (pulongest): Drop dead param from call to decimal2str. + (plongest): Ditto. + +2011-02-24 Joel Brobecker + + Revert the following patch (not approved yet): + 2011-02-21 Hui Zhu + * tracepoint.c (tp_printf): New function. + (eval_agent_expr): Handle gdb_agent_op_printf. + +2011-02-21 Hui Zhu + + * tracepoint.c (tp_printf): New function. + (eval_agent_expr): Handle gdb_agent_op_printf. + +2011-02-18 Tom Tromey + + * Makefile.in (tracepoint-ipa.o): Depend on ax.def. + (tracepoint.o): Likewise. + * tracepoint.c (enum gdb_agent_op): Use ax.def. + (gdb_agent_op_names): Likewise. + +2011-02-18 Tom Tromey + + * tracepoint.c (enum gdb_agent_op) : New constants. + (gdb_agent_op_names): Add pick and roll. + (eval_agent_expr) : New + cases. + +2011-02-15 Jan Kratochvil + + * aclocal.m4: Regenerated with aclocal-1.11.1. + +2011-02-14 Pedro Alves + + * server.c (handle_qxfer_traceframe_info): New. + (qxfer_packets): Register "traceframe-info". + (handle_query): Report support for qXfer:traceframe-info:read+. + * tracepoint.c (match_blocktype): New. + (traceframe_find_block_type): Rename to ... + (traceframe_walk_blocks): ... this. Add callback filter argument, + and use it. + (traceframe_find_block_type): New, reimplemented on top of + traceframe_walk_blocks. + (build_traceframe_info_xml): New. + (traceframe_read_info): New. + * server.h (traceframe_read_info): Declare. + +2011-02-11 Yao Qi + + * configure.ac: Call AC_PROG_RANLIB. + * Makefile.in: Remove signals.o from OBS. Link libcommon.a. + * configure: Regenerate. + +2011-02-07 Pedro Alves + + * server.c (gdb_read_memory): Change return semantics to allow + partial transfers. + (handle_search_memory_1): Adjust. + (process_serial_event) <'m' packet>: Handle partial transfers. + * tracepoint.c (traceframe_read_mem): Handle partial transfers. + +2011-01-28 Pedro Alves + + * regcache.c (init_register_cache): Initialize + regcache->register_status. + (free_register_cache): Release regcache->register_status. + (regcache_cpy): Copy register_status. + (registers_to_string): Print 'x's for unavailable registers. + (supply_register): Mark the register's status valid or + unavailable, depending on whether a buffer was passed in or not. + (supply_register_zeroed): New. + (supply_regblock): Mark the registers' status valid or + unavailable, depending on whether a buffer was passed in or not. + * regcache.h (REG_UNAVAILABLE, REG_VALID): New defines. + (struct regcache): New `register_status' field. + (supply_register_zeroed): Declare. + * i387-fp.c (i387_xsave_to_cache): Zero out registers using + supply_register_zeroed, rather than passing a NULL buffer to + supply_register. + * tracepoint.c (fetch_traceframe_registers): Update comment. + +2011-01-28 Pedro Alves + + * i387-fp.c (i387_xsave_to_cache): Make passing NULL as register + buffer explicit. + +2011-01-25 Pedro Alves + + * server.h (decode_xfer_write): Change prototype. + * remote-utils.c (decode_xfer_write): Remove `annex' parameter, + and don't extract the annex here. + * server.c (decode_xfer_read): Remove `annex' parameter, + and don't extract the annex here. + (decode_xfer): New. + (struct qxfer): New. + (handle_qxfer_auxv, handle_qxfer_features, handle_qxfer_libraries) + (handle_qxfer_osdata, handle_qxfer_siginfo, handle_qxfer_spu) + (handle_qxfer_statictrace): New functions, abstracted out from + handle_query, and made to use the struct qxfer interface. + (handle_threads_qxfer_proper): Rename to ... + (handle_qxfer_threads_proper): ... this. + (handle_threads_qxfer): Rename to ... + (handle_qxfer_threads): ... this. Adjust. + (qxfer_packets): New array. + (handle_qxfer): New function. + (handle_query): Use handle_qxfer. + +2011-01-05 Michael Snyder + + * gdbreplay.c: Shorten lines of >= 80 columns. + * linux-low.c: Ditto. + * linux-ppc-low.c: Ditto. + * linux-s390-low.c: Ditto. + * linux-sparc-low.c: Ditto. + * linux-x86-low.c: Ditto. + * linux-xtensa-low.c: Ditto. + * mem-break.c: Ditto. + * nto-low.c: Ditto. + * regcache.h: Ditto. + * remote-utils.c: Ditto. + * server.c: Ditto. + * server.h: Ditto. + * thread-db.c: Ditto. + * tracepoint.c: Ditto. + * utils.c: Ditto. + * win32-low.h: Ditto. + +2011-01-05 Joel Brobecker + + * gdbserver/configure.ac, gdbserver/gdbserver.1: Copyright year + update. + +2011-01-01 Joel Brobecker + + * server.c (gdbserver_version): Update copyright year in version + output. + * gdbreplay.c (gdbreplay_version): Ditto. + +2010-12-29 Jie Zhang + + * configure.srv (bfin-*-*linux*): Handle Blackfin/Linux targets. + * linux-bfin-low.c: New file. + * linux-low.c: Define PT_TEXT_ADDR, PT_TEXT_END_ADDR, and + PT_DATA_ADDR for BFIN targets. + * Makefile.in (SFILES): Add linux-bfin-low.c. + (clean): Remove reg-bfin.c. + (linux-bfin-low.o, reg-bfin.o, reg-bfin.c): New targets. + * README: Mention supported Blackfin targets. + +2010-12-23 Mike Frysinger + + * .gitignore: New file. + +2010-11-16 Mike Frysinger + + * linux-low.c (linux_tracefork_child): Add char* cast to arg. + +2010-10-22 Jie Zhang + + * Makefile.in: Add FLAGS_TO_PASS variable. + (install): Remove dependency of install-only and recursively + invoke make for install-only. + +2010-10-04 Doug Evans + + * Makefile.in (uninstall): Use $(DESTDIR). + +2010-09-24 Pedro Alves + + PR gdb/11842 + + * linux-x86-low.c (compat_siginfo_from_siginfo) + (siginfo_from_compat_siginfo): Also copy si_pid and si_uid when + si_code is < 0. Check for si_code == SI_TIMER before checking for + si_code < 0. + +2010-09-13 Joel Brobecker + + * lynx-i386-low.c: New file. + * configure.srv: Add handling of i[34567]86-*-lynxos* targets. + +2010-09-13 Joel Brobecker + + * lynx-low.c (ptrace_request_to_str): Remove handling for + request values that have been removed in LynxOS 5.x. + +2010-09-13 Joel Brobecker + + * lynx-low.c, lynx-ppc-loc.c: Include instead of + + +2010-09-09 Nathan Sidwell + + * configure.ac: Add --enable-inprocess-agent option. + * configure: Rebuilt. + +2010-09-06 Yao Qi + + * linux-low.c (linux_kill): Remove unused variable. + (linux_stabilize_threads): Likewise. + * server.c (start_inferior): Likewise. + (queue_stop_reply_callback): Likewise. + * tracepoint.c (do_action_at_tracepoint): Likewise. + +2010-09-06 Yao Qi + + * linux-low.c (maybe_move_out_of_jump_pad): Restore current_inferior + on return. + +2010-09-06 Jan Kratochvil + + * target.c (mywait) : Fix to use INTEGER. + +2010-09-06 Pedro Alves + + * Makefile.in (install-only): Replace $IPA_DEPFILES with + "$(IPA_DEPFILES)". + +2010-09-01 Joel Brobecker + + * gdbserver/lynx-low.c, gdbserver/lynx-low.h, + gdbserver/lynx-ppc-low.c: New files. + * Makefile.in (lynx_low_h): New variable. + (lynx-low.o, lynx-ppc-low.o): New rules. + * configure.ac: On LynxOS, link with -lnetinet. + * configure.srv: Add handling of powerpc-*-lynxos* targets. + * configure: regenerate. + +2010-09-01 Joel Brobecker + + * Makefile.in (vasprintf.o, vsnprintf.o): New rules. + * configure.ac: Add check for vasprintf and vsnprintf. + * configure, config.in: Regenerate. + * server.h (vasprintf, vsnprintf): Add conditional declarations. + +2010-09-01 Joel Brobecker + + * gdbreplay.c: Move include of alloca.h up, next to include of + malloc.h. + * server.h: Add include of malloc.h. + * mem-break.c: Remove include of malloc.h. + * server.c, tracepoint.c, utils.c, win32-low.c: Likewise. + +2010-09-01 Joel Brobecker + + * Makefile.in (memmem.o): Build with -Wno-error. + +2010-09-01 Joel Brobecker + + * utils.c (xsnprintf): Make non-static. + * server.h: Add xsnprintf declaration. + * linux-low.c, nto-low.c, target.c, thread-db.c, tracepoint.c: + replace calls to snprintf by calls to xsnprintf throughout. + +2010-09-01 Joel Brobecker + + * configure.ac: Add configure check for alloca. + * configure, config.in: Regenerate. + * server.h: Include alloca.h if it exists. + * gdbreplay.c: Include alloca.h if it exists. + +2010-08-28 Pedro Alves + + * linux-low.c (__SIGRTMIN): Define if not already defined. + (linux_create_inferior): Check for __ANDROID__ rather than + __SIGRTMIN. + (enqueue_one_deferred_signal): Don't requeue non-RT signals that + are already deferred. + (linux_wait_1): Check for __ANDROID__ rather than __SIGRTMIN. + (linux_resume_one_thread): Don't queue a SIGSTOP if the lwp is + stopped and already has a pending signal to report. + (proceed_one_lwp): : Don't queue a SIGSTOP if the lwp already has + a pending signal to report or is moving out of a jump pad. + (linux_init_signals): Check for __ANDROID__ rather than + __SIGRTMIN. + +2010-08-28 Pedro Alves + + * linux-low.c (linux_stabilize_threads): Wrap debug output in a + debug_threads check. Avoid a linear search when not doing debug + output. + +2010-08-27 Pedro Alves + + * event-loop.c (event_handle_func): Adjust to use gdb_fildes_t. + (struct gdb_event) : Change type to gdb_fildes_t. + (struct file_handler) : Change type to gdb_fildes_t. + (process_event): Change local fd's type to gdb_fildes_t. + (create_file_handler): Adjust prototype. + (delete_file_handler): Adjust prototype. + (handle_file_event): Adjust prototype. Use pfildes. + (create_file_event): Adjsut prototype. + * remote-utils.c (remote_desc, listen_desc): Change type to + gdb_fildes_t. + * server.h: New gdb_fildes_t typedef. + [USE_WIN32API]: Include winsock2.h. + (delete_file_handler, add_file_handler): Adjust prototypes. + (pfildes): Declare. + * utils.c (pfildes): New. + +2010-08-27 Pedro Alves + + * configure.ac (build_warnings): Add -Wno-char-subscripts. + * configure: Regenerate. + +2010-08-27 Pedro Alves + + * linux-low.c (linux_unprepare_to_access_memory): Rename to ... + (linux_done_accessing_memory): ... this. + (linux_target_ops): Adjust. + * linux-x86-low.c (x86_insert_point, x86_remove_point): Adjust. + * nto-low.c (nto_target_ops): Adjust comment. + * server.c (gdb_read_memory, gdb_write_memory): Adjust. + * spu-low.c (spu_target_ops): Adjust comment. + * target.h (target_ops): Rename unprepare_to_access_memory field + to done_accessing_memory. + (unprepare_to_access_memory): Rename to ... + (done_accessing_memory): ... this. + +2010-08-26 Pedro Alves + + * linux-low.c (linux_prepare_to_access_memory): New. + (linux_unprepare_to_access_memory): New. + (linux_target_ops): Install them. + * server.c (read_memory): Rename to ... + (gdb_read_memory): ... this. Use + prepare_to_access_memory/prepare_to_access_memory. + (write_memory): Rename to ... + (gdb_write_memory): ... this. Use + prepare_to_access_memory/prepare_to_access_memory. + (handle_search_memory_1): Adjust. + (process_serial_event): Adjust. + * target.h (struct target_ops): New fields + prepare_to_access_memory and unprepare_to_access_memory. + (prepare_to_access_memory, unprepare_to_access_memory): New. + * linux-x86-low.c (x86_insert_point, x86_remove_point): Use + prepare_to_access_memory/prepare_to_access_memory. + * nto-low.c (nto_target_ops): Adjust. + * spu-low.c (spu_target_ops): Adjust. + * win32-low.c (win32_target_ops): Adjust. + +2010-08-26 Pedro Alves + + * Makefile.in (WARN_CFLAGS): Get it from configure. + (WERROR_CFLAGS): New. + (INTERNAL_CFLAGS): Add WERROR_CFLAGS. + * configure.ac: Introduce --enable-werror, which adds -Werror to + the compiler command line. Enabled by default. Disable with + --disable-werror. Add -Wdeclaration-after-statement + Wpointer-arith and -Wformat-nonliteral to warning flags. + * configure: Regenerate. + +2010-08-26 Pedro Alves + + * mem-break.c [HAVE_MALLOC_H]: Include malloc.h. + +2010-08-26 Pedro Alves + + * gdbreplay.c (remote_error): New. + (gdbchar): New. + (expect): Use gdbchar. Check for error reading from GDB. + Clarify sync error output. + (play): Check for errors writing to GDB. + * linux-low.c (sigchld_handler): Really ignore `write' errors. + * remote-utils.c (getpkt): Check for errors writing to the remote + descriptor. + +2010-08-25 Pedro Alves + + * linux-low.c (linux_wait_1): Move non-debugging code out of + `debug_threads' control. + +2010-08-25 Pedro Alves + + * linux-low.c (linux_wait_1): Don't set last_status here. + * server.c (push_event, queue_stop_reply_callback): Assert we're + not pushing a TARGET_WAITKIND_IGNORE event. + (start_inferior, start_inferior, attach_inferior, handle_v_cont) + (myresume, handle_target_event): Set the thread's last_resume_kind + and last_status from the target returned status. + +2010-08-25 Pedro Alves + + PR threads/10729 + + * linux-x86-low.c (update_debug_registers_callback): New. + (i386_dr_low_set_addr): Use it. + (i386_dr_low_get_addr): New. + (i386_dr_low_set_control): Use update_debug_registers_callback. + (i386_dr_low_get_control): New. + (i386_dr_low_get_status): Adjust. + * linux-low.c (linux_stop_lwp): New. + * linux-low.h (linux_stop_lwp): Declare. + + * i386-low.c (I386_DR_GET_RW_LEN): Take the dr7 contents as + argument instead of a i386_debug_reg_state. + (I386_DR_WATCH_HIT): Take the dr6 contents as argument instead of + a i386_debug_reg_state. + (i386_insert_aligned_watchpoint): Adjust. + (i386_remove_aligned_watchpoint): Adjust. + (i386_low_stopped_data_address): Read the debug registers from the + inferior instead of from the mirrors. + * i386-low.h (struct i386_debug_reg_state): Extend comment. + (i386_dr_low_get_addr): Declare. + (i386_dr_low_get_control): Declare. + (i386_dr_low_get_status): Change prototype. + + * win32-i386-low.c (dr_status_mirror, dr_control_mirror): New globals. + (i386_dr_low_get_addr): New. + (i386_dr_low_get_control): New. + (i386_dr_low_get_status): Adjust prototype. Return + dr_status_mirror. + (i386_initial_stuff): Clear dr_status_mirror and + dr_control_mirror. + (i386_get_thread_context): Adjust. + (i386_set_thread_context): Adjust. + (i386_thread_added): Adjust. + +2010-08-24 Pedro Alves + + * linux-low.h (linux_thread_area): Delete declaration. + +2010-08-11 Thomas Schwinge + + * linux-low.c (linux_wait_1): Correctly return the ptid of the child + after its termination. + +2010-08-09 Pedro Alves + + * linux-low.c (gdb_wants_lwp_stopped): Delete. + (gdb_wants_all_stopped): Delete. + (linux_wait_1): Don't call them. + * server.c (handle_v_cont): Tag all threads as want-stopped. + (gdb_wants_thread_stopped): Fix comments. Tag the thread that + stopped as "client-wants-stopped". + +2010-07-31 Pedro Alves + + * Makefile.in (signals_h): New. + (server_h): Depend on it. + (server.o): Don't depend on $(signals_def). + (signals.o): Depend on $(signals_def). + +2010-07-31 Jan Kratochvil + + * Makefile.in (signals_def): New. + (server_h): Append include/gdb/signals.h and signals_def. + (server.o): Append signals_def. + +2010-07-25 Jan Kratochvil + + * server.c (handle_target_event): Use target_signal_to_host for + resume_info.sig initialization. + * target.h (struct thread_resume) : New comment. + +2010-07-20 Ozkan Sezer + + * server.c (handle_query): strcpy() the returned string from paddress() + instead of sprintf(). + * utils.c (paddress): Return phex_nz(). + +2010-07-07 Joel Brobecker + + * server.c (handle_v_cont): Call mourn_inferior if process + just exited. + (myresume): Likewise. + +2010-07-01 Pedro Alves + + Static tracepoints, and integration with UST. + + * configure.ac: Handle --with-ust. substitute ustlibs and ustinc. + * mem-break.c (uninsert_all_breakpoints) + (reinsert_all_breakpoints): New. + * mem-break.h (reinsert_all_breakpoints, uninsert_all_breakpoints): + * tracepoint.c (ust_loaded, helper_thread_id, cmd_buf): New. + (gdb_agent_ust_loaded, helper_thread_id) + (gdb_agent_helper_thread_id): New macros. + (struct ipa_sym_addresses): Add addr_ust_loaded, + addr_helper_thread_id, addr_cmd_buf. + (symbol_list): Add ust_loaded, helper_thread_id, cmd_buf. + (in_process_agent_loaded_ust): New. + (write_e_ust_not_loaded): New. + (maybe_write_ipa_ust_not_loaded): New. + (struct collect_static_trace_data_action): New. + (enum tracepoint_type) : New. + (struct tracepoint) : Mention static tracepoints. + (struct static_tracepoint_ctx): New. + (CMD_BUF_SIZE): New. + (add_tracepoint_action): Handle static tracepoint actions. + (unprobe_marker_at): New. + (clear_installed_tracepoints): Handle static tracepoints. + (cmd_qtdp): Handle static tracepoints. + (probe_marker_at): New. + (cmd_qtstart): Handle static tracepoints. + (response_tracepoint): Handle static tracepoints. + (cmd_qtfstm, cmd_qtsstm, cmd_qtstmat): New. + (handle_tracepoint_query): Handle qTfSTM, qTsSTM and qTSTMat. + (get_context_regcache): Handle static tracepoints. + (do_action_at_tracepoint): Handle static tracepoint actions. + (traceframe_find_block_type): Handle static trace data blocks. + (traceframe_read_sdata): New. + (download_tracepoints): Download static tracepoint actions. + [HAVE_UST] Include ust/ust.h, dlfcn.h, sys/socket.h, and sys/un.h. + (GDB_PROBE_NAME): New. + (ust_ops): New. + (GET_UST_SYM): New. + (USTF): New. + (dlsym_ust): New. + (ust_marker_to_static_tracepoint): New. + (gdb_probe): New. + (collect_ust_data_at_tracepoint): New. + (gdb_ust_probe): New. + (UNIX_PATH_MAX, SOCK_DIR): New. + (gdb_ust_connect_sync_socket): New. + (resume_thread, stop_thread): New. + (run_inferior_command): New. + (init_named_socket): New. + (gdb_ust_socket_init): New. + (cstr_to_hexstr): New. + (next_st): New. + (first_marker, next_marker): New. + (response_ust_marker): New. + (cmd_qtfstm, cmd_qtsstm): New. + (unprobe_marker_at, probe_marker_at): New. + (cmd_qtstmat, gdb_ust_thread): New. + (gdb_ust_init): New. + (initialize_tracepoint_ftlib): Call gdb_ust_init. + * linux-amd64-ipa.c [HAVE_UST]: Include ust/processor.h + (ST_REGENTRY): New. + (x86_64_st_collect_regmap): New. + (X86_64_NUM_ST_COLLECT_GREGS): New. + (AMD64_RIP_REGNUM): New. + (supply_static_tracepoint_registers): New. + * linux-i386-ipa.c [HAVE_UST]: Include ust/processor.h + (ST_REGENTRY): New. + (i386_st_collect_regmap): New. + (i386_NUM_ST_COLLECT_GREGS): New. + (supply_static_tracepoint_registers): New. + * server.c (handle_query): Handle qXfer:statictrace:read. + : Report support for StaticTracepoints, and + qXfer:statictrace:read features. + * server.h (traceframe_read_sdata) + (supply_static_tracepoint_registers): Declare. + * remote-utils.c (convert_int_to_ascii, hexchars, ishex, tohex) + (unpack_varlen_hex): Include in IPA build. + * Makefile.in (ustlibs, ustinc): New. + (IPA_OBJS): Add remote-utils-ipa.o. + ($(IPA_LIB)): Link -ldl and -lpthread. + (UST_CFLAGS): New. + (IPAGENT_CFLAGS): Add UST_CFLAGS. + * config.in, configure: Regenerate. + +2010-06-20 Ian Lance Taylor + Pedro Alves + + * linux-x86-low.c (always_true): Delete. + (EMIT_ASM, EMIT_ASM32): Use an uncondition asm jmp instead of + trying to fool the compiler with always_true. + +2010-06-20 Pedro Alves + + * tracepoint.c (condition_true_at_tracepoint): Don't run compiled + conditions in gdbserver. + +2010-06-19 Ulrich Weigand + + * spu-low.c (spu_read_memory): Wrap around local store limit. + (spu_write_memory): Likewise. + +2010-06-15 Pedro Alves + + * linux-x86-low.c (amd64_emit_const, amd64_emit_void_call_2) + (i386_emit_const, i386_emit_void_call_2): Replace int64_t uses with + LONGEST uses. + * server.h (struct emit_ops): Replace int64_t uses with LONGEST + uses. + * tracepoint.c (emit_const, emit_void_call_2): Replace int64_t + uses with LONGEST uses. + +2010-06-14 Stan Shebs + Pedro Alves + + Bytecode compiler. + + * linux-x86-low.c: Include limits.h. + (add_insns): New. + (always_true): New. + (EMIT_ASM): New. + (EMIT_ASM32): New. + (amd64_emit_prologue, amd64_emit_epilogue, amd64_emit_add) + (amd64_emit_sub, amd64_emit_mul, amd64_emit_lsh) + (amd64_emit_rsh_signed, amd64_emit_rsh_unsigned, amd64_emit_ext, + (amd64_emit_log_not, amd64_emit_bit_and, amd64_emit_bit_or) + (amd64_emit_bit_xor, amd64_emit_bit_not, amd64_emit_equal, + (amd64_emit_less_signed, amd64_emit_less_unsigned, amd64_emit_ref, + (amd64_emit_if_goto, amd64_emit_goto, amd64_write_goto_address) + (amd64_emit_const, amd64_emit_call, amd64_emit_reg) + (amd64_emit_pop, amd64_emit_stack_flush, amd64_emit_zero_ext) + (amd64_emit_swap, amd64_emit_stack_adjust, amd64_emit_int_call_1) + (amd64_emit_void_call_2): New. + (amd64_emit_ops): New. + (i386_emit_prologue, i386_emit_epilogue, i386_emit_add) + (i386_emit_sub,i386_emit_mul, i386_emit_lsh, i386_emit_rsh_signed) + (i386_emit_rsh_unsigned, i386_emit_ext, i386_emit_log_not) + (i386_emit_bit_and, i386_emit_bit_or, i386_emit_bit_xor) + (i386_emit_bit_not, i386_emit_equal, i386_emit_less_signed) + (i386_emit_less_unsigned, i386_emit_ref, i386_emit_if_goto) + (i386_emit_goto, i386_write_goto_address, i386_emit_const) + (i386_emit_call, i386_emit_reg, i386_emit_pop) + (i386_emit_stack_flush, i386_emit_zero_ext, i386_emit_swap) + (i386_emit_stack_adjust, i386_emit_int_call_1) + (i386_emit_void_call_2): New. + (i386_emit_ops): New. + (x86_emit_ops): New. + (the_low_target): Install x86_emit_ops. + * server.h (struct emit_ops): New. + (get_raw_reg_func_addr): Declare. + (current_insn_ptr, emit_error): Declare. + * tracepoint.c (get_raw_reg, get_trace_state_variable_value) + (set_trace_state_variable_value): New defines. + (struct ipa_sym_addresses): New fields addr_get_raw_reg, + addr_get_trace_state_variable_value and + addr_set_trace_state_variable_value. + (symbol_list): New fields for get_raw_reg, + get_trace_state_variable_value and set_trace_state_variable_value. + (condfn): New typedef. + (struct tracepoint): New field `compiled_cond'. + (do_action_at_tracepoint): Clear compiled_cond. + (get_trace_state_variable_value, set_trace_state_variable_value): + Export in the IPA. + (condition_true_at_tracepoint): If there's a compiled condition, + run that. + (current_insn_ptr, emit_error): New globals. + (struct bytecode_address): New. + (get_raw_reg_func_addr): New. + (emit_prologue, emit_epilogue, emit_add, emit_sub, emit_mul) + (emit_lsh, emit_rsh_signed, emit_rsh_unsigned, emit_ext) + (emit_log_not, emit_bit_and, emit_bit_or, emit_bit_xor) + (emit_bit_not, emit_equal, emit_less_signed, emit_less_unsigned) + (emit_ref, emit_if_goto, emit_goto, write_goto_address, emit_const) + (emit_reg, emit_pop, emit_stack_flush, emit_zero_ext, emit_swap) + (emit_stack_adjust, emit_int_call_1, emit_void_call_2): New. + (compile_tracepoint_condition, compile_bytecodes): New. + * target.h (emit_ops): Forward declare. + (struct target_ops): New field emit_ops. + (target_emit_ops): New. + * linux-amd64-ipa.c (gdb_agent_get_raw_reg): New. + * linux-i386-ipa.c (gdb_agent_get_raw_reg): New. + * linux-low.c (linux_emit_ops): New. + (linux_target_ops): Install it. + * linux-low.h (struct linux_target_ops): New field emit_ops. + +2010-06-14 Ulrich Weigand + + * linux-ppc-low.c (ppc_arch_setup): Use private regcache to test MSR. + * linux-s390-low.c (ppc_arch_setup): Use private regcache to test PSW. + +2010-06-01 Pedro Alves + Stan Shebs + + * Makefile.in (IPA_DEPFILES, extra_libraries): New. + (all): Depend on $(extra_libraries). + (install-only): Install the IPA. + (IPA_OBJS, IPA_LIB): New. + (clean): Remove the IPA lib. + (IPAGENT_CFLAGS): New. + (tracepoint-ipa.o, utils-ipa.o, remote-utils-ipa.o) + (regcache-ipa.o, i386-linux-ipa.o, linux-i386-ipa.o) + (linux-amd64-ipa.o, amd64-linux-ipa.o): New rules. + * linux-amd64-ipa.c, linux-i386-ipa.c: New files. + * configure.ac: Check for atomic builtins support in the compiler. + (IPA_DEPFILES, extra_libraries): Define. + * configure.srv (ipa_obj): Add description. + (ipa_i386_linux_regobj, ipa_amd64_linux_regobj): Define. + (i[34567]86-*-linux*): Set ipa_obj. + (x86_64-*-linux*): Set ipa_obj. + * linux-low.c (stabilizing_threads): New. + (supports_fast_tracepoints): New. + (linux_detach): Stabilize threads before detaching. + (handle_tracepoints): Handle internal tracing breakpoints. Assert + the lwp is either not stabilizing, or is moving out of a jump pad. + (linux_fast_tracepoint_collecting): New. + (maybe_move_out_of_jump_pad): New. + (enqueue_one_deferred_signal): New. + (dequeue_one_deferred_signal): New. + (linux_wait_for_event_1): If moving out of a jump pad, defer + pending signals to later. + (linux_stabilize_threads): New. + (linux_wait_1): Check if threads need moving out of jump pads, and + do it if so. + (stuck_in_jump_pad_callback): New. + (move_out_of_jump_pad_callback): New. + (lwp_running): New. + (linux_resume_one_lwp): Handle moving out of jump pads. + (linux_set_resume_request): Dequeue deferred signals. + (need_step_over_p): Also step over fast tracepoint jumps. + (start_step_over): Also uninsert fast tracepoint jumps. + (finish_step_over): Also reinsert fast tracepoint jumps. + (linux_install_fast_tracepoint_jump): New. + (linux_target_ops): Install linux_stabilize_threads and + linux_install_fast_tracepoint_jump_pad. + * linux-low.h (linux_target_ops) : New fields. + (struct lwp_info) : New fields. + (linux_get_thread_area): Declare. + * linux-x86-low.c (jump_insn): New. + (x86_get_thread_area): New. + (append_insns): New. + (push_opcode): New. + (amd64_install_fast_tracepoint_jump_pad): New. + (i386_install_fast_tracepoint_jump_pad): New. + (x86_install_fast_tracepoint_jump_pad): New. + (the_low_target): Install x86_get_thread_area and + x86_install_fast_tracepoint_jump_pad. + * mem-break.c (set_raw_breakpoint_at): Use read_inferior_memory. + (struct fast_tracepoint_jump): New. + (fast_tracepoint_jump_insn): New. + (fast_tracepoint_jump_shadow): New. + (find_fast_tracepoint_jump_at): New. + (fast_tracepoint_jump_here): New. + (delete_fast_tracepoint_jump): New. + (set_fast_tracepoint_jump): New. + (uninsert_fast_tracepoint_jumps_at): New. + (reinsert_fast_tracepoint_jumps_at): New. + (set_breakpoint_at): Use write_inferior_memory. + (uninsert_raw_breakpoint): Use write_inferior_memory. + (check_mem_read): Mask out fast tracepoint jumps. + (check_mem_write): Mask out fast tracepoint jumps. + * mem-break.h (struct fast_tracepoint_jump): Forward declare. + (set_fast_tracepoint_jump): Declare. + (delete_fast_tracepoint_jump) + (fast_tracepoint_jump_here, uninsert_fast_tracepoint_jumps_at) + (reinsert_fast_tracepoint_jumps_at): Declare. + * regcache.c: Don't compile many functions when building the + in-process agent library. + (init_register_cache) [IN_PROCESS_AGENT]: Don't allow allocating + the register buffer in the heap. + (free_register_cache): If the register buffer isn't owned by the + regcache, don't free it. + (set_register_cache) [IN_PROCESS_AGENT]: Don't re-alocate + pre-existing register caches. + * remote-utils.c (convert_int_to_ascii): Constify `from' parameter + type. + (convert_ascii_to_int): : Constify `from' parameter type. + (decode_M_packet, decode_X_packet): Replace the `to' parameter by + a `to_p' pointer to pointer parameter. If TO_P is NULL, malloc + the needed buffer in-place. + (relocate_instruction): New. + * server.c (handle_query) : If the target supports + tracepoints, give it a chance of looking up symbols. Report + support for fast tracepoints. + (handle_status): Stabilize threads. + (process_serial_event): Adjust. + * server.h (struct fast_tracepoint_jump): Forward declare. + (struct process_info) : New field. + (convert_ascii_to_int, convert_int_to_ascii): Adjust. + (decode_X_packet, decode_M_packet): Adjust. + (relocate_instruction): Declare. + (in_process_agent_loaded): Declare. + (tracepoint_look_up_symbols): Declare. + (struct fast_tpoint_collect_status): Declare. + (fast_tracepoint_collecting): Declare. + (force_unlock_trace_buffer): Declare. + (handle_tracepoint_bkpts): Declare. + (initialize_low_tracepoint) + (supply_fast_tracepoint_registers) [IN_PROCESS_AGENT]: Declare. + * target.h (struct target_ops) : New fields. + (stabilize_threads, install_fast_tracepoint_jump_pad): New. + * tracepoint.c [HAVE_MALLOC_H]: Include malloc.h. + [HAVE_STDINT_H]: Include stdint.h. + (trace_debug_1): Rename to ... + (trace_vdebug): ... this. + (trace_debug): Rename to ... + (trace_debug_1): ... this. Add `level' parameter. + (trace_debug): New. + (ATTR_USED, ATTR_NOINLINE): New. + (IP_AGENT_EXPORT): New. + (gdb_tp_heap_buffer, gdb_jump_pad_buffer, gdb_jump_pad_buffer_end) + (collecting, gdb_collect, stop_tracing, flush_trace_buffer) + (about_to_request_buffer_space, trace_buffer_is_full) + (stopping_tracepoint, expr_eval_result, error_tracepoint) + (tracepoints, tracing, trace_buffer_ctrl, trace_buffer_ctrl_curr) + (trace_buffer_lo, trace_buffer_hi, traceframe_read_count) + (traceframe_write_count, traceframes_created) + (trace_state_variables) + New renaming defines. + (struct ipa_sym_addresses): New. + (STRINGIZE_1, STRINGIZE, IPA_SYM): New. + (symbol_list): New. + (ipa_sym_addrs): New. + (all_tracepoint_symbols_looked_up): New. + (in_process_agent_loaded): New. + (write_e_ipa_not_loaded): New. + (maybe_write_ipa_not_loaded): New. + (tracepoint_look_up_symbols): New. + (debug_threads) [IN_PROCESS_AGENT]: New. + (read_inferior_memory) [IN_PROCESS_AGENT]: New. + (UNKNOWN_SIDE_EFFECTS): New. + (stop_tracing): New. + (flush_trace_buffer): New. + (stop_tracing_bkpt): New. + (flush_trace_buffer_bkpt): New. + (read_inferior_integer): New. + (read_inferior_uinteger): New. + (read_inferior_data_pointer): New. + (write_inferior_data_pointer): New. + (write_inferior_integer): New. + (write_inferior_uinteger): New. + (struct collect_static_trace_data_action): Delete. + (enum tracepoint_type): New. + (struct tracepoint) : New field `type'. + : Only include in + GDBserver. + + : New fields. + (tracepoints): Use IP_AGENT_EXPORT. + (last_tracepoint): Don't include in the IPA. + (stopping_tracepoint): Use IP_AGENT_EXPORT. + (trace_buffer_is_full): Use IP_AGENT_EXPORT. + (alloced_trace_state_variables): New. + (trace_state_variables): Use IP_AGENT_EXPORT. + (traceframe_t): Delete unused variable. + (circular_trace_buffer): Don't include in the IPA. + (trace_buffer_start): Delete. + (struct trace_buffer_control): New. + (trace_buffer_free): Delete. + (struct ipa_trace_buffer_control): New. + (GDBSERVER_FLUSH_COUNT_MASK, GDBSERVER_FLUSH_COUNT_MASK_PREV) + (GDBSERVER_FLUSH_COUNT_MASK_CURR, GDBSERVER_UPDATED_FLUSH_COUNT_BIT): + New. + (trace_buffer_ctrl): New. + (TRACE_BUFFER_CTRL_CURR): New. + (trace_buffer_start, trace_buffer_free, trace_buffer_end_free): + Reimplement as macros. + (trace_buffer_wrap): Delete. + (traceframe_write_count, traceframe_read_count) + (traceframes_created, tracing): Use IP_AGENT_EXPORT. + (struct tracepoint_hit_ctx) : New field. + (struct fast_tracepoint_ctx): New. + (memory_barrier): New. + (cmpxchg): New. + (record_tracepoint_error): Update atomically in the IPA. + (clear_inferior_trace_buffer): New. + (about_to_request_buffer_space): New. + (trace_buffer_alloc): Handle GDBserver and inferior simulatenous + updating the same buffer. + (add_tracepoint): Default the tracepoint's type to trap + tracepoint, and orig_size to -1. + (get_trace_state_variable) [IN_PROCESS_AGENT]: Handle allocated + internal variables. + (create_trace_state_variable): New parameter `gdb'. Handle it. + (clear_installed_tracepoints): Clear fast tracepoint jumps. + (cmd_qtdp): Handle fast tracepoints. + (cmd_qtdv): Adjust. + (max_jump_pad_size): New. + (gdb_jump_pad_head): New. + (get_jump_space_head): New. + (claim_jump_space): New. + (sort_tracepoints): New. + (MAX_JUMP_SIZE): New. + (cmd_qtstart): Handle fast tracepoints. Sync tracepoints with the + IPA. + (stop_tracing) [IN_PROCESS_AGENT]: Don't include the tdisconnected + support. Upload fast traceframes, and delete internal IPA + breakpoints. + (stop_tracing_handler): New. + (flush_trace_buffer_handler): New. + (cmd_qtstop): Upload fast tracepoints. + (response_tracepoint): Handle fast tracepoints. + (tracepoint_finished_step): Upload fast traceframes. Set the + tracepoint hit context's tracepoint type. + (handle_tracepoint_bkpts): New. + (tracepoint_was_hit): Set the tracepoint hit context's tracepoint + type. Add comment about fast tracepoints. + (collect_data_at_tracepoint) [IN_PROCESS_AGENT]: Don't access the + non-existing action_str field. + (get_context_regcache): Handle fast tracepoints. + (do_action_at_tracepoint) [!IN_PROCESS_AGENT]: Don't write the PC + to the regcache. + (fast_tracepoint_from_jump_pad_address): New. + (fast_tracepoint_from_ipa_tpoint_address): New. + (collecting_t): New. + (force_unlock_trace_buffer): New. + (fast_tracepoint_collecting): New. + (collecting): New. + (gdb_collect): New. + (write_inferior_data_ptr): New. + (target_tp_heap): New. + (target_malloc): New. + (download_agent_expr): New. + (UALIGN): New. + (download_tracepoints): New. + (download_trace_state_variables): New. + (upload_fast_traceframes): New. + (IPA_FIRST_TRACEFRAME): New. + (IPA_NEXT_TRACEFRAME_1): New. + (IPA_NEXT_TRACEFRAME): New. + [IN_PROCESS_AGENT]: Include sys/mman.h and fcntl.h. + [IN_PROCESS_AGENT] (gdb_tp_heap_buffer, gdb_jump_pad_buffer) + (gdb_jump_pad_buffer_end): New. + [IN_PROCESS_AGENT] (initialize_tracepoint_ftlib): New. + (initialize_tracepoint): Adjust. + [IN_PROCESS_AGENT]: Allocate the IPA heap, and jump pad scratch + buffer. Initialize the low module. + * utils.c (PREFIX, TOOLNAME): New. + (malloc_failure): Use PREFIX. + (error): In the IPA, an error causes an exit. + (fatal, warning): Use PREFIX. + (internal_error): Use TOOLNAME. + (NUMCELLS): Increase to 10. + * configure, config.in: Regenerate. + +2010-06-01 Pedro Alves + + * server.c (handle_query) : Do two passes over the + qSupported string to avoid nesting strtok. + +2010-05-28 Jan Kratochvil + + * Makefile.in (SFILES): Add $(srcdir)/proc-service.list. + (CDEPS): New. + * configure.ac (RDYNAMIC): New AC_MSG_CHECKING wrapping. Test also + -Wl,--dynamic-list. + * configure: Regenerate. + * proc-service.list: New. + +2010-05-28 Jan Kratochvil + + * linux-low.c (linux_core_of_thread): Fix crash on invalid CONTENT. + New comment. + +2010-05-26 Ozkan Sezer + + * gdbreplay.c (remote_open): Check error return from socket() call by + its equality to -1 not by it being negative. + * remote-utils.c (remote_open): Likewise. + +2010-05-23 Pedro Alves + + * config.h: Regenerate. + +2010-05-19 Maxim Kuvyrkov + + * linux-m68k-low.c (ps_get_thread_area): Don't define if kernel + doesn't provide PTRACE_GET_THREAD_AREA. + +2010-05-19 Maxim Kuvyrkov + + * linux-m68k-low.c: Include + (ps_get_thread_area): Implement. + +2010-05-03 Doug Evans + + * event-loop.c (struct callback_event): New struct. + (callback_list): New global. + (append_callback_event, delete_callback_event): New functions. + (process_callback): New function. + (start_event_loop): Call it. + * remote-utils.c (NOT_SCHEDULED): Define. + (readchar_buf, readchar_bufcnt, readchar_bufp): New static globals, + moved out of readchar. + (readchar): Rewrite. Call reschedule before returning. + (reset_readchar): New function. + (remote_close): Call it. + (process_remaining, reschedule): New functions. + * server.h (callback_handler_func): New typedef. + (append_callback_event, delete_callback_event): Declare. + +2010-05-03 Pedro Alves + + * proc-service.c (ps_pglobal_lookup): Use + thread_db_look_up_one_symbol. + * remote-utils.c (look_up_one_symbol): Add new `may_ask_gdb' + parameter. Use it instead of all_symbols_looked_up. + * server.h (struct process_info) : Delete + field. + (all_symbols_looked_up): Don't declare. + (look_up_one_symbol): Add new `may_ask_gdb' parameter. + * thread-db.c (struct thread_db) : New + field. + (thread_db_look_up_symbols): Adjust call to look_up_one_symbol. + Set all_symbols_looked_up here. + (thread_db_look_up_one_symbol): New. + (thread_db_get_tls_address): Adjust. + (thread_db_load_search, try_thread_db_load_1): Always allocate the + thread_db object on the heap, and tentatively set it in the + process structure. + (thread_db_init): Don't set all_symbols_looked_up here. + * linux-low.h (thread_db_look_up_one_symbol): Declare. + +2010-05-03 Pedro Alves + + * linux-low.c (linux_kill, linux_detach): Adjust. + (status_pending_p_callback): Remove redundant statement. Check + for !TARGET_WAITIKIND_IGNORE, instead of + TARGET_WAITKIND_STOPPED. + (handle_tracepoints): Make sure LWP is locked. Adjust. + (linux_wait_for_event_1): Adjust. + (linux_cancel_breakpoints): New. + (unsuspend_one_lwp): New. + (unsuspend_all_lwps): New. + (linux_wait_1): If finishing a step-over, unsuspend all lwps. + (send_sigstop_callback): Change return type to int, add new + `except' parameter and handle it. + (suspend_and_send_sigstop_callback): New. + (stop_all_lwps): Add new `suspend' and `expect' parameters, and + pass them down. If SUSPEND, also increment the lwp's suspend + count. + (linux_resume_one_lwp): Add notice about resuming a suspended LWP. + (need_step_over_p): Don't consider suspended LWPs. + (start_step_over): Adjust. + (proceed_one_lwp): Change return type to int, add new `except' + parameter and handle it. + (unsuspend_and_proceed_one_lwp): New. + (proceed_all_lwps): Use find_inferior instead of + for_each_inferior. + (unstop_all_lwps): Add `unsuspend' parameter. If UNSUSPEND, them + also decrement the suspend count of LWPs. Pass `except' down, + instead of hacking its suspend count. + (linux_pause_all): Add `freeze' parameter. Adjust. + (linux_unpause_all): New. + (linux_target_ops): Install linux_unpause_all. + * server.c (handle_status): Adjust. + * target.h (struct target_ops): New fields `unpause_all' and + `cancel_breakpoints'. Add new parameter to `pause_all'. + (pause_all): Add new `freeze' parameter. + (unpause_all): New. + (cancel_breakpoints): New. + * tracepoint.c (clear_installed_tracepoints): Pause threads, and + cancel breakpoints. + (cmd_qtstart): Pause threads. + (stop_tracing): Pause threads, and cancel breakpoints. + * win32-low.c (win32_target_ops): Adjust. + +2010-05-03 Pedro Alves + + * linux-low.c (linux_wait_for_event_1): Move passing the signal to + the inferior right away from here... + (linux_wait_1): ... to here, and adjust to check the thread's + last_resume_kind instead of the lwp's step or stop_expected flags. + +2010-05-02 Pedro Alves + + * README: Use consistent `GDB' and `GDBserver' spellings. + +2010-05-02 Pedro Alves + + * linux-low.c (linux_kill_one_lwp): Assume the lwp is stopped. + (linux_kill): Stop all lwps here. Don't delete the main lwp here. + (linux_detach_one_lwp): Assume the lwp is stopped. + (any_thread_of): Delete. + (linux_detach): Stop all lwps here. Don't blindly delete all + breakpoints. + (delete_lwp_callback): New. + (linux_mourn): Delete all lwps of the process that is gone. + (linux_wait_1): Don't delete the last lwp of the process here. + * mem-break.h (mark_breakpoints_out): Declare. + * mem-break.c (mark_breakpoints_out): New. + (free_all_breakpoints): Use it. + * server.c (handle_target_event): If the process is gone, mark + breakpoints out. + * thread-db.c (struct thread_db) : New field. + (thread_db_enable_reporting): Fix prototype. Store a thread event + breakpoint reference in the thread_db struct. + (thread_db_load_search): Clear the thread_db object. + (try_thread_db_load_1): Ditto. + (switch_to_process): New. + (disable_thread_event_reporting): Use it. + (remove_thread_event_breakpoints): New. + (thread_db_detach, thread_db_mourn): Use it. + +2010-05-01 Pedro Alves + + * linux-low.c (linux_enable_event_reporting): New. + (linux_wait_for_event_1, handle_extended_wait): Use it. + +2010-04-30 Pedro Alves + + * linux-low.c (linux_kill_one_lwp, linux_kill) + (linux_detach_one_lwp): Adjust to send_sigstop interface change. + (send_sigstop): Take an lwp_info as parameter instead. Queue a + SIGSTOP even if the LWP is stopped. + (send_sigstop_callback): New. + (stop_all_lwps): Use send_sigstop_callback instead. + (linux_resume_one_thread): Adjust. + (proceed_one_lwp): Still proceed an LWP that the client has + requested to stop, if we haven't reported it as stopped yet. Make + sure that LWPs the client want stopped, have a pending SIGSTOP. + +2010-04-26 Doug Evans + + * server.c (handle_general_set): Make static. + + * remote-utils.c (putpkt_binary_1): Call readchar instead of read. + Print received char after testing for error/eof instead of before. + (input_interrupt): Tweak comment. + +2010-04-23 Doug Evans + + * server.c (start_inferior): Print inferior argv if --debug. + +2010-04-21 Aleksandar Ristovski + + * Makefile.in (nto_low_h nto-low.o nto-x86-low.o): New dependency lists. + * nto-x86-low.c: Include server.h + +2010-04-20 Pierre Muller + + * win32-i386-low.c: Use __x86_64__ macro instead of __x86_64 to + be consistent with other sources of this directory. + (init_registers_amd64): Correct name of source file of this function + in the comment. + +2010-04-19 Pierre Muller + + * configure.srv (x86_64-*-mingw*): New configuration for Windows + 64-bit executables. + +2010-04-19 Pierre Muller + + * win32-i386-low.c: Add 64-bit support. + (CONTEXT_EXTENDED_REGISTERS): Set macro to zero if not exisiting. + (init_registers_amd64): Declare. + (mappings): Add 64-bit version of array. + (init_windows_x86): New function. + (the_low_target): Change init_arch field to init_windows_x86. + +2010-04-19 Pierre Muller + + * win32-low.c: Adapt to support also 64-bit architecture. + (child_xfer_memory): Use uintptr_t type for local variable `addr'. + (get_image_name): Use SIZE_T type for local variable `done'. + (psapi_get_dll_name): Use LPVOID type for parameter `BaseAddress'. + (toolhelp_get_dll_name): Idem. + (handle_load_dll): Use CORE_ADDR type for local variable `load_addr'. + Use uintptr_t typecast to avoid warning. + (handle_unload_dll): Use uintptr_t typecast to avoid warning. + (handle_exception): Use phex_nz to avoid warning. + (win32_wait): Remove unused local variable `process'. + +2010-04-19 Pierre Muller + + * configure.srv (srv_amd64_regobj): Replace `x86-64-avx.o' by + `amd64-avx.o'. + +2010-04-17 Pierre Muller + + * configure.ac: Use `ws2_32' library for srv_mingw. + * configure: Regenerate. + * gdbreplay.c: Include winsock2.h instead of winsock.h. + * remote-utils.c: Likewise. + +2010-04-17 H.J. Lu + + * linux-x86-low.c (xmltarget_amd64_linux_no_xml): Define only + if __x86_64__ is defined. + +2010-04-16 Pierre Muller + + * configure: Regenerate. + +2010-04-16 Pierre Muller + + * server.c (handle_query): Handle 'qGetTIBAddr' query. + * target.h (target_ops): New get_tib_address field. + * win32-low.h (win32_thread_info): Add thread_local_base field. + * win32-low.c (child_add_thread): Add tlb argument. + Set thread_local_base field to TLB. + (get_child_debug_event): Adapt to child_add_thread change. + (win32_get_tib_address): New function. + (win32_target_ops): Set get_tib_address field to + win32_get_tib_address. + * linux-low.c (linux_target_ops): Set get_tib_address field to NULL. + +2010-04-12 Pedro Alves + + * linux-low.c (linux_mourn): Also remove the process. + * server.c (handle_target_event): Don't remove the process here. + * nto-low.c (nto_mourn): New. + (nto_target_ops): Install it. + * spu-low.c (spu_mourn): New. + (spu_target_ops): Install it. + * win32-low.c (win32_mourn): New. + (win32_target_ops): Install it. + +2010-04-12 Pedro Alves + + * server.h (buffer_xml_printf): Remove redundant `;'. + +2010-04-12 Pedro Alves + + * regcache.c (set_register_cache): Invalidate regcaches before + changing the register cache layout. + (regcache_invalidate_one): Allow a NULL regcache. + * linux-x86-low.c (x86_linux_update_xmltarget): Invalidate + regcaches before changing the register cache layout or the target + regsets. + +2010-04-12 H.J. Lu + + * linux-x86-low.c (x86_linux_update_xmltarget): Avoid unused + variable warning on Linux/x86-64. + +2010-04-11 Pedro Alves + + GDBserver disconnected tracing support. + + * linux-low.c (linux_remove_process): Delete. + (add_lwp): Don't set last_resume_kind here. + (linux_kill): Use `mourn'. + (linux_detach): Use `thread_db_detach', and `mourn'. + (linux_mourn): New. + (linux_attach_lwp_1): Adjust comment. + (linux_attach): last_resume_kind moved the thread_info; adjust. + (status_pending_p_callback): Adjust. + (linux_wait_for_event_1): Adjust. + (count_events_callback, select_singlestep_lwp_callback) + (select_event_lwp_callback, cancel_breakpoints_callback) + (db_wants_lwp_stopped, linux_wait_1, need_step_over_p) + (proceed_one_lwp): Adjust. + (linux_async): Add debug output. + (linux_thread_stopped): New. + (linux_pause_all): New. + (linux_target_ops): Install linux_mourn, linux_thread_stopped and + linux_pause_all. + * linux-low.h (struct lwp_info): Delete last_resume_kind field. + (thread_db_free): Delete declaration. + (thread_db_detach, thread_db_mourn): Declare. + * thread-db.c (thread_db_init): Use thread_db_mourn. + (thread_db_free): Delete, split in two. + (disable_thread_event_reporting): New. + (thread_db_detach): New. + (thread_db_mourn): New. + + * server.h (struct thread_info) : New field. + : Add comment. + : New field. + (handler_func): Change return type to int. + (handle_serial_event, handle_target_event): Ditto. + (gdb_connected): Declare. + (tracing): Delete. + (disconnected_tracing): Declare. + (stop_tracing): Declare. + + * server.c (handle_query) : Report support for + disconnected tracing. + (queue_stop_reply_callback): Account for running threads. + (gdb_wants_thread_stopped): New. + (gdb_wants_all_threads_stopped): New. + (gdb_reattached_process): New. + (handle_status): Clear the `gdb_detached' flag of all processes. + In all-stop, stop all threads. + (main): Be sure to leave tfind mode. Handle disconnected tracing. + (process_serial_event): If the remote connection breaks, or if an + exit was forced with "monitor exit", force an event loop exit. + Handle disconnected tracing on detach. + (handle_serial_event): Adjust. + (handle_target_event): If GDB isn't connected, forward events back + to the inferior, unless the last process exited, in which case, + exit gdbserver. Adjust interface. + + * remote-utils.c (remote_open): Don't block in accept. Instead + register an event loop source on the listen socket file + descriptor. Refactor bits into ... + (listen_desc): ... this new global. + (gdb_connected): ... this new function. + (enable_async_notification): ... this new function. + (handle_accept_event): ... this new function. + (remote_close): Clear remote_desc. + + * inferiors.c (add_thread): Set the new thread's last_resume_kind. + + * target.h (struct target_ops) : + New fields. + (mourn_inferior): Define. + (target_process_qsupported): Avoid the dangling else problem. + (thread_stopped): Define. + (pause_all): Define. + (target_waitstatus_to_string): Declare. + * target.c (target_waitstatus_to_string): New. + + * tracepoint.c (tracing): Make extern. + (disconnected_tracing): New. + (stop_tracing): Make extern. Handle tracing stops due to GDB + disconnecting. + (cmd_qtdisconnected): New. + (cmd_qtstatus): Report disconnected tracing status in trace reply. + (handle_tracepoint_general_set): Handle QTDisconnected. + + * event-loop.c (event_handler_func): Change return type to int. + (process_event): Bail out if the event handler wants the event + loop to stop. + (handle_file_event): Ditto. + (start_event_loop): Bail out if the event handler wants the event + loop to stop. + + * nto-low.c (nto_target_ops): Adjust. + * spu-low.c (spu_wait): Don't remove the process here. + (spu_target_ops): Adjust. + * win32-low.c (win32_wait): Don't remove the process here. + (win32_target_ops): Adjust. + +2010-04-11 Pedro Alves + + * regcache.c (realloc_register_cache): Invalidate inferior's + regcache before recreating it. + +2010-04-09 Pedro Alves + + * tracepoint.c (cmd_qtstatus): Report trace buffer circularity. + +2010-04-09 Stan Shebs + Pedro Alves + + * server.h (LONGEST): New. + (struct thread_info) : New field. + (unpack_varlen_hex, xrealloc, pulongest, plongest, phex_nz): + Declare. + (initialize_tracepoint, handle_tracepoint_general_set) + (handle_tracepoint_query, tracepoint_finished_step) + (tracepoint_was_hit, release_while_stepping_state_list): + (current_traceframe): Declare. + * server.c (handle_general_set): Handle tracepoint packets. + (read_memory): New. + (write_memory): New. + (handle_search_memory_1): Use read_memory. + (handle_query): Report support for conditional tracepoints, trace + state variables, and tracepoint sources. Handle tracepoint + queries. + (main): Initialize the tracepoints module. + (process_serial_event): Handle traceframe reads/writes. + + * linux-low.c (handle_tracepoints): New. + (linux_wait_1): Call it. + (linux_resume_one_lwp): Handle while-stepping. + (linux_supports_tracepoints, linux_read_pc, linux_write_pc): New. + (linux_target_ops): Install them. + * linux-low.h (struct linux_target_ops) : + New field. + * linux-x86-low.c (x86_supports_tracepoints): New. + (the_low_target). Install it. + + * mem-break.h (delete_breakpoint): Declare. + * mem-break.c (delete_breakpoint): Make external. + + * target.h (struct target_ops): Add `supports_tracepoints', + `read_pc', and `write_pc' fields. + (target_supports_tracepoints): Define. + * utils.c (xrealloc, decimal2str, pulongest, plongest, thirty_two) + (phex_nz): New. + + * regcache.h (struct regcache) : New field. + (init_register_cache, regcache_cpy): Declare. + (regcache_read_pc, regcache_write_pc): Declare. + (register_cache_size): Declare. + (supply_regblock): Declare. + * regcache.c (init_register_cache): New. + (new_register_cache): Use it. + (regcache_cpy): New. + (register_cache_size): New. + (supply_regblock): New. + (regcache_read_pc, regcache_write_pc): New. + + * tracepoint.c: New. + + * Makefile.in (OBS): Add tracepoint.o. + (tracepoint.o): New rule. + +2010-04-08 H.J. Lu + + * Makefile.in (clean): Also remove i386-mmx.c i386-mmx-linux.c. + (i386-mmx.o): New. + (i386-mmx.c): Likewise. + (i386-mmx-linux.o): Likewise. + (i386-mmx-linux.c): Likewise. + + * configure.srv (srv_i386_regobj): Add i386-mmx.o. + (srv_i386_linux_regobj): Add i386-mmx-linux.o. + (srv_i386_xmlfiles): Add i386/i386-mmx.xml. + (srv_i386_linux_xmlfiles): Add i386/i386-mmx-linux.xml. + + * linux-x86-low.c (init_registers_i386_mmx_linux): New. + (x86_linux_update_xmltarget): Call init_registers_i386_mmx_linux + and return if ptrace PTRACE_GETFPXREGS failed in 32bit. + +2010-04-07 H.J. Lu + + * Makefile.in (clean): Updated. + (i386-avx.o): New. + (i386-avx.c): Likewise. + (i386-avx-linux.o): Likewise. + (i386-avx-linux.c): Likewise. + (amd64-avx.o): Likewise. + (amd64-avx.c): Likewise. + (amd64-avx-linux.o): Likewise. + (amd64-avx-linux.c): Likewise. + + * configure.srv (srv_i386_regobj): Add i386-avx.o. + (srv_i386_linux_regobj): Add i386-avx-linux.o. + (srv_amd64_regobj): Add amd64-avx.o. + (srv_amd64_linux_regobj): Add amd64-avx-linux.o. + (srv_i386_32bit_xmlfiles): Add i386/32bit-avx.xml. + (srv_i386_64bit_xmlfiles): Add i386/64bit-avx.xml. + (srv_i386_xmlfiles): Add i386/i386-avx.xml. + (srv_amd64_xmlfiles): Add i386/amd64-avx.xml. + (srv_i386_linux_xmlfiles): Add i386/i386-avx-linux.xml. + (srv_amd64_linux_xmlfiles): Add i386/amd64-avx-linux.xml. + + * i387-fp.c: Include "i386-xstate.h". + (i387_xsave): New. + (i387_cache_to_xsave): Likewise. + (i387_xsave_to_cache): Likewise. + (x86_xcr0): Likewise. + + * i387-fp.h (i387_cache_to_xsave): Likewise. + (i387_xsave_to_cache): Likewise. + (x86_xcr0): Likewise. + + * linux-arm-low.c (target_regsets): Initialize nt_type to 0. + * linux-crisv32-low.c (target_regsets): Likewise. + * linux-m68k-low.c (target_regsets): Likewise. + * linux-mips-low.c (target_regsets): Likewise. + * linux-ppc-low.c (target_regsets): Likewise. + * linux-s390-low.c (target_regsets): Likewise. + * linux-sh-low.c (target_regsets): Likewise. + * linux-sparc-low.c (target_regsets): Likewise. + * linux-xtensa-low.c (target_regsets): Likewise. + + * linux-low.c: Include . + (regsets_fetch_inferior_registers): Support nt_type. + (regsets_store_inferior_registers): Likewise. + (linux_process_qsupported): New. + (linux_target_ops): Add linux_process_qsupported. + + * linux-low.h (regset_info): Add nt_type. + (linux_target_ops): Add process_qsupported. + + * linux-x86-low.c: Include "i386-xstate.h", "elf/common.h" + and . + (init_registers_i386_avx_linux): New. + (init_registers_amd64_avx_linux): Likewise. + (xmltarget_i386_linux_no_xml): Likewise. + (xmltarget_amd64_linux_no_xml): Likewise. + (PTRACE_GETREGSET): Likewise. + (PTRACE_SETREGSET): Likewise. + (x86_fill_xstateregset): Likewise. + (x86_store_xstateregset): Likewise. + (use_xml): Likewise. + (x86_linux_update_xmltarget): Likewise. + (x86_linux_process_qsupported): Likewise. + (target_regsets): Add NT_X86_XSTATE entry and Initialize nt_type. + (x86_arch_setup): Don't call init_registers_amd64_linux nor + init_registers_i386_linux here. Call + x86_linux_update_xmltarget. + (the_low_target): Add x86_linux_process_qsupported. + + * server.c (handle_query): Call target_process_qsupported. + + * target.h (target_ops): Add process_qsupported. + (target_process_qsupported): New. + +2010-04-03 Pedro Alves + + * inferiors.c (add_thread): Set last_status kind to + TARGET_WAITKIND_IGNORE. + * linux-low.c (cancel_breakpoint): Remove unnecessary regcache + fetch. Use ptid_of. Avoid unnecessary get_lwp_thread calls. + (linux_wait_1): Move `thread' local definition to block that uses + it. Don't NULL initialize `event_child'. + (linux_resume_one_thread): Avoid unnecessary get_lwp_thread calls. + Alway set the thread's last_status to TARGET_WAITKIND_IGNORE. + * linux-x86-low.c (x86_breakpoint_at): Read raw memory. + +2010-04-01 Pedro Alves + + * linux-low.c (get_stop_pc): Don't adjust the PC if stopped with + an extended waitstatus, or by a watchpoint. + (cancel_breakpoints_callback): Don't cancel a breakpoint if the + thread was stepping or has been stopped by a watchpoint. + +2010-04-01 Pedro Alves + + * mem-break.c (struct raw_breakpoint): New field shlib_disabled. + (set_gdb_breakpoint_at): If GDB is inserting a breakpoint on top + of another, then delete the previous, and validate all + breakpoints. + (validate_inserted_breakpoint): New. + (delete_disabled_breakpoints): New. + (validate_breakpoints): New. + (check_mem_read): Validate breakpoints before trusting their + shadow. Delete disabled breakpoints. + (check_mem_write): Validate breakpoints before trusting they + should be inserted. Delete disabled breakpoints. + * mem-break.h (validate_breakpoints): + * server.c (handle_query): Validate breakpoints when we see a + qSymbol query. + +2010-04-01 Pedro Alves + + * linux-low.c (linux_wait_1): Avoid setting need_step_over is + there's a GDB breakpoint at stop_pc. Always report a trap to GDB + if we could tell there's a GDB breakpoint at stop_pc. + (need_step_over_p): Don't do a step over if we find a GDB + breakpoint at the resume PC. + + * mem-break.c (struct raw_breakpoint): New. + (enum bkpt_type): New type `gdb_breakpoint'. + (struct breakpoint): Delete the `PC', `old_data' and `inserted' + fields. New field `raw'. + (find_raw_breakpoint_at): New. + (set_raw_breakpoint_at): Handle refcounting. Create a raw + breakpoint instead. + (set_breakpoint_at): Adjust. + (delete_raw_breakpoint): New. + (release_breakpoint): New. + (delete_breakpoint): Rename to... + (delete_breakpoint_1): ... this. Add proc parameter. Use + release_breakpoint. Return ENOENT. + (delete_breakpoint): Reimplement. + (find_breakpoint_at): Delete. + (find_gdb_breakpoint_at): New. + (delete_breakpoint_at): Delete. + (set_gdb_breakpoint_at): New. + (delete_gdb_breakpoint_at): New. + (gdb_breakpoint_here): New. + (set_reinsert_breakpoint): Use release_breakpoint. + (uninsert_breakpoint): Rename to ... + (uninsert_raw_breakpoint): ... this. + (uninsert_breakpoints_at): Adjust to handle raw breakpoints. + (reinsert_raw_breakpoint): Change parameter type to + raw_breakpoint. + (reinsert_breakpoints_at): Adjust to handle raw breakpoints + instead. + (check_breakpoints): Adjust. Use release_breakpoint. + (breakpoint_here): Rewrite using find_raw_breakpoint_at. + (breakpoint_inserted_here): Ditto. + (check_mem_read): Adjust to iterate over raw breakpoints instead. + Don't trust the breakpoint's shadow if it is not inserted. + (check_mem_write): Adjust to iterate over raw breakpoints instead. + (delete_all_breakpoints): Adjust. + (free_all_breakpoints): Mark all breakpoints as uninserted, and + use delete_breakpoint_1. + + * mem-break.h (breakpoints_supported): Delete declaration. + (set_gdb_breakpoint_at): Declare. + (gdb_breakpoint_here): Declare. + (delete_breakpoint_at): Delete. + (delete_gdb_breakpoint_at): Declare. + + * server.h (struct raw_breakpoint): Forward declare. + (struct process_info): New field `raw_breakpoints'. + + * linux-x86-low.c (x86_insert_point, x86_remote_point): Handle Z0 + breakpoints. + +2010-03-24 Pedro Alves + + * linux-low.c (status_pending_p_callback): Fix comment. + (linux_wait_for_event_1): Move most of the internal breakpoint + handling from here... + (linux_wait_1): ... to here. + (count_events_callback): New. + (select_singlestep_lwp_callback): New. + (select_event_lwp_callback): New. + (cancel_breakpoints_callback): New. + (select_event_lwp): New. + (linux_wait_1): Simplify internal breakpoint handling. Give equal + priority to all LWPs that have had events that should be reported + to the client. Cancel breakpoints when about to reporting the + event to the client, not while stopping lwps. No longer cancel + finished single-steps here. + (cancel_finished_single_step): Delete. + (cancel_finished_single_steps): Delete. + +2010-03-24 Pedro Alves + + * mem-break.c (enum bkpt_type): New. + (struct breakpoint): New field `type'. + (set_breakpoint_at): Change return type to struct breakpoint + pointer. Set type to `other_breakpoint' by default. + (delete_breakpoint): Rewrite, supporting more than one breakpoint + in the breakpoint list. + (delete_reinsert_breakpoints): Only delete reinsert breakpoints. + (reinsert_breakpoint): Rename to ... + (reinsert_raw_breakpoint): ... this. + (reinsert_breakpoints_at): Adjust. + * mem-break.h (struct breakpoint): Declare. + (set_breakpoint_at): Change return type to struct breakpoint + pointer. + +2010-03-24 Pedro Alves + + * server.c (handle_query): Assign, not compare. + +2010-03-24 Pedro Alves + + Teach linux gdbserver to step-over-breakpoints. + + * linux-low.c (can_hardware_single_step): New. + (supports_breakpoints): New. + (handle_extended_wait): If stopping threads, read the stop pc of + the new cloned LWP. + (get_pc): New. + (get_stop_pc): Add `lwp' parameter. Handle it. Bail out if the + low target doesn't support retrieving the PC. + (add_lwp): Set last_resume_kind to resume_continue. + (linux_attach_lwp_1): Adjust comments. Always set stop_expected. + (linux_attach): Don't clear stop_expected. Set the lwp's + last_resume_kind to resume_stop. + (linux_detach_one_lwp): Don't check for removed breakpoints. + (check_removed_breakpoint): Delete. + (status_pending_p): Rename to ... + (status_pending_p_callback): ... this. Don't check for removed + breakpoints. Don't consider threads that are stopped from GDB's + perspective. + (linux_wait_for_lwp): Always read the stop_pc here. + (cancel_breakpoint): New. + (step_over_bkpt): New global. + (linux_wait_for_event_1): Implement stepping over breakpoints. + (gdb_wants_lwp_stopped): New. + (gdb_wants_all_stopped): New. + (linux_wait_1): Tag threads as gdb-wants-stopped. Cancel finished + single-step traps here. Store the thread's last reported target + wait status. + (send_sigstop): Don't clear stop_expected. Always set it, + instead. + (mark_lwp_dead): Remove reference to pending_is_breakpoint. + (cancel_finished_single_step): New. + (cancel_finished_single_steps): New. + (wait_for_sigstop): Don't cancel finished single-step traps here. + (linux_resume_one_lwp): Don't check for removed breakpoints. + Don't set `step' on non-hardware step archs. + (linux_set_resume_request): Ignore resume_stop requests if already + stopping or stopped. Set the lwp's last_resume_kind. + (resume_status_pending_p): Don't check for removed breakpoints. + (need_step_over_p): New. + (start_step_over): New. + (finish_step_over): New. + (linux_resume_one_thread): Always queue a sigstop for resume_stop + requests. Clear the thread's last reported target waitstatus. + Don't use the `suspended' flag. Don't consider pending breakpoints. + (linux_resume): Start a step-over if necessary. + (proceed_one_lwp): New. + (proceed_all_lwps): New. + (unstop_all_lwps): New. + * linux-low.h (struct lwp_info): Rewrite comment for the + `suspended' flag. Add the `stop_pc' field. Delete the + `pending_stop_pc' field. Tweak the `stepping' flag's comment. + Add `'last_resume_kind' and `need_step_over' fields. + * inferiors.c (struct thread_info): Delete, moved elsewhere. + * mem-break.c (struct breakpoint): Delete `reinserting' flag. + Delete `breakpoint_to_reinsert' field. New flag `inserted'. + (set_raw_breakpoint_at): New. + (set_breakpoint_at): Rewrite to use it. + (reinsert_breakpoint_handler): Delete. + (set_reinsert_breakpoint): New. + (reinsert_breakpoint_by_bp): Delete. + (delete_reinsert_breakpoints): New. + (uninsert_breakpoint): Rewrite. + (uninsert_breakpoints_at): New. + (reinsert_breakpoint): Rewrite. + (reinsert_breakpoints_at): New. + (check_breakpoints): Rewrite. + (breakpoint_here): New. + (breakpoint_inserted_here): New. + (check_mem_read): Adjust. + * mem-break.h (breakpoints_supported, breakpoint_here) + (breakpoint_inserted_here, set_reinsert_breakpoint): Declare. + (reinsert_breakpoint_by_bp): Delete declaration. + (delete_reinsert_breakpoints): Declare. + (reinsert_breakpoint): Delete declaration. + (reinsert_breakpoints_at): Declare. + (uninsert_breakpoint): Delete declaration. + (uninsert_breakpoints_at): Declare. + (check_breakpoints): Adjust prototype. + * server.h: Adjust include order. + (struct thread_info): Declare here. Add a `last_status' field. + +2010-03-23 Michael Snyder + + * server.c (crc32): New function. + (handle_query): Add handling for 'qCRC:' request. + +2010-03-23 Pedro Alves + + * linux-x86-low.c (x86_linux_prepare_to_resume): Clear DR6 if the + lwp had been stopped by a watchpoint. + +2010-03-16 Pedro Alves + + * server.h (internal_error): Declare. + (gdb_assert, ASSERT_FUNCTION, gdb_assert_fail): Define. + * utils.c (internal_error): New function. + +2010-03-15 Andreas Schwab + + * configure.srv: Fix typo setting srv_regobj. + +2010-03-15 Pedro Alves + + * linux-low.c (fetch_register): Avoid passing a non string literal + format to `error'. + (usr_store_inferior_registers): Ditto. + +2010-03-14 Pedro Alves + + * linux-low.c (linux_write_memory): Bail out early if peeking + memory failed. + +2010-03-14 Pedro Alves + + * linux-low.h (struct lwp_info): New fields + `stopped_by_watchpoint' and `stopped_data_address'. + * linux-low.c (linux_wait_for_lwp): Check for watchpoint triggers + here, and cache them in the lwp object. + (wait_for_sigstop): Check stopped_by_watchpoint lwp field + directly. + (linux_resume_one_lwp): Clear the lwp's stopped_by_watchpoint + field. + (linux_stopped_by_watchpoint): Rewrite. + (linux_stopped_data_address): Rewrite. + +2010-03-06 Simo Melenius + + * linux-low.c (linux_wait_for_lwp): Fetch the regcache after + switching the current inferior, not before. + +2010-03-01 H.J. Lu + + * Makefile.in (clean): Replace reg-i386.c, reg-x86-64.c, + reg-i386-linux.c and reg-x86-64-linux.c with i386.c, amd64.c, + i386-linux.c and amd64-linux.c. + (reg-i386.o): Removed. + (reg-i386.c): Likewise. + (reg-i386-linux.o): Likewise. + (reg-i386-linux.c): Likewise. + (reg-x86-64.o): Likewise. + (reg-x86-64.c): Likewise. + (reg-x86-64-linux.o): Likewise. + (reg-x86-64-linux.c): Likewise. + (i386.o): New. + (i386.c): Likewise. + (i386-linux.o): Likewise. + (i386-linux.c): Likewise. + (amd64.o): Likewise. + (amd64.c): Likewise. + (amd64-linux.o): Likewise. + (amd64-linux.c): Likewise. + + * configure.srv (srv_i386_regobj): New. + (srv_i386_linux_regobj): Likewise. + (srv_amd64_regobj): Likewise. + (srv_amd64_linux_regobj): Likewise. + (srv_i386_32bit_xmlfiles): Likewise. + (srv_i386_64bit_xmlfiles): Likewise. + (srv_i386_xmlfiles): Likewise. + (srv_amd64_xmlfiles): Likewise. + (srv_i386_linux_xmlfiles): Likewise. + (srv_amd64_linux_xmlfiles): Likewise. + (i[34567]86-*-cygwin*): Set srv_regobj to $srv_i386_regobj. Set + srv_xmlfiles to $srv_i386_xmlfiles. + (i[34567]86-*-mingw32ce*): Likewise. + (i[34567]86-*-mingw*): Likewise. + (i[34567]86-*-nto*): Likewise. + (i[34567]86-*-linux*): Set srv_regobj to $srv_i386_linux_regobj + and $srv_amd64_linux_regobj. Set srv_xmlfiles to + $srv_i386_linux_xmlfiles and $srv_amd64_linux_xmlfiles. + (x86_64-*-linux*): Likewise. + + * linux-x86-low.c (init_registers_x86_64_linux): Removed. + (init_registers_amd64_linux): New. + (x86_arch_setup): Replace init_registers_x86_64_linux with + init_registers_amd64_linux. + +2010-02-23 Maxim Kuvyrkov + + * configure.ac: Check for libdl. If it is not available link against + static libthread_db. + * configure: Regenerate. + +2010-02-22 Pedro Alves + + PR9605 + + * i386-low.c (i386_length_and_rw_bits): Throw a fatal error if + handing a read watchpoint. + (i386_low_insert_watchpoint): Read watchpoints aren't supported. + +2010-02-12 Doug Evans + + * linux-low.c (linux_supports_tracefork_flag): Document. + (linux_look_up_symbols): Add comment. + +2010-02-03 H.J. Lu + + * regcache.c (supply_register): Clear regcache if buf is NULL. + +2010-02-02 Nicolas Roche + Joel Brobecker + + * inferiors.c (find_inferior): Add function documentation. + (unloaded_dll): Handle the case where the unloaded dll has not + been previously registered in the dll list. + +2010-02-01 Daniel Jacobowitz + + * linux-arm-low.c (thumb_breakpoint_len): Delete. + (thumb2_breakpoint): New. + (arm_breakpoint_at): Check for Thumb-2 breakpoints. + +2010-01-29 Daniel Jacobowitz + + * linux-low.c (get_stop_pc): Check for SIGTRAP. + (linux_wait_for_event_1): Handle SIGILL and SIGSEGV as possible + breakpoints. + +2010-01-21 Pedro Alves + + * linux-ppc-low.c (ppc_arch_setup): Adjust to regcache changes. + +2010-01-21 Jan Kratochvil + + * linux-s390-low.c (s390_collect_ptrace_register) + (s390_supply_ptrace_register): Adjust it for the new regcache parameter. + +2010-01-21 Doug Evans + + * linux-low.c (PTRACE_ARG3_TYPE): Change from long to void*. + (PTRACE_ARG4_TYPE): New macro. + (handle_extended_wait): Cast ptrace arg4 to PTRACE_ARG4_TYPE. + (linux_wait_for_event_1, linux_resume_one_lwp): Ditto. + (fetch_register): Cast to uintptr_t before casting to PTRACE_ARG3_TYPE. + (usr_store_inferior_registers): Ditto. + (linux_read_memory, linux_write_memory): Ditto. + (linux_test_for_tracefork): Ditto. + + * linux-arm-low.c: Remove redundant include of gdb_proc_service.h. + Only include elf.h if gdb_proc_service.h didn't include linux/elf.h. + +2010-01-21 Pedro Alves + + * proc-service.c (ps_lgetregs): Don't refetch registers from the + target. + +2010-01-21 Pedro Alves + + * spu-low.c (spu_fetch_registers, spu_store_registers): Change + prototype to take a regcache. Adjust. + +2010-01-20 Pedro Alves + + * regcache.h (struct thread_info): Forward declare. + (struct regcache): New. + (new_register_cache): Adjust prototype. + (get_thread_regcache): Declare. + (free_register_cache): Adjust prototype. + (registers_to_string, registers_from_string): Ditto. + (supply_register, supply_register_by_name, collect_register) + (collect_register_as_string, collect_register_by_name): Ditto. + * regcache.c (struct inferior_regcache_data): Delete. + (get_regcache): Rename to ... + (get_thread_regcache): ... this. Adjust. Switch inferior before + fetching registers. + (regcache_invalidate_one): Adjust. + (regcache_invalidate): Fix prototype. + (new_register_cache): Return the new register cache. + (free_register_cache): Change prototype. + (realloc_register_cache): Adjust. + (registers_to_string): Change prototype to take a regcache. Adjust. + (registers_from_string): Ditto. + (register_data): Ditto. + (supply_register): Ditto. + (supply_register_by_name): Ditto. + (collect_register): Ditto. + (collect_register_as_string): Ditto. + (collect_register_by_name): Ditto. + * server.c (process_serial_event): Adjust. + * linux-low.h (regset_fill_func, regset_store_func): Change + prototype. + (get_pc, set_pc, collect_ptrace_register, supply_ptrace_register): + Change prototype. + * linux-low.c (get_stop_pc): Adjust. + (check_removed_breakpoint): Adjust. + (linux_wait_for_event): Adjust. + (linux_resume_one_lwp): Adjust. + (fetch_register): Add regcache parameter. Adjust. + (usr_store_inferior_registers): Ditto. + (regsets_fetch_inferior_registers): Ditto. + (regsets_store_inferior_registers): Ditto. + (linux_fetch_registers, linux_store_registers): Ditto. + * i387-fp.c (i387_cache_to_fsave): Change prototype to take a + regcache. Adjust. + (i387_fsave_to_cache, i387_cache_to_fxsave, i387_fxsave_to_cache): + Ditto. + * i387-fp.h (i387_cache_to_fsave, i387_fsave_to_cache): Change + prototype to take a regcache. + (i387_cache_to_fxsave, i387_fxsave_to_cache): Ditto. + * remote-utils.c (convert_ascii_to_int, outreg) + (prepare_resume_reply): Change prototype to take a regcache. + Adjust. + * target.h (struct target_ops) : + Change prototype to take a regcache. + (fetch_inferior_registers, store_inferior_registers): Change + prototype to take a regcache. Adjust. + * proc-service.c (ps_lgetregs): Adjust. + * linux-x86-low.c (x86_fill_gregset, x86_store_gregset) + (x86_fill_fpregset, x86_store_fpregset, x86_fill_fpxregset) + (x86_store_fpxregset, x86_get_pc, x86_set_pc): Change prototype to + take a regcache. Adjust. + * linux-arm-low.c (arm_fill_gregset, arm_store_gregset) + (arm_fill_wmmxregset, arm_store_wmmxregset, arm_fill_vfpregset) + (arm_store_vfpregset, arm_get_pc, arm_set_pc): + (arm_breakpoint_at): Change prototype to take a regcache. Adjust. + * linux-cris-low.c (cris_get_pc, cris_set_pc) + (cris_cannot_fetch_register): + (cris_breakpoint_at): Change prototype to take a regcache. + Adjust. + * linux-crisv32-low.c (cris_get_pc, cris_set_pc, + cris_reinsert_addr, cris_write_data_breakpoint): Change prototype + to take a regcache. Adjust. + (cris_breakpoint_at, cris_insert_point, cris_remove_point): + Adjust. + * linux-m32r-low.c (m32r_get_pc, m32r_set_pc): Change prototype to + take a regcache. Adjust. + * linux-m68k-low.c (m68k_fill_gregset, m68k_store_gregset) + (m68k_fill_fpregset, m68k_store_fpregset, m68k_get_pc, + (m68k_set_pc): Change prototype to take a regcache. Adjust. + * linux-mips-low.c (mips_get_pc): + (mips_set_pc): Change prototype to take a regcache. Adjust. + (mips_reinsert_addr): Adjust. + (mips_collect_register): Change prototype to take a regcache. + Adjust. + (mips_supply_register): + (mips_collect_register_32bit, mips_supply_register_32bit) + (mips_fill_gregset, mips_store_gregset, mips_fill_fpregset) + (mips_store_fpregset): Ditto. + * linux-ppc-low.c (ppc_supply_ptrace_register) + (ppc_supply_ptrace_register): Ditto. + (parse_spufs_run): Adjust. + (ppc_get_pc, ppc_set_pc, ppc_fill_gregset, ppc_fill_vsxregset) + (ppc_store_vsxregset, ppc_fill_vrregset, ppc_store_vrregset) + (ppc_fill_evrregset, ppc_store_evrregset): Change prototype to + take a regcache. Adjust. + * linux-s390-low.c (s390_collect_ptrace_register) + (s390_supply_ptrace_register, s390_fill_gregset, s390_get_pc) + (s390_set_pc): Change prototype to take a regcache. Adjust. + (s390_arch_setup): Adjust. + * linux-sh-low.c (sh_get_pc, sh_breakpoint_at) + (sh_fill_gregset): Change prototype to take a regcache. Adjust. + * linux-sparc-low.c (sparc_fill_gregset_to_stack) + (sparc_fill_gregset, sparc_store_gregset_from_stack) + (sparc_store_gregset, sparc_get_pc): Change prototype to take a + regcache. Adjust. + (sparc_breakpoint_at): Adjust. + * linux-xtensa-low.c (xtensa_fill_gregset): + (xtensa_store_gregset): + (xtensa_fill_xtregset, xtensa_store_xtregset, xtensa_get_pc) + (xtensa_set_pc): Change prototype to take a regcache. Adjust. + * nto-low.c (nto_fetch_registers, nto_store_registers): Change + prototype to take a regcache. Adjust. + * win32-arm-low.c (arm_fetch_inferior_register) + (arm_store_inferior_register): Change prototype to take a + regcache. Adjust. + * win32-i386-low.c (i386_fetch_inferior_register) + (i386_store_inferior_register): Change prototype to take a + regcache. Adjust. + * win32-low.c (child_fetch_inferior_registers) + (child_store_inferior_registers): Change prototype to take a + regcache. Adjust. + (win32_wait): Adjust. + (win32_fetch_inferior_registers): Change prototype to take a + regcache. Adjust. + (win32_store_inferior_registers): Adjust. + * win32-low.h (struct win32_target_ops) : Change prototype to take a regcache. + +2010-01-20 Doug Evans + + * linux-low.c (linux_create_inferior): Wrap use of __SIGRTMIN in + #ifdef. + (linux_wait_for_event1, linux_init_signals): Ditto. + (W_STOPCODE): Provide definition if missing. + +2010-01-13 Vladimir Prus + + * linux-low.c (linux_core_of_thread): New. + (compare_ints, show_process, list_threads): New. + (linux_qxfer_osdata): Report threads and cores. + (linux_target_op): Register linux_core_of_thread. + * remote-utils.c (prepare_resume_reply): Report the core. + (buffer_xml_printf): Support %d specifier. + * server.c (handle_threads_qxfer_proper, handle_threads_qxfer): + New. + (handle_query): Handle qXfer:threads. Announce availability + thereof. + * target.h (struct target_ops): New field core_of_thread. + +2010-01-04 Ulrich Weigand + + * Makefile.in (clean): Remove new generated files. + (reg-s390.o, reg-s390.c): Remove rules. + (reg-s390x.o, reg-s390x.c): Likewise. + (s390-linux32.o, s390-linux32.c): Add rules. + (s390-linux64.o, s390-linux64.c): Likewise. + (s390x-linux64.o, s390x-linux64.c): Likewise. + * configure.srv (s390*-*-linux*): Update srv_regobj and srv_xmlfiles. + * linux-s390-low.c: Include . + (HWCAP_S390_HIGH_GPRS): Define if undefined. + (init_registers_s390): Remove prototype. + (init_registers_s390x): Likewise. + (init_registers_s390_linux32): Add prototype. + (init_registers_s390_linux64): Likewise. + (init_registers_s390x_linux64): Likewise. + (s390_num_regs_3264): New define. + (s390_regmap_3264): New global variable. + (s390_cannot_fetch_register): Remove obsolete check. + (s390_cannot_store_register): Likewise. + (s390_collect_ptrace_register): Handle upper/lower register halves. + (s390_supply_ptrace_register): Likewise. + (s390_fill_gregset): Update to register number changes. + (s390_get_hwcap): New routine. + (s390_arch_setup): Detect 32-bit process running on 64-bit system. + Install appropriate regmap and register set. + +2010-01-01 Joel Brobecker + + * server.c (gdbserver_version): Update copyright year to 2010. + * gdbreplay.c (gdbreplay_version): Likewise. + +2009-12-28 Doug Evans + + * linux-low.c: Delete inclusion of ansidecl.h, elf/common.h, + elf/external.h. Include instead but only if necessary. + +2009-12-28 Pedro Alves + + * linux-low.c (linux_remove_process): Remove `detaching' + parameter. Don't release/detach from thread_db here. + (linux_kill): Release/detach from thread_db here, ... + (linux_detach): ... and here, before actually detaching. + (linux_wait_1): ... and here, when a process exits. + * thread-db.c (any_thread_of): New. + (thread_db_free): Switch the current inferior to a thread of the + passed in process. + +2009-12-21 Doug Evans + + * linux-x86-low.c: Delete outdated comment about Elf32_Phdr. + + * linux-low.c (kill_lwp): Use __NR_tkill instead of SYS_tkill. + Move definition of tkill_failed to ifdef __NR_tkill to avoid gcc + warning ifndef __NR_tkill. Move setting of errno there too. + Delete unnecessary resetting of errno after syscall. + Minor comment changes to match gdb/linux-nat.c:kill_lwp. + + * configure.ac: Check for dladdr. + * config.in: Regenerate. + * configure: Regenerate. + * thread-db.c (dladdr_to_soname): Only define ifdef HAVE_DLADDR. + (try_thread_db_load): Update. + + * linux-low.c (my_waitpid): Delete unnecessary prototype. + +2009-12-18 Doug Evans + + * event-loop.c: Include unistd.h if it exists. + + * linux-low.c (my_waitpid): Move definition away from being in + between linux_tracefork_child/linux_test_for_tracefork. + + * gdb_proc_service.h (psaddr_t): Fix type. + * thread-db.c (thread_db_info.td_thr_tls_get_addr_p): Fix + signature to match glibc. + +2009-12-16 Doug Evans + + * linux-low.c (linux_read_memory): Fix argument to read. + +2009-11-26 Pedro Alves + + * win32-low.c (get_child_debug_event): On EXIT_THREAD_DEBUG_EVENT + events, don't leave current_inferior pointing at null. + +2009-11-26 Pedro Alves + + * win32-low.c (LOG): Delete. + (OUTMSG): Output to stderr. + (OUTMSG2): Conditionalize on `debug_threads' variable, instead of + on compile time LOG macro. + (win32_wait): Fix debug output. + +2009-11-26 Pedro Alves + + * win32-low.c (win32_add_one_solib): If the dll name is + "ntdll.dll", prepend the system directory to the dll path. + +2009-11-17 Daniel Jacobowitz + + * m68k-tdep.c (m68k_gdbarch_init): Reuse previous initialization. + +2009-11-17 Nathan Sidwell + Vladimir Prus + + * Makefile.in (reg-cf.o, reg-cf.c): New targets. + * configure.ac: Check for __mcoldfire__ and set + gdb_cv_m68k_is_coldfire. + * configure.srv: Use gdb_cv_m68k_is_coldfire to select between + reg-cf.o and reg-m68k.o. + * configure: Regenerated. + +2009-11-16 Pedro Alves + + * linux-low.c (linux_remove_process): Add `detaching' parameter. + Pass it to thread_db_free. + (linux_kill, linux_detach, linux_wait_1): Adjust to pass the + proper `detaching' argument to linux_remove_process. + * linux-low.h (thread_db_free): Add `detaching' parameter. + * thread-db.c (thread_db_init): Pass false as `detaching' argument + to thread_db_free. + (thread_db_free): Add `detaching' parameter. Only + call td_ta_clear_event if detaching from process. + +2009-11-12 Maxim Kuvyrkov + + * thread-db.c (thread_db_free): Fix typo. + +2009-11-11 Paul Pluzhnikov + + PR gdb/10838 + * thread-db.c (thread_db_free): Call td_ta_clear_event. + +2009-11-03 Nathan Sidwell + + * configure.ac (i[34567]86-*): Check if we're targetting x86-64 + with an i686 compiler. + * configure.srv (i[34567]86-*-linux*): Pull in x86-64 handling if + needed. + * configure: Rebuilt. + +2009-10-29 Sandra Loosemore + + PR gdb/10783 + + * server.c (handle_search_memory_1): Correct read_addr initialization + in loop for searching subsequent chunks. + +2009-10-29 Paul Pluzhnikov + + * configure.ac: New --with-libthread-db option. + * thread-db.c: Allow direct dependence on libthread_db. + (thread_db_free): Adjust. + * config.in: Regenerate. + * configure: Likewise. + +2009-10-28 Paul Pluzhnikov + + PR gdb/10757 + * thread-db.c (attach_thread): New function. + (maybe_attach_thread): Return success/failure. + (find_new_threads_callback): Adjust. + (thread_db_find_new_threads): Loop until no new threads. + +2009-10-13 Pedro Alves + + * proc-service.c (ps_lgetregs): Formatting. + +2009-10-08 Paul Pluzhnikov + + * acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove. + * configure.ac: Adjust. + * linux-low.h (struct process_info_private): Move members to struct + thread_db. + (thread_db_free, thread_db_handle_monitor_command): New prototype. + * linux-low.c (linux_remove_process): Adjust. + (linux_wait_for_event_1, linux_look_up_symbols): Likewise. + * server.c (handle_query): Move code ... + (handle_monitor_command): ... here. New function. + * target.h (struct target_ops): New member. + * thread-db.c (struct thread_db): New. + (libthread_db_search_path): New variable. + (thread_db_create_event, thread_db_enable_reporting) + (find_one_thread, maybe_attach_thread, find_new_threads_callback) + (thread_db_find_new_threads, (thread_db_get_tls_address): Adjust. + (try_thread_db_load_1, dladdr_to_soname): New functions. + (try_thread_db_load, thread_db_load_search): New functions. + (thread_db_init): Search for libthread_db. + (thread_db_free): New function. + (thread_db_handle_monitor_command): Likewise. + * config.in: Regenerate. + * configure: Regenerate. + +2009-09-27 Ulrich Weigand + + * spu-low.c (spu_kill): Wait for inferior to terminate. + Call clear_inferiors. + (spu_detach): Call clear_inferiors. + +2009-08-22 Ralf Wildenhues + + * aclocal.m4: Regenerate. + * config.in: Likewise. + * configure: Likewise. + +2009-07-31 Ulrich Weigand + + * linux-ppc-low.c (INSTR_SC, NR_spu_run): Define. + (parse_spufs_run): New function. + (ppc_get_pc, ppc_set_pc): Detect and handle SPU PC. + (ppc_breakpoint_at): Handle SPU breakpoints. + +2009-07-31 Ulrich Weigand + + * linux-low.c: Include and . + (SPUFS_MAGIC): Define. + (spu_enumerate_spu_ids): New function. + (linux_qxfer_spu): New function. + (linux_target_ops): Install linux_qxfer_spu. + +2009-07-31 Ulrich Weigand + + * configure.srv (powerpc*-*-linux*): Add powerpc-cell32l.o + and powerpc-cell64l.o to srv_regobj. Add rs6000/powerpc-cell32l.xml + and rs6000/powerpc-cell64l.xml to srv_xmlfiles. + * Makefile.in (powerpc-cell32l.o, powerpc-cell32l.c): New rules. + (powerpc-cell64l.o, powerpc-cell64l.c): Likewise. + (clean): Handle powerpc-cell32l.c and powerpc-cell64l.c. + * linux-ppc-low.c (PPC_FEATURE_CELL): Define. + (init_registers_powerpc_cell32l): Add prototype. + (init_registers_powerpc_cell64l): Likewise. + (ppc_arch_setup): Detect Cell/B.E. architecture. + +2009-07-30 Ralf Wildenhues + + * Makefile.in (datarootdir): New variable. + +2009-07-28 Daniel Jacobowitz + + * linux-low.c (linux_write_memory): Update debugging output. + * Makefile.in (clean): Add new descriptions. + (arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o) + (arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules. + * configure.srv: Add new files for arm*-*-linux*. + * linux-arm-low.c: Add new declarations. + (PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined. + (arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3) + (HWCAP_VFPv3D16): New. + (arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT + instead of __IWMMXT__. + (arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap) + (arm_arch_setup): New. + (target_regsets): Remove #ifdef. Add VFP regset. + (the_low_target): Use arm_arch_setup. + +2009-07-28 Daniel Jacobowitz + + * linux-low.c (linux_kill_one_lwp): Adjust kernel workaround to skip + the main thread again. + +2009-07-06 Aleksandar Ristovski + + Adding Neutrino gdbserver. + * configure: Regenerated. + * configure.ac: Add case for srv_qnx and set LIBS accordingly. + * configure.srv (i[34567]86-*-nto*): New target. + * nto-low.c, nto-low.h, nto-x86-low.c: New files. + * remote-utils.c [__QNX__]: Include sys/iomgr.h + (nto_comctrl) [__QNX__]: New function. + (enable_async_io, disable_async_io) [__QNX__]: Call nto_comctrl. + +2009-07-05 Danny Backx + + * configure.srv (i[34567]86-*-mingw32ce*): Add i386-low.o to + srv_tgtobj. + +2009-07-04 Danny Backx + Pedro Alves + + * win32-i386-low.c (i386_get_thread_context): Handle systems that + don't support CONTEXT_EXTENDED_REGISTERS. + (i386_win32_breakpoint, i386_win32_breakpoint_len): New. + (the_low_target): Install them. + * win32-low.c (get_child_debug_event): Handle WaitForDebugEvent + failing with ERROR_PIPE_NOT_CONNECTED. + +2009-06-30 Doug Evans + Pierre Muller + + Add h/w watchpoint support to x86-linux, win32-i386. + * Makefile.in (SFILES): Add i386-low.c + (i386_low_h): Define. + (i386-low.o): Add dependencies. + (linux-x86-low.o): Add i386-low.h dependency. + (win32-i386-low.o): Ditto. + * i386-low.c: New file. + * i386-low.h: New file. + * configure.srv (i[34567]86-*-cygwin*): Add i386-low.o to srv_tgtobj. + (i[34567]86-*-linux*, i[34567]86-*-mingw*, x86_64-*-linux*): Ditto. + * linux-low.c (linux_add_process): Initialize arch_private. + (linux_remove_process): Free arch_private. + (add_lwp): Initialize arch_private. + (delete_lwp): Free arch_private. + (linux_resume_one_lwp): Call the_low_target.prepare_to_resume if + provided. + * linux-low.h (process_info_private): New member arch_private. + (lwp_info): New member arch_private. + (linux_target_ops): New members new_process, new_thread, + prepare_to_resume. + (ptid_of): New macro. + * linux-x86-low.c: Include stddef.h, i386-low.h. + (arch_process_info): New struct. + (arch_lwp_info): New struct. + (x86_linux_dr_get, x86_linux_dr_set): New functions. + (i386_dr_low_set_addr, i386_dr_low_set_control): New functions. + (i386_dr_low_get_status): New function. + (x86_insert_point, x86_remove_point): New functions. + (x86_stopped_by_watchpoint): New function. + (x86_stopped_data_address): New function. + (x86_linux_new_process, x86_linux_new_thread): New functions. + (x86_linux_prepare_to_resume): New function. + (the_low_target): Add entries for insert_point, remove_point, + stopped_by_watchpoint, stopped_data_address, new_process, new_thread, + prepare_to_resume. + * server.c (debug_hw_points): New global. + (monitor_show_help): Document set debug-hw-points. + (handle_query): Process "set debug-hw-points". + * server.h (debug_hw_points): Declare. + (paddress): Declare. + * utils.c (NUMCELLS, CELLSIZE): New macros. + (get_sell, xsnprintf, paddress): New functions. + * win32-arm-low.c (the_low_target): Add entries for insert_point, + remove_point, stopped_by_watchpoint, stopped_data_address. + * win32-i386-low.c: Include i386-low.h. + (debug_reg_state): Replaces dr. + (i386_dr_low_set_addr, i386_dr_low_set_control): New functions. + (i386_dr_low_get_status): New function. + (i386_insert_point, i386_remove_point): New functions. + (i386_stopped_by_watchpoint): New function. + (i386_stopped_data_address): New function. + (i386_initial_stuff): Update. + (get_thread_context,set_thread_context,i386_thread_added): Update. + (the_low_target): Add entries for insert_point, + remove_point, stopped_by_watchpoint, stopped_data_address. + * win32-low.c (win32_insert_watchpoint): New function. + (win32_remove_watchpoint): New function. + (win32_stopped_by_watchpoint): New function. + (win32_stopped_data_address): New function. + (win32_target_ops): Add entries for insert_watchpoint, + remove_watchpoint, stopped_by_watchpoint, stopped_data_address. + * win32-low.h (win32_target_ops): New members insert_point, + remove_point, stopped_by_watchpoint, stopped_data_address. + +2009-06-25 Pedro Alves + + * server.c (process_serial_event): Re-return unsupported, not + error, if the type isn't recognized. Re-allow supporting only + insert or remove packets. Also call require_running for + breakpoints. Add missing break statement to default case. Tidy. + * target.h (struct target_ops): Rename insert_watchpoint to + insert_point, and remove_watchpoint to remove_point. + + * linux-low.h (struct linux_target_ops): Likewise. + * linux-low.c (linux_insert_watchpoint): Rename to ... + (linux_insert_point): ... this. Adjust. + (linux_remove_watchpoint): Rename to ... + (linux_remove_point): ... this. Adjust. + (linux_target_ops): Adjust. + * linux-crisv32-low.c (cris_insert_watchpoint): Rename to ... + (cris_insert_point): ... this. + (cris_remove_watchpoint): Rename to ... + (cris_remove_point): ... this. + (the_low_target): Adjust. + +2009-06-24 Pierre Muller + + * server.c (handle_v_kill): Pass signal_pid to + kill_inferior if multi_process is zero. + +2009-06-23 Aleksandar Ristovski + + * server.c (process_serial_event): Add support for Z0 and Z1 packet. + * target.h (target_ops): Comment for *_watchpoint to make it clear + the functions can get types '0' and '1'. + +2009-06-22 Aleksandar Ristovski + + * linux-low.c (usr_fetch_inferior_registers): Remove check for regno 0. + * proc-service.c (ps_lgetregs): Pass -1 to fetch all registers. + * regcache.c (get_regcache): Likewise. + * spu-low.c (spu_fetch_registers): Remove 0 to -1 conversion. + * win32-low.c (child_fetch_inferior_registers): Remove check for + regno 0. + +2009-06-19 Aleksandar Ristovski + Pedro Alves + + * target.h (struct target_ops) : New + callback. + (target_supports_multi_process): New. + * server.c (handle_query): Even if GDB reports support, only + enable multi-process if the target also supports it. Report + multi-process support only if the target backend supports it. + * linux-low.c (linux_supports_multi_process): New function. + (linux_target_ops): Install it as target_supports_multi_process + callback. + +2009-05-24 Doug Evans + + Global renaming of find_thread_pid to find_thread_ptid. + * server.h (find_thread_ptid): Renamed from find_thread_pid. + * inferiors.c (find_thread_ptid): Renamed from find_thread_pid. + All callers updated. + + * linux-low.c (handle_extended_wait): Use linux_resume_one_lwp + to resume the newly created thread, don't call ptrace (PTRACE_CONT) + directly. + + * linux-low.c (get_stop_pc): Print pc if debug_threads. + (check_removed_breakpoint, linux_wait_for_lwp): Ditto. + (linux_resume_one_lwp): Ditto. + +2009-05-23 Doug Evans + + * linux-low.c (linux_resume_one_lwp): Change type of first arg + from struct inferior_list_entry * to struct lwp_info *. + All callers updated. + +2009-05-13 Doug Evans + + * linux-x86-low.c: Don't include assert.h. + (x86_siginfo_fixup): Use fatal, not assert. + (x86_arch_setup): Fix comment. + +2009-05-12 Doug Evans + + Biarch support for i386/amd64 gdbserver. + * Makefile.in (SFILES): Remove linux-i386-low.c, linux-x86-64-low.c. + Add linux-x86-low.c. + (linux-i386-low.o, linux-x86-64-low.o): Delete. + (linux-x86-low.o): Add. + * linux-x86-64-low.c: Delete. + * linux-i386-low.c: Delete. + * linux-x86-low.c: New file. + * configure.srv (i?86-linux srv_tgtobj): Replace linux-i386-low.o with + linux-x86-low.o. + (x86_64-linux srv_tgtobj): Replace linux-x86-64-low.o with + linux-x86-low.o. + (x86_64-linux srv_regobj): Add reg-i386-linux.o. + * linux-low.c: Include ansidecl.h, elf/common.h, elf/external.h. + (linux_child_pid_to_exec_file): New function. + (elf_64_header_p, elf_64_file_p): New functions. + (siginfo_fixup): New function. + (linux_xfer_siginfo): New local inf_siginfo. Call siginfo_fixup to + give target a chance to convert layout. + * linux-low.h (linux_target_ops): New member siginfo_fixup. + (linux_child_pid_to_exec_file, elf_64_file_p): Declare. + +2009-05-07 Doug Evans + + * linux-low.c (regsets_fetch_inferior_registers): Fix memory leak. + (regsets_store_inferior_registers): Ditto. + +2009-05-06 Pedro Alves + + PR server/10048 + + * linux-low.c (must_set_ptrace_flags): Delete. + (linux_create_inferior): Set `lwp->must_set_ptrace_flags' instead + of the global. + (linux_attach_lwp_1): Don't set PTRACE_SETOPTIONS here. Set + `lwp->must_set_ptrace_flags' instead. + (linux_wait_for_event_1): Set ptrace options here. + (linux_wait_1): ... not here. + +2009-04-30 Doug Evans + + * inferiors.c (started_inferior_callback): New function. + (attached_inferior_callback): New function. + (have_started_inferiors_p, have_attached_inferiors_p): New functions. + * server.c (print_started_pid, print_attached_pid): New functions. + (detach_or_kill_for_exit): New function. + (main): Call it instead of for_each_inferior (kill_inferior_callback). + * server.h (have_started_inferiors_p): Declare. + (have_attached_inferiors_p): Declare. + + * inferiors.c (remove_process): Fix memory leak, free process. + * linux-low.c (linux_remove_process): New function. + (linux_kill): Call it instead of remove_process. + (linux_detach, linux_wait_1): Ditto. + +2009-04-19 Danny Backx + + * configure.srv: Add x86 Windows CE target. + +2009-04-03 Ulrich Weigand + + * inferiors.c (get_thread_process): Make global. + * server.h (get_thread_process): Add prototype. + * thread-db.c (find_one_thread): Use get_thread_process + instead of current_process. + (thread_db_get_tls_address): Do not crash if called when + thread layer is not yet initialized. + +2009-04-03 Ulrich Weigand + + * remote-utils.c (prepare_resume_reply): Null-terminate packet. + * spu-low.c (current_tid): Rename to ... + (current_ptid): ... this. + (fetch_ppc_register, fetch_ppc_memory, store_ppc_memory, + spu_proc_xfer_spu, spu_resume, spu_request_interrupt): Use + ptid_get_lwp (current_ptid) instead of current_tid. + (spu_kill, spu_detach, spu_join, spu_wait): Use pid argument + instead of current_tid. Use find_process_pid to verify pid + argument is valid. Pass proper argument to remove_process. + (spu_thread_alive): Compare current_ptid instead of current_tid. + (spu_resume): Likewise. + +2009-04-02 Pedro Alves + + * linux-low.c (usr_store_inferior_registers): Declare local `pid' + variable. + +2009-04-01 Pedro Alves + + Implement the multiprocess extensions, and add linux multiprocess + support. + + * server.h (ULONGEST): Declare. + (struct ptid, ptid_t): New. + (minus_one_ptid, null_ptid): Declare. + (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) + (ptid_get_tid, ptid_equal, ptid_is_pid): Declare. + (struct inferior_list_entry): Change `id' type from unsigned from + to ptid_t. + (struct sym_cache, struct breakpoint, struct + process_info_private): Forward declare. + (struct process_info): Declare. + (current_process): Declare. + (all_processes): Declare. + (initialize_inferiors): Declare. + (add_thread): Adjust to use ptid_t. + (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto. + (add_process, remove_process, find_thread_pid): Declare. + (find_inferior_id): Adjust to use ptid_t. + (cont_thread, general_thread, step_thread): Change type to ptid_t. + (multi_process): Declare. + (push_event): Adjust to use ptid_t. + (read_ptid, write_ptid): Declare. + (prepare_resume_reply): Adjust to use ptid_t. + (clear_symbol_cache): Declare. + * inferiors.c (all_processes): New. + (null_ptid, minus_one_ptid): New. + (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp) + (ptid_get_tid, ptid_equal, ptid_is_pid): New. + (add_thread): Change unsigned long to ptid. Remove gdb_id + parameter. Adjust. + (thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid. + (gdb_id_to_thread): Rename to ... + (find_thread_pid): ... this. Change unsigned long to ptid. + (gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid. + (loaded_dll, pull_pid_from_list): Adjust. + (add_process, remove_process, find_process_pid) + (get_thread_process, current_process, initialize_inferiors): New. + * target.h (struct thread_resume) : Change type to ptid_t. + (struct target_waitstatus) : Ditto. + (struct target_ops) : Add `pid' argument. Change + return type to int. + (struct target_ops) : Add `pid' argument. + (struct target_ops) : Change pid's type to ptid_t. + (struct target_ops) : Add `ptid' field. Change return type + to ptid. + (kill_inferior, detach_inferior, join_inferior): Add `pid' argument. + (mywait): Add `ptid' argument. Change return type to ptid_t. + (target_pid_to_str): Declare. + * target.c (set_desired_inferior): Adjust to use ptids. + (mywait): Add new `ptid' argument. Adjust. + (target_pid_to_str): New. + * mem-break.h (free_all_breakpoints): Declare. + * mem-break.c (breakpoints): Delelete. + (set_breakpoint_at, delete_breakpoint, find_breakpoint_at) + (check_mem_read, check_mem_write, delete_all_breakpoints): Adjust + to use per-process breakpoint list. + (free_all_breakpoints): New. + * remote-utils.c (struct sym_cache) : Drop `const'. + (symbol_cache, all_symbols_looked_up): Delete. + (hexchars): New. + (ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one, + read_ptid): New. + (prepare_resume_reply): Change ptid argument's type from unsigned + long to ptid_t. Adjust. Implement W;process and X;process. + (free_sym_cache, clear_symbol_cache): New. + (look_up_one_symbol): Adjust to per-process symbol cache. * + * server.c (cont_thread, general_thread, step_thread): Change type + to ptid_t. + (attached): Delete. + (multi_process): New. + (last_ptid): Change type to ptid_t. + (struct vstop_notif) : Change type to ptid_t. + (queue_stop_reply, push_event): Change `ptid' argument's type to + ptid_t. + (discard_queued_stop_replies): Add `pid' argument. + (start_inferior): Adjust to use ptids. Adjust to mywait interface + changes. Don't reference the `attached' global. + (attach_inferior): Adjust to mywait interface changes. + (handle_query): Adjust to use ptids. Parse GDB's qSupported + features. Handle and report "multiprocess+". Handle + "qAttached:PID". + (handle_v_cont): Adjust to use ptids. Adjust to mywait interface + changes. + (handle_v_kill): New. + (handle_v_stopped): Adjust to use target_pid_to_str. + (handle_v_requests): Allow multiple attaches and runs when + multiprocess extensions are in effect. Handle "vKill". + (myresume): Adjust to use ptids. + (queue_stop_reply_callback): Add `arg' parameter. Handle it. + (handle_status): Adjust to discard_queued_stop_replies interface + change. + (first_thread_of, kill_inferior_callback) + (detach_or_kill_inferior_callback, join_inferiors_callback): New. + (main): Call initialize_inferiors. Adjust to use ptids, killing + and detaching from all inferiors. Handle multiprocess packet + variants. + * linux-low.h: Include gdb_proc_service.h. + (struct process_info_private): New. + (struct linux_target_ops) : Use ptid_get_pid. + : Use ptid_get_lwp. + (get_lwp_thread): Adjust. + (struct lwp_info): Add `dead' member. + (find_lwp_pid): Declare. + * linux-low.c (thread_db_active): Delete. + (new_inferior): Adjust comment. + (inferior_pid): Delete. + (linux_add_process): New. + (handle_extended_wait): Adjust. + (add_lwp): Change unsigned long to ptid. + (linux_create_inferior): Add process to processes table. Adjust + to use ptids. Don't set new_inferior here. + (linux_attach_lwp): Rename to ... + (linux_attach_lwp_1): ... this. Add `initial' argument. Handle + it. Adjust to use ptids. + (linux_attach_lwp): New. + (linux_attach): Add process to processes table. Don't set + new_inferior here. + (struct counter): New. + (second_thread_of_pid_p, last_thread_of_process_p): New. + (linux_kill_one_lwp): Add `args' parameter. Handle it. Adjust to + multiple processes. + (linux_kill): Add `pid' argument. Handle it. Adjust to multiple + processes. Remove process from process table. + (linux_detach_one_lwp): Add `args' parameter. Handle it. Adjust + to multiple processes. + (any_thread_of): New. + (linux_detach): Add `pid' argument, and handle it. Remove process + from processes table. + (linux_join): Add `pid' argument. Handle it. + (linux_thread_alive): Change unsighed long argument to ptid_t. + Consider dead lwps as not being alive. + (status_pending_p): Rename `dummy' argument to `arg'. Filter out + threads we're not interested in. + (same_lwp, find_lwp_pid): New. + (linux_wait_for_lwp): Change `pid' argument's type from int to + ptid_t. Adjust. + (linux_wait_for_event): Rename to ... + (linux_wait_for_event_1): ... this. Change `pid' argument's type + from int to ptid_t. Adjust. + (linux_wait_for_event): New. + (linux_wait_1): Add `ptid' argument. Change return type to + ptid_t. Adjust. Use last_thread_of_process_p. Remove processes + that exit from the process table. + (linux_wait): Add `ptid' argument. Change return type to ptid_t. + Adjust. + (mark_lwp_dead): New. + (wait_for_sigstop): Adjust to use ptids. If a process exits while + stopping all threads, mark its main lwp as dead. + (linux_set_resume_request, linux_resume_one_thread): Adjust to use + ptids. + (fetch_register, usr_store_inferior_registers) + (regsets_fetch_inferior_registers) + (regsets_store_inferior_registers, linux_read_memory) + (linux_write_memory): Inline `inferior_pid'. + (linux_look_up_symbols): Adjust to use per-process + `thread_db_active'. + (linux_request_interrupt): Adjust to use ptids. + (linux_read_auxv): Inline `inferior_pid'. + (initialize_low): Don't reference thread_db_active. + * gdb_proc_service.h (struct ps_prochandle) : Remove. + * proc-service.c (ps_lgetregs): Use find_lwp_pid. + (ps_getpid): Return the pid of the current inferior. + * thread-db.c (proc_handle, thread_agent): Delete. + (thread_db_create_event, thread_db_enable_reporting): Adjust to + per-process data. + (find_one_thread): Change argument type to ptid_t. Adjust to + per-process data. + (maybe_attach_thread): Adjust to per-process data and ptids. + (thread_db_find_new_threads): Ditto. + (thread_db_init): Ditto. + * spu-low.c (spu_create_inferior, spu_attach): Add process to + processes table. Adjust to use ptids. + (spu_kill, spu_detach): Adjust interface. Remove process from + processes table. + (spu_join, spu_thread_alive): Adjust interface. + (spu_wait): Adjust interface. Remove process from processes + table. Adjust to use ptids. + * win32-low.c (current_inferior_tid): Delete. + (current_inferior_ptid): New. + (debug_event_ptid): New. + (thread_rec): Take a ptid. Adjust. + (child_add_thread): Add `pid' argument. Adjust to use ptids. + (child_delete_thread): Ditto. + (do_initial_child_stuff): Add `attached' argument. Add process to + processes table. + (child_fetch_inferior_registers, child_store_inferior_registers): + Adjust. + (win32_create_inferior): Pass 0 to do_initial_child_stuff. + (win32_attach): Pass 1 to do_initial_child_stuff. + (win32_kill): Adjust interface. Remove process from processes + table. + (win32_detach): Ditto. + (win32_join): Adjust interface. + (win32_thread_alive): Take a ptid. + (win32_resume): Adjust to use ptids. + (get_child_debug_event): Ditto. + (win32_wait): Adjust interface. Remove exiting process from + processes table. + +2009-04-01 Pedro Alves + + Non-stop mode support. + + * server.h (non_stop): Declare. + (gdb_client_data, handler_func): Declare. + (delete_file_handler, add_file_handler, start_event_loop): + Declare. + (handle_serial_event, handle_target_event, push_event) + (putpkt_notif): Declare. + * target.h (enum resume_kind): New. + (struct thread_resume): Replace `step' field by `kind' field. + (TARGET_WNOHANG): Define. + (struct target_ops) : Add `options' argument. + : New fields. + (target_supports_non_stop, target_async): New. + (start_non_stop): Declare. + (mywait): Add `options' argument. + * target.c (mywait): Add `options' argument. Print child exit + notifications here. + (start_non_stop): New. + * server.c (non_stop, own_buf, mem_buf): New globals. + (struct vstop_notif): New. + (notif_queue): New global. + (queue_stop_reply, push_event, discard_queued_stop_replies) + (send_next_stop_reply): New. + (start_inferior): Adjust to use resume_kind. Adjust to mywait + interface changes. + (attach_inferior): In non-stop mode, don't wait for the target + here. + (handle_general_set): Handle QNonStop. + (handle_query): When handling qC, return the current general + thread, instead of the first thread of the list. + (handle_query): If the backend supports non-stop mode, include + QNonStop+ in the qSupported query response. + (handle_v_cont): Adjust to use resume_kind. Handle resume_stop + and non-stop mode. + (handle_v_attach, handle_v_run): Handle non-stop mode. + (handle_v_stopped): New. + (handle_v_requests): Report support for vCont;t. Handle vStopped. + (myresume): Adjust to use resume_kind. Handle non-stop. + (queue_stop_reply_callback): New. + (handle_status): Handle non-stop mode. + (main): Clear non_stop flag on reconnection. Use the event-loop. + Refactor serial protocol handling from here ... + (process_serial_event): ... to this new function. When GDB + selects any thread, select one here. In non-stop mode, wait until + GDB acks all pending events before exiting. + (handle_serial_event, handle_target_event): New. + * remote-utils.c (remote_open): Install remote_desc in the event + loop. + (remote_close): Remove remote_desc from the event loop. + (putpkt_binary): Rename to... + (putpkt_binary_1): ... this. Add `is_notic' argument. Handle it. + (putpkt_binary): New as wrapper around putpkt_binary_1. + (putpkt_notif): New. + (prepare_resume_reply): In non-stop mode, don't change the + general_thread. + * event-loop.c: New. + * Makefile.in (OBJ): Add event-loop.o. + (event-loop.o): New rule. + + * linux-low.h (pid_of): Moved here. + (lwpid_of): New. + (get_lwp_thread): Use lwpid_of. + (struct lwp_info): Delete `lwpid' field. Add `suspended' field. + * linux-low.c (pid_of): Delete. + (inferior_pid): Use lwpid_of. + (linux_event_pipe): New. + (target_is_async_p): New. + (delete_lwp): New. + (handle_extended_wait): Use lwpid_of. + (add_lwp): Don't set lwpid field. + (linux_attach_lwp): Adjust debug output. Use lwpid_of. + (linux_kill_one_lwp): If killing a running lwp, stop it first. + Use lwpid_of. Adjust to linux_wait_for_event interface changes. + (linux_detach_one_lwp): If detaching from a running lwp, stop it + first. Adjust to linux_wait_for_event interface changes. Use + lwpid_of. + (linux_detach): Don't delete the main lwp here. + (linux_join): Use my_waitpid. Avoid signal_pid. Use lwpid_of. + (status_pending_p): Don't consider explicitly suspended lwps. + (linux_wait_for_lwp): Take an integer pid instead of a lwp_info + pointer. Add OPTIONS argument. Change return type to int. Use + my_waitpid instead of sleeping. Handle WNOHANG. Use lwpid_of. + (linux_wait_for_event): Take an integer pid instead of a lwp_info + pointer. Add status pointer argument. Return a pid instead of a + status. Use lwpid_of. Adjust to linux_wait_for_lwp interface + changes. In non-stop mode, don't switch to a random thread. + (linux_wait): Rename to... + (linux_wait_1): ... this. Add target_options argument, and handle + it. Adjust to use resume_kind. Use lwpid_of. In non-stop mode, + don't handle the continue thread. Handle TARGET_WNOHANG. Merge + clean exit and signal exit code. Don't stop all threads in + non-stop mode. In all-stop mode, only stop all threads when + reporting a stop to GDB. Handle explicit thread stop requests. + (async_file_flush, async_file_mark): New. + (linux_wait): New. + (send_sigstop): Use lwpid_of. + (wait_for_sigstop): Use lwpid_of. Adjust to linux_wait_for_event + interface changes. In non-stop mode, don't switch to a random + thread. + (linux_resume_one_lwp): Use lwpid_of. + (linux_continue_one_thread, linux_queue_one_thread): Merge into ... + (linux_resume_one_thread): ... this. Handle resume_stop. In + non-stop mode, don't look for pending flag in all threads. + (resume_status_pending_p): Don't consider explicitly suspended + threads. + (my_waitpid): Reimplement. Emulate __WALL. + (linux_request_interrupt, linux_read_offsets, linux_xfer_siginfo): + Use lwpid_of. + (sigchld_handler, linux_supports_non_stop, linux_async) + (linux_start_non_stop): New. + (linux_target_ops): Register linux_supports_non_stop, linux_async + and linux_start_non_stop. + (initialize_low): Install SIGCHLD handler. + * thread-db.c (thread_db_create_event, find_one_thread) + (thread_db_get_tls_address): Use lwpid_of. + * win32-low.c (win32_detach): Adjust to use resume_kind. + (win32_wait): Add `options' argument. + * spu-low.c (spu_resume): Adjust to use resume_kind. + (spu_wait): Add `options' argument. + +2009-04-01 Pedro Alves + + Decouple target code from remote protocol. + + * target.h (enum target_waitkind): New. + (struct target_waitstatus): New. + (struct target_ops) : Return an unsigned long. Take a + target_waitstatus pointer instead of a char pointer. + (mywait): Likewise. + * target.c (mywait): Change prototype to return an unsigned long. + Take a target_waitstatus pointer instead of a char pointer. Adjust. + * server.h (thread_from_wait, old_thread_from_wait): Delete + declarations. + (prepare_resume_reply): Change prototype to take a + target_waitstatus. + * server.c (thread_from_wait, old_thread_from_wait): Delete. + (last_status, last_ptid): New. + (start_inferior): Remove "statusptr" argument. Adjust. Return a + pid instead of a signal. + (attach_inferior): Remove "status" and "signal" parameters. + Adjust. + (handle_query): For qGetTLSAddr, parse the thread id with strtol, + not as an address. + (handle_v_cont, handle_v_attach, handle_v_run, handle_v_kill) + (handle_v_requests, myresume): Remove "status" and "signal" + parameters. Adjust. + (handle_status): New. + (main): Delete local `status'. Adjust. + * remote-utils.c: Include target.h. + (prepare_resume_reply): Change prototype to take a + target_waitstatus. Adjust. + + * linux-low.c (linux_wait): Adjust to new target_ops->wait + interface. + * spu-low.c (spu_wait): Adjust. + * win32-low.c (enum target_waitkind, struct target_waitstatus): + Delete. + (win32_wait): Adjust. + +2009-04-01 Pedro Alves + + * target.h (struct thread_resume): Delete leave_stopped member. + (struct target_ops): Add a `n' argument to the `resume' callback. + * server.c (start_inferior): Adjust. + (handle_v_cont, myresume): Adjust. + * linux-low.c (check_removed_breakpoint): Adjust to resume + interface change, and to removed leave_stopped field. + (resume_ptr): Delete. + (struct thread_resume_array): New. + (linux_set_resume_request): Add new `arg' parameter. Adjust to + resume interface change. + (linux_continue_one_thread, linux_queue_one_thread) + (resume_status_pending_p): Check if the resume field is NULL + instead of checking the leave_stopped member. + (linux_resume): Adjust to the target resume interface change. + * spu-low.c (spu_resume): Adjust to the target resume interface + change. + * win32-low.c (win32_detach, win32_resume): Ditto. + +2009-04-01 Pedro Alves + + * linux-low.c (linux_wait_for_event): Don't clear the `stepping' + flag. + (wait_for_sigstop): Don't leave a finished single-step SIGTRAP + pending. + (linux_continue_one_thread): Only preserve the stepping flag if + there's a pending breakpoint. + +2009-03-31 Pedro Alves + + * server.c (main): After the inferior having exited, call + remote_close before exiting gdbserver. + +2009-03-25 Thiago Jung Bauermann + + Fix size of FPSCR in Power 7 processors. + * linux-ppc-low.c (PPC_FEATURE_ARCH_2_05): Remove #define. + (PPC_FEATURE_HAS_DFP): New #define. + (ppc_arch_setup): Check for DFP feature instead of ISA 2.05 to decide on + size of the FPSCR. + +2009-03-23 Pedro Alves + + * server.c (handle_query) Whitespace and formatting. + +2009-03-22 Pedro Alves + + * i387-fp.c, linux-arm-low.c, linux-cris-low.c, + linux-crisv32-low.c, linux-i386-low.c, linux-low.c, + linux-mips-low.c, linux-s390-low.c, linux-sparc-low.c, + linux-x86-64-low.c, linux-xtensa-low.c, proc-service.c, + regcache.c, remote-utils.c, server.c, spu-low.c, target.h, + thread-db.c, win32-low.c, xtensa-xtregs.c, gdbreplay.c, + Makefile.in, configure.ac: Fix whitespace throughout. + * configure: Regenerate. + +2009-03-22 Pedro Alves + + * inferiors.c (find_inferior): Make it safe for the callback + function to delete the currently iterated inferior. + +2009-03-22 Pedro Alves + + * Makefile.in (linuw_low_h): Move higher. + (thread-db.o): Depend on $(linux_low_h). + +2009-03-17 Pedro Alves + + Rename "process" to "lwp" throughout. + + * linux-low.c (all_processes): Rename to... + (all_lwps): ... this. + (inferior_pid, handle_extended_wait, get_stop_pc): Adjust. + (add_process): Rename to ... + (add_lwp): ... this. Adjust. + (linux_create_inferior): Adjust. + (linux_attach_lwp): Adjust. + (linux_attach): Adjust. + (linux_kill_one_process): Rename to ... + (linux_kill_one_lwp): ... this. Adjust. + (linux_kill): Adjust. + (linux_detach_one_process): Rename to ... + (linux_detach_one_lwp): ... this. Adjust. + (linux_detach): Adjust. + (check_removed_breakpoint): Adjust. + (status_pending_p): Adjust. + (linux_wait_for_process): Rename to ... + (linux_wait_for_lwp): ... this. Adjust. + (linux_wait_for_event): Adjust. + (send_sigstop): Adjust. + (wait_for_sigstop): Adjust. + (stop_all_processes): Rename to ... + (stop_all_lwps): ... this. + (linux_resume_one_process): Rename to ... + (linux_resume_one_lwp): ... this. Adjust. + (linux_set_resume_request, linux_continue_one_thread) + (linux_queue_one_thread, resume_status_pending_p) + (usr_store_inferior_registers, regsets_store_inferior_registers) + (linux_request_interrupt, linux_read_offsets, linux_xfer_siginfo): + Adjust. + * linux-low.h (get_process): Rename to ... + (get_lwp): ... this. Adjust. + (get_thread_process): Rename to ... + (get_thread_lwp): ... this. Adjust. + (get_process_thread): Rename to ... + (get_lwp_thread): ... this. Adjust. + (struct process_info): Rename to ... + (struct lwp_info): ... this. + (all_processes): Rename to ... + (all_lwps): ... this. + * proc-service.c (ps_lgetregs): Adjust. + * thread-db.c (thread_db_create_event, find_one_thread) + (maybe_attach_thread, thread_db_get_tls_address): Adjust. + +2009-03-14 Pedro Alves + + * server.c (handle_query): Handle "qAttached". + +2009-03-13 Nathan Sidwell + + * Makefile.in, hostio-errno.c, errno.c, xtensa-xtregs.c: Change to + GPLv3, update license URL. + +2009-03-01 Doug Evans + + * Makefile.in (INCLUDE_CFLAGS): Add -I$(srcdir)/../common. + (server_h): Add gdb_signals.h. + (signals.o): Update. + * server.h (target_signal_from_host,target_signal_to_host_p) + (target_signal_to_host,target_signal_to_name): Moved to gdb_signals.h. + +2009-02-14 Pierre Muller + + * remote-utils.c (getpkt): Also generate remote-debug + information if noack_mode is set. + +2009-02-06 Pedro Alves + + * server.c (handle_query): Report qXfer:siginfo:read and + qXfer:siginfo:write as supported and handle them. + * target.h (struct target_ops) : New field. + * linux-low.c (linux_xfer_siginfo): New. + (linux_target_ops): Set it. + +2009-01-26 Pedro Alves + + * server.c (gdbserver_usage): Mention --remote-debug. + (main): Accept '--remote-debug' switch. + +2009-01-18 Doug Evans + + * regcache.c (new_register_cache): No need to check result of xcalloc. + * server.c (handle_search_memory): Back out calls to xmalloc, + result is checked and error is returned to user upon failure. + (handle_query): Ditto. Add more checks for result of malloc. + (handle_v_cont): Check result of malloc, report error back to + user upon failure. + (handle_v_run): Ditto. Call freeargv. + * server.h (freeargv): Declare. + * utils.c (freeargv): New fn. + +2009-01-15 Doug Evans + + * gdbreplay.c (perror_with_name): Make arg const char *. + * server.h (target_signal_to_name): Make return type const char *. + * thread-db.c (thread_db_err_str): Make return type const char *. + * utils.c (perror_with_name): Make arg const char *. + +2009-01-14 Pedro Alves + + * win32-low.c (get_child_debug_event): Issue a final DBG_CONTINUE + when handling a EXIT_PROCESS_DEBUG_EVENT. + +2009-01-06 Joel Brobecker + + * gdbreplay.c (gdbreplay_version): Update copyright year. + * server.c (gdbserver_version): Likewise. + +2009-01-05 Doug Evans + + * linux-low.c (linux_attach_lwp): Add some comments/fixmes. + (handle_extended_wait): Improve comment. + +2008-12-13 Doug Evans + + * utils.c (xmalloc,xcalloc,xstrdup): New fns. + * server.h (ATTR_MALLOC): New macro. + (xmalloc,xcalloc,xstrdup): Declare. + * hostio.c: Replace malloc,calloc,strdup with xmalloc,xcalloc,xstrdup. + * inferiors.c: Ditto. + * linux-low.c: Ditto. + * mem-break.c: Ditto. + * regcache.c: Ditto. + * remote-utils.c: Ditto. + * server.c: Ditto. + * target.c: Ditto. + * win32-low.c: Ditto. + +2008-12-12 Doug Evans + + * linux-low.c (linux_wait_for_process): Don't clobber current_inferior + in debugging printf. + + * linux-low.c (handle_extended_wait): Simplify, use my_waitpid. + +2008-12-09 Doug Evans + + * linux-low.h (struct process_info): Delete member tid, unused. + * thread-db.c (find_one_thread): Update. + (maybe_attach_thread): Update. + +2008-12-02 Pedro Alves + + * target.h (struct target_ops): Add qxfer_osdata member. + * linux-low.c: Include ctype.h and pwd.h and sys/types.h + and dirent.h. + (linux_qxfer_osdata): New functions. + (linux_target_ops): Register linux_qxfer_osdata as qxfer_osdata + callback. + * server.c (handle_query): Handle "qXfer:osdata:read:". + * remote-utils.c (buffer_grow, buffer_free, buffer_init, buffer_finish) + (buffer_xml_printf): New functions. + * server.h (struct buffer): New. + (buffer_grow_str, buffer_grow_str0): New macros. + (buffer_grow, buffer_free, buffer_init, buffer_finish) + (buffer_xml_printf): Declare. + +2008-11-24 Doug Evans + + * Makefile.in (VERSION,DIST,LINT,LINTFLAGS): Delete, unused. + +2008-11-24 Daniel Jacobowitz + + * server.c (handle_v_run): Always use the supplied argument list. + +2008-11-19 Bob Wilson + + * xtensa-xtregs.c (XTENSA_ELF_XTREG_SIZE): Change to 4. + (xtensa_regmap_table): Add entry for scompare1. + +2008-11-18 Thiago Jung Bauermann + + * Makefile.in (powerpc-isa205-32l.o, powerpc-isa205-32l.c, + powerpc-isa205-altivec32l.o, powerpc-isa205-altivec32l.c, + powerpc-isa205-vsx32l.o, powerpc-isa205-vsx32l.c, + powerpc-isa205-64l.o, powerpc-isa205-64l.c, + powerpc-isa205-altivec64l.o, powerpc-isa205-altivec64l.c, + powerpc-isa205-vsx64l.o, powerpc-isa205-vsx64l.c): New targets. + * configure.srv (powerpc*-*-linux*): Add ISA 2.05 object files and + XML target descriptions. + * linux-ppc-low.c (ppc_arch_setup): Init registers with 64-bit FPSCR + when inferior is running on an ISA 2.05 or later processor. Add + special case to return offset for full 64-bit slot of FPSCR when + in 32-bits. + +2008-11-14 Daniel Gutson + + * Makefile.in (SFILES, clean): Added sparc64 files. + (reg-sparc64.o, reg-sparc64.c): New. + * configure.srv (sparc*-*-linux*): New configuration. + * linux-low.c (regsets_fetch_inferior_registers): Swap ptrace + syscall arguments for SPARC. + (regsets_store_inferior_registers): Likewise. + * linux-sparc-low.c: New file. + +2008-10-21 Doug Evans + + * Makefile.in (BFD_DIR,BFD,BFD_SRC,BFD_CFLAGS): Delete. + (READLINE_DIR,READLINE_DEP): Delete. + (INTERNAL_CFLAGS): Update. + (LINTFLAGS): Update. + +2008-10-10 Pedro Alves + + * server.c (handle_v_run): If GDB didn't specify an argv, use the + whole argv from the last run, not just argv[0]. + +2008-09-08 Pedro Alves + + * regcache.c (new_register_cache): Return NULL if the register + cache size isn't known yet. + (free_register_cache): Avoid dereferencing a NULL regcache. + +2008-09-04 Daniel Jacobowitz + + * configure.srv: Merge MIPS and MIPS64. + +2008-08-24 Maciej W. Rozycki + + * Makefile.in (uninstall): Apply $(EXEEXT) too. + +2008-08-18 Luis Machado + + * Makefile.in: Add required vsx dependencies. + + * linux-ppc-low: Define PPC_FEATURE_HAS_VSX. + Declare init_registers_powerpc_vsx32l. + Declare init_registers_powerpc_vsx64l. + Define PTRACE_GETVSXREGS and PTRACE_SETVSXREGS. + (ppc_arch_setup): Check for VSX in hwcap. + (ppc_fill_vsxregset): New function. + (ppc_store_vsxregset): New function. + Add new VSX entry in regset_info target_regsets. + + * configure.srv: Add new VSX dependencies. + +2008-08-12 Pedro Alves + + * remote-utils.c (noack_mode, transport_is_reliable): New globals. + (remote_open): Set or clear transport_is_reliable. + (putpkt_binary): Don't expect acks in noack mode. + (getpkt): Don't send ack/nac in noack mode. + * server.c (handle_general_set): Handle QStartNoAckMode. + (handle_query): If connected by tcp pass QStartNoAckMode+ in + qSupported. + (main): Reset noack_mode on every connection. + * server.h (noack_mode): Declare. + +2008-08-07 Ralf Wildenhues + + * Makefile.in (GDBREPLAY_OBS): New variable. + (gdbreplay$(EXEEXT)): Use it to avoid unportable $^. + +2008-08-05 Ulrich Weigand + Daniel Jacobowitz + + * linux-low.c (linux_resume_one_process): Ignore ESRCH. + (usr_store_inferior_registers): Likewise. + (regsets_store_inferior_registers): Likewise. + +2008-07-31 Rolf Jansen + Pedro Alves + + * configure.ac: Check for memmem declaration. + * server.c [HAVE_MALLOC_H]: Include malloc.h. + (disable_packet_vCont, disable_packet_Tthread, disable_packet_qC) + (disable_packet_qfThreadInfo): Unconditionally compile. + * server.h [!HAVE_DECL_MEMMEM]: Declare memmem. + * configure, config.in: Regenerate. + +2008-07-28 Doug Kwan + + * linux-low.c (sys/dir.h, sys/user.h): Remove includes. + (linux_write_memory): Remove declaration of errno. + +2008-07-12 Ulrich Weigand + + * linux-low.c (handle_extended_wait): Do not use "status" + variable uninitialized. + +2008-07-07 Pedro Alves + + * server.c (handle_v_attach): Inhibit reporting dll changes. + +2008-06-27 Pedro Alves + + * remote-utils.c (prepare_resume_reply): If requested, don't + output "thread:TID" in the T stop reply. + + * server.c (disable_packet_vCont, disable_packet_Tthread) + (disable_packet_qC, disable_packet_qfThreadInfo): New globals. + (handle_query): If requested, disable support for qC, qfThreadInfo + and qsThreadInfo. + (handle_v_requests): If requested, disable support for vCont. + (gdbserver_show_disableable): New. + (main): Handle --disable-packet and --disable-packet=LIST. + + * server.h (disable_packet_vCont, disable_packet_Tthread) + (disable_packet_qC, disable_packet_qfThreadInfo): Declare. + +2008-06-20 Carlos O'Donell + + * server.c (gdbserver_usage): Mention --version. + +2008-06-06 Daniel Jacobowitz + + * Makefile.in (gdbreplay.o): New rule. + +2008-06-06 Joseph Myers + + * gdbreplay.c (gdbreplay_version): Say gdbreplay in version + message, not gdbserver. + +2008-06-05 Vladimir Prus + Nathan Sidwell + Joseph Myers + + * acinclude.m4: Include ../../config/acx.m4. + * configure.ac: Use ACX_PKGVERSION and ACX_BUGURL. + * configure, config.in: Regenerate. + * Makefile.in (gdbreplay$(EXEEXT)): Add version.o. + * server.c (gdbserver_version): Print PKGVERSION. + (gdbsrever_usage): Add stream parameter. Print REPORT_BUGS_TO. + (main): Adjust gdbserver_usage calls. + * gdbreplay.c (version, host_name): Add declarations. + (gdbreplay_version, gdbreplay_usage): New. + (main): Accept --version and --help options. + +2008-06-04 Daniel Jacobowitz + + * linux-arm-low.c (thumb_breakpoint, thumb_breakpoint_len): New. + (arm_breakpoint_at): Handle Thumb. + (the_low_target): Add comment. + +2008-05-29 Ulrich Weigand + + * linux-ppc-low.c (ppc_collect_ptrace_register): Clear buffer. + +2008-05-09 Doug Evans + + * server.h (decode_search_memory_packet): Declare. + * remote-utils.c (decode_search_memory_packet): New fn. + * server.c (handle_search_memory_1): New fn. + (handle_search_memory): New fn. + (handle_query): Process qSearch:memory packets. + +2008-05-08 Ulrich Weigand + + * regcache.c (registers_length): Remove. + (set_register_cache): Verify that PBUFSIZ is large enough to hold a + full register packet. + * regcache.h (registers_length): Remove prototype. + * server.h (PBUFSIZ): Define to 16384. + +2008-05-03 Ulrich Weigand + + * configure.srv (powerpc*-*-linux*): Set srv_regobj to + powerpc-32l.o, powerpc-altivec32l.o, powerpc-e500l.o, + powerpc-64l.o, and powerpc-altivec64l.o. + Remove rs6000/powerpc-32.xml, rs6000/powerpc-64.xml, and + rs6000/powerpc-e500.xml; add rs6000/powerpc-32l.xml, + rs6000/powerpc-altivec32l.xml, rs6000/powerpc-e500l.xml, + rs6000/powerpc-64l.xml, rs6000/powerpc-altivec64l.xml, + rs6000/power-linux.xml, and rs6000/power64-linux.xml + to srv_xmlfiles. + + * Makefile.in (reg-ppc.o, reg-ppc.c): Remove, replace by ... + (powerpc-32l.o, powerpc-32l.c): ... these new rules. + (powerpc-32.o, powerpc-32.c): Remove, replace by ... + (powerpc-altivec32l.o, powerpc-altivec32l.c): ... these new rules. + (powerpc-e500.o, powerpc-e500.c): Remove, replace by ... + (powerpc-e500l.o, powerpc-e500l.c): ... these new rules. + (reg-ppc64.o, reg-ppc64.c): Remove, replace by ... + (powerpc-64l.o, powerpc-64l.c): ... these new rules. + (powerpc-64.o, powerpc-64.c): Remove, replace by ... + (powerpc-altivec64l.o, powerpc-altivec64l.c): ... these new rules. + (clean): Update. + + * linux-ppc-low.c (init_registers_ppc): Remove, replace by ... + (init_registers_powerpc_32l): ... this new prototype. + (init_registers_powerpc_32): Remove, replace by ... + (init_registers_powerpc_altivec32l): ... this new prototype. + (init_registers_powerpc_e500): Remove, replace by ... + (init_registers_powerpc_e500l): ... this new prototype. + (init_registers_ppc64): Remove, replace by ... + (init_registers_powerpc_64l): ... this new prototype. + (init_registers_powerpc_64): Remove, replace by ... + (init_registers_powerpc_altivec64l): ... this new prototype. + (ppc_num_regs): Set to 73. + (PT_ORIG_R3, PT_TRAP): Define if necessary. + (ppc_regmap, ppc_regmap_e500): Add values for orig_r3 and trap. + (ppc_cannot_store_register): Handle orig_r3 and trap. + (ppc_arch_setup): Update init_registers_... calls. + (ppc_fill_gregset): Handle orig_r3 and trap. + + * inferiors.c (clear_inferiors): Reset current_inferior. + +2008-04-23 Paolo Bonzini + + * acinclude.m4: Add override.m4. + * configure: Regenerate. + +2008-04-21 Ulrich Weigand + + * linux-ppc-low.c (ppc_arch_setup): Reset ppc_hwcap after the + initial call to init_register_ppc64. + +2008-04-21 Ulrich Weigand + + * configure.srv (powerpc64-*-linux*, powerpc-*-linux*): Merge into + single powerpc*-*-linux* case. + (s390-*-linux*, s390x-*-linux*): Merge into single s390*-*-linux* case. + +2008-04-17 Ulrich Weigand + + * configure.srv [powerpc64-*-linux*]: Remove powerpc-e500.o from + srv_regobj. Remove rs6000/powerpc-e500.xml and rs6000/power-spe.xml + from reg_xmlfiles. + * linux-ppc-low.c: Include . + (PPC_FEATURE_HAS_ALTIVEC, PPC_FEATURE_HAS_SPE): Define. + (ppc_hwcap): New global variable. + (ppc_regmap): Remove __SPE__ #ifdef sections. + (ppc_regmap_e500): New global variable. + (ppc_cannot_store_register): Update __SPE__ special case. + (ppc_get_hwcap): New function. + (ppc_arch_setup): Use it to determine whether inferior supports + AltiVec or SPE registers. Set the_low_target.regmap if appropriate. + (ppc_fill_vrregset, ppc_store_vrregset): Define unconditionally. + Do not access registers if target does not support AltiVec. + (ppc_fill_evrregset, ppc_store_evrregset): Define unconditionally. + Do not access registers if target does not support SPE. + (target_regsets): Unconditionally include AltiVec and SPE regsets. + +2008-04-17 Daniel Jacobowitz + + * linux-low.c (disabled_regsets, num_regsets): New. + (use_regsets_p): Delete. + (linux_wait_for_process): Clear disabled_regsets. + (regsets_fetch_inferior_registers): Check and set it. + (regsets_store_inferior_registers): Likewise. + (linux_fetch_registers, linux_store_registers): Do not use + use_regsets_p. + (initialize_low): Allocate disabled_regsets. + +2008-04-14 Daniel Jacobowitz + + * Makefile.in (LIBOBJS): New. + (OBS): Use LIBOBJS. + (memmem.o): New rule. + * configure.ac: Use AC_CONFIG_LIBOBJ_DIR and check for memmem. + * configure: Regenerated. + +2008-04-04 Ulrich Weigand + + * server.c (handle_query): Never return "unsupported" for + qXfer:features:read queries. + +2008-03-27 Ulrich Weigand + + * server.c (get_features_xml): Fix inverted condition. + (handle_query): Always support qXfer:feature:read. + +2008-03-10 Daniel Jacobowitz + + * server.c (wrapper_argv): New. + (start_inferior): Handle wrapper_argv. If set, expect an extra + trap. + (gdbserver_usage): Document --wrapper. + (main): Parse --wrapper. + +2008-02-28 Ulrich Weigand + + * configure.srv [powerpc64-*-linux*]: Add all files mentioned for + powerpc-*-linux* to srv_regobj and reg_xmlfiles. + * linux-ppc-low.c (ppc_get_pc): Support bi-arch operation. + (ppc_set_pc): Likewise. + (ppc_arch_setup): New function. + (ppc_fill_gregset): Call ppc_collect_ptrace_register instead + of collect_register. + (the_low_target): Use ppc_arch_setup as arch_setup initializer. + +2008-02-28 Ulrich Weigand + + * configure.srv [powerpc64-*-linux*]: Use linux-ppc-low.o + instead of linux-ppc64-low.o. + * linux-ppc64-low.c: Remove file. + * Makefile.in (SFILES): Remove linux-ppc64-low.c. + (linux-ppc64-low.o): Remove rule. + + * linux-ppc-low.c (init_registers_ppc64): Add prototype. + (init_registers_powerpc_64): Likewise. + (ppc_regmap): Conditionally define depending on __powerpc64__. + (ppc_cannot_store_register): Do not special-case "fpscr" when + compiled on __powerpc64__. + (ppc_collect_ptrace_register): New function. + (ppc_supply_ptrace_register): New function. + (ppc_breakpoint): Change type to "unsigned int". + (ppc_breakpoint_at): Change type of "insn" to "unsigned int". + (the_low_target): Conditionally provide initializers for the + arch_setup member depending on __powerpc64__. Install + collect_ptrace_register and supply_ptrace_register members. + +2008-02-28 Ulrich Weigand + + * regcache.h (gdbserver_xmltarget): Add extern declaration. + * server.c (gdbserver_xmltarget): Define. + (get_features_xml): Use it to replace "target.xml" and arch_string. + + * configure.srv: Remove srv_xmltarget. Add XML files that were + mentioned there to srv_xmlfiles instead. Remove conditional tests + on gdb_cv_arm_iwmmxt, gdb_cv_ppc_altivec, gdb_cv_ppc_spe; set + srv_xmlfiles and srv_regobj to include all possible choices. + * configure.ac (srv_xmltarget): Remove. + (srv_xmlfiles): Do not add "target.xml". + (gdb_cv_arm_iwmmxt, gdb_cv_ppc_altivec, gdb_cv_ppc_spe): Remove + checks for supplementary target information. + * configure: Regenerate. + * Makefile.in (XML_TARGET): Remove. + (target.xml): Remove rule. + (clean): Do not clean up target.xml. + (.PRECIOUS): Do not mention target.xml. + + * target.h (struct target_ops): Remove arch_string member. + * linux-low.c (linux_arch_string): Remove. + (linux_target_ops): Remove arch_string initializer. + * linux-low.h (struct linux_target_ops): Remove arch_string member. + * linux-i386-low.c (the_low_target): Remove arch_string initializer. + * linux-x86-64-low.c (the_low_target): Remove arch_string initializer. + * spu-low.c (spu_arch_string): Remove. + (spu_target_ops): Remove arch_string initializer. + * win32-low.c (win32_arch_string): Remove. + (win32_target_ops): Remove arch_string initializer. + * win32-low.h (struct win32_target_ops): Remove arch_string member. + * win32-arm-low.c (the_low_target): Remove arch_string initializer. + * win32-i368-low.c (the_low_target): Remove arch_string initializer. + +2008-02-27 Ulrich Weigand + + * linux-low.h (struct linux_target_ops): Replace left_pad_xfer field + by collect_ptrace_register and supply_ptrace_register hooks. + * linux-low.c (fetch_register): Use supply_ptrace_register callback + instead of checking for the_low_target.left_pad_xfer. + (usr_store_inferior_registers): Use collect_ptrace_register callback + instead of checking for the_low_target.left_pad_xfer. + + * linux-s390-low.c (s390_collect_ptrace_register): New function. + (s390_supply_ptrace_register): Likewise. + (s390_fill_gregset): Call s390_collect_ptrace_register. + (the_low_target): Update. + + * linux-ppc64-low.c (ppc_collect_ptrace_register): New function. + (ppc_supply_ptrace_register): Likewise. + (the_low_target): Update. + + * linux-i386-low.c (the_low_target): Update. + * linux-x86-64-low.c (the_low_target): Update. + +2008-02-27 Ulrich Weigand + + * configure.srv [s390x-*-linux*]: Set srv_regobj to include both + reg-s390.o and reg-s390x.o. + + * linux-low.c (new_inferior): New global variable. + (linux_create_inferior, linux_attach): Set it. + (linux_wait_for_process): Call the_low_target.arch_setup after the + target has stopped for the first time. + (initialize_low): Do not call the_low_target.arch_setup. + + * linux-s390-low.c (s390_get_pc): Support bi-arch operation. + (s390_set_pc): Likewise. + (s390_arch_setup): New function. + (the_low_target): Use s390_arch_setup as arch_setup routine. + + * regcache.c (realloc_register_cache): New function. + (set_register_cache): Call it for each existing regcache. + +2008-02-27 Ulrich Weigand + + * server.h (init_registers): Remove prototype. + + * linux-low.h (struct linux_target_ops): Add arch_setup field. + * linux-low.c (initialize_low): Call the_low_target.arch_setup () + instead of init_registers (). + * linux-arm-low.c (init_registers_arm): Add prototype. + (init_registers_arm_with_iwmmxt): Likewise. + (the_low_target): Add initializer for arch_setup field. + * linux-cris-low.c (init_registers_cris): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-crisv32-low.c (init_registers_crisv32): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-i386-low.c (init_registers_i386_linux): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-ia64-low.c (init_registers_ia64): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-m32r-low.c (init_registers_m32r): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-m68k-low.c (init_registers_m68k): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-mips-low.c (init_registers_mips_linux): Add prototype. + (init_registers_mips64_linux): Likewise. + (the_low_target): Add initializer for arch_setup field. + * linux-ppc-low.c (init_registers_ppc): Add prototype. + (init_registers_powerpc_32, init_registers_powerpc_e500): Likewise. + (the_low_target): Add initializer for arch_setup field. + * linux-ppc64-low.c (init_registers_ppc64): Add prototype. + (init_registers_powerpc_64): Likewise. + (the_low_target): Add initializer for arch_setup field. + * linux-s390-low.c (init_registers_s390): Add prototype. + (init_registers_s390x): Likewise. + (the_low_target): Add initializer for arch_setup field. + * linux-sh-low.c (init_registers_sh): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-x86-64-low.c (init_registers_x86_64_linux): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * linux-xtensa-low.c (init_registers_xtensa): Add prototype. + (the_low_target): Add initializer for arch_setup field. + + * win32-low.h (struct win32_target_ops): Add arch_setup field. + * win32-low.c (initialize_low): Call the_low_target.arch_setup () + instead of init_registers (). + * win32-arm-low.c (init_registers_arm): Add prototype. + (the_low_target): Add initializer for arch_setup field. + * win32-i386-low.c (init_registers_i386): Add prototype. + (the_low_target): Add initializer for arch_setup field. + + * spu-low.c (init_registers_spu): Add prototype. + (initialize_low): Call initialie_registers_spu () instead of + initialize_registers (). + +2008-02-19 Pedro Alves + + * server.c (handle_v_requests): When handling the vRun and vAttach + packets, if already debugging a process, don't kill it. Return an + error instead. + +2008-02-17 Daniel Jacobowitz + + * server.c (handle_query): Correct length check. + +2008-02-14 Pedro Alves + + * win32-low.c (do_initial_child_stuff): Add process handle + parameter. Set current_process_handle and current_process_id from the + parameters. Clear globals. + (win32_create_inferior): Don't set current_process_handle and + current_process_id here. Instead pass them on the call to + do_initial_child_stuff. + (win32_attach): Likewise. + (win32_clear_inferiors): New. + (win32_kill): Don't close the current process handle or the + current thread handle here. Instead call win32_clear_inferiors. + (win32_detach): Don't open a new handle to the process. Call + win32_clear_inferiors. + (win32_join): Don't rely on current_process_handle; open a new + handle using the process id. + (win32_wait): Call win32_clear_inferiors when the inferior process + has exited. + +2008-02-14 Daniel Jacobowitz + + * server.c (monitor_show_help): Add "exit". + +2008-02-11 Maxim Grigoriev + + * Makefile.in (SFILES): Add linux-xtensa-low.c. + (clean): Add reg-xtensa.c. + (linux-xtensa-low.o, reg-xtensa.o, reg-xtensa.c): New dependencies. + * configure.srv (xtensa*-*-linux*) New target. + * linux-xtensa-low.c: New. + * xtensa-xtregs.c: New. + +2008-02-01 Pedro Alves + + * hostio.c: Don't include errno.h. + (errno_to_fileio_errno): Move to hostio-errno. + * hostio.c: (hostio_error): Remove the error parameter. Defer the + error number outputting to the target->hostio_last_error callback. + (hostio_packet_error): Use FILEIO_EINVAL directly. + (handle_open, handle_pread, hostio_error, handle_unlink): Update + calls to hostio_error. + * hostio-errno.c: New. + * server.h (hostio_last_error_from_errno): Declare. + * target.h (target_ops): Add hostio_last_error member. + * linux-low.c (linux_target_op): Register hostio_last_error_from_errno + as hostio_last_error handler. + * spu-low.c (spu_target_ops): Likewise. + * win32-low.c [_WIN32_WCE] (win32_error_to_fileio_error) + (wince_hostio_last_error): New functions. + (win32_target_ops) [_WIN32_WCE]: Register wince_hostio_last_error + as hostio_last_error handler. + (win32_target_ops) [!_WIN32_WCE]: Register + hostio_last_error_from_errno as hostio_last_error handler. + * Makefile.in (SFILES): Add hostio.c and hostio-errno.c. + (hostio-errno.o): New rule. + * configure.ac (GDBSERVER_DEPFILES): Add $srv_hostio_err_objs. + * configure.srv (srv_hostio_err_objs): New variable. Default to + hostio-errno.o. + (arm*-*-mingw32ce*): Set srv_hostio_err_objs to "". + * configure: Regenerate. + +2008-01-29 Daniel Jacobowitz + + * linux-low.c (linux_attach_lwp): Do not _exit after errors. + (linux_kill, linux_detach): Clean up the process list. + * remote-utils.c (remote_open): Improve port number parsing. + (putpkt_binary, input_interrupt): Only send interrupts if the target + is running. + * server.c (extended_protocol): Make static. + (attached): Define earlier. + (exit_requested, response_needed, program_argv): New variables. + (target_running): New. + (start_inferior): Clear attached here. + (attach_inferior): Set attached here. + (require_running): Define. + (handle_query): Use require_running and target_running. Implement + "monitor exit". + (handle_v_attach, handle_v_run): New. + (handle_v_requests): Use require_running. Handle vAttach and vRun. + (gdbserver_usage): Update. + (main): Redo argument parsing. Handle --debug and --multi. Handle + --attach along with other options or after the port. Save + program_argv. Support no initial program. Resynchronize + communication with GDB after an error. Handle "monitor exit". + Use require_running and target_running. Always allow the extended + protocol. Do not error out for Hc0 or Hc-1. Do not automatically + restart in extended mode. + * README: Refer to the GDB manual. Update --attach usage. + +2007-12-20 Andreas Schwab + + * linux-low.c (STACK_SIZE): Define. + (linux_tracefork_child): Use it. Use __clone2 on ia64. + (linux_test_for_tracefork): Likewise. + +2007-12-18 Daniel Jacobowitz + + * linux-low.c (linux_wait_for_event): Update messages. Do not + reinsert auto-delete breakpoints. + * mem-break.c (struct breakpoint): Change return type of handler to + int. + (set_breakpoint_at): Update handler type. + (reinsert_breakpoint_handler): Return 1 instead of calling + delete_breakpoint. + (reinsert_breakpoint_by_bp): Check for the original breakpoint before + setting a new one. + (check_breakpoints): Delete auto-delete breakpoints and return 2. + * mem-break.h (set_breakpoint_at): Update handler type. + * thread-db.c (thread_db_create_event, thread_db_create_event): Update. + * win32-low.c (auto_delete_breakpoint): New. + (get_child_debug_event): Use it. + +2007-12-16 Daniel Jacobowitz + + * configure.ac: Check for pread and pwrite. + * hostio.c (handle_pread): Fall back to lseek and read. + (handle_pwrite): Fall back to lseek and write. + * config.in, configure: Regenerated. + +2007-12-07 Daniel Jacobowitz + + * server.c (myresume): Add own_buf argument. + (main): Update calls. + +2007-12-06 Daniel Jacobowitz + + * linux-low.c (linux_wait, linux_resume): Do not handle async I/O. + * remote-utils.c (remote_open): Do not call disable_async_io. + (block_async_io): Delete. + (unblock_async_io): Make static. + (initialize_async_io): New. + * server.c (handle_v_cont): Handle async I/O here. + (myresume): Likewise. Move other common resume tasks here... + (main): ... from here. Call initialize_async_io. Disable async + I/O before the main loop. + * server.h (initialize_async_io): Declare. + (block_async_io, unblock_async_io): Delete prototypes. + * spu-low.c (spu_resume, spu_wait): Do not handle async I/O here. + +2007-12-06 Mick Davis + + * remote-utils.c (readchar): Allow binary data in received messages. + +2007-12-03 Pedro Alves + + * win32-low.c (attaching): New global. + (win32_create_inferior): Clear the `attaching' global. + (win32_attach): Set the `attaching' global. + (get_child_debug_event) [_WIN32_WCE]: Stop the inferior when + attaching. Only set a breakpoint at the entry point if not + attaching. + +2007-12-03 Pedro Alves + + * server.c (main): Don't report dll events on the initial + connection on attaches. + +2007-12-03 Pedro Alves + + * server.c (main): Relax numerical bases supported for the pid of + the --attach command line argument. + +2007-12-03 Pedro Alves + + * win32-low.c (win32_attach): Call OpenProcess before + DebugActiveProcess, not after. Add last error output to error + call. + +2007-12-03 Pedro Alves + + * win32-low.c (win32_get_thread_context) + (win32_set_thread_context): New functions. + (thread_rec): Use win32_get_thread_context. + (continue_one_thread, win32_resume): Use win32_set_thread_context. + * win32-low.h (win32_thread_info) [_WIN32_WCE]: Add `base_context' + field. + +2007-12-03 Leo Zayas + Pedro Alves + + * win32-low.c (soft_interrupt_requested, faked_breakpoint): New + global variables. + (child_add_thread): Minor cleanup. + (child_continue): Resume artificially suspended threads before + calling ContinueDebugEvent. + (suspend_one_thread): New. + (fake_breakpoint_event): New. + (get_child_debug_event): Change return type to int. Check here if + gdb sent an interrupt request. If a soft interrupt was requested, + fake a breakpoint event. Return 0 if there is no event to handle, + and 1 otherwise. + (win32_wait): Don't check here if gdb sent an interrupt request. + Ensure there is a valid event to handle. + (win32_request_interrupt): Add soft interruption method as last + resort. + +2007-12-03 Leo Zayas + Pedro Alves + + * win32-low.h (win32_thread_info): Add descriptions to the + structure members. Replace `suspend_count' counter by a + `suspended' flag. + * win32-low.c (thread_rec): Update condition of when to get the + context from the inferior. Rely on ContextFlags being set if it + has already been retrieved. Only suspend the inferior thread if + we haven't already. Warn if that fails. + (continue_one_thread): s/suspend_count/suspended/. Only call + ResumeThread once. Warn if that fails. + +2007-12-02 Pedro Alves + + * win32-low.c (win32_wait): Don't read from the inferior when it + has already exited. + +2007-12-02 Pedro Alves + + * Makefile.in (win32_low_h): New variable. + (win32-low.o): Add dependency on $(win32_low_h). + (win32-arm-low.o, win32-i386-low.o): New rules. + +2007-11-30 Daniel Jacobowitz + + * hostio.c: Correct copyright year. + +2007-11-30 Daniel Jacobowitz + + * Makefile.in (OBS): Add hostio.o. + (hostio.o): New rule. + * server.h (handle_vFile): Declare. + * hostio.c: New file. + * server.c (handle_v_requests): Take packet_len and new_packet_len + for binary packets. Call handle_vFile. + (main): Update call to handle_v_requests. + +2007-11-05 Daniel Jacobowitz + + * linux-low.c: Include . + +2007-11-01 Daniel Jacobowitz + + * linux-low.c (linux_tracefork_grandchild): New. + (linux_tracefork_child): Use clone. + (linux_test_for_tracefork): Use clone; allocate and free a stack. + +2007-10-31 Joel Brobecker + + * Makefile.in: Use $(SHELL) instead of "sh" to call regdat.sh. + +2007-10-24 Daniel Jacobowitz + + * linux-low.c (handle_extended_wait): Handle unexpected signals. + +2007-10-23 Daniel Jacobowitz + + * inferiors.c (change_inferior_id): Delete. + (add_pid_to_list, pull_pid_from_list): New. + * linux-low.c (PTRACE_SETOPTIONS, PTRACE_GETEVENTMSG) + (PTRACE_O_TRACESYSGOOD, PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) + (PTRACE_O_TRACECLONE, PTRACE_O_TRACEEXEC, PTRACE_O_TRACEVFORKDONE) + (PTRACE_O_TRACEEXIT, PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK) + (PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC, PTRACE_EVENT_VFORK_DONE) + (PTRACE_EVENT_EXIT, __WALL): Provide default definitions. + (stopped_pids, thread_db_active, must_set_ptrace_flags): New variables. + (using_threads): Always set to 1. + (handle_extended_wait): New. + (add_process): Do not set TID. + (linux_create_inferior): Set must_set_ptrace_flags. + (linux_attach_lwp): Remove TID argument. Do not check using_threads. + Use PTRACE_SETOPTIONS. Call new_thread_notify. Update all callers. + (linux_thread_alive): Rename TID argument to LWPID. + (linux_wait_for_process): Handle unknown processes. Do not use TID. + (linux_wait_for_event): Do not use TID or check using_threads. Update + call to dead_thread_notify. Call handle_extended_wait. + (linux_create_inferior): Use PTRACE_SETOPTIONS. + (send_sigstop): Delete sigstop_sent. + (wait_for_sigstop): Avoid TID. + (linux_supports_tracefork_flag, linux_tracefork_child, my_waitpid) + (linux_test_for_tracefork): New. + (linux_lookup_signals): Use thread_db_active and + linux_supports_tracefork_flag. + (initialize_low): Use thread_db_active and linux_test_for_tracefork. + * linux-low.h (get_process_thread): Avoid TID. + (struct process_ifo): Move thread_known and tid to the end. Remove + sigstop_sent. + (linux_attach_lwp, thread_db_init): Update prototypes. + * server.h (change_inferior_id): Delete prototype. + (add_pid_to_list, pull_pid_from_list): New prototypes. + * thread-db.c (thread_db_use_events): New. + (find_first_thread): Rename to... + (find_one_thread): ...this. Update callers and messages. Do not + call fatal. Check thread_db_use_events. Do not call + change_inferior_id or new_thread_notify. + (maybe_attach_thread): Update. Do not call new_thread_notify. + (thread_db_init): Set thread_db_use_events. Check use_events. + * utils.c (fatal, warning): Correct message prefix. + +2007-10-15 Daniel Jacobowitz + + * Makefile.in (clean): Remove new files. + (powerpc-32.o, powerpc-32.c, powerpc-e500.o, powerpc-e500.c) + (powerpc-64.o, powerpc-64.c): New rules. + * configure.srv: Use alternate register sets for powerpc64-*-linux* + with AltiVec, powerpc-*-linux* with AltiVec, and powerpc-*-linux* + with SPE. + * linux-ppc-low.c (ppc_regmap): Do not fetch the FP registers for + SPE targets. + (ppc_cannot_store_register): Do not check for FPSCR for SPE targets. + (PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS, ppc_fill_vrregset) + (ppc_store_vrregset, PTRACE_GETEVRREGS, PTRACE_SETEVRREGS) + (struct gdb_evrregset_t, ppc_fill_evrregset, ppc_store_evrregset): New. + (target_regsets): Add AltiVec and SPE register sets. + * configure.ac: Check for AltiVec and SPE. + * linux-ppc64-low.c (PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS) + (ppc_fill_vrregset, ppc_store_vrregset): New. + (target_regsets): Add AltiVec register set. + * configure: Regenerated. + +2007-09-19 Daniel Jacobowitz + + * linux-low.c (O_LARGEFILE): Define. + (linux_read_memory): Use /proc/PID/mem. + * configure.ac: Use AC_GNU_SOURCE. Check for pread64. + * configure, config.in: Regenerated. + +2007-09-04 Daniel Jacobowitz + + * linux-low.c (linux_wait_for_event): Do not pass signals while + single-stepping. + +2007-09-03 Pedro Alves + + * win32-low.c (create_process): New. + (win32_create_inferior): Use create_process instead of + CreateProcess. If create_process failed retry appending an ".exe" + suffix. Store the GetLastError result immediatelly after + create_process calls and use it on the call to error. + +2007-09-03 Pedro Alves + + * win32-low.c (handle_load_dll): Don't use toolhelp when waiting. + +2007-08-23 Joel Brobecker + + * configure.ac: Switch license to GPLv3. + +2007-08-01 Michael Snyder + + * remote-utils.c (putpkt_binary): Memory leak, free buf2. + +2007-07-31 Pedro Alves + + * win32-low.c (winapi_CloseToolhelp32Snapshot) [_WIN32_WCE]: New + typedef. + (win32_CloseToolhelp32Snapshot) [_WIN32_WCE]: New global var. + (load_toolhelp) [_WIN32_WCE]: Load TOOLHELP.DLL. Get + CloseToolhelp32Snapshot. + (toolhelp_get_dll_name) [_WIN32_WCE]: Close the snapshot with + CloseToolhelp32Snapshot. + +2007-07-27 Michael Snyder + + * server.c (main): Check for inferior exit before main loop. + +2007-07-18 Pedro Alves + + * remote-utils.c (remote_open): Set SO_KEEPALIVE on remote_desc + instead of on tmp_desc. + +2007-07-17 Pedro Alves + Daniel Jacobowitz + + * inferiors.c (all_dlls, dlls_changed, get_dll): New. + (add_thread): Minor cleanups. + (clear_inferiors): Move lower in the file. Clear the DLL + list. + (free_one_dll, match_dll, loaded_dll, unloaded_dll, clear_list): New. + * remote-utils.c (prepare_resume_reply): Check dlls_changed. + (xml_escape_text): New. + * server.c (handle_query): Handle qXfer:libraries:read. Report it + for qSupported. + (handle_v_cont): Report errors. + (gdbserver_version): Update. + (main): Correct size of own_buf. Do not report initial DLL events. + * server.h (struct dll_info, all_dlls, dlls_changed, loaded_dll) + (unloaded_dll, xml_escape_text): New. + * win32-low.c (enum target_waitkind): Update comments. + (win32_add_one_solib, get_image_name, winapi_EnumProcessModules) + (winapi_GetModuleInformation, winapi_GetModuleFileNameExA) + (win32_EnumProcessModules, win32_GetModuleInformation) + (win32_GetModuleFileNameExA, load_psapi, psapi_get_dll_name) + (winapi_CreateToolhelp32Snapshot, winapi_Module32First) + (winapi_Module32Next, win32_CreateToolhelp32Snapshot) + (win32_Module32First, win32_Module32Next, load_toolhelp) + (toolhelp_get_dll_name, handle_load_dll, handle_unload_dll): New. + (get_child_debug_event): Handle DLL events. + (win32_wait): Likewise. + +2007-07-12 Daniel Jacobowitz + + * configure.srv: Set srv_linux_regsets for sh*-*-linux*. + * linux-sh-low.c (sh_fill_gregset, target_regsets): New. + +2007-07-08 Pedro Alves + + * win32-low.c (handle_output_debug_string): Ignore event if not + waiting. + +2007-07-08 Pedro Alves + + * win32-arm-low.c (arm_wince_breakpoint): Fix typo. + +2007-07-03 Daniel Jacobowitz + + * remote-utils.c (look_up_one_symbol): Handle 'm' packets. + +2007-07-02 Daniel Jacobowitz + + * inferiors.c (change_inferior_id): Add comment. + * linux-low.c (check_removed_breakpoint): Add an early + prototype. Improve debug output. + (linux_attach): Doc update. + (linux_detach_one_process, linux_detach): Clean up before releasing + each process. + (send_sigstop, wait_for_sigstop): Improve comments and debug output. + * linux-low.h (struct process_info): Doc improvement. + * mem-break.c (delete_all_breakpoints): New. + * mem-break.h (delete_all_breakpoints): New prototype. + * thread-db.c (find_first_thread): New. + (thread_db_create_event): Call it instead of + thread_db_find_new_threads. Clean up unused variables. + (maybe_attach_thread): Remove first thread handling. + (thread_db_find_new_threads): Use find_first_thread. + (thread_db_get_tls_address): Likewise. + +2007-06-27 Daniel Jacobowitz + + * thread-db.c (thread_db_find_new_threads): Add prototype. + (thread_db_create_event): Check for the main thread before adding + a new thread. + (maybe_attach_thread): Only enable event reporting if TID == 0. + (thread_db_get_tls_address): Check for new threads. + +2007-06-20 Daniel Jacobowitz + + * linux-low.c (linux_create_inferior): Try execv before execvp. + * spu-low.c (spu_create_inferior): Likewise. + +2007-06-13 Mike Frysinger + + * linux-low.c (linux_create_inferior): Change execv to execvp. + * spu-low.c (spu_create_inferior): Likewies. + +2007-06-13 Daniel Jacobowitz + + * Makefile.in (clean): Clean new files instead of deleted ones. + (reg-mips.o, reg-mips.c, reg-mips64.o, reg-mips64.c): Delete. + (mips-linux.o, mips-linux.c, mips64-linux.o, mips64-linux.c): New + rules. + * configure.srv: Specify XML files and new regformats for MIPS and + MIPS64 GNU/Linux. + * linux-mips-low.c (mips_num_regs): Set to only used registers. + (mips_regmap): Do not fetch $0. Remove unused registers. Add + an entry for the restart register. + (mips_cannot_fetch_register, mips_cannot_store_register) + (mips_reinsert_addr, mips_fill_fpregset, mips_store_fpregset): Update + register names to match the XML descriptions. + (mips_fill_gregset, mips_store_gregset): Likewise. Handle the + restart register instead of $0. + +2007-06-12 Ulrich Weigand + Markus Deuling + + * remote-utils.c (decode_xfer_write): New function. + * server.h (decode_xfer_write): Add prototype. + * server.c (handle_query): Add PACKET_LEN argument. Support + qXfer:spu:read and qXfer:spu:write packets. + (main): Pass packet_len to handle_query. + * spu-low.c (spu_target_ops): Add spu_proc_xfer_spu. + * target.h (target_ops): Add qxfer_spu. + +2007-06-12 Ulrich Weigand + + * spu-low.c (spu_proc_xfer_spu): Do not return failure when + accessing non-seekable spufs files. + +2007-05-16 Markus Deuling + + * server.c (handle_query): Add reply for qC packet. + +2007-05-10 Pedro Alves + Leo Zayas + + * server.h (check_remote_input_interrupt_request): New function. + * remote_utils.c (INVALID_DESCRIPTOR): New define. + (remote_desc): Initialize with INVALID_DESCRIPTOR. + (input_interrupt): Expose on USE_WIN32API too. Fix whitespace. + (check_remote_input_interrupt_request): New function. + * server.h (check_remote_input_interrupt_request): Declare. + * win32-low.c (winapi_DebugBreakProcess, + winapi_GenerateConsoleCtrlEvent): New typedefs. + (get_child_debug_event): Lower Win32 debug event polling from 1 sec + to 250 ms. + (win32_wait): Check for remote interrupt request + with check_remote_input_interrupt_request. + (win32_request_interrupt): New function. + (win32_target_op): Set request_interrupt to win32_request_interrupt. + +2007-05-10 Pedro Alves + + * win32-low.c (debug_registers_changed, + debug_registers_used, CONTEXT_EXTENDED_REGISTERS, + CONTEXT_FLOATING_POINT, CONTEXT_DEBUG_REGISTERS, + CONTEXT_DEBUGGER, CONTEXT_DEBUGGER_DR): Delete. + (thread_rec): Get context using the low target. + (child_add_thread): Call thread_added on the low target, + which does the same thing. + (regptr): Delete. + (do_initial_child_stuff): Remove debug registers references. + Set context using the low target. Resume threads after + setting the contexts. + (child_continue): Remove dead variable. Remove debug + registers references. + (child_fetch_inferior_registers): Go through the low target. + (do_child_store_inferior_registers): Remove. + (child_store_inferior_registers): Go through the low target. + (win32_resume): Remove debug registers references. + Set context using the low target. + (handle_exception): Change return type to void. Don't record + context here. Set status to TARGET_WAITKIND_SPURIOUS on a + first chance exception. + (get_child_debug_event): Change return type to void. Remove + goto loop. Always return after waiting for debug event. + (win32_wait): Convert to switch statement. Handle spurious + events. + + * win32-i386-low.c (debug_registers_changed, + debug_registers_used): New. + (initial_stuff): Rename to ... + (i386_initial_stuff): ... this. Clear debug registers + state variables. + (store_debug_registers): Delete. + (i386_get_thread_context): New. + (load_debug_registers): Delete. + (i386_set_thread_context): New. + (i386_thread_added): New. + (single_step): Rename to ... + (i386_single_step): ... this. + (do_fetch_inferior_registers): Rename to ... + (i386_fetch_inferior_register): ... this. + (i386_store_inferior_register): New. + (the_low_target): Adapt to new interface. + + * win32-arm-low.c (CONTEXT_FLOATING_POINT): Define. + (arm_get_thread_context): New. + (arm_set_thread_context): New. + (regptr): New. + (do_fetch_inferior_registers): Rename to ... + (arm_fetch_inferior_register): ... this. + (arm_store_inferior_register): New. + (arm_wince_breakpoint): Reimplement as unsigned long. + (arm_wince_breakpoint_len): Define. + (the_low_target): Adapt to new interface. + + * win32-low.h (target_ops): Remove regmap, store_debug_registers and + load_debug_registers. Add get_thread_context, set_thread_context, + thread_added and store_inferior_register. Rename + fetch_inferior_registers to fetch_inferior_register. + (regptr): Remove declaration. + +2007-05-10 Pedro Alves + + * linux-low.c (linux_detach): Change return type to int. Return 0. + * spu-low.c (spu_detach): Likewise. + +2007-05-10 Pedro Alves + + * target.h (target_ops): Change return type of detach to int. + Add join. + (join_inferior): New. + * server.c (main): Don't skip detach support on mingw32. + If the inferior doesn't support detaching return error. + Call join_inferior instead of using waitpid. + * linux-low.c (linux_join): New. + (linux_target_op): Add linux_join. + * spu-low.c (spu_join): New. + (spu_target_ops): Add spu_join. + * win32-low.c (win32_detach): Adapt to new interface. + Reopen current_process_handle before detaching. Issue a child + resume before detaching. + (win32_join): New. + (win32_target_op): Add win32_join. + +2007-05-10 Pedro Alves + + * win32-low.c (win32-attach): Fix return value. + * target.h (target_ops): Describe ATTACH return values. + +2007-05-10 Pedro Alves + + * win32-low.c (GETPROCADDRESS): Define. + (winapi_DebugActiveProcessStop): Add WINAPI. typedef as pointer. + (winapi_DebugSetProcessKillOnExit): Likewise. + (win32_create_inferior): Force usage of ansi CreateProcessA. + (win32_attach): Use GETPROCADDRESS. + (win32_detach): Likewise. + +2007-05-10 Pedro Alves + + * win32-low.c (win32_wait): Don't use WSTOPSIG. + +2007-03-30 Pedro Alves + + * win32-low.c: Commit leftover changes from 2007-03-29. + +2007-03-30 Daniel Jacobowitz + + * i387-fp.c (struct i387_fsave, struct i387_fxsave): Make 16-bit + fields short instead of int. Add explicit padding. + (i387_cache_to_fsave): Remove unnecessary casts. + (i387_fsave_to_cache): Doc fix. + (i387_cache_to_fxsave): Remove unnecessary casts and masking. + +2007-03-30 Daniel Jacobowitz + + * i387-fp.c (i387_cache_to_fxsave): Reinitialize val2 before use. + (i387_fxsave_to_cache): Check fp->ftag while building ftag value. + +2007-03-29 Pedro Alves + + * configure.srv (arm*-*-mingw32ce*): Move near the other + arm targets. + +2007-03-29 Pedro Alves + + * configure.ac: Add errno checking. + (AC_CHECK_HEADERS): Add errno.h, fcntl.h, signal.h, + sys/file.h and malloc.h. + (AC_CHECK_DECLS): Add perror. + (srv_mingwce): Handle. + * configure.srv (i[34567]86-*-cygwin*): Add + win32-i386-low.o to srv_tgtobj. + (i[34567]86-*-mingw*): Likewise. + (arm*-*-mingw32ce*): Add case. + * gdbreplay.c [HAVE_SYS_FILE_H, HAVE_SIGNAL_H, + HAVE_FCNTL_H, HAVE_ERRNO_H, HAVE_MALLOC_H]: Check. + [__MINGW32CE__] (strerror): New function. + [__MINGW32CE__] (errno): Define to GetLastError. + [__MINGW32CE__] (COUNTOF): New macro. + (remote_open): Remove extra close call. + * mem-break.c (delete_breakpoint_at): New function. + * mem-break.h (delete_breakpoint_at): Declare. + * remote-utils.c [HAVE_SYS_FILE_H, HAVE_SIGNAL_H, + HAVE_FCNTL_H, HAVE_UNISTD_H, HAVE_ERRNO_H]: Check. + [USE_WIN32API] (read, write): Add char* casts. + * server.c [HAVE_UNISTD_H, HAVE_SIGNAL_H]: Check. + * server.h: Include wincecompat.h on Windows CE. + [HAVE_ERRNO_H]: Check. + (perror): Declare if not declared. + * utils.c: Add stdlib.h, errno.h and malloc.h includes. + (perror_with_name): Remove errno declaration. + * wincecompat.h: New. + * wincecompat.c: New. + * win32-low.h: New. + * win32-arm-low.c: New. + * win32-i386-low.c: New. + (win32-low.c): Include mem-break.h and win32-low.h, and winnt.h. + (OUTMSG2): Make it safe. + (_T): New macro. + (COUNTOF): New macro. + (NUM_REGS): Get it from the low target. + (CONTEXT_EXTENDED_REGISTERS, CONTEXT_FLOATING_POINT, + CONTEXT_DEBUG_REGISTERS): Add fallbacks to 0. + (thread_rec): Let low target handle debug registers. + (child_add_thread): Likewise. + (child_init_thread_list): Likewise. + (continue_one_thread): Likewise. + (regptr): New. + (do_child_fetch_inferior_registers): Move to ... + * win32-i386-low.c: ... here, and rename to ... + (do_fetch_inferior_registers): ... this. + * win32-low.c (child_fetch_inferior_registers): + Go through the low target. + (do_child_store_inferior_registers): Use regptr. + (strwinerror): New function. + (win32_create_inferior): Handle Windows CE. + Use strwinerror instead of strerror on Windows error + codes. Add program to the error output. + Don't close the main thread handle on Windows CE. + (win32_attach): Use coredll.dll on Windows CE. + (win32_kill): Close current process and current + thread handles. + (win32_detach): Use coredll.dll on Windows CE. + (win32_resume): Let low target handle debug registers, and + step request. + (handle_exception): Add/Remove initial breakpoint. Avoid + non-existant WSTOPSIG on Windows CE. + (win32_read_inferior_memory): Cast to remove warning. + (win32_arch_string): Go through the low target. + (initialize_low): Call set_breakpoint_data with the low + target's breakpoint. + * win32-low.c (dr, FLAG_TRACE_BIT, FCS_REGNUM, + FOP_REGNUM, mappings): Move to ... + * win32-i386-low.c: ... here. + * win32-low.c (win32_thread_info): Move to ... + * win32-low.h: ... here. + * Makefile.in (SFILES): Add win32-low.c, win32-i386-low.c, + win32-arm-low.c and wincecompat.c. + (all:): Add $EXEEXT. + (install-only:): Likewise. + (gdbserver:): Likewise. + (gdbreplay:): Likewise. + * config.in: Regenerate. + * configure: Regenerate. + +2007-03-28 Pedro Alves + + * win32-low.c: Rename typedef thread_info to + win32_thread_info throughout. + +2007-03-28 Pedro Alves + + * win32-i386-low.c: Rename to ... + * win32-low.c: ... this. + * configure.srv: Replace win32-i386-low.o with win32-low.o. + * Makefile.in: Likewise. + +2007-03-27 Pedro Alves + + * remote-utils.c (monitor_output): Constify msg parameter. + * server.h (monitor_output): Likewise. + * win32-i386-low.c (handle_output_debug_string): New. + (win32_kill): Handle OUTPUT_DEBUG_STRING_EVENT events using + handle_output_debug_string. + (get_child_debug_event): Likewise. + +2007-03-27 Mat Hostetter + + * server.c (main): Correct strtoul check. + +2007-03-27 Jon Ringle + + * linux-low.c: Check __ARCH_HAS_MMU__ also. + +2007-03-27 Brooks Moses + + * Makefile.in: Add dummy "pdf" and "install-pdf" targets. + +2007-02-27 Daniel Jacobowitz + + * terminal.h: Check HAVE_SGTTY_H. + +2007-02-27 Mat Hostetter + + * remote-utils.c (remote_open): Print out the assigned port number. + +2007-02-26 Daniel Jacobowitz + + * remote-utils.c (monitor_output): New function. + * server.c (debug_threads): Define here. + (monitor_show_help): New function. + (handle_query): Handle qRcmd. + (main): Do not handle 'd' packet. + * server.h (debug_threads, remote_debug, monitor_output): Declare. + * linux-low.c, spu-low.c, win32-i386-low.c: Remove definitions + of debug_threads. + +2007-02-25 Pedro Alves + + * Makefile.in (EXEEXT): New. + (clean): Use $(EXEEXT). + +2007-02-25 Pedro Alves + + * target.h (target_ops): Rename send_signal to request_interrupt, + and remove enum target_signal parameter. + * linux-low.c (linux_request_interrupt): Rename from + linux_send_signal, and always send SIGINT. + * spu-low.c (spu_request_interrupt): Rename from spu_send_signal, + and always send SIGINT. + * remote-utils.c (putpkt_binary): Call request_interrupt, instead + of send_signal. + (input_interrupt): Likewise. + +2007-02-25 Pedro Alves + + * server.c (get_features_xml): Check if target implemented + arch_string. + * win32-i386-low.c (win32_arch_string): New. + (win32_target_ops): Add win32_arch_string as arch_string member. + +2007-02-22 Markus Deuling + + * spu-low.c (spu_arch_string): New. + (spu_target_ops): Add spu_arch_string. + +2007-02-16 Daniel Jacobowitz + + * remote-utils.c: Remove HAVE_TERMINAL_H check. + * configure.ac: Do not check for terminal.h. + * configure, config.in: Regenerated. + +2007-02-08 Daniel Jacobowitz + + * Makefile.in (OBS): Add $(XML_BUILTIN). + (XML_DIR, XML_TARGET, XML_FILES, XML_BUILTIN): New. + (clean): Update. + (target.xml, xml-builtin.c, stamp-xml, arm-with-iwmmxt.o) + (arm-with-iwmmxt.c): New. + * config.in, configure: Regenerate. + * configure.ac: Check for iWMMXt. Handle srv_xmltarget, + srv_xmlbuiltin, and srv_xmlfiles. Define USE_XML. + * configure.srv: Mention srv_xmltarget and srv_xmlfiles. + (arm*-*-linux*): Add iWMMXt and regset support. + * linux-arm-low.c (PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS): Define. + (arm_fill_gregset, arm_store_gregset, arm_fill_wmmxregset) + (arm_store_wmmxregset, target_regsets): New. + * server.c (get_features_xml): Take annex argument. Check builtin + XML documents. + (handle_query): Handle multiple annexes. + +2007-01-29 Daniel Jacobowitz + + * remote-utils.c [USE_WIN32API] (read, write): Define. + (putpkt_binary, input_interrupt, readchar, getpkt): Use read and + write. + +2007-01-09 Daniel Jacobowitz + + * linux-i386-low.c (the_low_target): Set arch_string. + * linux-x86-64-low.c (the_low_target): Likewise. + * linux-low.c (linux_arch_string): New. + (linux_target_ops): Add it. + * linux-low.h (struct linux_target_ops): Add arch_string. + * server.c (write_qxfer_response): Use const void * for DATA. + (get_features_xml): New. + (handle_query): Handle qXfer:features:read. Report it for qSupported. + * target.h (struct target_ops): Add arch_string method. + +2007-01-03 Denis Pilat + Daniel Jacobowitz + + * linux-low.c (linux_kill): Handle being called with no threads. + * win32-i386-low.c (win32_kill): Likewise. + (get_child_debug_event): Clear current_process_handle. + +2006-12-30 Denis PILAT + Daniel Jacobowitz + + * remote-utils.c (remote_open): Check the type of specified + serial port devices before opening them. + * server.c (main): Kill the inferior if an error occurs during + the first remote_open. + +2006-12-05 Markus Deuling + + * README: Update supported targets. + +2006-11-28 Daniel Jacobowitz + + * Makefile.in (clean): Remove reg-mips64.c. + (reg-mips64.c, reg-mips64.o): New rules. + * configure.srv: Handle mips64. Include regset support for mips. + * linux-mips-low.c (union mips_register): New. + (mips_get_pc, mips_set_pc, mips_reinsert_addr): Use it. + (mips_breakpoint, mips_breakpoint_at): Use int. + (mips_collect_register, mips_supply_register) + (mips_collect_register_32bit, mips_supply_register_32bit) + (mips_fill_gregset, mips_store_gregset, mips_fill_fpregset) + (mips_store_fpregset, target_regsets): New. + * thread-db.c (thread_db_get_tls_address): Use uintptr_t. + +2006-11-22 Ulrich Weigand + + * configure.srv: Add target "spu*-*-*". + * Makefile.in (clean): Remove reg-spu.c. + (reg-spu.c, reg-spu.o, spu-low.o): Add dependencies. + * spu-low.c: New file. + +2006-11-16 Daniel Jacobowitz + + * configure.ac: Correct td_thr_tls_get_addr test. + * configure: Regenerated. + +2006-11-16 Daniel Jacobowitz + + * linux-low.c (linux_wait_for_event): Reformat. Use the + pass_signals array. + * remote-utils.c (decode_address_to_semicolon): New. + * server.c (pass_signals, handle_general_set): New. + (handle_query): Mention QPassSignals for qSupported. + (main): Call handle_general_set. + * server.h (pass_signals, decode_address_to_semicolon): New. + +2006-11-06 Daniel Jacobowitz + + * server.c (handle_query): Correct error handling for read_auxv. + +2005-10-19 Ulrich Weigand + + * configure.srv [s390-*-linux*, s390x-*-linux*]: Set srv_linux_regsets + and srv_linux_thread_db to yes. + * linux-s390-low.c (s390_fill_gregset): New function. + (target_regsets): Define data structure. + +2006-10-17 Daniel Jacobowitz + + * acinclude.m4 (SRV_CHECK_TLS_GET_ADDR): New. + * configure.ac: Use it. Define HAVE_TD_THR_TLS_GET_ADDR. + * config.in, configure: Regenerated. + * inferiors.c (gdb_id_to_thread): New function. + (gdb_id_to_thread_id): Use it. + * linux-low.c (linux_target_ops): Use thread_db_get_tls_address. + * linux-low.h (struct process_info): Add th member. + (thread_db_get_tls_address): New prototype. + * remote-utils.c (decode_address): Make non-static. + * server.c (handle_query): Handle qGetTLSAddr. + * server.h (gdb_id_to_thread, decode_address): New prototypes. + * target.h (struct target_ops): Add get_tls_address. + * thread-db.c (maybe_attach_thread): Save the thread handle. + (thread_db_get_tls_address): New. + +2006-09-28 Daniel Jacobowitz + + * linux-low.c (PTRACE_GETSIGINFO, PTRACE_SETSIGINFO): Define. + (linux_resume_one_process): Take a siginfo_t *. Update all + callers. Queue it if necessary. Use PTRACE_SETSIGINFO. + (struct pending_signals): Add a siginfo_t. + (linux_wait_for_process): Always set last_status. + (linux_wait_for_event): Use PTRACE_GETSIGINFO. + (linux_queue_one_thread): Use PTRACE_GETSIGINFO. + * linux-low.h (struct process_info): Add last_status. + +2006-09-21 Daniel Jacobowitz + + * remote-utils.c (try_rle): New function. + (putpkt_binary): Use it. + +2006-08-19 Daniel Jacobowitz + + * Makefile.in (clean): Clean reg-x86-64-linux.c. + (reg-x86-64-linux.o, reg-x86-64-linux.c): New. + * configure.srv (x86_64-*-linux*): Use reg-x86-64-linux.o. + * linux-x86-64-low.c (x86_64_regmap): Include ORIG_RAX. + (x86_64_fill_gregset, x86_64_store_gregset): Skip floating + point registers. + +2006-08-08 Richard Sandiford + + * server.c (terminal_fd): New variable. + (old_foreground_pgrp): Likewise. + (restore_old_foreground_pgrp): New function. + (start_inferior): Record the terminal file descriptor in terminal_fd + and its original foreground group in old_foreground_pgrp. Register + restore_old_foreground_pgrp with atexit(). + +2006-07-26 Daniel Jacobowitz + + * server.c (handle_query): Correct qPart to qXfer. + +2006-07-22 Daniel Jacobowitz + + * configure.ac: Check for more headers which are missing on + Windows. Automatically supply -lwsock32 and USE_WIN32API. + * configure.srv: Add Cygwin and mingw32. + * remote-utils.c: Don't include headers unconditionally which + are missing on mingw32. Include for mingw32. + (remote_open): Adjust for mingw32 support. Flush + standard error after writing to it. + (remote_close, putpkt_binary, input_interrupt, block_async_io) + (unblock_async_io, enable_async_io, disable_async_io) + (readchar, getpkt): Update for Winsock support. + (prepare_resume_reply): Expect a protocol signal number. + * server.c: Disable on mingw32. + (start_inferior): Adjust for mingw32 support. Flush + standard error after writing to it. + (attach_inferior): Likewise. Use protocol signal + numbers. + (main): Skip 'D' packet on mingw32. Use protocol signal numbers + and names. + * win32-i386-low.c: New file. + * Makefile.in (XM_CLIBS): Set. + (gdbserver, gdbreplay): Use $(INTERNAL_CFLAGS). + (win32-i386-low.o): New dependency rule. + * linux-low.c (linux_wait): Use target signal numbers. + * target.h (struct target_ops): Doc fix. + * server.h (target_signal_to_name): New prototype. + * gdbreplay.c: Don't include headers unconditionally which + are missing on mingw32. Include for mingw32. + (remote_close, remote_open): Adjust for Winsock support. + * configure, config.in: Regenerated. + +2006-07-12 Daniel Jacobowitz + + * server.c (decode_xfer_read, write_qxfer_response): New. + (handle_query): Take a packet length argument. Handle + qXfer:auxv:read instead of qPart:auxv:read. Mention it in + the qSupported response. + (main): Update call to handle_query. + +2006-06-22 Daniel Jacobowitz + + * remote-utils.c (remote_escape_output, remote_unescape_input): New. + (putpkt_binary): Renamed from putpkt and adjusted for binary + data. + (putpkt): New wrapper for putpkt_binary. + (readchar): Don't mask off the high bit. + (decode_X_packet): New function. + * server.c (main): Call putpkt_binary if a handler sets the packet + length. Save the length of the incoming packet. Handle 'X'. + * server.h (gdb_byte, remote_escape_output, decode_X_packet): New. + +2006-06-21 Daniel Jacobowitz + + * server.c (handle_query): Handle qSupported. + +2006-05-30 Daniel Jacobowitz + + * remote-utils.c (all_symbols_looked_up): New variable. + (look_up_one_symbol): Check it. + * server.h (look_up_one_symbol): New declaration. + * thread-db.c (thread_db_init): Set all_symbols_looked_up. + +2006-05-30 Daniel Jacobowitz + + * Makefile.in (linux-arm-low.o): Update dependencies. + * linux-arm-low.c: Include "gdb_proc_service.h". + (PTRACE_GET_THREAD_AREA): Define. + (ps_get_thread_area): New function. + +2006-05-09 Nathan Sidwell + + * configure.srv (m68k*-*-uclinux*): New target. + * linux-low.c (linux_create_inferior): Use vfork on mmuless systems. + (linux_resume_one_process): Remove extraneous cast. + (linux_read_offsets): New. + (linux_target_op): Add linux_read_offsets on mmuless systems. + * server.c (handle_query): Add qOffsets logic. + * target.h (struct target_ops): Add read_offsets. + +2006-03-15 Daniel Jacobowitz + + * linux-mips-low.c: Include and "gdb_proc_service.h". + (PTRACE_GET_THREAD_AREA): Define. + (ps_get_thread_area): New function. + * Makefile.in (linux-i386-low.o, linux-mips-low.o) + (linux-x86-64-low.o): Update. + +2006-03-15 Daniel Jacobowitz + + * configure.ac: Remove checks for prfpregset_t. + * gdb_proc_service.h: New file. + * linux-i386-low.c, linux-x86-64-low.c, thread-db.c: Use the + new "gdb_proc_service.h". + * proc-service.c: Likewise. + (ps_pglobal_lookup, ps_pdread, ps_pdwrite): Use psaddr_t. + (ps_lgetfpregs, ps_lsetfpregs): Use a void* argument. + * Makefile.in (gdb_proc_service_h): Updated. + * configure, config.in: Regenerated. + +2006-03-03 Daniel Jacobowitz + + * remote-utils.c (prepare_resume_reply): Move declaration + of gdb_id_from_wait to the top of the block. + +2006-02-15 Daniel Jacobowitz + + * linux-low.c (regsets_store_inferior_registers): Read the regset + from the target before filling it. + +2006-02-08 Daniel Jacobowitz + + * server.c (attach_inferior): Return SIGTRAP for a successful + attach. + +2006-02-01 Daniel Jacobowitz + + * Makefile.in (OBS): Add version.o. + (STAGESTUFF): Delete. + (version.o): Add dependencies. + (version.c): Replace rule. + (clean): Remove version.c. + * server.c (gdbserver_version): New. + (gdbserver_usage): Use printf. + (main): Handle --version and --help. + * server.h (version, host_name): Add declarations. + +2005-12-23 Eli Zaretskii + + * linux-arm-low.c: + * linux-arm-low.c: + * inferiors.c: + * i387-fp.h: + * i387-fp.c: + * gdbreplay.c: + * regcache.c: + * proc-service.c: + * mem-break.h: + * mem-break.c: + * linux-x86-64-low.c: + * linux-sh-low.c: + * linux-s390-low.c: + * linux-ppc64-low.c: + * linux-ppc-low.c: + * linux-mips-low.c: + * linux-m68k-low.c: + * linux-m32r-low.c: + * linux-low.h: + * linux-low.c: + * linux-ia64-low.c: + * linux-i386-low.c: + * linux-crisv32-low.c: + * thread-db.c: + * terminal.h: + * target.h: + * target.c: + * server.h: + * server.c: + * remote-utils.c: + * regcache.h: + * utils.c: + * Makefile.in: + * configure.ac: + * gdbserver.1: Add (C) after Copyright. Update the FSF + address. + +2005-11-13 Daniel Jacobowitz + + * linux-arm-low.c (arm_eabi_breakpoint): New variable. + (arm_breakpoint_at): Recognize both breakpoints. + (the_low_target): Use the correct breakpoint instruction. + +2005-11-02 Daniel Jacobowitz + + * configure.srv (x86_64-*-linux*): Turn on thread_db support. + * linux-x86-64-low.c (x86_64_breakpoint, x86_64_breakpoint_len) + (x86_64_get_pc, x86_64_set_pc, x86_64_breakpoint_at): New. + (the_low_target): Update. + +2005-10-25 Andreas Schwab + + * server.c (main): Allocate mem_buf with PBUFSIZ bytes. + + * linux-ia64-low.c (ia64_regmap): Remove NAT registers. + (ia64_num_regs): Reduce to 462. + +2005-09-17 Daniel Jacobowitz + + * acinclude.m4: Correct quoting. + * aclocal.m4: Regenerated. + + Suggested by SZOKOVACS Robert : + * thread-db.c (thread_db_err_str): Handle TD_VERSION. + (thread_db_init): Call thread_db_err_str. + * configure.ac: Check for TD_VERSION. + * config.in, configure: Regenerated. + +2005-07-31 Kaveh R. Ghazi + + * server.h (error, fatal, warning): Add ATTR_FORMAT. + +2005-07-13 Daniel Jacobowitz + + * configure.ac: Define HAVE_LINUX_REGSETS even if PTRACE_GETREGS + is not available. Define HAVE_PTRACE_GETREGS if it is. + * config.in, configure: Regenerated. + * configure.srv: Set srv_linux_regsets for PowerPC and PowerPC64. + * linux-i386-low.c, linux-m68k-low.c: Update to use + HAVE_PTRACE_GETREGS. + * linux-low.c (regsets_fetch_inferior_registers) + (regsets_store_inferior_registers): Only return 0 if we processed + GENERAL_REGS. + * linux-ppc-low.c (ppc_fill_gregset, target_regsets): New. + * linux-ppc64-low.c (ppc_fill_gregset, target_regsets): New. + +2005-07-13 Daniel Jacobowitz + + * inferiors.c (struct thread_info): Add gdb_id. + (add_thread): Add gdb_id argument. + (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): New. + * linux-low.c (linux_create_inferior, linux_attach_lwp): Update + calls to add_thread. + * remote-utils.c (prepare_resume_reply: Use thread_to_gdb_id. + * server.c (handle_query): Use thread_to_gdb_id. + (handle_v_cont, main): Use gdb_id_to_thread_id. + * server.h (add_thread): Update prototype. + (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): New + prototypes. + +2005-07-13 Daniel Jacobowitz + + * linux-low.c (fetch_register, usr_store_inferior_registers): Handle + left-padded registers. + * linux-low.h (struct linux_target_ops): Add left_pad_xfer. + * linux-ppc64-low.c (the_low_target): Set left_pad_xfer. + +2005-07-01 Steve Ellcey + + * configure.ac (BFD_NEED_DECLARATION): Replace with AC_CHECK_DECLS. + * configure: Regenerate. + * config.in: Regenerate. + * server.h (NEED_DECLARATION_STRERROR): + Replace with !HAVE_DECL_STRERROR. + +2005-06-16 Daniel Jacobowitz + + * linux-low.c (linux_wait, linux_send_signal): Don't test + an unsigned long variable for > 0 if it could be MAX_ULONG. + * server.c (myresume): Likewise. + * target.c (set_desired_inferior): Likewise. + +2005-06-13 Mark Kettenis + + * configure.ac: Simplify and improve check for socklen_t. + * configure, config.in: Regenerate. + +2005-06-12 Daniel Jacobowitz + + * acconfig.h: Remove. + * configure.ac: Add a test for socklen_t. Use three-argument + AC_DEFINE throughout. + * config.in: Regenerated using autoheader 2.59. + * configure: Regenerated. + + * gdbreplay.c (socklen_t): Provide a default. + (remote_open): Use socklen_t. + * remote-utils.c (socklen_t): Provide a default. + (remote_open): Use socklen_t. + (convert_int_to_ascii, convert_ascii_to_int, decode_M_packet): Use + unsigned char. + + * i387-fp.c (struct i387_fsave, struct i387_fxsave): Use unsigned + char for buffers. + * linux-low.c (linux_read_memory, linux_write_memory) + (linux_read_auxv): Likewise. + * mem-break.c (breakpoint_data, set_breakpoint_data, check_mem_read) + (check_mem_write): Likewise. + * mem-break.h (set_breakpoint_data, check_mem_read, check_mem_write): + Likewise. + * regcache.c (struct inferior_rgcache_data, registers_to_string) + (registers_from_string, register_data): Likewise. + * server.c (handle_query, main): Likewise. + * server.h (convert_ascii_to_int, convert_int_to_ascii) + (decode_M_packet): Likewise. + * target.c (read_inferior_memory, write_inferior_memory): Likewise. + * target.h (struct target_ops): Update read_memory, write_memory, + and read_auxv. + (read_inferior_memory, write_inferior_memory): Update. + * linux-low.h (struct linux_target_ops): Change type of breakpoint + to unsigned char *. + * linux-arm-low.c, linux-cris-low.c, linux-crisv32-low.c, + linux-i386-low.c, linux-m32r-low.c, linux-m68k-low.c, + linux-mips-low.c, linux-ppc-low.c, linux-ppc64-low.c, + linux-s390-low.c, linux-sh-low.c: Update for changes in + read_inferior_memory and the_low_target->breakpoint. + +2005-05-28 Daniel Jacobowitz + + * Makefile.in (SFILES): Add linux-ppc64-low.c. + (linux-ppc64-low.o, reg-ppc64.c, reg-ppc64.o): New targets. + * configure.srv: Add powerpc64-*-linux*. + * linux-ppc64-low.c: New file. + +2005-05-23 Orjan Friberg + + * linux-cris-low.c: New file with support for CRIS. + * linux-crisv32-low.c: Ditto for CRISv32. + * Makefile.in (SFILES): Add linux-cris-low.c, linux-crisv32-low.c. + (clean): Add reg-cris.c and reg-crisv32.c. + Add linux-cris-low.o, linux-crisv32-low.o, reg-cris.o, reg-cris.c, + reg-crisv32.o, and reg-crisv32.c to make rules. + * configure.srv: Add cris-*-linux* and crisv32-*-linux* to list of + recognized targets. + +2005-05-16 Ulrich Weigand + + * linux-low.c (fetch_register): Ensure buffer size is a multiple + of sizeof (PTRACE_XFER_TYPE). + (usr_store_inferior_registers): Likewise. Zero out excess bytes. + +2005-05-12 Orjan Friberg + + * target.h (struct target_ops): Add insert_watchpoint, + remove_watchpoint, stopped_by_watchpoint, stopped_data_address function + pointers for hardware watchpoint support. + * linux-low.h (struct linux_target_ops): Ditto. + * linux-low.c (linux_insert_watchpoint, linux_remove_watchpoint) + (linux_stopped_by_watchpoint, linux_stopped_data_address): New. Add + to linux_target_ops. + * remote-utils.c (prepare_resume_reply): Add watchpoint information to + reply packet. + * server.c (main): Recognize 'Z' and 'z' packets. + +2005-05-10 Ulrich Weigand + + * linux-s390-low.c (s390_breakpoint, s390_breakpoint_len): Define. + (s390_get_pc, s390_set_pc, s390_breakpoint_at): New functions. + (the_low_target): Add new members. + +2005-05-04 Daniel Jacobowitz + + * proc-service.c (ps_lgetregs): Search all_processes instead of + all_threads. + +2005-05-04 Daniel Jacobowitz + + * server.c (start_inferior): Change return type to int. + (attach_inferior): Change sigptr to int *. + (handle_v_cont, handle_v_requests): Change signal to int *. + (main): Change signal to int. + +2005-04-15 Kei Sakamoto + + * Makefile.in: Add linux-m32r-low.o, reg-m32r.c and reg-m32r.o. + * configure.srv: Add m32r*-*-linux*. + * linux-m32r-low.c: New file. + +2005-03-04 Daniel Jacobowitz + + * Makefile.in (stamp-h): Set CONFIG_HEADERS explicitly. + +2005-03-03 Daniel Jacobowitz + + * inferiors.c (change_inferior_id, add_thread, find_inferior_id): + Take unsigned long arguments for PIDs. + * linux-low.c (add_process, linux_attach_lwp, linux_attach) + (linux_thread_alive, linux_wait_for_event, kill_lwp, send_sigstop) + (wait_for_sigstop, linux_resume_one_process) + (regsets_fetch_inferior_registers, linux_send_signal) + (linux_read_auxv): Likewise. Update the types of variables holding + PIDs. Update format string specifiers. + * linux-low.h (struct process_info, linux_attach_lwp): Likewise. + * remote-utils.c (prepare_resume_reply): Likewise. + * server.c (cont_thread, general_thread, step_thread) + (thread_from_wait, old_thread_from_wait, signal_pid): Change type to + unsigned long. + (handle_query): Update format specifiers. + (handle_v_cont, main): Use strtoul for thread IDs. + * server.h (struct inferior_list_entry): Use unsigned long for ID. + (add_thread, find_inferior_id, change_inferior_id, cont_thread) + (general_thread, step_thread, thread_from_wait) + (old_thread_from_wait): Update. + * target.h (struct thread_resume): Use unsigned long for THREAD. + (struct target_ops): Use unsigned long for arguments to attach and + thread_alive. + +2005-02-24 Daniel Jacobowitz + + * acinclude.m4: Include bfd/bfd.m4 directly. + * configure.ac: Use AC_ARG_PROGRAM. Suggested by Aron Griffis + . + * aclocal.m4, configure: Regenerated. + +2005-01-07 Andrew Cagney + + * configure.ac: Rename configure.in, require autoconf 2.59. + * configure: Re-generate. + +2004-12-08 Daniel Jacobowitz + + * acinclude.m4 (SRV_CHECK_THREAD_DB): Add ps_get_thread_area. Reset + LIBS when finished. + * aclocal.m4: Regenerated. + * configure: Regenerated. + +2004-11-21 Andreas Schwab + + * linux-m68k-low.c (m68k_num_gregs): Define. + (m68k_fill_gregset, m68k_store_gregset, m68k_fill_fpregset) + (m68k_store_fpregset, target_regsets) [HAVE_LINUX_REGSETS]: New. + (m68k_breakpoint, m68k_breakpoint_len, m68k_get_pc, m68k_set_pc) + (m68k_breakpoint_at): New. Add to the_low_target. + + * configure.srv (m68*-*-linux*): Set srv_linux_regsets and + srv_linux_thread_db to yes. + +2004-10-20 Joel Brobecker + + * linux-x86-64-low.c (ARCH_SET_GS): Add definition if missing. + (ARCH_SET_FS): Likewise. + (ARCH_GET_FS): Likewise. + (ARCH_GET_GS): Likewise. + +2004-10-16 Daniel Jacobowitz + + * linux-i386-low.c (ps_get_thread_area): New. + * linux-x86-64-low.c (ps_get_thread_area): New. + * linux-low.c: Include . + (linux_kill_one_process): Don't kill the first thread here. + (linux_kill): Kill the first thread here. + (kill_lwp): New function. + (send_sigstop, linux_send_signal): Use it. + * proc-service.c: Clean up #ifdefs. + (fpregset_info): Delete. + (ps_lgetregs): Update and enable implementation. + (ps_lsetregs, ps_lgetfpregs, ps_lsetfpregs): Remove disabled + implementations. + * remote-utils.c (struct sym_cache, symbol_cache): New. + (input_interrupt): Print a clearer message. + (async_io_enabled): New variable. + (enable_async_io, disable_async_io): Use it. Update comments. + (look_up_one_symbol): Use the symbol cache. + * thread-db.c (thread_db_look_up_symbols): New function. + (thread_db_init): Update comments. Call thread_db_look_up_symbols. + +2004-10-16 Daniel Jacobowitz + + * configure.in: Test for -rdynamic. + * configure: Regenerated. + * Makefile (INTERNAL_LDFLAGS): New. + (gdbserver, gdbreplay): Use it. + +2004-09-02 Andrew Cagney + + * Makefile.in (TAGS): Replace TM_FILE with DEPRECATED_TM_FILE. + +2004-03-23 Daniel Jacobowitz + + * linux-low.c (linux_wait): Clear all_processes list also. + +2004-03-12 Daniel Jacobowitz + + * linux-low.c: Include . Remove extern declaration of + errno. + +2004-03-12 Daniel Jacobowitz + + * gdbreplay.c, server.h, utils.c: Update copyright years. + +2004-03-04 Nathan J. Williams + + * server.c (main): Print child status or termination signal from + variable 'signal', not 'sig'. + +2004-03-04 Nathan J. Williams + + * linux-low.c (linux_read_memory): Change return type to + int. Check for and return error from ptrace(). + * target.c (read_inferior_memory): Change return type to int. Pass + back return status from the_target->read_memory(). + * target.h (struct target_ops): Adapt *read_memory() prototype. + Update comment. + (read_inferior_memory): Adapt prototype. + * server.c (main): Return an error packet if + read_inferior_memory() returns an error. + +2004-03-04 Daniel Jacobowitz + + * Makefile.in (distclean): Remove config.h, stamp-h, and config.log. + Unify with other clean targets. + +2004-02-29 Daniel Jacobowitz + + * server.c (handle_v_cont): Call set_desired_inferior. + +2004-02-29 Daniel Jacobowitz + + * remote-utils.c (prepare_resume_reply): Always supply "thread:". + +2004-02-29 Daniel Jacobowitz + + * linux-low.c (linux_wait): Unblock async I/O. + (linux_resume): Block and enable async I/O. + * remote-utils.c (block_async_io, unblock_async_io): New functions. + * server.h (block_async_io, unblock_async_io): Add prototypes. + +2004-02-29 Daniel Jacobowitz + + * remote-utils.c (remote_open): Print a status notice after + opening a TCP port. + * server.c (attach_inferior): Print a status notice after + attaching. + +2004-02-29 Daniel Jacobowitz + + * linux-arm-low.c (arm_get_pc): Print out stop PC in debug mode. + +2004-02-26 Daniel Jacobowitz + + * remote-utils.c (write_enn): Use "E01" instead of "ENN" for the + error packet. + * server.c, target.h: Update copyright years. + +2004-02-25 Roland McGrath + + * target.h (struct target_ops): New member `read_auxv'. + * server.c (handle_query): Handle qPart:auxv:read: query using that. + * linux-low.c (linux_read_auxv): New function. + (linux_target_ops): Initialize `read_auxv' member to that. + +2004-02-17 Ulrich Weigand + + Committed by Jim Blandy . + + * linux-s390-low.c (s390_num_regs): Update. + (s390_regmap): Remove control registers. Use __s390x__ predefine + instead of GPR_SIZE to distiguish s390 and s390x targets. + +2004-01-31 Daniel Jacobowitz + + * linux-low.c: Update copyright year. + (check_removed_breakpoint): Clear pending_is_breakpoint. + (linux_set_resume_request, linux_queue_one_thread) + (resume_status_pending_p): New functions. + (linux_continue_one_thread): Use process->resume. + (linux_resume): Only resume threads if there are no pending events. + * linux-low.h (struct process_info): Add resume request + pointer. + +2004-01-30 Daniel Jacobowitz + + * regcache.c (new_register_cache): Clear the allocated register + buffer. Suggested by Atsushi Nemoto . + +2003-10-13 Daniel Jacobowitz + + * linux-low.c (linux_resume): Take a struct thread_resume * + argument. + (linux_wait): Update call. + (resume_ptr): New static variable. + (linux_continue_one_thread): Renamed from + linux_continue_one_process. Use resume_ptr. + (linux_resume): Use linux_continue_one_thread. + * server.c (handle_v_cont, handle_v_requests): New functions. + (myresume): New function. + (main): Handle 'v' case. + * target.h (struct thread_resume): New type. + (struct target_ops): Change argument of "resume" to struct + thread_resume *. + (myresume): Delete macro. + +2003-08-08 H.J. Lu + + * Makefile.in (install-only): Create dest dir. Support DESTDIR. + (uninstall): Support DESTDIR. + +Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy + + * configure.srv: Add xscale*linux copy of arm*linux entry. + +2003-07-24 Daniel Jacobowitz + + * linux-arm-low.c (arm_reinsert_addr): New function. + (the_low_target): Add arm_reinsert_addr. + +2003-07-08 Mark Kettenis + + * mem-break.c: Remove whitespace at end of file. + +2003-06-28 Daniel Jacobowitz + + * configure.in: Check whether we need to prototype strerror. + * server.h: Optionally prototype strerror. + * gdbreplay.c (perror_with_name): Use strerror. + * linux-low.c (linux_attach_lwp): Use strerror. + * utils.c (perror_with_name): Use strerror. + * config.in, configure: Regenerated. + +2003-06-28 Daniel Jacobowitz + + * linux-sh-low.c (sh_regmap): Fix FP register offsets, reported by + SUGIOKA Toshinobu . + +2003-06-20 Daniel Jacobowitz + + * Makefile.in (SFILES): Update. + * low-hppabsd.c, low-lynx.c, low-nbsd.c, low-sim.c, low-sparc.c, + low-sun3.c: Remove files. + +2003-06-17 Daniel Jacobowitz + + * linux-low.c: Move comment to linux_thread_alive where it belonged. + (linux_detach_one_process, linux_detach): New functions. + (linux_target_ops): Add linux_detach. + * server.c (main): Handle 'D' packet. + * target.h (struct target_ops): Add "detach" member. + (detach_inferior): Define. + +2003-06-13 Mark Kettenis + + From Kelley Cook : + * configure.srv: Accept i[34567]86 variants. + +2003-06-05 Daniel Jacobowitz + + * linux-low.c (linux_wait_for_event): Correct comment typos. + (linux_resume_one_process): Call check_removed_breakpoint. + (linux_send_signal): New function. + (linux_target_ops): Add linux_send_signal. + * remote-utils.c (putpkt, input_interrupt): Use send_signal instead + of kill. + * target.h (struct target_ops): Add send_signal. + +2003-05-29 Jim Blandy + + * linux-low.c (usr_store_inferior_registers): Transfer buf in + PTRACE_XFER_TYPE-sized chunks, not int-sized chunks. Otherwise, + if 'int' is smaller than PTRACE_XFER_TYPE, you end up throwing + away part of the register's value. + +2003-03-26 Daniel Jacobowitz + + * linux-low.c (linux_create_inferior): Use __SIGRTMIN. + (linux_wait_for_event, linux_init_signals): Likewise. + +2003-03-17 Daniel Jacobowitz + + * configure.in: Check for stdlib.h. + * configure: Regenerated. + * config.in: Regenerated. + +2003-01-04 Andreas Schwab + + * linux-m68k-low.c (m68k_num_regs): Define to 29 instead of 31. + +2003-01-02 Andrew Cagney + + * Makefile.in: Remove obsolete code. + +2002-11-20 Daniel Jacobowitz + + * linux-s390-low.c (s390_regmap): Check GPR_SIZE instead of + defined(PT_FPR0_HI). + +2002-11-17 Stuart Hughes + + * linux-arm-low.c (arm_num_regs): Increase. + (arm_regmap): Include status register. + +2002-11-17 Daniel Jacobowitz + + * linux-low.c (register_addr): Remove incorrect -1 check. + +2002-08-29 Daniel Jacobowitz + + * linux-low.c (linux_create_inferior): Call setpgid. Return + the new PID. + (unstopped_p, linux_signal_pid): Remove. + (linux_target_ops): Remove linux_signal_pid. + * remote-utils.c (putpkt, input_interrupt): Use signal_pid + global instead of target method. + * target.h (struct target_ops): Remove signal_pid. Update comment + for create_inferior. + * server.c (signal_pid): New variable. + (create_inferior): Set signal_pid. Block SIGTTOU and SIGTTIN in + gdbserver. Set the child to be the foreground process group. + (attach_inferior): Set signal_pid. + +2002-08-23 Daniel Jacobowitz + + * ChangeLog: New file, with entries from gdb/ChangeLog after GDB 5.2. + +2002-08-20 Jim Blandy + + * Makefile.in (LDFLAGS): Allow the configure script to establish a + default for this. + +2002-08-01 Andrew Cagney + + * Makefile.in: Make chill references obsolete. + +2002-07-24 Kevin Buettner + + * configure.in (unistd.h): Add to AC_CHECK_HEADERS list. + * configure: Regenerate. + * config.in: Regenerate. + +2002-07-09 David O'Brien + + * gdbreplay.c (stdlib.h, unistd.h): Conditionaly include. + (perror_with_name, remote_close, remote_open, expect, play): Static. + +2002-07-04 Michal Ludvig + + * linux-x86-64-low.c (x86_64_regmap): Make it an array of + byte offsets instead of an array of indexes. + (x86_64_store_gregset, x86_64_store_fpregset): Parameter made const. + +2002-06-13 Daniel Jacobowitz + + * regcache.c: Add comment. + +2002-06-11 Daniel Jacobowitz + + * thread-db.c: New file. + * proc-service.c: New file. + * acinclude.m4: New file. + * Makefile.in: Add GDBSERVER_LIBS, gdb_proc_service_h, + proc-service.o, and thread-db.o. + (linux-low.o): Add USE_THREAD_DB. + * acconfig.h: Add HAVE_PRGREGSET_T, HAVE_PRFPREGSET_T, + HAVE_LWPID_T, HAVE_PSADDR_T, and PRFPREGSET_T_BROKEN. + * aclocal.m4: Regenerated. + * config.in: Regenerated. + * configure: Regenerated. + * configure.in: Check for proc_service.h, sys/procfs.h, + thread_db.h, and linux/elf.h headrs. + Check for lwpid_t, psaddr_t, prgregset_t, prfpregset_t, and + PRFPREGSET_T_BROKEN. Introduce srv_thread_depfiles and USE_THREAD_DB. + Check for -lthread_db and thread support. + * configure.srv: Enable thread_db support for ARM, i386, MIPS, + PowerPC, and SuperH. + * i387-fp.c: Constify arguments. + * i387-fp.h: Likewise. + * inferiors.c: (struct thread_info): Renamed from + `struct inferior_info'. Remove PID member. Use generic inferior + list header. All uses updated. + (inferiors, signal_pid): Removed. + (all_threads): New variable. + (get_thread): Define. + (add_inferior_to_list): New function. + (for_each_inferior): New function. + (change_inferior_id): New function. + (add_inferior): Removed. + (remove_inferior): New function. + (add_thread): New function. + (free_one_thread): New function. + (remove_thread): New function. + (clear_inferiors): Use for_each_inferior and free_one_thread. + (find_inferior): New function. + (find_inferior_id): New function. + (inferior_target_data): Update argument type. + (set_inferior_target_data): Likewise. + (inferior_regcache_data): Likewise. + (set_inferior_regcache_data): Likewise. + * linux-low.c (linux_bp_reinsert): Remove. + (all_processes, stopping_threads, using_thrads) + (struct pending_signals, debug_threads, pid_of): New. + (inferior_pid): Replace with macro. + (struct inferior_linux_data): Remove. + (get_stop_pc, add_process): New functions. + (linux_create_inferior): Restore SIGRTMIN+1 before calling exec. + Use add_process and add_thread. + (linux_attach_lwp): New function, based on old linux_attach. Use + add_process and add_thread. Set stop_expected for new threads. + (linux_attach): New function. + (linux_kill_one_process): New function. + (linux_kill): Kill all LWPs. + (linux_thread_alive): Use find_inferior_id. + (check_removed_breakpoints, status_pending_p): New functions. + (linux_wait_for_process): Renamed from linux_wait_for_one_inferior. + Update. Use WNOHANG. Wait for cloned processes also. Update process + struct for the found process. + (linux_wait_for_event): New function. + (linux_wait): Use it. Support LWPs. + (send_sigstop, wait_for_sigstop, stop_all_processes) + (linux_resume_one_process, linux_continue_one_process): New functions. + (linux_resume): Support LWPs. + (REGISTER_RAW_SIZE): Remove. + (fetch_register): Use register_size instead. Call supply_register. + (usr_store_inferior_registers): Likewise. Call collect_register. + Fix recursive case. + (regsets_fetch_inferior_registers): Improve error message. + (regsets_store_inferior_registers): Add debugging. + (linux_look_up_symbols): Call thread_db_init if USE_THREAD_DB. + (unstopped_p, linux_signal_pid): New functions. + (linux_target_ops): Add linux_signal_pid. + (linux_init_signals): New function. + (initialize_low): Call it. Initialize using_threads. + * regcache.c (inferior_regcache_data): Add valid + flag. + (get_regcache): Fetch registers lazily. Add fetch argument + and update all callers. + (regcache_invalidate_one, regcache_invalidate): New + functions. + (new_register_cache): Renamed from create_register_cache. + Return the new regcache. + (free_register_cache): Change argument to a void *. + (registers_to_string, registers_from_string): Call get_regcache + with fetch flag set. + (register_data): Make static. Pass fetch flag to get_regcache. + (supply_register): Call get_regcache with fetch flag clear. + (collect_register): Call get_regcache with fetch flag set. + (collect_register_as_string): New function. + * regcache.h: Update. + * remote-utils.c (putpkt): Flush after debug output and use + stderr. + Handle input interrupts while waiting for an ACK. + (input_interrupt): Use signal_pid method. + (getpkt): Flush after debug output and use stderr. + (outreg): Use collect_register_as_string. + (new_thread_notify, dead_thread_notify): New functions. + (prepare_resume_reply): Check using_threads. Set thread_from_wait + and general_thread. + (look_up_one_symbol): Flush after debug output. + * server.c (step_thread, server_waiting): New variables. + (start_inferior): Don't use signal_pid. Update call to mywait. + (attach_inferior): Update call to mywait. + (handle_query): Handle qfThreadInfo and qsThreadInfo. + (main): Don't fetch/store registers explicitly. Use + set_desired_inferior. Support proposed ``Hs'' packet. Update + calls to mywait. + * server.h: Update. + (struct inferior_list, struct_inferior_list_entry): New. + * target.c (set_desired_inferior): New. + (write_inferior_memory): Constify. + (mywait): New function. + * target.h: Update. + (struct target_ops): New signal_pid method. + (mywait): Removed macro, added prototype. + + * linux-low.h (regset_func): Removed. + (regset_fill_func, regset_store_func): New. + (enum regset_type): New. + (struct regset_info): Add type field. Use new operation types. + (struct linux_target_ops): stop_pc renamed to get_pc. + Add decr_pc_after_break and breakpoint_at. + (get_process, get_thread_proess, get_process_thread) + (strut process_info, all_processes, linux_attach_lwp) + (thread_db_init): New. + + * linux-arm-low.c (arm_get_pc, arm_set_pc, + arm_breakpoint, arm_breakpoint_len, arm_breakpoint_at): New. + (the_low_target): Add new members. + * linux-i386-low.c (i386_store_gregset, i386_store_fpregset) + (i386_store_fpxregset): Constify. + (target_regsets): Add new kind identifier. + (i386_get_pc): Renamed from i386_stop_pc. Simplify. + (i386_set_pc): Add debugging. + (i386_breakpoint_at): New function. + (the_low_target): Add new members. + * linux-mips-low.c (mips_get_pc, mips_set_pc) + (mips_breakpoint, mips_breakpoint_len, mips_reinsert_addr) + (mips_breakpoint_at): New. + (the_low_target): Add new members. + * linux-ppc-low.c (ppc_get_pc, ppc_set_pc) + (ppc_breakpoint, ppc_breakpoint_len, ppc_breakpoint_at): New. + (the_low_target): Add new members. + * linux-sh-low.c (sh_get_pc, sh_set_pc) + (sh_breakpoint, sh_breakpoint_len, sh_breakpoint_at): New. + (the_low_target): Add new members. + * linux-x86-64-low.c (target_regsets): Add new kind + identifier. + +2002-05-15 Daniel Jacobowitz + + From Martin Pool : + * server.c (gdbserver_usage): New function. + (main): Call it. + +2002-05-14 Daniel Jacobowitz + + * mem-break.c (reinsert_breakpoint_by_bp): Correct typo + stop_at -> stop_pc. + +2002-05-04 Andrew Cagney + + * Makefile.in: Remove obsolete code. + +2002-04-24 Michal Ludvig + + * linux-low.c (regsets_fetch_inferior_registers), + (regsets_store_inferior_registers): Removed cast to int from + ptrace() calls. + * regcache.h: Added declaration of struct inferior_info. + +2002-04-20 Daniel Jacobowitz + + * inferiors.c (struct inferior_info): Add regcache_data. + (add_inferior): Call create_register_cache. + (clear_inferiors): Call free_register_cache. + (inferior_regcache_data, set_inferior_regcache_data): New functions. + * regcache.c (struct inferior_regcache_data): New. + (registers): Remove. + (get_regcache): New function. + (create_register_cache, free_register_cache): New functions. + (set_register_cache): Don't initialize the register cache here. + (registers_to_string, registers_from_string, register_data): Call + get_regcache. + * regcache.h: Add prototypes. + * server.h: Likewise. + +2002-04-20 Daniel Jacobowitz + + * mem-break.c: New file. + * mem-break.h: New file. + * Makefile.in: Add mem-break.o rule; update server.h + dependencies. + * inferiors.c (struct inferior_info): Add target_data + member. + (clear_inferiors): Free target_data member if set. + (inferior_target_data, set_inferior_target_data): New functions. + * linux-i386-low.c (i386_breakpoint, i386_breakpoint_len) + (i386_stop_pc, i386_set_pc): New. Add to the_low_target. + * linux-low.c (linux_bp_reinsert): New variable. + (struct inferior_linux_data): New. + (linux_create_inferior): Use set_inferior_target_data. + (linux_attach): Likewise. Call add_inferior. + (linux_wait_for_one_inferior): New function. + (linux_wait): Call it. + (linux_write_memory): Add const. + (initialize_low): Call set_breakpoint_data. + * linux-low.h (struct linux_target_ops): Add breakpoint + handling members. + * server.c (attach_inferior): Remove extra add_inferior + call. + * server.h: Include mem-break.h. Update inferior.c + prototypes. + * target.c (read_inferior_memory) + (write_inferior_memory): New functions. + * target.h (read_inferior_memory) + (write_inferior_memory): Change macros to prototypes. + (struct target_ops): Update comments. Add const to write_memory + definition. + +2002-04-11 Daniel Jacobowitz + + * linux-low.c (usr_store_inferior_registers): Support + registers which are allowed to fail to store. + * linux-low.h (linux_target_ops): Likewise. + * linux-ppc-low.c (ppc_regmap): Support FPSCR. + (ppc_cannot_store_register): FPSCR may not be storable. + +2002-04-09 Daniel Jacobowitz + + * server.h: Include if HAVE_STRING_H. + * ChangeLog: Correct paths in last ChangeLog entry. + +2002-04-09 Daniel Jacobowitz + + * linux-low.h: Remove obsolete prototypes. + (struct linux_target_ops): New. + (extern the_low_target): New. + * linux-low.c (num_regs, regmap): Remove declarations. + (register_addr): Use the_low_target explicitly. + (fetch_register): Likewise. + (usr_fetch_inferior_registers): Likewise. + (usr_store_inferior_registers): Likewise. + * linux-arm-low.c (num_regs): Remove. + (arm_num_regs): Define. + (arm_regmap): Renamed from regmap, made static. + (arm_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (arm_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-i386-low.c (num_regs): Remove. + (i386_num_regs): Define. + (i386_regmap): Renamed from regmap, made static. + (i386_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (i386_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-ia64-low.c (num_regs): Remove. + (ia64_num_regs): Define. + (ia64_regmap): Renamed from regmap, made static. + (ia64_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (ia64_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-m68k-low.c (num_regs): Remove. + (m68k_num_regs): Define. + (m68k_regmap): Renamed from regmap, made static. + (m68k_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (m68k_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-mips-low.c (num_regs): Remove. + (mips_num_regs): Define. + (mips_regmap): Renamed from regmap, made static. + (mips_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (mips_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-ppc-low.c (num_regs): Remove. + (ppc_num_regs): Define. + (ppc_regmap): Renamed from regmap, made static. + (ppc_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (ppc_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-s390-low.c (num_regs): Remove. + (s390_num_regs): Define. + (s390_regmap): Renamed from regmap, made static. + (s390_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (s390_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-sh-low.c (num_regs): Remove. + (sh_num_regs): Define. + (sh_regmap): Renamed from regmap, made static. + (sh_cannot_fetch_register): Renamed from cannot_fetch_register, + made static. + (sh_cannot_store_register): Renamed from cannot_store_register, + made static. + (the_low_target): New. + * linux-x86-64-low.c (x86_64_regmap): Renamed from regmap. + (the_low_target): New. + +2002-04-09 Daniel Jacobowitz + + * Makefile.in: Add stamp-h target. + * configure.in: Create stamp-h. + * configure: Regenerated. + +2002-04-09 Daniel Jacobowitz + + * inferiors.c: New file. + * target.c: New file. + * target.h: New file. + * Makefile.in: Add target.o and inferiors.o. Update + dependencies. + * linux-low.c (inferior_pid): New static variable, + moved from server.c. + (linux_create_inferior): Renamed from create_inferior. + Call add_inferior. Return 0 on success instead of a PID. + (linux_attach): Renamed from myattach. + (linux_kill): Renamed from kill_inferior. Call clear_inferiors (). + (linux_thread_alive): Renamed from mythread_alive. + (linux_wait): Renamed from mywait. Call clear_inferiors () if the + child dies. + (linux_resume): Renamed from myresume. Add missing ``return 0''. + (regsets_store_inferior_registers): Correct error message. + Add missing ``return 0''. + (linux_fetch_registers): Renamed from fetch_inferior_registers. + (linux_store_registers): Renamed from store_inferior_registers. + (linux_read_memory): Renamed from read_inferior_memory. + (linux_write_memory): Renamed from write_inferior_memory. + (linux_target_ops): New structure. + (initialize_low): Call set_target_ops (). + * remote-utils.c (unhexify): New function. + (hexify): New function. + (input_interrupt): Send signals to ``signal_pid''. + * server.c (inferior_pid): Remove. + (start_inferior): Update create_inferior call. + (attach_inferior): Call add_inferior. + (handle_query): New function. + (main): Call handle_query for `q' packets. + * server.h: Include "target.h". Remove obsolete prototypes. + Add prototypes for "inferiors.c", "target.c", hexify, and unhexify. + +2002-04-09 Daniel Jacobowitz + + * Makefile.in: Add WARN_CFLAGS. Update configury + dependencies. + * configure.in: Check for + * configure: Regenerate. + * config.in: Regenerate. + * gdbreplay.c: Include needed system headers. + (remote_open): Remove strchr prototype. + * linux-low.h: Correct #ifdef to HAVE_LINUX_USRREGS. + * regcache.c (supply_register): Change buf argument to const void *. + (supply_register_by_name): Likewise. + (collect_register): Change buf argument to void *. + (collect_register_by_name): Likewise. + * regcache.h: Add missing prototypes. + * remote-utils.c: Include for inet_ntoa. + * server.c (handle_query): New function. + (attached): New static variable, moved out of main. + (main): Quiet longjmp clobber warnings. + * server.h: Add ATTR_NORETURN and ATTR_FORMAT. Update prototypes. + * utils.c (error): Remove NORETURN. + (fatal): Likewise. diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in new file mode 100644 index 00000000000..60a52d3412b --- /dev/null +++ b/gdbserver/Makefile.in @@ -0,0 +1,719 @@ +# Copyright (C) 1989-2020 Free Software Foundation, Inc. + +# This file is part of GDB. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 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, see . + +# Please keep lists in this file sorted alphabetically, with one item per line. +# See gdb/Makefile.in for guidelines on ordering files and directories. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_noncanonical@ +target_alias = @target_noncanonical@ +program_transform_name = @program_transform_name@ +bindir = @bindir@ +libdir = @libdir@ +tooldir = $(libdir)/$(target_alias) + +datarootdir = @datarootdir@ +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = @infodir@ +htmldir = $(prefix)/html +includedir = @includedir@ +CONFIG_SRC_SUBDIR = @CONFIG_SRC_SUBDIR@ + +install_sh = @install_sh@ + +SHELL = @SHELL@ +EXEEXT = @EXEEXT@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +RANLIB = @RANLIB@ + +CC = @CC@ +CXX = @CXX@ +CXX_DIALECT = @CXX_DIALECT@ +AR = @AR@ +AR_FLAGS = rc +STRIP = @STRIP@ + +# Dependency tracking information. +DEPMODE = @CCDEPMODE@ +DEPDIR = @DEPDIR@ +depcomp = $(SHELL) $(srcdir)/../depcomp + +# Directory containing source files. Don't clean up the spacing, +# this exact string is matched for by the "configure" script. +srcdir = @srcdir@ +abs_top_srcdir = @abs_top_srcdir@ +abs_srcdir = @abs_srcdir@ +VPATH = @srcdir@ + +include $(srcdir)/../gdb/silent-rules.mk + +# Note that these are overridden by GNU make-specific code below if +# GNU make is used. The overrides implement dependency tracking. +COMPILE.pre = $(CXX) -x c++ $(CXX_DIALECT) +COMPILE.post = -c -o $@ +COMPILE = $(ECHO_CXX) $(COMPILE.pre) $(INTERNAL_CFLAGS) $(COMPILE.post) +POSTCOMPILE = @true + +# It is also possible that you will need to add -I/usr/include/sys to the +# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which +# is where it should be according to Posix). + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +#CC_LD = g++ -static +CC_LD = $(CXX) $(CXX_DIALECT) + +# Where is the "include" directory? Traditionally ../include or ./include +INCLUDE_DIR = ${srcdir}/../include +INCLUDE_DEP = $$(INCLUDE_DIR) + +LIBIBERTY_BUILDDIR = build-libiberty-gdbserver +LIBIBERTY = $(LIBIBERTY_BUILDDIR)/libiberty.a + +# Where is ust? These will be empty if ust was not available. +ustlibs = @ustlibs@ +ustinc = @ustinc@ + +# gnulib +GNULIB_BUILDDIR = build-gnulib-gdbserver +LIBGNU = $(GNULIB_BUILDDIR)/import/libgnu.a +INCGNU = -I$(srcdir)/../gnulib/import -I$(GNULIB_BUILDDIR)/import + +# Generated headers in the gnulib directory. These must be listed +# so that they are generated before other files are compiled. +GNULIB_H = $(GNULIB_BUILDDIR)/import/string.h @GNULIB_STDINT_H@ + +INCSUPPORT = -I$(srcdir)/.. -I.. + +# All the includes used for CFLAGS and for lint. +# -I. for config files. +# -I${srcdir} for our headers. +# -I$(srcdir)/../gdb/regformats for regdef.h. +# +# We do not include ../target or ../nat in here because headers +# in those directories should be included with the subdirectory. +# e.g.: "target/wait.h". +# +INCLUDE_CFLAGS = -I. -I${srcdir} \ + -I$(srcdir)/../gdb/regformats -I$(srcdir)/.. -I$(INCLUDE_DIR) \ + -I$(srcdir)/../gdb $(INCGNU) $(INCSUPPORT) + +# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS +# from the config/ directory. +GLOBAL_CFLAGS = ${MT_CFLAGS} ${MH_CFLAGS} +#PROFILE_CFLAGS = -pg + +WARN_CFLAGS = @WARN_CFLAGS@ +WERROR_CFLAGS = @WERROR_CFLAGS@ + +WARN_CFLAGS_NO_FORMAT = `echo " $(WARN_CFLAGS) " \ + | sed "s/ -Wformat-nonliteral / -Wno-format-nonliteral /g"` + +# These are specifically reserved for setting from the command line +# when running make. I.E. "make CFLAGS=-Wmissing-prototypes". +CFLAGS = @CFLAGS@ +CXXFLAGS = @CXXFLAGS@ +CPPFLAGS = @CPPFLAGS@ + +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ + +# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros. +INTERNAL_CFLAGS_BASE = ${CXXFLAGS} ${GLOBAL_CFLAGS} \ + ${PROFILE_CFLAGS} ${INCLUDE_CFLAGS} ${CPPFLAGS} $(PTHREAD_CFLAGS) +INTERNAL_WARN_CFLAGS = ${INTERNAL_CFLAGS_BASE} $(WARN_CFLAGS) +INTERNAL_CFLAGS = ${INTERNAL_WARN_CFLAGS} $(WERROR_CFLAGS) -DGDBSERVER + +# LDFLAGS is specifically reserved for setting from the command line +# when running make. +LDFLAGS = @LDFLAGS@ +INTERNAL_LDFLAGS = $(LDFLAGS) @RDYNAMIC@ + +# All source files that go into linking GDB remote server. + +SFILES = \ + $(srcdir)/debug.c \ + $(srcdir)/dll.c \ + $(srcdir)/gdbreplay.c \ + $(srcdir)/hostio.c \ + $(srcdir)/hostio-errno.c \ + $(srcdir)/i387-fp.c \ + $(srcdir)/inferiors.c \ + $(srcdir)/linux-aarch64-low.c \ + $(srcdir)/linux-arm-low.c \ + $(srcdir)/linux-bfin-low.c \ + $(srcdir)/linux-cris-low.c \ + $(srcdir)/linux-crisv32-low.c \ + $(srcdir)/linux-ia64-low.c \ + $(srcdir)/linux-low.c \ + $(srcdir)/linux-m32r-low.c \ + $(srcdir)/linux-m68k-low.c \ + $(srcdir)/linux-mips-low.c \ + $(srcdir)/linux-nios2-low.c \ + $(srcdir)/linux-ppc-low.c \ + $(srcdir)/linux-s390-low.c \ + $(srcdir)/linux-sh-low.c \ + $(srcdir)/linux-sparc-low.c \ + $(srcdir)/linux-tile-low.c \ + $(srcdir)/linux-x86-low.c \ + $(srcdir)/linux-xtensa-low.c \ + $(srcdir)/mem-break.c \ + $(srcdir)/proc-service.c \ + $(srcdir)/proc-service.list \ + $(srcdir)/regcache.c \ + $(srcdir)/remote-utils.c \ + $(srcdir)/server.c \ + $(srcdir)/symbol.c \ + $(srcdir)/target.c \ + $(srcdir)/thread-db.c \ + $(srcdir)/utils.c \ + $(srcdir)/win32-arm-low.c \ + $(srcdir)/win32-i386-low.c \ + $(srcdir)/win32-low.c \ + $(srcdir)/wincecompat.c \ + $(srcdir)/x86-low.c \ + $(srcdir)/../gdb/alloc.c \ + $(srcdir)/../gdb/arch/arm.c \ + $(srcdir)/../gdb/arch/arm-get-next-pcs.c \ + $(srcdir)/../gdb/arch/arm-linux.c \ + $(srcdir)/../gdb/arch/ppc-linux-common.c \ + $(srcdir)/../gdbsupport/btrace-common.c \ + $(srcdir)/../gdbsupport/buffer.c \ + $(srcdir)/../gdbsupport/cleanups.c \ + $(srcdir)/../gdbsupport/common-debug.c \ + $(srcdir)/../gdbsupport/common-exceptions.c \ + $(srcdir)/../gdbsupport/common-inferior.c \ + $(srcdir)/../gdbsupport/common-regcache.c \ + $(srcdir)/../gdbsupport/common-utils.c \ + $(srcdir)/../gdbsupport/errors.c \ + $(srcdir)/../gdbsupport/environ.c \ + $(srcdir)/../gdbsupport/fileio.c \ + $(srcdir)/../gdbsupport/filestuff.c \ + $(srcdir)/../gdbsupport/job-control.c \ + $(srcdir)/../gdbsupport/gdb-dlfcn.c \ + $(srcdir)/../gdbsupport/gdb_tilde_expand.c \ + $(srcdir)/../gdbsupport/gdb_vecs.c \ + $(srcdir)/../gdbsupport/gdb_wait.c \ + $(srcdir)/../gdbsupport/netstuff.c \ + $(srcdir)/../gdbsupport/new-op.c \ + $(srcdir)/../gdbsupport/pathstuff.c \ + $(srcdir)/../gdbsupport/print-utils.c \ + $(srcdir)/../gdbsupport/ptid.c \ + $(srcdir)/../gdbsupport/rsp-low.c \ + $(srcdir)/../gdbsupport/safe-strerror.c \ + $(srcdir)/../gdbsupport/tdesc.c \ + $(srcdir)/../gdbsupport/xml-utils.c \ + $(srcdir)/../gdb/nat/aarch64-sve-linux-ptrace.c \ + $(srcdir)/../gdb/nat/linux-btrace.c \ + $(srcdir)/../gdb/nat/linux-namespaces.c \ + $(srcdir)/../gdb/nat/linux-osdata.c \ + $(srcdir)/../gdb/nat/linux-personality.c \ + $(srcdir)/../gdb/nat/mips-linux-watch.c \ + $(srcdir)/../gdb/nat/ppc-linux.c \ + $(srcdir)/../gdb/nat/fork-inferior.c \ + $(srcdir)/../gdb/target/waitstatus.c + +DEPFILES = @GDBSERVER_DEPFILES@ + +LIBOBJS = @LIBOBJS@ + +SOURCES = $(SFILES) +TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} + +OBS = \ + alloc.o \ + ax.o \ + gdbsupport/agent.o \ + gdbsupport/btrace-common.o \ + gdbsupport/buffer.o \ + gdbsupport/cleanups.o \ + gdbsupport/common-debug.o \ + gdbsupport/common-exceptions.o \ + gdbsupport/common-inferior.o \ + gdbsupport/job-control.o \ + gdbsupport/common-regcache.o \ + gdbsupport/common-utils.o \ + gdbsupport/errors.o \ + gdbsupport/environ.o \ + gdbsupport/fileio.o \ + gdbsupport/filestuff.o \ + gdbsupport/format.o \ + gdbsupport/gdb-dlfcn.o \ + gdbsupport/gdb_tilde_expand.o \ + gdbsupport/gdb_vecs.o \ + gdbsupport/gdb_wait.o \ + gdbsupport/netstuff.o \ + gdbsupport/new-op.o \ + gdbsupport/pathstuff.o \ + gdbsupport/print-utils.o \ + gdbsupport/ptid.o \ + gdbsupport/rsp-low.o \ + gdbsupport/safe-strerror.o \ + gdbsupport/signals.o \ + gdbsupport/signals-state-save-restore.o \ + gdbsupport/tdesc.o \ + gdbsupport/xml-utils.o \ + debug.o \ + dll.o \ + event-loop.o \ + hostio.o \ + inferiors.o \ + mem-break.o \ + notif.o \ + regcache.o \ + remote-utils.o \ + server.o \ + symbol.o \ + target.o \ + tdesc.o \ + tracepoint.o \ + utils.o \ + version.o \ + target/waitstatus.o \ + $(DEPFILES) \ + $(LIBOBJS) \ + $(XML_BUILTIN) + +GDBREPLAY_OBS = \ + gdbsupport/cleanups.o \ + gdbsupport/common-exceptions.o \ + gdbsupport/common-utils.o \ + gdbsupport/rsp-low.o \ + gdbsupport/errors.o \ + gdbsupport/netstuff.o \ + gdbsupport/print-utils.o \ + gdbsupport/safe-strerror.o \ + gdbreplay.o \ + utils.o \ + version.o + +GDBSERVER_LIBS = @GDBSERVER_LIBS@ $(PTHREAD_LIBS) +XM_CLIBS = @LIBS@ +CDEPS = $(srcdir)/proc-service.list + +# XML files to compile in to gdbserver, if any. +XML_DIR = $(srcdir)/../gdb/features +XML_FILES = @srv_xmlfiles@ +XML_BUILTIN = @srv_xmlbuiltin@ + +IPA_DEPFILES = @IPA_DEPFILES@ +extra_libraries = @extra_libraries@ + +SUBDIRS = $(GNULIB_BUILDDIR) $(LIBIBERTY_BUILDDIR) +CLEANDIRS = $(SUBDIRS) + +# List of subdirectories in the build tree that must exist. +# This is used to force build failures in existing trees when +# a new directory is added. +# The format here is for the `case' shell command. +REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR) | $(LIBIBERTY_BUILDDIR) + +FLAGS_TO_PASS = \ + "prefix=$(prefix)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "datarootdir=$(datarootdir)" \ + "docdir=$(docdir)" \ + "htmldir=$(htmldir)" \ + "pdfdir=$(pdfdir)" \ + "libdir=$(libdir)" \ + "mandir=$(mandir)" \ + "datadir=$(datadir)" \ + "includedir=$(includedir)" \ + "against=$(against)" \ + "DESTDIR=$(DESTDIR)" \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" \ + "CXX=$(CXX)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "DLLTOOL=$(DLLTOOL)" \ + "LDFLAGS=$(LDFLAGS)" \ + "RANLIB=$(RANLIB)" \ + "MAKEINFO=$(MAKEINFO)" \ + "MAKEHTML=$(MAKEHTML)" \ + "MAKEHTMLFLAGS=$(MAKEHTMLFLAGS)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "RUNTEST=$(RUNTEST)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" + +# All generated files which can be included by another file. +generated_files = config.h $(GNULIB_H) + +all: gdbserver$(EXEEXT) gdbreplay$(EXEEXT) $(extra_libraries) + @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do + +# Traditionally "install" depends on "all". But it may be useful +# not to; for example, if the user has made some trivial change to a +# source file and doesn't care about rebuilding or just wants to save the +# time it takes for make to check that all is up to date. +# install-only is intended to address that need. +install: all + @$(MAKE) $(FLAGS_TO_PASS) install-only + +install-only: + n=`echo gdbserver | sed '$(program_transform_name)'`; \ + if [ x$$n = x ]; then n=gdbserver; else true; fi; \ + if [ x"$(IPA_DEPFILES)" != x ]; then \ + $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(libdir); \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $(IPA_LIB) $(DESTDIR)$(libdir)/$(IPA_LIB); \ + fi; \ + $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(bindir); \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) gdbserver$(EXEEXT) $(DESTDIR)$(bindir)/$$n$(EXEEXT) + # Note that we run install and not install-only, as the latter + # is not part of GNU standards and in particular not provided + # in libiberty. + @$(MAKE) $(FLAGS_TO_PASS) DO=install "DODIRS=$(SUBDIRS)" subdir_do + +install-strip: + $(MAKE) $(FLAGS_TO_PASS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install-only + +uninstall: force + n=`echo gdbserver | sed '$(program_transform_name)'`; \ + if [ x$$n = x ]; then n=gdbserver; else true; fi; \ + rm -f $(DESTDIR)/$(bindir)/$$n$(EXEEXT) $(DESTDIR)$(man1dir)/$$n.1 + @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do + +installcheck: +check: +info dvi pdf: +install-info: +install-pdf: +html: +install-html: +clean-info: force + @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do + +gdbserver$(EXEEXT): $(sort $(OBS)) ${CDEPS} $(LIBGNU) $(LIBIBERTY) + $(SILENCE) rm -f gdbserver$(EXEEXT) + $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) \ + -o gdbserver$(EXEEXT) $(OBS) $(LIBGNU) $(LIBIBERTY) \ + $(GDBSERVER_LIBS) $(XM_CLIBS) + +$(LIBGNU) $(LIBIBERTY) $(GNULIB_H): all-lib +all-lib: $(GNULIB_BUILDDIR)/Makefile $(LIBIBERTY_BUILDDIR)/Makefile + @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS="$(SUBDIRS)" subdir_do +.PHONY: all-lib + +gdbreplay$(EXEEXT): $(sort $(GDBREPLAY_OBS)) $(LIBGNU) $(LIBIBERTY) + $(SILENCE) rm -f gdbreplay$(EXEEXT) + $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) \ + -o gdbreplay$(EXEEXT) $(GDBREPLAY_OBS) $(XM_CLIBS) $(LIBGNU) \ + $(LIBIBERTY) + +IPA_OBJS = \ + alloc-ipa.o \ + ax-ipa.o \ + gdbsupport/common-utils-ipa.o \ + gdbsupport/errors-ipa.o \ + gdbsupport/format-ipa.o \ + gdbsupport/print-utils-ipa.o \ + gdbsupport/rsp-low-ipa.o \ + gdbsupport/safe-strerror-ipa.o \ + gdbsupport/tdesc-ipa.o \ + regcache-ipa.o \ + remote-utils-ipa.o \ + tdesc-ipa.o \ + tracepoint-ipa.o \ + utils-ipa.o \ + ${IPA_DEPFILES} + +IPA_LIB = libinproctrace.so + +$(IPA_LIB): $(sort $(IPA_OBJS)) ${CDEPS} + $(SILENCE) rm -f $(IPA_LIB) + $(ECHO_CXXLD) $(CC_LD) -shared -fPIC -Wl,--soname=$(IPA_LIB) \ + -Wl,--no-undefined $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) \ + -o $(IPA_LIB) ${IPA_OBJS} -ldl -pthread + +# Put the proper machine-specific files first, so M-. on a machine +# specific routine gets the one for the correct machine. +# The xyzzy stuff below deals with empty DEPFILES +TAGS: ${TAGFILES} + etags \ + `for i in yzzy ${DEPFILES}; do \ + if [ x$$i != xyzzy ]; then \ + echo ${srcdir}/$$i | sed -e 's/\.o$$/\.c/' \ + -e 's,/\(arch\|nat\|target\)/,/../\1/,' \ + -e 's,/\(gdbsupport\)/,/../../\1/,'; \ + fi; \ + done` \ + ${TAGFILES} +tags: TAGS + +clean: + rm -f *.o ${ADD_FILES} *~ + rm -f gdbserver$(EXEEXT) gdbreplay$(EXEEXT) core make.log + rm -f $(IPA_LIB) + rm -f *-generated.c + rm -f stamp-xml + rm -f $(DEPDIR)/*.Po + for i in $(CONFIG_SRC_SUBDIR); do \ + rm -f $$i/*.o; \ + rm -f $$i/$(DEPDIR)/*; \ + done + @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do + +maintainer-clean realclean distclean: clean + @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do + rm -rf $(GNULIB_BUILDDIR) + rm -f Makefile config.status config.h stamp-h config.log + rm -f Makefile + for i in $(CONFIG_SRC_SUBDIR); do \ + rmdir $$i/$(DEPDIR); \ + done + +subdir_do: force + @for i in $(DODIRS); do \ + case $$i in \ + $(REQUIRED_SUBDIRS)) \ + if [ ! -f ./$$i/Makefile ] ; then \ + echo "Missing $$i/Makefile" >&2 ; \ + exit 1 ; \ + fi ;; \ + esac ; \ + if [ -f ./$$i/Makefile ] ; then \ + if (cd ./$$i; \ + $(MAKE) $(FLAGS_TO_PASS) $(DO)) ; then true ; \ + else exit 1 ; fi ; \ + else true ; fi ; \ + done + +config.h: stamp-h ; @true +stamp-h: config.in config.status + $(SHELL) ./config.status config.h + +Makefile: Makefile.in config.status + $(SHELL) ./config.status $@ + +$(GNULIB_BUILDDIR)/Makefile: $(srcdir)/../gnulib/Makefile.in config.status + @cd $(GNULIB_BUILDDIR); CONFIG_FILES="Makefile" \ + CONFIG_COMMANDS="depfiles" \ + CONFIG_HEADERS= \ + CONFIG_LINKS= \ + $(SHELL) config.status + +config.status: configure configure.srv $(srcdir)/../bfd/development.sh + $(SHELL) ./config.status --recheck + +# automatic rebuilding in automake-generated Makefiles requires +# this rule in the toplevel Makefile, which, with GNU make, causes +# the desired updates through the implicit regeneration of the Makefile +# and all of its prerequisites. +am--refresh: + @: + +force: + +version-generated.c: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh + $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdb \ + $(host_alias) $(target_alias) $@ + +xml-builtin-generated.c: stamp-xml; @true +stamp-xml: $(XML_DIR)/feature_to_c.sh Makefile $(XML_FILES) + $(SILENCE) rm -f xml-builtin.tmp + $(ECHO_GEN_XML_BUILTIN_GENERATED) $(SHELL) $(XML_DIR)/feature_to_c.sh \ + xml-builtin.tmp $(XML_FILES) + $(SILENCE) $(SHELL) $(srcdir)/../move-if-change xml-builtin.tmp xml-builtin-generated.c + $(SILENCE) echo stamp > stamp-xml + +.PRECIOUS: xml-builtin.c + +# GNU Make has an annoying habit of putting *all* the Makefile variables +# into the environment, unless you include this target as a circumvention. +# Rumor is that this will be fixed (and this target can be removed) +# in GNU Make 4.0. +.NOEXPORT: + +# GNU Make 3.63 has a different problem: it keeps tacking command line +# overrides onto the definition of $(MAKE). This variable setting +# will remove them. +MAKEOVERRIDES = + +regdat_sh = $(srcdir)/../gdb/regformats/regdat.sh + +UST_CFLAGS = $(ustinc) -DCONFIG_UST_GDB_INTEGRATION + +# Undo gnulib replacements for the IPA shared library build. +# The gnulib headers are still needed, but gnulib is not linked +# into the IPA lib so replacement apis don't work. +UNDO_GNULIB_CFLAGS = -Drpl_strerror_r=strerror_r + +# Note, we only build the IPA if -fvisibility=hidden is supported in +# the first place. +IPAGENT_CFLAGS = $(INTERNAL_CFLAGS) $(UST_CFLAGS) \ + $(UNDO_GNULIB_CFLAGS) \ + -fPIC -DIN_PROCESS_AGENT \ + -fvisibility=hidden + +IPAGENT_COMPILE = $(ECHO_CXX) $(COMPILE.pre) $(IPAGENT_CFLAGS) $(COMPILE.post) + +# Rules for special cases. + +ax-ipa.o: ax.c + $(IPAGENT_COMPILE) $(WARN_CFLAGS_NO_FORMAT) $< + $(POSTCOMPILE) + +ax.o: ax.c + $(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $< + $(POSTCOMPILE) + +# Rules for objects that go in the in-process agent. + +arch/%-ipa.o: ../gdb/arch/%.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + +gdbsupport/%-ipa.o: ../gdbsupport/%.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + +%-ipa.o: %-generated.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + +%-ipa.o: %.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + +%-ipa.o: ../gdb/%.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + +# Note: Between two matching pattern rules, GNU Make 3.81 chooses the first one. +# Therefore, this one needs to be before "%.o: %.c" for it to be considered for +# files such as linux-amd64-ipa.o generated from linux-amd64-ipa.c. +# +# Later versions of GNU Make choose the rule with the shortest stem, so it would +# work in any order. + +%-ipa.o: %-ipa.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) + +# Rules for objects that go in the gdbserver binary. + +arch/%.o: ../gdb/arch/%.c + $(COMPILE) $< + $(POSTCOMPILE) + +gdbsupport/%.o: ../gdbsupport/%.c + $(COMPILE) $< + $(POSTCOMPILE) + +%.o: %-generated.c + $(COMPILE) $< + $(POSTCOMPILE) + +%.o: %.c + $(COMPILE) $< + $(POSTCOMPILE) + +nat/%.o: ../gdb/nat/%.c + $(COMPILE) $< + $(POSTCOMPILE) + +target/%.o: ../gdb/target/%.c + $(COMPILE) $< + $(POSTCOMPILE) + +%.o: ../gdb/%.c + $(COMPILE) $< + $(POSTCOMPILE) + +# Rules for register format descriptions. Suffix destination files with +# -generated to identify and clean them easily. + +%-generated.c: ../gdb/regformats/%.dat $(regdat_sh) + $(ECHO_REGDAT) $(SHELL) $(regdat_sh) $< $@ + +%-generated.c: ../gdb/regformats/arm/%.dat $(regdat_sh) + $(ECHO_REGDAT) $(SHELL) $(regdat_sh) $< $@ + +%-generated.c: ../gdb/regformats/rs6000/%.dat $(regdat_sh) + $(ECHO_REGDAT) $(SHELL) $(regdat_sh) $< $@ + +# +# Dependency tracking. +# + +ifeq ($(DEPMODE),depmode=gcc3) +# Note that we put the dependencies into a .Tpo file, then move them +# into place if the compile succeeds. We need this because gcc does +# not atomically write the dependency output file. +override COMPILE.post = -c -o $@ -MT $@ -MMD -MP \ + -MF $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo +override POSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo \ + $(@D)/$(DEPDIR)/$(basename $(@F)).Po +else +override COMPILE.pre = source='$<' object='$@' libtool=no \ + DEPDIR=$(DEPDIR) $(DEPMODE) $(depcomp) \ + $(CXX) -x c++ $(CXX_DIALECT) +# depcomp handles atomicity for us, so we don't need a postcompile +# step. +override POSTCOMPILE = +endif + +# A list of all the objects we might care about in this build, for +# dependency tracking. +all_object_files = $(OBS) $(GDBREPLAY_OBS) $(IPA_OBJS) + +# Ensure that generated files are created early. Use order-only +# dependencies if available. They require GNU make 3.80 or newer, +# and the .VARIABLES variable was introduced at the same time. +ifdef .VARIABLES +$(all_object_files): | $(generated_files) +else +$(all_object_files) : $(generated_files) +endif + +# All the .deps files to include. +all_deps_files = $(foreach dep,$(patsubst %.o,%.Po,$(all_object_files)),\ + $(dir $(dep))/$(DEPDIR)/$(notdir $(dep))) + +# Dependencies. +-include $(all_deps_files) + +# Disable implicit make rules. +include $(srcdir)/../gdb/disable-implicit-rules.mk + +# Do not delete intermediate files (e.g. *-generated.c). +.SECONDARY: + +# This is the end of "Makefile.in". diff --git a/gdbserver/README b/gdbserver/README new file mode 100644 index 00000000000..17d435c18f5 --- /dev/null +++ b/gdbserver/README @@ -0,0 +1,149 @@ + README for GDBserver & GDBreplay + by Stu Grossman and Fred Fish + +Introduction: + +This is GDBserver, a remote server for Un*x-like systems. It can be used to +control the execution of a program on a target system from a GDB on a different +host. GDB and GDBserver communicate using the standard remote serial protocol +implemented in remote.c, and various *-stub.c files. They communicate via +either a serial line or a TCP connection. + +For more information about GDBserver, see the GDB manual. + +Usage (server (target) side): + +First, you need to have a copy of the program you want to debug put onto +the target system. The program can be stripped to save space if needed, as +GDBserver doesn't care about symbols. All symbol handling is taken care of by +the GDB running on the host system. + +To use the server, you log on to the target system, and run the `gdbserver' +program. You must tell it (a) how to communicate with GDB, (b) the name of +your program, and (c) its arguments. The general syntax is: + + target> gdbserver COMM PROGRAM [ARGS ...] + +For example, using a serial port, you might say: + + target> gdbserver /dev/com1 emacs foo.txt + +This tells GDBserver to debug emacs with an argument of foo.txt, and to +communicate with GDB via /dev/com1. GDBserver now waits patiently for the +host GDB to communicate with it. + +To use a TCP connection, you could say: + + target> gdbserver host:2345 emacs foo.txt + +This says pretty much the same thing as the last example, except that we are +going to communicate with the host GDB via TCP. The `host:2345' argument means +that we are expecting to see a TCP connection from `host' to local TCP port +2345. (Currently, the `host' part is ignored.) You can choose any number you +want for the port number as long as it does not conflict with any existing TCP +ports on the target system. This same port number must be used in the host +GDBs `target remote' command, which will be described shortly. Note that if +you chose a port number that conflicts with another service, GDBserver will +print an error message and exit. + +On some targets, GDBserver can also attach to running programs. This is +accomplished via the --attach argument. The syntax is: + + target> gdbserver --attach COMM PID + +PID is the process ID of a currently running process. It isn't necessary +to point GDBserver at a binary for the running process. + +Usage (host side): + +You need an unstripped copy of the target program on your host system, since +GDB needs to examine it's symbol tables and such. Start up GDB as you normally +would, with the target program as the first argument. (You may need to use the +--baud option if the serial line is running at anything except 9600 baud.) +Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET-PROG'. After that, the only +new command you need to know about is `target remote'. It's argument is either +a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT +descriptor. For example: + + (gdb) target remote /dev/ttyb + +communicates with the server via serial line /dev/ttyb, and: + + (gdb) target remote the-target:2345 + +communicates via a TCP connection to port 2345 on host `the-target', where +you previously started up GDBserver with the same port number. Note that for +TCP connections, you must start up GDBserver prior to using the `target remote' +command, otherwise you may get an error that looks something like +`Connection refused'. + +Building GDBserver: + +The supported targets as of November 2006 are: + arm-*-linux* + bfin-*-uclinux + bfin-*-linux-uclibc + crisv32-*-linux* + cris-*-linux* + i[34567]86-*-cygwin* + i[34567]86-*-linux* + i[34567]86-*-mingw* + ia64-*-linux* + m32r*-*-linux* + m68*-*-linux* + m68*-*-uclinux* + mips*64*-*-linux* + mips*-*-linux* + powerpc[64]-*-linux* + s390[x]-*-linux* + sh-*-linux* + spu*-*-* + x86_64-*-linux* + +Building GDBserver for your host is very straightforward. If you build +GDB natively on a host which GDBserver supports, it will be built +automatically when you build GDB. You can also build just GDBserver: + + % mkdir obj + % cd obj + % path-to-toplevel-sources/configure --disable-gdb + % make all-gdbserver + +(If you have a combined binutils+gdb tree, you may want to also +disable other directories when configuring, e.g., binutils, gas, gold, +gprof, and ld.) + +If you prefer to cross-compile to your target, then you can also build +GDBserver that way. In a Bourne shell, for example: + + % export CC=your-cross-compiler + % path-to-topevel-sources/configure your-target-name --disable-gdb + % make + +Using GDBreplay: + +A special hacked down version of GDBserver can be used to replay remote +debug log files created by GDB. Before using the GDB "target" command to +initiate a remote debug session, use "set remotelogfile " to tell +GDB that you want to make a recording of the serial or tcp session. Note +that when replaying the session, GDB communicates with GDBreplay via tcp, +regardless of whether the original session was via a serial link or tcp. + +Once you are done with the remote debug session, start GDBreplay and +tell it the name of the log file and the host and port number that GDB +should connect to (typically the same as the host running GDB): + + $ gdbreplay logfile host:port + +Then start GDB (preferably in a different screen or window) and use the +"target" command to connect to GDBreplay: + + (gdb) target remote host:port + +Repeat the same sequence of user commands to GDB that you gave in the +original debug session. GDB should not be able to tell that it is talking +to GDBreplay rather than a real target, all other things being equal. Note +that GDBreplay echos the command lines to stderr, as well as the contents of +the packets it sends and receives. The last command echoed by GDBreplay is +the next command that needs to be typed to GDB to continue the session in +sync with the original session. diff --git a/gdbserver/acinclude.m4 b/gdbserver/acinclude.m4 new file mode 100644 index 00000000000..5a284515c82 --- /dev/null +++ b/gdbserver/acinclude.m4 @@ -0,0 +1,58 @@ +dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE. +m4_include(../bfd/bfd.m4) + +m4_include(../gdb/acx_configure_dir.m4) + +# This gets AM_GDB_WARNINGS. +m4_include(../gdb/warning.m4) + +dnl This gets autoconf bugfixes +m4_include(../config/override.m4) + +dnl For ACX_PKGVERSION and ACX_BUGURL. +m4_include(../config/acx.m4) + +m4_include(../config/depstand.m4) +m4_include(../config/lead-dot.m4) + +dnl Needed for common.m4 +dnl For AC_LIB_HAVE_LINKFLAGS. +m4_include(../config/lib-ld.m4) +m4_include(../config/lib-prefix.m4) +m4_include(../config/lib-link.m4) +dnl codeset.m4 is needed for common.m4, but not for +dnl anything else in gdbserver. +m4_include(../config/codeset.m4) +m4_include(../gdbsupport/common.m4) + +dnl For libiberty_INIT. +m4_include(../gdb/libiberty.m4) + +dnl For GDB_AC_PTRACE. +m4_include(../gdb/ptrace.m4) + +m4_include(../gdb/ax_cxx_compile_stdcxx.m4) + +dnl For GDB_AC_SELFTEST. +m4_include(../gdb/selftest.m4) + +m4_include([../config/ax_pthread.m4]) + +dnl Check for existence of a type $1 in libthread_db.h +dnl Based on BFD_HAVE_SYS_PROCFS_TYPE in bfd/bfd.m4. + +AC_DEFUN([GDBSERVER_HAVE_THREAD_DB_TYPE], +[AC_MSG_CHECKING([for $1 in thread_db.h]) + AC_CACHE_VAL(gdbserver_cv_have_thread_db_type_$1, + [AC_TRY_COMPILE([ +#include ], + [$1 avar], + gdbserver_cv_have_thread_db_type_$1=yes, + gdbserver_cv_have_thread_db_type_$1=no + )]) + if test $gdbserver_cv_have_thread_db_type_$1 = yes; then + AC_DEFINE([HAVE_]translit($1, [a-z], [A-Z]), 1, + [Define if has $1.]) + fi + AC_MSG_RESULT($gdbserver_cv_have_thread_db_type_$1) +]) diff --git a/gdbserver/aclocal.m4 b/gdbserver/aclocal.m4 new file mode 100644 index 00000000000..110b416e615 --- /dev/null +++ b/gdbserver/aclocal.m4 @@ -0,0 +1,202 @@ +# generated automatically by aclocal 1.15.1 -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +m4_include([acinclude.m4]) diff --git a/gdbserver/ax.c b/gdbserver/ax.c new file mode 100644 index 00000000000..213db410a07 --- /dev/null +++ b/gdbserver/ax.c @@ -0,0 +1,1376 @@ +/* Agent expression code for remote server. + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "ax.h" +#include "gdbsupport/format.h" +#include "tracepoint.h" +#include "gdbsupport/rsp-low.h" + +static void ax_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2); + +#ifdef IN_PROCESS_AGENT +int debug_agent = 0; +#endif + +static void +ax_vdebug (const char *fmt, ...) +{ + char buf[1024]; + va_list ap; + + va_start (ap, fmt); + vsprintf (buf, fmt, ap); +#ifdef IN_PROCESS_AGENT + fprintf (stderr, PROG "/ax: %s\n", buf); +#else + debug_printf (PROG "/ax: %s\n", buf); +#endif + va_end (ap); +} + +#define ax_debug_1(level, fmt, args...) \ + do { \ + if (level <= debug_threads) \ + ax_vdebug ((fmt), ##args); \ + } while (0) + +#define ax_debug(FMT, args...) \ + ax_debug_1 (1, FMT, ##args) + +/* This enum must exactly match what is documented in + gdb/doc/agentexpr.texi, including all the numerical values. */ + +enum gdb_agent_op + { +#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) \ + gdb_agent_op_ ## NAME = VALUE, +#include "gdbsupport/ax.def" +#undef DEFOP + gdb_agent_op_last + }; + +static const char *gdb_agent_op_names [gdb_agent_op_last] = + { + "?undef?" +#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , # NAME +#include "gdbsupport/ax.def" +#undef DEFOP + }; + +#ifndef IN_PROCESS_AGENT +static const unsigned char gdb_agent_op_sizes [gdb_agent_op_last] = + { + 0 +#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , SIZE +#include "gdbsupport/ax.def" +#undef DEFOP + }; +#endif + +/* A wrapper for gdb_agent_op_names that does some bounds-checking. */ + +static const char * +gdb_agent_op_name (int op) +{ + if (op < 0 || op >= gdb_agent_op_last || gdb_agent_op_names[op] == NULL) + return "?undef?"; + return gdb_agent_op_names[op]; +} + +#ifndef IN_PROCESS_AGENT + +/* The packet form of an agent expression consists of an 'X', number + of bytes in expression, a comma, and then the bytes. */ + +struct agent_expr * +gdb_parse_agent_expr (const char **actparm) +{ + const char *act = *actparm; + ULONGEST xlen; + struct agent_expr *aexpr; + + ++act; /* skip the X */ + act = unpack_varlen_hex (act, &xlen); + ++act; /* skip a comma */ + aexpr = XNEW (struct agent_expr); + aexpr->length = xlen; + aexpr->bytes = (unsigned char *) xmalloc (xlen); + hex2bin (act, aexpr->bytes, xlen); + *actparm = act + (xlen * 2); + return aexpr; +} + +void +gdb_free_agent_expr (struct agent_expr *aexpr) +{ + if (aexpr != NULL) + { + free (aexpr->bytes); + free (aexpr); + } +} + +/* Convert the bytes of an agent expression back into hex digits, so + they can be printed or uploaded. This allocates the buffer, + callers should free when they are done with it. */ + +char * +gdb_unparse_agent_expr (struct agent_expr *aexpr) +{ + char *rslt; + + rslt = (char *) xmalloc (2 * aexpr->length + 1); + bin2hex (aexpr->bytes, rslt, aexpr->length); + return rslt; +} + +/* Bytecode compilation. */ + +CORE_ADDR current_insn_ptr; + +int emit_error; + +struct bytecode_address +{ + int pc; + CORE_ADDR address; + int goto_pc; + /* Offset and size of field to be modified in the goto block. */ + int from_offset, from_size; + struct bytecode_address *next; +} *bytecode_address_table; + +void +emit_prologue (void) +{ + target_emit_ops ()->emit_prologue (); +} + +void +emit_epilogue (void) +{ + target_emit_ops ()->emit_epilogue (); +} + +static void +emit_add (void) +{ + target_emit_ops ()->emit_add (); +} + +static void +emit_sub (void) +{ + target_emit_ops ()->emit_sub (); +} + +static void +emit_mul (void) +{ + target_emit_ops ()->emit_mul (); +} + +static void +emit_lsh (void) +{ + target_emit_ops ()->emit_lsh (); +} + +static void +emit_rsh_signed (void) +{ + target_emit_ops ()->emit_rsh_signed (); +} + +static void +emit_rsh_unsigned (void) +{ + target_emit_ops ()->emit_rsh_unsigned (); +} + +static void +emit_ext (int arg) +{ + target_emit_ops ()->emit_ext (arg); +} + +static void +emit_log_not (void) +{ + target_emit_ops ()->emit_log_not (); +} + +static void +emit_bit_and (void) +{ + target_emit_ops ()->emit_bit_and (); +} + +static void +emit_bit_or (void) +{ + target_emit_ops ()->emit_bit_or (); +} + +static void +emit_bit_xor (void) +{ + target_emit_ops ()->emit_bit_xor (); +} + +static void +emit_bit_not (void) +{ + target_emit_ops ()->emit_bit_not (); +} + +static void +emit_equal (void) +{ + target_emit_ops ()->emit_equal (); +} + +static void +emit_less_signed (void) +{ + target_emit_ops ()->emit_less_signed (); +} + +static void +emit_less_unsigned (void) +{ + target_emit_ops ()->emit_less_unsigned (); +} + +static void +emit_ref (int size) +{ + target_emit_ops ()->emit_ref (size); +} + +static void +emit_if_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_if_goto (offset_p, size_p); +} + +static void +emit_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_goto (offset_p, size_p); +} + +static void +write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) +{ + target_emit_ops ()->write_goto_address (from, to, size); +} + +static void +emit_const (LONGEST num) +{ + target_emit_ops ()->emit_const (num); +} + +static void +emit_reg (int reg) +{ + target_emit_ops ()->emit_reg (reg); +} + +static void +emit_pop (void) +{ + target_emit_ops ()->emit_pop (); +} + +static void +emit_stack_flush (void) +{ + target_emit_ops ()->emit_stack_flush (); +} + +static void +emit_zero_ext (int arg) +{ + target_emit_ops ()->emit_zero_ext (arg); +} + +static void +emit_swap (void) +{ + target_emit_ops ()->emit_swap (); +} + +static void +emit_stack_adjust (int n) +{ + target_emit_ops ()->emit_stack_adjust (n); +} + +/* FN's prototype is `LONGEST(*fn)(int)'. */ + +static void +emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + target_emit_ops ()->emit_int_call_1 (fn, arg1); +} + +/* FN's prototype is `void(*fn)(int,LONGEST)'. */ + +static void +emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + target_emit_ops ()->emit_void_call_2 (fn, arg1); +} + +static void +emit_eq_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_eq_goto (offset_p, size_p); +} + +static void +emit_ne_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_ne_goto (offset_p, size_p); +} + +static void +emit_lt_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_lt_goto (offset_p, size_p); +} + +static void +emit_ge_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_ge_goto (offset_p, size_p); +} + +static void +emit_gt_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_gt_goto (offset_p, size_p); +} + +static void +emit_le_goto (int *offset_p, int *size_p) +{ + target_emit_ops ()->emit_le_goto (offset_p, size_p); +} + +/* Scan an agent expression for any evidence that the given PC is the + target of a jump bytecode in the expression. */ + +static int +is_goto_target (struct agent_expr *aexpr, int pc) +{ + int i; + unsigned char op; + + for (i = 0; i < aexpr->length; i += 1 + gdb_agent_op_sizes[op]) + { + op = aexpr->bytes[i]; + + if (op == gdb_agent_op_goto || op == gdb_agent_op_if_goto) + { + int target = (aexpr->bytes[i + 1] << 8) + aexpr->bytes[i + 2]; + if (target == pc) + return 1; + } + } + + return 0; +} + +/* Given an agent expression, turn it into native code. */ + +enum eval_result_type +compile_bytecodes (struct agent_expr *aexpr) +{ + int pc = 0; + int done = 0; + unsigned char op, next_op; + int arg; + /* This is only used to build 64-bit value for constants. */ + ULONGEST top; + struct bytecode_address *aentry, *aentry2; + +#define UNHANDLED \ + do \ + { \ + ax_debug ("Cannot compile op 0x%x\n", op); \ + return expr_eval_unhandled_opcode; \ + } while (0) + + if (aexpr->length == 0) + { + ax_debug ("empty agent expression\n"); + return expr_eval_empty_expression; + } + + bytecode_address_table = NULL; + + while (!done) + { + op = aexpr->bytes[pc]; + + ax_debug ("About to compile op 0x%x, pc=%d\n", op, pc); + + /* Record the compiled-code address of the bytecode, for use by + jump instructions. */ + aentry = XNEW (struct bytecode_address); + aentry->pc = pc; + aentry->address = current_insn_ptr; + aentry->goto_pc = -1; + aentry->from_offset = aentry->from_size = 0; + aentry->next = bytecode_address_table; + bytecode_address_table = aentry; + + ++pc; + + emit_error = 0; + + switch (op) + { + case gdb_agent_op_add: + emit_add (); + break; + + case gdb_agent_op_sub: + emit_sub (); + break; + + case gdb_agent_op_mul: + emit_mul (); + break; + + case gdb_agent_op_div_signed: + UNHANDLED; + break; + + case gdb_agent_op_div_unsigned: + UNHANDLED; + break; + + case gdb_agent_op_rem_signed: + UNHANDLED; + break; + + case gdb_agent_op_rem_unsigned: + UNHANDLED; + break; + + case gdb_agent_op_lsh: + emit_lsh (); + break; + + case gdb_agent_op_rsh_signed: + emit_rsh_signed (); + break; + + case gdb_agent_op_rsh_unsigned: + emit_rsh_unsigned (); + break; + + case gdb_agent_op_trace: + UNHANDLED; + break; + + case gdb_agent_op_trace_quick: + UNHANDLED; + break; + + case gdb_agent_op_log_not: + emit_log_not (); + break; + + case gdb_agent_op_bit_and: + emit_bit_and (); + break; + + case gdb_agent_op_bit_or: + emit_bit_or (); + break; + + case gdb_agent_op_bit_xor: + emit_bit_xor (); + break; + + case gdb_agent_op_bit_not: + emit_bit_not (); + break; + + case gdb_agent_op_equal: + next_op = aexpr->bytes[pc]; + if (next_op == gdb_agent_op_if_goto + && !is_goto_target (aexpr, pc) + && target_emit_ops ()->emit_eq_goto) + { + ax_debug ("Combining equal & if_goto"); + pc += 1; + aentry->pc = pc; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_eq_goto (&(aentry->from_offset), &(aentry->from_size)); + } + else if (next_op == gdb_agent_op_log_not + && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) + && !is_goto_target (aexpr, pc + 1) + && target_emit_ops ()->emit_ne_goto) + { + ax_debug ("Combining equal & log_not & if_goto"); + pc += 2; + aentry->pc = pc; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_ne_goto (&(aentry->from_offset), &(aentry->from_size)); + } + else + emit_equal (); + break; + + case gdb_agent_op_less_signed: + next_op = aexpr->bytes[pc]; + if (next_op == gdb_agent_op_if_goto + && !is_goto_target (aexpr, pc)) + { + ax_debug ("Combining less_signed & if_goto"); + pc += 1; + aentry->pc = pc; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_lt_goto (&(aentry->from_offset), &(aentry->from_size)); + } + else if (next_op == gdb_agent_op_log_not + && !is_goto_target (aexpr, pc) + && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) + && !is_goto_target (aexpr, pc + 1)) + { + ax_debug ("Combining less_signed & log_not & if_goto"); + pc += 2; + aentry->pc = pc; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_ge_goto (&(aentry->from_offset), &(aentry->from_size)); + } + else + emit_less_signed (); + break; + + case gdb_agent_op_less_unsigned: + emit_less_unsigned (); + break; + + case gdb_agent_op_ext: + arg = aexpr->bytes[pc++]; + if (arg < (sizeof (LONGEST) * 8)) + emit_ext (arg); + break; + + case gdb_agent_op_ref8: + emit_ref (1); + break; + + case gdb_agent_op_ref16: + emit_ref (2); + break; + + case gdb_agent_op_ref32: + emit_ref (4); + break; + + case gdb_agent_op_ref64: + emit_ref (8); + break; + + case gdb_agent_op_if_goto: + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_if_goto (&(aentry->from_offset), &(aentry->from_size)); + break; + + case gdb_agent_op_goto: + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_goto (&(aentry->from_offset), &(aentry->from_size)); + break; + + case gdb_agent_op_const8: + emit_stack_flush (); + top = aexpr->bytes[pc++]; + emit_const (top); + break; + + case gdb_agent_op_const16: + emit_stack_flush (); + top = aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + emit_const (top); + break; + + case gdb_agent_op_const32: + emit_stack_flush (); + top = aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + emit_const (top); + break; + + case gdb_agent_op_const64: + emit_stack_flush (); + top = aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + emit_const (top); + break; + + case gdb_agent_op_reg: + emit_stack_flush (); + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + emit_reg (arg); + break; + + case gdb_agent_op_end: + ax_debug ("At end of expression\n"); + + /* Assume there is one stack element left, and that it is + cached in "top" where emit_epilogue can get to it. */ + emit_stack_adjust (1); + + done = 1; + break; + + case gdb_agent_op_dup: + /* In our design, dup is equivalent to stack flushing. */ + emit_stack_flush (); + break; + + case gdb_agent_op_pop: + emit_pop (); + break; + + case gdb_agent_op_zero_ext: + arg = aexpr->bytes[pc++]; + if (arg < (sizeof (LONGEST) * 8)) + emit_zero_ext (arg); + break; + + case gdb_agent_op_swap: + next_op = aexpr->bytes[pc]; + /* Detect greater-than comparison sequences. */ + if (next_op == gdb_agent_op_less_signed + && !is_goto_target (aexpr, pc) + && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) + && !is_goto_target (aexpr, pc + 1)) + { + ax_debug ("Combining swap & less_signed & if_goto"); + pc += 2; + aentry->pc = pc; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_gt_goto (&(aentry->from_offset), &(aentry->from_size)); + } + else if (next_op == gdb_agent_op_less_signed + && !is_goto_target (aexpr, pc) + && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not) + && !is_goto_target (aexpr, pc + 1) + && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto) + && !is_goto_target (aexpr, pc + 2)) + { + ax_debug ("Combining swap & less_signed & log_not & if_goto"); + pc += 3; + aentry->pc = pc; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + aentry->goto_pc = arg; + emit_le_goto (&(aentry->from_offset), &(aentry->from_size)); + } + else + emit_swap (); + break; + + case gdb_agent_op_getv: + emit_stack_flush (); + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + emit_int_call_1 (get_get_tsv_func_addr (), + arg); + break; + + case gdb_agent_op_setv: + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + emit_void_call_2 (get_set_tsv_func_addr (), + arg); + break; + + case gdb_agent_op_tracev: + UNHANDLED; + break; + + /* GDB never (currently) generates any of these ops. */ + case gdb_agent_op_float: + case gdb_agent_op_ref_float: + case gdb_agent_op_ref_double: + case gdb_agent_op_ref_long_double: + case gdb_agent_op_l_to_d: + case gdb_agent_op_d_to_l: + case gdb_agent_op_trace16: + UNHANDLED; + break; + + default: + ax_debug ("Agent expression op 0x%x not recognized\n", op); + /* Don't struggle on, things will just get worse. */ + return expr_eval_unrecognized_opcode; + } + + /* This catches errors that occur in target-specific code + emission. */ + if (emit_error) + { + ax_debug ("Error %d while emitting code for %s\n", + emit_error, gdb_agent_op_name (op)); + return expr_eval_unhandled_opcode; + } + + ax_debug ("Op %s compiled\n", gdb_agent_op_name (op)); + } + + /* Now fill in real addresses as goto destinations. */ + for (aentry = bytecode_address_table; aentry; aentry = aentry->next) + { + int written = 0; + + if (aentry->goto_pc < 0) + continue; + + /* Find the location that we are going to, and call back into + target-specific code to write the actual address or + displacement. */ + for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next) + { + if (aentry2->pc == aentry->goto_pc) + { + ax_debug ("Want to jump from %s to %s\n", + paddress (aentry->address), + paddress (aentry2->address)); + write_goto_address (aentry->address + aentry->from_offset, + aentry2->address, aentry->from_size); + written = 1; + break; + } + } + + /* Error out if we didn't find a destination. */ + if (!written) + { + ax_debug ("Destination of goto %d not found\n", + aentry->goto_pc); + return expr_eval_invalid_goto; + } + } + + return expr_eval_no_error; +} + +#endif + +/* Make printf-type calls using arguments supplied from the host. We + need to parse the format string ourselves, and call the formatting + function with one argument at a time, partly because there is no + safe portable way to construct a varargs call, and partly to serve + as a security barrier against bad format strings that might get + in. */ + +static void +ax_printf (CORE_ADDR fn, CORE_ADDR chan, const char *format, + int nargs, ULONGEST *args) +{ + const char *f = format; + int i; + const char *current_substring; + int nargs_wanted; + + ax_debug ("Printf of \"%s\" with %d args", format, nargs); + + format_pieces fpieces (&f); + + nargs_wanted = 0; + for (auto &&piece : fpieces) + if (piece.argclass != literal_piece) + ++nargs_wanted; + + if (nargs != nargs_wanted) + error (_("Wrong number of arguments for specified format-string")); + + i = 0; + for (auto &&piece : fpieces) + { + current_substring = piece.string; + ax_debug ("current substring is '%s', class is %d", + current_substring, piece.argclass); + switch (piece.argclass) + { + case string_arg: + { + gdb_byte *str; + CORE_ADDR tem; + int j; + + tem = args[i]; + if (tem == 0) + { + printf (current_substring, "(null)"); + break; + } + + /* This is a %s argument. Find the length of the string. */ + for (j = 0;; j++) + { + gdb_byte c; + + read_inferior_memory (tem + j, &c, 1); + if (c == 0) + break; + } + + /* Copy the string contents into a string inside GDB. */ + str = (gdb_byte *) alloca (j + 1); + if (j != 0) + read_inferior_memory (tem, str, j); + str[j] = 0; + + printf (current_substring, (char *) str); + } + break; + + case long_long_arg: +#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) + { + long long val = args[i]; + + printf (current_substring, val); + break; + } +#else + error (_("long long not supported in agent printf")); +#endif + case int_arg: + { + int val = args[i]; + + printf (current_substring, val); + break; + } + + case long_arg: + { + long val = args[i]; + + printf (current_substring, val); + break; + } + + case size_t_arg: + { + size_t val = args[i]; + + printf (current_substring, val); + break; + } + + case literal_piece: + /* Print a portion of the format string that has no + directives. Note that this will not include any + ordinary %-specs, but it might include "%%". That is + why we use printf_filtered and not puts_filtered here. + Also, we pass a dummy argument because some platforms + have modified GCC to include -Wformat-security by + default, which will warn here if there is no + argument. */ + printf (current_substring, 0); + break; + + default: + error (_("Format directive in '%s' not supported in agent printf"), + current_substring); + } + + /* Maybe advance to the next argument. */ + if (piece.argclass != literal_piece) + ++i; + } + + fflush (stdout); +} + +/* The agent expression evaluator, as specified by the GDB docs. It + returns 0 if everything went OK, and a nonzero error code + otherwise. */ + +enum eval_result_type +gdb_eval_agent_expr (struct eval_agent_expr_context *ctx, + struct agent_expr *aexpr, + ULONGEST *rslt) +{ + int pc = 0; +#define STACK_MAX 100 + ULONGEST stack[STACK_MAX], top; + int sp = 0; + unsigned char op; + int arg; + + /* This union is a convenient way to convert representations. For + now, assume a standard architecture where the hardware integer + types have 8, 16, 32, 64 bit types. A more robust solution would + be to import stdint.h from gnulib. */ + union + { + union + { + unsigned char bytes[1]; + unsigned char val; + } u8; + union + { + unsigned char bytes[2]; + unsigned short val; + } u16; + union + { + unsigned char bytes[4]; + unsigned int val; + } u32; + union + { + unsigned char bytes[8]; + ULONGEST val; + } u64; + } cnv; + + if (aexpr->length == 0) + { + ax_debug ("empty agent expression"); + return expr_eval_empty_expression; + } + + /* Cache the stack top in its own variable. Much of the time we can + operate on this variable, rather than dinking with the stack. It + needs to be copied to the stack when sp changes. */ + top = 0; + + while (1) + { + op = aexpr->bytes[pc++]; + + ax_debug ("About to interpret byte 0x%x", op); + + switch (op) + { + case gdb_agent_op_add: + top += stack[--sp]; + break; + + case gdb_agent_op_sub: + top = stack[--sp] - top; + break; + + case gdb_agent_op_mul: + top *= stack[--sp]; + break; + + case gdb_agent_op_div_signed: + if (top == 0) + { + ax_debug ("Attempted to divide by zero"); + return expr_eval_divide_by_zero; + } + top = ((LONGEST) stack[--sp]) / ((LONGEST) top); + break; + + case gdb_agent_op_div_unsigned: + if (top == 0) + { + ax_debug ("Attempted to divide by zero"); + return expr_eval_divide_by_zero; + } + top = stack[--sp] / top; + break; + + case gdb_agent_op_rem_signed: + if (top == 0) + { + ax_debug ("Attempted to divide by zero"); + return expr_eval_divide_by_zero; + } + top = ((LONGEST) stack[--sp]) % ((LONGEST) top); + break; + + case gdb_agent_op_rem_unsigned: + if (top == 0) + { + ax_debug ("Attempted to divide by zero"); + return expr_eval_divide_by_zero; + } + top = stack[--sp] % top; + break; + + case gdb_agent_op_lsh: + top = stack[--sp] << top; + break; + + case gdb_agent_op_rsh_signed: + top = ((LONGEST) stack[--sp]) >> top; + break; + + case gdb_agent_op_rsh_unsigned: + top = stack[--sp] >> top; + break; + + case gdb_agent_op_trace: + agent_mem_read (ctx, NULL, (CORE_ADDR) stack[--sp], + (ULONGEST) top); + if (--sp >= 0) + top = stack[sp]; + break; + + case gdb_agent_op_trace_quick: + arg = aexpr->bytes[pc++]; + agent_mem_read (ctx, NULL, (CORE_ADDR) top, (ULONGEST) arg); + break; + + case gdb_agent_op_log_not: + top = !top; + break; + + case gdb_agent_op_bit_and: + top &= stack[--sp]; + break; + + case gdb_agent_op_bit_or: + top |= stack[--sp]; + break; + + case gdb_agent_op_bit_xor: + top ^= stack[--sp]; + break; + + case gdb_agent_op_bit_not: + top = ~top; + break; + + case gdb_agent_op_equal: + top = (stack[--sp] == top); + break; + + case gdb_agent_op_less_signed: + top = (((LONGEST) stack[--sp]) < ((LONGEST) top)); + break; + + case gdb_agent_op_less_unsigned: + top = (stack[--sp] < top); + break; + + case gdb_agent_op_ext: + arg = aexpr->bytes[pc++]; + if (arg < (sizeof (LONGEST) * 8)) + { + LONGEST mask = 1 << (arg - 1); + top &= ((LONGEST) 1 << arg) - 1; + top = (top ^ mask) - mask; + } + break; + + case gdb_agent_op_ref8: + agent_mem_read (ctx, cnv.u8.bytes, (CORE_ADDR) top, 1); + top = cnv.u8.val; + break; + + case gdb_agent_op_ref16: + agent_mem_read (ctx, cnv.u16.bytes, (CORE_ADDR) top, 2); + top = cnv.u16.val; + break; + + case gdb_agent_op_ref32: + agent_mem_read (ctx, cnv.u32.bytes, (CORE_ADDR) top, 4); + top = cnv.u32.val; + break; + + case gdb_agent_op_ref64: + agent_mem_read (ctx, cnv.u64.bytes, (CORE_ADDR) top, 8); + top = cnv.u64.val; + break; + + case gdb_agent_op_if_goto: + if (top) + pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]); + else + pc += 2; + if (--sp >= 0) + top = stack[sp]; + break; + + case gdb_agent_op_goto: + pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]); + break; + + case gdb_agent_op_const8: + /* Flush the cached stack top. */ + stack[sp++] = top; + top = aexpr->bytes[pc++]; + break; + + case gdb_agent_op_const16: + /* Flush the cached stack top. */ + stack[sp++] = top; + top = aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + break; + + case gdb_agent_op_const32: + /* Flush the cached stack top. */ + stack[sp++] = top; + top = aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + break; + + case gdb_agent_op_const64: + /* Flush the cached stack top. */ + stack[sp++] = top; + top = aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + top = (top << 8) + aexpr->bytes[pc++]; + break; + + case gdb_agent_op_reg: + /* Flush the cached stack top. */ + stack[sp++] = top; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + { + int regnum = arg; + struct regcache *regcache = ctx->regcache; + + switch (register_size (regcache->tdesc, regnum)) + { + case 8: + collect_register (regcache, regnum, cnv.u64.bytes); + top = cnv.u64.val; + break; + case 4: + collect_register (regcache, regnum, cnv.u32.bytes); + top = cnv.u32.val; + break; + case 2: + collect_register (regcache, regnum, cnv.u16.bytes); + top = cnv.u16.val; + break; + case 1: + collect_register (regcache, regnum, cnv.u8.bytes); + top = cnv.u8.val; + break; + default: + internal_error (__FILE__, __LINE__, + "unhandled register size"); + } + } + break; + + case gdb_agent_op_end: + ax_debug ("At end of expression, sp=%d, stack top cache=0x%s", + sp, pulongest (top)); + if (rslt) + { + if (sp <= 0) + { + /* This should be an error */ + ax_debug ("Stack is empty, nothing to return"); + return expr_eval_empty_stack; + } + *rslt = top; + } + return expr_eval_no_error; + + case gdb_agent_op_dup: + stack[sp++] = top; + break; + + case gdb_agent_op_pop: + if (--sp >= 0) + top = stack[sp]; + break; + + case gdb_agent_op_pick: + arg = aexpr->bytes[pc++]; + stack[sp] = top; + top = stack[sp - arg]; + ++sp; + break; + + case gdb_agent_op_rot: + { + ULONGEST tem = stack[sp - 1]; + + stack[sp - 1] = stack[sp - 2]; + stack[sp - 2] = top; + top = tem; + } + break; + + case gdb_agent_op_zero_ext: + arg = aexpr->bytes[pc++]; + if (arg < (sizeof (LONGEST) * 8)) + top &= ((LONGEST) 1 << arg) - 1; + break; + + case gdb_agent_op_swap: + /* Interchange top two stack elements, making sure top gets + copied back onto stack. */ + stack[sp] = top; + top = stack[sp - 1]; + stack[sp - 1] = stack[sp]; + break; + + case gdb_agent_op_getv: + /* Flush the cached stack top. */ + stack[sp++] = top; + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + top = agent_get_trace_state_variable_value (arg); + break; + + case gdb_agent_op_setv: + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + agent_set_trace_state_variable_value (arg, top); + /* Note that we leave the value on the stack, for the + benefit of later/enclosing expressions. */ + break; + + case gdb_agent_op_tracev: + arg = aexpr->bytes[pc++]; + arg = (arg << 8) + aexpr->bytes[pc++]; + agent_tsv_read (ctx, arg); + break; + + case gdb_agent_op_tracenz: + agent_mem_read_string (ctx, NULL, (CORE_ADDR) stack[--sp], + (ULONGEST) top); + if (--sp >= 0) + top = stack[sp]; + break; + + case gdb_agent_op_printf: + { + int nargs, slen, i; + CORE_ADDR fn = 0, chan = 0; + /* Can't have more args than the entire size of the stack. */ + ULONGEST args[STACK_MAX]; + char *format; + + nargs = aexpr->bytes[pc++]; + slen = aexpr->bytes[pc++]; + slen = (slen << 8) + aexpr->bytes[pc++]; + format = (char *) &(aexpr->bytes[pc]); + pc += slen; + /* Pop function and channel. */ + fn = top; + if (--sp >= 0) + top = stack[sp]; + chan = top; + if (--sp >= 0) + top = stack[sp]; + /* Pop arguments into a dedicated array. */ + for (i = 0; i < nargs; ++i) + { + args[i] = top; + if (--sp >= 0) + top = stack[sp]; + } + + /* A bad format string means something is very wrong; give + up immediately. */ + if (format[slen - 1] != '\0') + error (_("Unterminated format string in printf bytecode")); + + ax_printf (fn, chan, format, nargs, args); + } + break; + + /* GDB never (currently) generates any of these ops. */ + case gdb_agent_op_float: + case gdb_agent_op_ref_float: + case gdb_agent_op_ref_double: + case gdb_agent_op_ref_long_double: + case gdb_agent_op_l_to_d: + case gdb_agent_op_d_to_l: + case gdb_agent_op_trace16: + ax_debug ("Agent expression op 0x%x valid, but not handled", + op); + /* If ever GDB generates any of these, we don't have the + option of ignoring. */ + return expr_eval_unhandled_opcode; + + default: + ax_debug ("Agent expression op 0x%x not recognized", op); + /* Don't struggle on, things will just get worse. */ + return expr_eval_unrecognized_opcode; + } + + /* Check for stack badness. */ + if (sp >= (STACK_MAX - 1)) + { + ax_debug ("Expression stack overflow"); + return expr_eval_stack_overflow; + } + + if (sp < 0) + { + ax_debug ("Expression stack underflow"); + return expr_eval_stack_underflow; + } + + ax_debug ("Op %s -> sp=%d, top=0x%s", + gdb_agent_op_name (op), sp, phex_nz (top, 0)); + } +} diff --git a/gdbserver/ax.h b/gdbserver/ax.h new file mode 100644 index 00000000000..1fba69e7ad1 --- /dev/null +++ b/gdbserver/ax.h @@ -0,0 +1,144 @@ +/* Data structures and functions associated with agent expressions in GDB. + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_AX_H +#define GDBSERVER_AX_H + +#include "regcache.h" + +#ifdef IN_PROCESS_AGENT +#define debug_threads debug_agent +#endif + +struct traceframe; + +/* Enumeration of the different kinds of things that can happen during + agent expression evaluation. */ + +enum eval_result_type + { + expr_eval_no_error, + expr_eval_empty_expression, + expr_eval_empty_stack, + expr_eval_stack_overflow, + expr_eval_stack_underflow, + expr_eval_unhandled_opcode, + expr_eval_unrecognized_opcode, + expr_eval_divide_by_zero, + expr_eval_invalid_goto + }; + +struct agent_expr +{ + int length; + + unsigned char *bytes; +}; + +#ifndef IN_PROCESS_AGENT + +/* The packet form of an agent expression consists of an 'X', number + of bytes in expression, a comma, and then the bytes. */ +struct agent_expr *gdb_parse_agent_expr (const char **actparm); + +/* Release an agent expression. */ +void gdb_free_agent_expr (struct agent_expr *aexpr); + +/* Convert the bytes of an agent expression back into hex digits, so + they can be printed or uploaded. This allocates the buffer, + callers should free when they are done with it. */ +char *gdb_unparse_agent_expr (struct agent_expr *aexpr); +void emit_prologue (void); +void emit_epilogue (void); +enum eval_result_type compile_bytecodes (struct agent_expr *aexpr); +#endif + +/* The context when evaluating agent expression. */ + +struct eval_agent_expr_context +{ + /* The registers when evaluating agent expression. */ + struct regcache *regcache; + /* The traceframe, if any, when evaluating agent expression. */ + struct traceframe *tframe; + /* The tracepoint, if any, when evaluating agent expression. */ + struct tracepoint *tpoint; +}; + +enum eval_result_type + gdb_eval_agent_expr (struct eval_agent_expr_context *ctx, + struct agent_expr *aexpr, + ULONGEST *rslt); + +/* Bytecode compilation function vector. */ + +struct emit_ops +{ + void (*emit_prologue) (void); + void (*emit_epilogue) (void); + void (*emit_add) (void); + void (*emit_sub) (void); + void (*emit_mul) (void); + void (*emit_lsh) (void); + void (*emit_rsh_signed) (void); + void (*emit_rsh_unsigned) (void); + void (*emit_ext) (int arg); + void (*emit_log_not) (void); + void (*emit_bit_and) (void); + void (*emit_bit_or) (void); + void (*emit_bit_xor) (void); + void (*emit_bit_not) (void); + void (*emit_equal) (void); + void (*emit_less_signed) (void); + void (*emit_less_unsigned) (void); + void (*emit_ref) (int size); + void (*emit_if_goto) (int *offset_p, int *size_p); + void (*emit_goto) (int *offset_p, int *size_p); + void (*write_goto_address) (CORE_ADDR from, CORE_ADDR to, int size); + void (*emit_const) (LONGEST num); + void (*emit_call) (CORE_ADDR fn); + void (*emit_reg) (int reg); + void (*emit_pop) (void); + void (*emit_stack_flush) (void); + void (*emit_zero_ext) (int arg); + void (*emit_swap) (void); + void (*emit_stack_adjust) (int n); + + /* Emit code for a generic function that takes one fixed integer + argument and returns a 64-bit int (for instance, tsv getter). */ + void (*emit_int_call_1) (CORE_ADDR fn, int arg1); + + /* Emit code for a generic function that takes one fixed integer + argument and a 64-bit int from the top of the stack, and returns + nothing (for instance, tsv setter). */ + void (*emit_void_call_2) (CORE_ADDR fn, int arg1); + + /* Emit code specialized for common combinations of compare followed + by a goto. */ + void (*emit_eq_goto) (int *offset_p, int *size_p); + void (*emit_ne_goto) (int *offset_p, int *size_p); + void (*emit_lt_goto) (int *offset_p, int *size_p); + void (*emit_le_goto) (int *offset_p, int *size_p); + void (*emit_gt_goto) (int *offset_p, int *size_p); + void (*emit_ge_goto) (int *offset_p, int *size_p); +}; + +extern CORE_ADDR current_insn_ptr; +extern int emit_error; + +#endif /* GDBSERVER_AX_H */ diff --git a/gdbserver/config.in b/gdbserver/config.in new file mode 100644 index 00000000000..da8c313c360 --- /dev/null +++ b/gdbserver/config.in @@ -0,0 +1,496 @@ +/* config.in. Generated from configure.ac by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if std::thread works. */ +#undef CXX_STD_THREAD + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define if self-testing features should be enabled */ +#undef GDB_SELF_TEST + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* define if the compiler supports basic C++11 syntax */ +#undef HAVE_CXX11 + +/* Define to 1 if you have the declaration of `ADDR_NO_RANDOMIZE', and to 0 if + you don't. */ +#undef HAVE_DECL_ADDR_NO_RANDOMIZE + +/* Define to 1 if you have the declaration of `asprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_ASPRINTF + +/* Define to 1 if you have the declaration of `basename(char *)', and to 0 if + you don't. */ +#undef HAVE_DECL_BASENAME + +/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */ +#undef HAVE_DECL_FFS + +/* Define to 1 if you have the declaration of `perror', and to 0 if you don't. + */ +#undef HAVE_DECL_PERROR + +/* Define to 1 if you have the declaration of `ptrace', and to 0 if you don't. + */ +#undef HAVE_DECL_PTRACE + +/* Define to 1 if you have the declaration of `snprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_SNPRINTF + +/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. + */ +#undef HAVE_DECL_STRSTR + +/* Define to 1 if you have the declaration of `strtol', and to 0 if you don't. + */ +#undef HAVE_DECL_STRTOL + +/* Define to 1 if you have the declaration of `strtoll', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOLL + +/* Define to 1 if you have the declaration of `strtoul', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOUL + +/* Define to 1 if you have the declaration of `strtoull', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOULL + +/* Define to 1 if you have the declaration of `strverscmp', and to 0 if you + don't. */ +#undef HAVE_DECL_STRVERSCMP + +/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VASPRINTF + +/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VSNPRINTF + +/* Define to 1 if you have the `dladdr' function. */ +#undef HAVE_DLADDR + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if the system has the type `Elf32_auxv_t'. */ +#undef HAVE_ELF32_AUXV_T + +/* Define to 1 if the system has the type `Elf64_auxv_t'. */ +#undef HAVE_ELF64_AUXV_T + +/* Define if has elf_fpregset_t. */ +#undef HAVE_ELF_FPREGSET_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fdwalk' function. */ +#undef HAVE_FDWALK + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define if has fpregset_t. */ +#undef HAVE_FPREGSET_T + +/* Define to 1 if you have the `getauxval' function. */ +#undef HAVE_GETAUXVAL + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the `getrlimit' function. */ +#undef HAVE_GETRLIMIT + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define if has gregset_t. */ +#undef HAVE_GREGSET_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if your system has the kinfo_getfile function. */ +#undef HAVE_KINFO_GETFILE + +/* Define if you have and nl_langinfo(CODESET). */ +#undef HAVE_LANGINFO_CODESET + +/* Define to 1 if you have the `dl' library (-ldl). */ +#undef HAVE_LIBDL + +/* Define if you have the ipt library. */ +#undef HAVE_LIBIPT + +/* Define if the target supports branch tracing. */ +#undef HAVE_LINUX_BTRACE + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_ELF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_PERF_EVENT_H + +/* Define if the target supports register sets. */ +#undef HAVE_LINUX_REGSETS + +/* Define if the target supports PTRACE_PEEKUSR for register access. */ +#undef HAVE_LINUX_USRREGS + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if the system has the type `long long'. */ +#undef HAVE_LONG_LONG + +/* Define if has lwpid_t. */ +#undef HAVE_LWPID_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define if you support the personality syscall. */ +#undef HAVE_PERSONALITY + +/* Define to 1 if you have the `pipe' function. */ +#undef HAVE_PIPE + +/* Define to 1 if you have the `pipe2' function. */ +#undef HAVE_PIPE2 + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `pread64' function. */ +#undef HAVE_PREAD64 + +/* Define if has prfpregset_t. */ +#undef HAVE_PRFPREGSET_T + +/* Define if has prgregset32_t. */ +#undef HAVE_PRGREGSET32_T + +/* Define if has prgregset_t. */ +#undef HAVE_PRGREGSET_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_PROC_SERVICE_H + +/* Define if has psaddr_t. */ +#undef HAVE_PSADDR_T + +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + +/* Define to 1 if you have the `pthread_setname_np' function. */ +#undef HAVE_PTHREAD_SETNAME_NP + +/* Define to 1 if you have the `pthread_sigmask' function. */ +#undef HAVE_PTHREAD_SIGMASK + +/* Define to 1 if you have the `ptrace64' function. */ +#undef HAVE_PTRACE64 + +/* Define if the target supports PTRACE_GETFPXREGS for extended register + access. */ +#undef HAVE_PTRACE_GETFPXREGS + +/* Define if the target supports PTRACE_GETREGS for register access. */ +#undef HAVE_PTRACE_GETREGS + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTRACE_H + +/* Define to 1 if you have the `pt_insn_event' function. */ +#undef HAVE_PT_INSN_EVENT + +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* Define to 1 if you have the `sbrk' function. */ +#undef HAVE_SBRK + +/* Define to 1 if you have the `setns' function. */ +#undef HAVE_SETNS + +/* Define to 1 if you have the `setpgid' function. */ +#undef HAVE_SETPGID + +/* Define to 1 if you have the `setpgrp' function. */ +#undef HAVE_SETPGRP + +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + +/* Define to 1 if you have the `sigaltstack' function. */ +#undef HAVE_SIGALTSTACK + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the `sigprocmask' function. */ +#undef HAVE_SIGPROCMASK + +/* Define if sigsetjmp is available. */ +#undef HAVE_SIGSETJMP + +/* Define to 1 if you have the `socketpair' function. */ +#undef HAVE_SOCKETPAIR + +/* Define to 1 if the system has the type `socklen_t'. */ +#undef HAVE_SOCKLEN_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if `enabled' is a member of `struct pt_insn'. */ +#undef HAVE_STRUCT_PT_INSN_ENABLED + +/* Define to 1 if `resynced' is a member of `struct pt_insn'. */ +#undef HAVE_STRUCT_PT_INSN_RESYNCED + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLKSIZE + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLOCKS + +/* Define to 1 if `fs_base' is a member of `struct user_regs_struct'. */ +#undef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE + +/* Define to 1 if `gs_base' is a member of `struct user_regs_struct'. */ +#undef HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE + +/* Define to 1 if the target supports __sync_*_compare_and_swap */ +#undef HAVE_SYNC_BUILTINS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PROCFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PTRACE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_REG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define if TD_VERSION is available. */ +#undef HAVE_TD_VERSION + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_THREAD_DB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if UST is available */ +#undef HAVE_UST + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WAIT_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Additional package description */ +#undef PKGVERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to the type of arg 1 for ptrace. */ +#undef PTRACE_TYPE_ARG1 + +/* Define to the type of arg 3 for ptrace. */ +#undef PTRACE_TYPE_ARG3 + +/* Define to the type of arg 4 for ptrace. */ +#undef PTRACE_TYPE_ARG4 + +/* Define to the type of arg 5 for ptrace. */ +#undef PTRACE_TYPE_ARG5 + +/* Define as the return type of ptrace. */ +#undef PTRACE_TYPE_RET + +/* Bug reporting address */ +#undef REPORT_BUGS_TO + +/* The size of `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if we should use libthread_db directly. */ +#undef USE_LIBTHREAD_DB_DIRECTLY + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define if we should use libthread_db. */ +#undef USE_THREAD_DB + +/* Define if we should use the Windows API, instead of the POSIX API. On + Windows, we use the Windows API when building for MinGW, but the POSIX API + when building for Cygwin. */ +#undef USE_WIN32API + +/* Define if an XML target description is available. */ +#undef USE_XML + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/gdbserver/configure b/gdbserver/configure new file mode 100755 index 00000000000..4b9d7e3718f --- /dev/null +++ b/gdbserver/configure @@ -0,0 +1,12159 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="server.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_header_list= +ac_subst_vars='LTLIBOBJS +LIBOBJS +GNULIB_STDINT_H +extra_libraries +IPA_DEPFILES +srv_xmlfiles +srv_xmlbuiltin +GDBSERVER_LIBS +GDBSERVER_DEPFILES +RDYNAMIC +REPORT_BUGS_TEXI +REPORT_BUGS_TO +PKGVERSION +WERROR_CFLAGS +WARN_CFLAGS +ustinc +ustlibs +LTLIBIPT +LIBIPT +HAVE_LIBIPT +PTHREAD_CFLAGS +PTHREAD_LIBS +PTHREAD_CC +ax_pthread_config +SED +ALLOCA +CCDEPMODE +CONFIG_SRC_SUBDIR +DEPDIR +am__leading_dot +host_noncanonical +target_noncanonical +CXX_DIALECT +HAVE_CXX11 +RANLIB +AR +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +INSTALL_STRIP_PROGRAM +STRIP +install_sh +EGREP +GREP +CPP +ac_ct_CXX +CXXFLAGS +CXX +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_maintainer_mode +enable_largefile +enable_unit_tests +with_intel_pt +with_gnu_ld +enable_rpath +with_libipt_prefix +with_ust +with_ust_include +with_ust_lib +enable_werror +enable_build_warnings +enable_gdb_build_warnings +with_pkgversion +with_bugurl +with_libthread_db +enable_inprocess_agent +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --disable-largefile omit support for large files + --enable-unit-tests Enable the inclusion of unit tests when compiling + GDB + --disable-rpath do not hardcode runtime library paths + --enable-werror treat compile warnings as errors + --enable-build-warnings enable build-time compiler warnings if gcc is used + --enable-gdb-build-warnings + enable GDB specific build-time compiler warnings if + gcc is used + --enable-inprocess-agent + inprocess agent + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-intel-pt include Intel Processor Trace support (auto/yes/no) + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-libipt-prefix[=DIR] search for libipt in DIR/include and DIR/lib + --without-libipt-prefix don't search for libipt in includedir and libdir + --with-ust=PATH Specify prefix directory for the installed UST package + Equivalent to --with-ust-include=PATH/include + plus --with-ust-lib=PATH/lib + --with-ust-include=PATH Specify directory for installed UST include files + --with-ust-lib=PATH Specify the directory for the installed UST library + --with-pkgversion=PKG Use PKG in the version string in place of "GDB" + --with-bugurl=URL Direct users to URL to report a bug + --with-libthread-db=PATH + use given libthread_db directly + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_cxx_check_func LINENO FUNC VAR +# ------------------------------------ +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_cxx_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_func + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +as_fn_append ac_header_list " stdlib.h" +as_fn_append ac_header_list " unistd.h" +as_fn_append ac_header_list " sys/param.h" +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + +ac_config_headers="$ac_config_headers config.h:config.in" + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = xyes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if ${ac_cv_safe_to_define___extensions__+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + + +# We require a C++11 compiler. Check if one is available, and if +# necessary, set CXX_DIALECT to some -std=xxx switch. + + ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=true + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + CXX_DIALECT="" + ac_success=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 +$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } +if ${ax_cv_cxx_compile_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_cxx_compile_cxx11=yes +else + ax_cv_cxx_compile_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 +$as_echo "$ax_cv_cxx_compile_cxx11" >&6; } + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX_DIALECT="$switch" + ac_success=yes + break + fi + done + fi + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX_DIALECT="$switch" + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 + fi + fi + if test x$ac_success = xno; then + HAVE_CXX11=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 +$as_echo "$as_me: No compiler with C++11 support was found" >&6;} + else + HAVE_CXX11=1 + +$as_echo "#define HAVE_CXX11 1" >>confdefs.h + + fi + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + + +# Set the 'development' global. +. $srcdir/../bfd/development.sh + + +# Check whether we will enable the inclusion of unit tests when +# compiling GDB. +# +# The default value of this option changes depending whether we're on +# development mode (in which case it's "true") or not (in which case +# it's "false"). +# Check whether --enable-unit-tests was given. +if test "${enable_unit_tests+set}" = set; then : + enableval=$enable_unit_tests; case "${enableval}" in + yes) enable_unittests=true ;; + no) enable_unittests=false ;; + *) as_fn_error $? "bad value ${enableval} for --{enable,disable}-unit-tests option" "$LINENO" 5 ;; +esac +else + enable_unittests=$development +fi + + +if $enable_unittests; then + +$as_echo "#define GDB_SELF_TEST 1" >>confdefs.h + + + srv_selftest_objs="gdbsupport/selftest.o" + +fi + + + case ${build_alias} in + "") build_noncanonical=${build} ;; + *) build_noncanonical=${build_alias} ;; +esac + + case ${host_alias} in + "") host_noncanonical=${build_noncanonical} ;; + *) host_noncanonical=${host_alias} ;; +esac + + case ${target_alias} in + "") target_noncanonical=${host_noncanonical} ;; + *) target_noncanonical=${target_alias} ;; +esac + + + + + + +# Dependency checking. +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depdir" + + + +# Create sub-directories for objects and dependencies. +CONFIG_SRC_SUBDIR="arch gdbsupport nat target" + + +ac_config_commands="$ac_config_commands gdbdepdir" + + +depcc="$CC" am_compiler_list= + +am_depcomp=$ac_aux_dir/depcomp +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + if test $depmode = none; then break; fi + + $as_echo "$as_me:$LINENO: trying $depmode" >&5 + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "include sub/conftest.Po" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + depcmd="depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c" + echo "| $depcmd" | sed -e 's/ */ /g' >&5 + if env $depcmd > conftest.err 2>&1 && + grep sub/conftst6.h sub/conftest.Po >>conftest.err 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po >>conftest.err 2>&1 && + ${MAKE-make} -s -f confmf >>conftest.err 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + $as_echo "$as_me:$LINENO: success" >&5 + break + fi + fi + $as_echo "$as_me:$LINENO: failure, diagnostics are:" >&5 + sed -e 's/^/| /' < conftest.err >&5 + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +if test x${am_cv_CC_dependencies_compiler_type-none} = xnone +then as_fn_error $? "no usable dependency style found" "$LINENO" 5 +else CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + +fi + + +gnulib_extra_configure_args= +# If large-file support is disabled, make sure gnulib does the same. +if test "$enable_largefile" = no; then +gnulib_extra_configure_args="$gnulib_extra_configure_args --disable-largefile" +fi + +# Configure gnulib. We can't use AC_CONFIG_SUBDIRS as that'd expect +# to find the the source subdir to be configured directly under +# gdbserver/. We need to build gnulib under some other directory not +# "gnulib", to avoid the problem of both GDB and GDBserver wanting to +# build it in the same directory, when building in the source dir. + + in_src="../gnulib" + in_build="build-gnulib-gdbserver" + in_extra_args="$gnulib_extra_configure_args" + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + ac_dir=$in_build + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + + case $srcdir in + [\\/]* | ?:[\\/]* ) + ac_srcdir=$srcdir/$in_src ;; + *) # Relative name. + ac_srcdir=../$srcdir/$in_src ;; + esac + + cd "$ac_dir" + + ac_sub_configure=$ac_srcdir/configure + + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + if test -n "$in_extra_args"; then + # Add the extra args at the end. + ac_sub_configure_args="$ac_sub_configure_args $in_extra_args" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + + cd "$ac_popdir" + + + + in_src="../libiberty" + in_build="build-libiberty-gdbserver" + in_extra_args= + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + ac_dir=$in_build + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + + case $srcdir in + [\\/]* | ?:[\\/]* ) + ac_srcdir=$srcdir/$in_src ;; + *) # Relative name. + ac_srcdir=../$srcdir/$in_src ;; + esac + + cd "$ac_dir" + + ac_sub_configure=$ac_srcdir/configure + + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + if test -n "$in_extra_args"; then + # Add the extra args at the end. + ac_sub_configure_args="$ac_sub_configure_args $in_extra_args" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + + cd "$ac_popdir" + + +for ac_header in termios.h sys/reg.h string.h sys/procfs.h linux/elf.h fcntl.h signal.h sys/file.h sys/ioctl.h netinet/in.h sys/socket.h netdb.h netinet/tcp.h arpa/inet.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +for ac_header in vfork.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +if test "x$ac_cv_header_vfork_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VFORK_H 1 +_ACEOF + +fi + +done + +for ac_func in fork vfork +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 +$as_echo_n "checking for working fork... " >&6; } +if ${ac_cv_func_fork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_fork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* By Ruediger Kuhlmann. */ + return fork () < 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_fork_works=yes +else + ac_cv_func_fork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 +$as_echo "$ac_cv_func_fork_works" >&6; } + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 +$as_echo_n "checking for working vfork... " >&6; } +if ${ac_cv_func_vfork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_vfork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +$ac_includes_default +#include +#ifdef HAVE_VFORK_H +# include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include , but some compilers + (e.g. gcc -O) don't grok . Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + return ( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_vfork_works=yes +else + ac_cv_func_vfork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 +$as_echo "$ac_cv_func_vfork_works" >&6; } + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h + +else + +$as_echo "#define vfork fork" >>confdefs.h + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h + +fi + +for ac_func in pread pwrite pread64 +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + + + + + for ac_header in $ac_header_list +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 +$as_echo_n "checking for ld used by GCC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${acl_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$acl_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$acl_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${acl_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + acl_cv_prog_gnu_ld=yes +else + acl_cv_prog_gnu_ld=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_prog_gnu_ld" >&5 +$as_echo "$acl_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$acl_cv_prog_gnu_ld + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 +$as_echo_n "checking for shared library run path origin... " >&6; } +if ${acl_cv_rpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 +$as_echo "$acl_cv_rpath" >&6; } + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then : + enableval=$enable_rpath; : +else + enable_rpath=yes +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + + # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 +$as_echo_n "checking for working alloca.h... " >&6; } +if ${ac_cv_working_alloca_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_working_alloca_h=yes +else + ac_cv_working_alloca_h=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 +$as_echo "$ac_cv_working_alloca_h" >&6; } +if test $ac_cv_working_alloca_h = yes; then + +$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 +$as_echo_n "checking for alloca... " >&6; } +if ${ac_cv_func_alloca_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +void *alloca (size_t); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_func_alloca_works=yes +else + ac_cv_func_alloca_works=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 +$as_echo "$ac_cv_func_alloca_works" >&6; } + +if test $ac_cv_func_alloca_works = yes; then + +$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=\${LIBOBJDIR}alloca.$ac_objext + +$as_echo "#define C_ALLOCA 1" >>confdefs.h + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 +$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } +if ${ac_cv_os_cray+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined CRAY && ! defined CRAY2 +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then : + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 +$as_echo "$ac_cv_os_cray" >&6; } +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 +$as_echo_n "checking stack direction for C alloca... " >&6; } +if ${ac_cv_c_stack_direction+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_c_stack_direction=0 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +find_stack_direction (int *addr, int depth) +{ + int dir, dummy = 0; + if (! addr) + addr = &dummy; + *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; + dir = depth ? find_stack_direction (addr, depth - 1) : 0; + return dir + dummy; +} + +int +main (int argc, char **argv) +{ + return find_stack_direction (0, argc + !argv + 20) < 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_stack_direction=1 +else + ac_cv_c_stack_direction=-1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 +$as_echo "$ac_cv_c_stack_direction" >&6; } +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + + + WIN32APILIBS= + case ${host} in + *mingw32*) + +$as_echo "#define USE_WIN32API 1" >>confdefs.h + + WIN32APILIBS="-lws2_32" + ;; + esac + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 +$as_echo_n "checking for nl_langinfo and CODESET... " >&6; } +if ${am_cv_langinfo_codeset+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char* cs = nl_langinfo(CODESET); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_langinfo_codeset=yes +else + am_cv_langinfo_codeset=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_langinfo_codeset" >&5 +$as_echo "$am_cv_langinfo_codeset" >&6; } + if test $am_cv_langinfo_codeset = yes; then + +$as_echo "#define HAVE_LANGINFO_CODESET 1" >>confdefs.h + + fi + + + for ac_header in linux/perf_event.h locale.h memory.h signal.h sys/resource.h sys/socket.h sys/un.h sys/wait.h thread_db.h wait.h termios.h dlfcn.h linux/elf.h sys/procfs.h proc_service.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_func in getpagesize +do : + ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" +if test "x$ac_cv_func_getpagesize" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETPAGESIZE 1 +_ACEOF + +fi +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 +$as_echo_n "checking for working mmap... " >&6; } +if ${ac_cv_func_mmap_fixed_mapped+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_mmap_fixed_mapped=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +/* malloc might have been renamed as rpl_malloc. */ +#undef malloc + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the file system buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propagated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ + +#include +#include + +#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H +char *malloc (); +#endif + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +int +main () +{ + char *data, *data2, *data3; + const char *cdata2; + int i, pagesize; + int fd, fd2; + + pagesize = getpagesize (); + + /* First, make a file with some known garbage in it. */ + data = (char *) malloc (pagesize); + if (!data) + return 1; + for (i = 0; i < pagesize; ++i) + *(data + i) = rand (); + umask (0); + fd = creat ("conftest.mmap", 0600); + if (fd < 0) + return 2; + if (write (fd, data, pagesize) != pagesize) + return 3; + close (fd); + + /* Next, check that the tail of a page is zero-filled. File must have + non-zero length, otherwise we risk SIGBUS for entire page. */ + fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd2 < 0) + return 4; + cdata2 = ""; + if (write (fd2, cdata2, 1) != 1) + return 5; + data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); + if (data2 == MAP_FAILED) + return 6; + for (i = 0; i < pagesize; ++i) + if (*(data2 + i)) + return 7; + close (fd2); + if (munmap (data2, pagesize)) + return 8; + + /* Next, try to mmap the file at a fixed address which already has + something else allocated at it. If we can, also make sure that + we see the same garbage. */ + fd = open ("conftest.mmap", O_RDWR); + if (fd < 0) + return 9; + if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + return 10; + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + return 11; + + /* Finally, make sure that changes to the mapped area do not + percolate back to the file as seen by read(). (This is a bug on + some variants of i386 svr4.0.) */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = (char *) malloc (pagesize); + if (!data3) + return 12; + if (read (fd, data3, pagesize) != pagesize) + return 13; + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + return 14; + close (fd); + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_mmap_fixed_mapped=yes +else + ac_cv_func_mmap_fixed_mapped=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 +$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } +if test $ac_cv_func_mmap_fixed_mapped = yes; then + +$as_echo "#define HAVE_MMAP 1" >>confdefs.h + +fi +rm -f conftest.mmap conftest.txt + + for ac_header in vfork.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +if test "x$ac_cv_header_vfork_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VFORK_H 1 +_ACEOF + +fi + +done + +for ac_func in fork vfork +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 +$as_echo_n "checking for working fork... " >&6; } +if ${ac_cv_func_fork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_fork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* By Ruediger Kuhlmann. */ + return fork () < 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_fork_works=yes +else + ac_cv_func_fork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 +$as_echo "$ac_cv_func_fork_works" >&6; } + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 +$as_echo_n "checking for working vfork... " >&6; } +if ${ac_cv_func_vfork_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_vfork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +$ac_includes_default +#include +#ifdef HAVE_VFORK_H +# include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include , but some compilers + (e.g. gcc -O) don't grok . Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + return ( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_vfork_works=yes +else + ac_cv_func_vfork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 +$as_echo "$ac_cv_func_vfork_works" >&6; } + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h + +else + +$as_echo "#define vfork fork" >>confdefs.h + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h + +fi + + for ac_func in fdwalk getrlimit pipe pipe2 socketpair sigaction \ + ptrace64 sbrk setns sigaltstack sigprocmask \ + setpgid setpgrp getrusage getauxval +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + ac_fn_c_check_decl "$LINENO" "ADDR_NO_RANDOMIZE" "ac_cv_have_decl_ADDR_NO_RANDOMIZE" "#include +" +if test "x$ac_cv_have_decl_ADDR_NO_RANDOMIZE" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_ADDR_NO_RANDOMIZE $ac_have_decl +_ACEOF + + + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + # if !HAVE_DECL_ADDR_NO_RANDOMIZE + # define ADDR_NO_RANDOMIZE 0x0040000 + # endif + /* Test the flag could be set and stays set. */ + personality (personality (0xffffffff) | ADDR_NO_RANDOMIZE); + if (!(personality (personality (0xffffffff)) & ADDR_NO_RANDOMIZE)) + return 1 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + have_personality=true +else + have_personality=false +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + # if !HAVE_DECL_ADDR_NO_RANDOMIZE + # define ADDR_NO_RANDOMIZE 0x0040000 + # endif + /* Test the flag could be set and stays set. */ + personality (personality (0xffffffff) | ADDR_NO_RANDOMIZE); + if (!(personality (personality (0xffffffff)) & ADDR_NO_RANDOMIZE)) + return 1 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_personality=true +else + have_personality=false +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + if $have_personality + then + +$as_echo "#define HAVE_PERSONALITY 1" >>confdefs.h + + fi + + ac_fn_c_check_decl "$LINENO" "strstr" "ac_cv_have_decl_strstr" "$ac_includes_default" +if test "x$ac_cv_have_decl_strstr" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRSTR $ac_have_decl +_ACEOF + + + # ----------------------- # + # Checks for structures. # + # ----------------------- # + + ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 +_ACEOF + + +fi +ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 +_ACEOF + + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing kinfo_getfile" >&5 +$as_echo_n "checking for library containing kinfo_getfile... " >&6; } +if ${ac_cv_search_kinfo_getfile+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char kinfo_getfile (); +int +main () +{ +return kinfo_getfile (); + ; + return 0; +} +_ACEOF +for ac_lib in '' util util-freebsd; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_kinfo_getfile=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_kinfo_getfile+:} false; then : + break +fi +done +if ${ac_cv_search_kinfo_getfile+:} false; then : + +else + ac_cv_search_kinfo_getfile=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_kinfo_getfile" >&5 +$as_echo "$ac_cv_search_kinfo_getfile" >&6; } +ac_res=$ac_cv_search_kinfo_getfile +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_KINFO_GETFILE 1" >>confdefs.h + +fi + + + # Check for std::thread. This does not work on some platforms, like + # mingw and DJGPP. + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + if test "x$PTHREAD_CC" != "x"; then : + CC="$PTHREAD_CC" +fi + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 +$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_join (); +int +main () +{ +return pthread_join (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_pthread_ok=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 +$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} +fi +rm -f conftest* + + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +if test "x$GCC" = "xyes"; then : + ax_pthread_flags="-pthread -pthreads $ax_pthread_flags" +fi + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +if test "x$ax_pthread_check_macro" = "x--"; then : + ax_pthread_check_cond=0 +else + ax_pthread_check_cond="!defined($ax_pthread_check_macro)" +fi + +# Are we compiling with Clang? + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 +$as_echo_n "checking whether $CC is Clang... " >&6; } +if ${ax_cv_PTHREAD_CLANG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then : + ax_cv_PTHREAD_CLANG=yes +fi +rm -f conftest* + + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG" >&6; } +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 +$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } +if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + if test "x$ax_pthread_try" = "xunknown"; then : + break +fi + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_link="$ax_pthread_2step_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + if test "x$ax_pthread_try" = "x"; then : + ax_pthread_try=no +fi + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 +$as_echo_n "checking whether pthreads work without any flags... " >&6; } + ;; + + -mt,pthread) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5 +$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; } + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 +$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + # Extract the first word of "pthread-config", so it can be a program name with args. +set dummy pthread-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ax_pthread_config+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ax_pthread_config"; then + ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ax_pthread_config="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" +fi +fi +ax_pthread_config=$ac_cv_prog_ax_pthread_config +if test -n "$ax_pthread_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 +$as_echo "$ax_pthread_config" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$ax_pthread_config" = "xno"; then : + continue +fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 +$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; } +int +main () +{ +pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */ + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_pthread_ok=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xyes"; then : + break +fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 +$as_echo_n "checking for joinable pthread attribute... " >&6; } +if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int attr = $ax_pthread_attr; return attr /* ; */ + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 +$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } + if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"; then : + +cat >>confdefs.h <<_ACEOF +#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR +_ACEOF + + ax_pthread_joinable_attr_defined=yes + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 +$as_echo_n "checking whether more special flags are required for pthreads... " >&6; } +if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 +$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } + if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"; then : + PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 +$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; } +if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int i = PTHREAD_PRIO_INHERIT; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_PRIO_INHERIT=yes +else + ax_cv_PTHREAD_PRIO_INHERIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 +$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } + if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"; then : + +$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h + + ax_pthread_prio_inherit_defined=yes + +fi + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + case "x/$CC" in #( + x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : + #handle absolute path differently from PATH based program lookup + case "x$CC" in #( + x/*) : + if as_fn_executable_p ${CC}_r; then : + PTHREAD_CC="${CC}_r" +fi ;; #( + *) : + for ac_prog in ${CC}_r +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PTHREAD_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PTHREAD_CC"; then + ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PTHREAD_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PTHREAD_CC=$ac_cv_prog_PTHREAD_CC +if test -n "$PTHREAD_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 +$as_echo "$PTHREAD_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$PTHREAD_CC" && break +done +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + ;; +esac ;; #( + *) : + ;; +esac + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + + + + + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + threads=yes + : +else + ax_pthread_ok=no + threads=no +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + if test "$threads" = "yes"; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$PTHREAD_CFLAGS $save_CXXFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::thread" >&5 +$as_echo_n "checking for std::thread... " >&6; } +if ${gdb_cv_cxx_std_thread+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + void callback() { } +int +main () +{ +std::thread t(callback); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + gdb_cv_cxx_std_thread=yes +else + gdb_cv_cxx_std_thread=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_cxx_std_thread" >&5 +$as_echo "$gdb_cv_cxx_std_thread" >&6; } + + # This check must be here, while LIBS includes any necessary + # threading library. + for ac_func in pthread_sigmask pthread_setname_np +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + LIBS="$save_LIBS" + CXXFLAGS="$save_CXXFLAGS" + fi + if test "$gdb_cv_cxx_std_thread" = "yes"; then + +$as_echo "#define CXX_STD_THREAD 1" >>confdefs.h + + fi + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigsetjmp" >&5 +$as_echo_n "checking for sigsetjmp... " >&6; } +if ${gdb_cv_func_sigsetjmp+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main () +{ +sigjmp_buf env; while (! sigsetjmp (env, 1)) siglongjmp (env, 1); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_sigsetjmp=yes +else + gdb_cv_func_sigsetjmp=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_sigsetjmp" >&5 +$as_echo "$gdb_cv_func_sigsetjmp" >&6; } + if test "$gdb_cv_func_sigsetjmp" = "yes"; then + +$as_echo "#define HAVE_SIGSETJMP 1" >>confdefs.h + + fi + + +# Check whether --with-intel_pt was given. +if test "${with_intel_pt+set}" = set; then : + withval=$with_intel_pt; +else + with_intel_pt=auto +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use intel pt" >&5 +$as_echo_n "checking whether to use intel pt... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_intel_pt" >&5 +$as_echo "$with_intel_pt" >&6; } + + if test "${with_intel_pt}" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Intel Processor Trace support disabled; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: Intel Processor Trace support disabled; some features may be unavailable." >&2;} + HAVE_LIBIPT=no + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #ifndef PERF_ATTR_SIZE_VER5 + # error + #endif + +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + perf_event=yes +else + perf_event=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext + if test "$perf_event" != yes; then + if test "$with_intel_pt" = yes; then + as_fn_error $? "linux/perf_event.h missing or too old" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: linux/perf_event.h missing or too old; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: linux/perf_event.h missing or too old; some features may be unavailable." >&2;} + fi + fi + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libipt-prefix was given. +if test "${with_libipt_prefix+set}" = set; then : + withval=$with_libipt_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi + +fi + + LIBIPT= + LTLIBIPT= + INCIPT= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='ipt ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBIPT="${LIBIPT}${LIBIPT:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBIPT; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBIPT; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBIPT="${LIBIPT}${LIBIPT:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so" + else + LIBIPT="${LIBIPT}${LIBIPT:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBIPT="${LIBIPT}${LIBIPT:+ }$found_a" + else + LIBIPT="${LIBIPT}${LIBIPT:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCIPT; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCIPT="${INCIPT}${INCIPT:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBIPT; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBIPT="${LIBIPT}${LIBIPT:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBIPT; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBIPT="${LIBIPT}${LIBIPT:+ }$dep" + LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }$dep" + ;; + esac + done + fi + else + LIBIPT="${LIBIPT}${LIBIPT:+ }-l$name" + LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBIPT="${LIBIPT}${LIBIPT:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBIPT="${LIBIPT}${LIBIPT:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-R$found_dir" + done + fi + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCIPT; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libipt" >&5 +$as_echo_n "checking for libipt... " >&6; } +if ${ac_cv_libipt+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIBIPT" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "intel-pt.h" +int +main () +{ +pt_insn_alloc_decoder (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_libipt=yes +else + ac_cv_libipt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libipt" >&5 +$as_echo "$ac_cv_libipt" >&6; } + if test "$ac_cv_libipt" = yes; then + HAVE_LIBIPT=yes + +$as_echo "#define HAVE_LIBIPT 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libipt" >&5 +$as_echo_n "checking how to link with libipt... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBIPT" >&5 +$as_echo "$LIBIPT" >&6; } + else + HAVE_LIBIPT=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBIPT= + LTLIBIPT= + fi + + + + + + + if test "$HAVE_LIBIPT" != yes; then + if test "$with_intel_pt" = yes; then + as_fn_error $? "libipt is missing or unusable" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libipt is missing or unusable; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: libipt is missing or unusable; some features may be unavailable." >&2;} + fi + else + save_LIBS=$LIBS + LIBS="$LIBS $LIBIPT" + for ac_func in pt_insn_event +do : + ac_fn_c_check_func "$LINENO" "pt_insn_event" "ac_cv_func_pt_insn_event" +if test "x$ac_cv_func_pt_insn_event" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PT_INSN_EVENT 1 +_ACEOF + +fi +done + + ac_fn_c_check_member "$LINENO" "struct pt_insn" "enabled" "ac_cv_member_struct_pt_insn_enabled" "#include +" +if test "x$ac_cv_member_struct_pt_insn_enabled" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_PT_INSN_ENABLED 1 +_ACEOF + + +fi +ac_fn_c_check_member "$LINENO" "struct pt_insn" "resynced" "ac_cv_member_struct_pt_insn_resynced" "#include +" +if test "x$ac_cv_member_struct_pt_insn_resynced" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_PT_INSN_RESYNCED 1 +_ACEOF + + +fi + + LIBS=$save_LIBS + fi + fi + + if test "$ac_cv_header_sys_procfs_h" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gregset_t in sys/procfs.h" >&5 +$as_echo_n "checking for gregset_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_gregset_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +gregset_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_gregset_t=yes +else + bfd_cv_have_sys_procfs_type_gregset_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_gregset_t = yes; then + +$as_echo "#define HAVE_GREGSET_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_gregset_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_gregset_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fpregset_t in sys/procfs.h" >&5 +$as_echo_n "checking for fpregset_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_fpregset_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +fpregset_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_fpregset_t=yes +else + bfd_cv_have_sys_procfs_type_fpregset_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_fpregset_t = yes; then + +$as_echo "#define HAVE_FPREGSET_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_fpregset_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_fpregset_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prgregset_t in sys/procfs.h" >&5 +$as_echo_n "checking for prgregset_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_prgregset_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +prgregset_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_prgregset_t=yes +else + bfd_cv_have_sys_procfs_type_prgregset_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_prgregset_t = yes; then + +$as_echo "#define HAVE_PRGREGSET_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_prgregset_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_prgregset_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prfpregset_t in sys/procfs.h" >&5 +$as_echo_n "checking for prfpregset_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_prfpregset_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +prfpregset_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_prfpregset_t=yes +else + bfd_cv_have_sys_procfs_type_prfpregset_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then + +$as_echo "#define HAVE_PRFPREGSET_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_prfpregset_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_prfpregset_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prgregset32_t in sys/procfs.h" >&5 +$as_echo_n "checking for prgregset32_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_prgregset32_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +prgregset32_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_prgregset32_t=yes +else + bfd_cv_have_sys_procfs_type_prgregset32_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_prgregset32_t = yes; then + +$as_echo "#define HAVE_PRGREGSET32_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_prgregset32_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_prgregset32_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lwpid_t in sys/procfs.h" >&5 +$as_echo_n "checking for lwpid_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_lwpid_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +lwpid_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_lwpid_t=yes +else + bfd_cv_have_sys_procfs_type_lwpid_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_lwpid_t = yes; then + +$as_echo "#define HAVE_LWPID_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_lwpid_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_lwpid_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for psaddr_t in sys/procfs.h" >&5 +$as_echo_n "checking for psaddr_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_psaddr_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +psaddr_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_psaddr_t=yes +else + bfd_cv_have_sys_procfs_type_psaddr_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_psaddr_t = yes; then + +$as_echo "#define HAVE_PSADDR_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_psaddr_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_psaddr_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for elf_fpregset_t in sys/procfs.h" >&5 +$as_echo_n "checking for elf_fpregset_t in sys/procfs.h... " >&6; } + if ${bfd_cv_have_sys_procfs_type_elf_fpregset_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 +#include +int +main () +{ +elf_fpregset_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bfd_cv_have_sys_procfs_type_elf_fpregset_t=yes +else + bfd_cv_have_sys_procfs_type_elf_fpregset_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $bfd_cv_have_sys_procfs_type_elf_fpregset_t = yes; then + +$as_echo "#define HAVE_ELF_FPREGSET_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_have_sys_procfs_type_elf_fpregset_t" >&5 +$as_echo "$bfd_cv_have_sys_procfs_type_elf_fpregset_t" >&6; } + + fi + + +# Check the return and argument types of ptrace. + + +for ac_header in sys/ptrace.h ptrace.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +gdb_ptrace_headers=' +#include +#if HAVE_SYS_PTRACE_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif +' +# There is no point in checking if we don't have a prototype. +ac_fn_c_check_decl "$LINENO" "ptrace" "ac_cv_have_decl_ptrace" "$gdb_ptrace_headers +" +if test "x$ac_cv_have_decl_ptrace" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_PTRACE $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + +else + + : ${gdb_cv_func_ptrace_ret='int'} + : ${gdb_cv_func_ptrace_args='int,int,long,long'} + +fi + +# Check return type. Varargs (used on GNU/Linux) conflict with the +# empty argument list, so check for that explicitly. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of ptrace" >&5 +$as_echo_n "checking return type of ptrace... " >&6; } +if ${gdb_cv_func_ptrace_ret+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ +extern long ptrace (enum __ptrace_request, ...); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_ret='long' +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ +extern int ptrace (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_ret='int' +else + gdb_cv_func_ptrace_ret='long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_ptrace_ret" >&5 +$as_echo "$gdb_cv_func_ptrace_ret" >&6; } + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_RET $gdb_cv_func_ptrace_ret +_ACEOF + +# Check argument types. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for ptrace" >&5 +$as_echo_n "checking types of arguments for ptrace... " >&6; } +if ${gdb_cv_func_ptrace_args+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ +extern long ptrace (enum __ptrace_request, ...); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_args='enum __ptrace_request,int,long,long' +else + +for gdb_arg1 in 'int' 'long'; do + for gdb_arg2 in 'pid_t' 'int' 'long'; do + for gdb_arg3 in 'int *' 'caddr_t' 'int' 'long' 'void *'; do + for gdb_arg4 in 'int' 'long' 'void *'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ + +extern $gdb_cv_func_ptrace_ret + ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4"; + break 4; +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + for gdb_arg5 in 'int *' 'int' 'long'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ + +extern $gdb_cv_func_ptrace_ret + ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4, $gdb_arg5); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4,$gdb_arg5"; + break 5; +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done + done + done +done +# Provide a safe default value. +: ${gdb_cv_func_ptrace_args='int,int,long,long'} + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_ptrace_args" >&5 +$as_echo "$gdb_cv_func_ptrace_args" >&6; } +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$gdb_cv_func_ptrace_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_ARG1 $1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_ARG3 $3 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_ARG4 $4 +_ACEOF + +if test -n "$5"; then + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_ARG5 $5 +_ACEOF + +fi + + +# Check for UST +ustlibs="" +ustinc="" + + +# Check whether --with-ust was given. +if test "${with_ust+set}" = set; then : + withval=$with_ust; +fi + + +# Check whether --with-ust_include was given. +if test "${with_ust_include+set}" = set; then : + withval=$with_ust_include; +fi + + +# Check whether --with-ust_lib was given. +if test "${with_ust_lib+set}" = set; then : + withval=$with_ust_lib; +fi + + +case $with_ust in + no) + ustlibs= + ustinc= + ;; + "" | yes) + ustlibs=" -lust " + ustinc="" + ;; + *) + ustlibs="-L$with_ust/lib -lust" + ustinc="-I$with_ust/include " + ;; +esac +if test "x$with_ust_include" != x; then + ustinc="-I$with_ust_include " +fi +if test "x$with_ust_lib" != x; then + ustlibs="-L$with_ust_lib -lust" +fi + +if test "x$with_ust" != "xno"; then + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $ustinc" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ust" >&5 +$as_echo_n "checking for ust... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define CONFIG_UST_GDB_INTEGRATION +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; +$as_echo "#define HAVE_UST 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; }; ustlibs= ; ustinc= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$saved_CFLAGS" +fi + +# Flags needed for UST + + + + +# Check whether --enable-werror was given. +if test "${enable_werror+set}" = set; then : + enableval=$enable_werror; case "${enableval}" in + yes | y) ERROR_ON_WARNING="yes" ;; + no | n) ERROR_ON_WARNING="no" ;; + *) as_fn_error $? "bad value ${enableval} for --enable-werror" "$LINENO" 5 ;; + esac +fi + + +# Enable -Werror by default when using gcc. Turn it off for releases. +if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" && $development; then + ERROR_ON_WARNING=yes +fi + +WERROR_CFLAGS="" +if test "${ERROR_ON_WARNING}" = yes ; then + WERROR_CFLAGS="-Werror" +fi + +# The options we'll try to enable. +build_warnings="-Wall -Wpointer-arith \ +-Wno-unused -Wunused-value -Wunused-variable -Wunused-function \ +-Wno-switch -Wno-char-subscripts \ +-Wempty-body -Wunused-but-set-parameter -Wunused-but-set-variable \ +-Wno-sign-compare -Wno-error=maybe-uninitialized \ +-Wno-mismatched-tags \ +-Wno-error=deprecated-register \ +-Wsuggest-override \ +-Wimplicit-fallthrough=3 \ +-Wduplicated-cond \ +-Wshadow=local \ +-Wdeprecated-copy \ +-Wdeprecated-copy-dtor \ +-Wredundant-move \ +-Wmissing-declarations" + +case "${host}" in + *-*-mingw32*) + # Enable -Wno-format by default when using gcc on mingw since many + # GCC versions complain about %I64. + build_warnings="$build_warnings -Wno-format" ;; + *-*-solaris*) + # Solaris 11.4 uses #pragma no_inline that GCC + # doesn't understand. + build_warnings="$build_warnings -Wno-unknown-pragmas" + # Solaris 11 marks vfork deprecated. + build_warnings="$build_warnings -Wno-deprecated-declarations" ;; + *) + # Note that gcc requires -Wformat for -Wformat-nonliteral to work, + # but there's a special case for this below. + build_warnings="$build_warnings -Wformat-nonliteral" ;; +esac + +# Check whether --enable-build-warnings was given. +if test "${enable_build_warnings+set}" = set; then : + enableval=$enable_build_warnings; case "${enableval}" in + yes) ;; + no) build_warnings="-w";; + ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${build_warnings} ${t}";; + *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${t} ${build_warnings}";; + *) build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then + echo "Setting compiler warning flags = $build_warnings" 6>&1 +fi +fi +# Check whether --enable-gdb-build-warnings was given. +if test "${enable_gdb_build_warnings+set}" = set; then : + enableval=$enable_gdb_build_warnings; case "${enableval}" in + yes) ;; + no) build_warnings="-w";; + ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${build_warnings} ${t}";; + *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${t} ${build_warnings}";; + *) build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then + echo "Setting GDB specific compiler warning flags = $build_warnings" 6>&1 +fi +fi + +# The set of warnings supported by a C++ compiler is not the same as +# of the C compiler. +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +WARN_CFLAGS="" +if test "x${build_warnings}" != x -a "x$GCC" = xyes +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler warning flags" >&5 +$as_echo_n "checking compiler warning flags... " >&6; } + # Separate out the -Werror flag as some files just cannot be + # compiled with it enabled. + for w in ${build_warnings}; do + # GCC does not complain about -Wno-unknown-warning. Invert + # and test -Wunknown-warning instead. + case $w in + -Wno-*) + wtest=`echo $w | sed 's/-Wno-/-W/g'` ;; + -Wformat-nonliteral) + # gcc requires -Wformat before -Wformat-nonliteral + # will work, so stick them together. + w="-Wformat $w" + wtest="$w" + ;; + *) + wtest=$w ;; + esac + + case $w in + -Werr*) WERROR_CFLAGS=-Werror ;; + *) + # Check whether GCC accepts it. + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror $wtest" + saved_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -Werror $wtest" + if test "x$w" = "x-Wunused-variable"; then + # Check for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38958, + # fixed in GCC 4.9. This test is derived from the gdb + # source code that triggered this bug in GCC. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +struct scoped_restore_base {}; + struct scoped_restore_tmpl : public scoped_restore_base { + ~scoped_restore_tmpl() {} + }; +int +main () +{ +const scoped_restore_base &b = scoped_restore_tmpl(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + WARN_CFLAGS="${WARN_CFLAGS} $w" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + WARN_CFLAGS="${WARN_CFLAGS} $w" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$saved_CFLAGS" + CXXFLAGS="$saved_CXXFLAGS" + esac + done + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WARN_CFLAGS} ${WERROR_CFLAGS}" >&5 +$as_echo "${WARN_CFLAGS} ${WERROR_CFLAGS}" >&6; } +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +old_LIBS="$LIBS" +LIBS="$LIBS -ldl" +for ac_func in dladdr +do : + ac_fn_c_check_func "$LINENO" "dladdr" "ac_cv_func_dladdr" +if test "x$ac_cv_func_dladdr" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLADDR 1 +_ACEOF + +fi +done + +LIBS="$old_LIBS" + + + # Check for presence and size of long long. + ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default" +if test "x$ac_cv_type_long_long" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_LONG_LONG 1 +_ACEOF + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +$as_echo_n "checking size of long long... " >&6; } +if ${ac_cv_sizeof_long_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (long long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 +$as_echo "$ac_cv_sizeof_long_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long +_ACEOF + + +fi + + + as_ac_Symbol=`$as_echo "ac_cv_have_decl_basename(char *)" | $as_tr_sh` +ac_fn_c_check_decl "$LINENO" "basename(char *)" "$as_ac_Symbol" "$ac_includes_default" +if eval test \"x\$"$as_ac_Symbol"\" = x"yes"; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_BASENAME $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" "$ac_includes_default" +if test "x$ac_cv_have_decl_ffs" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_FFS $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "asprintf" "ac_cv_have_decl_asprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_asprintf" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_ASPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vasprintf" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VASPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_snprintf" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SNPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vsnprintf" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VSNPRINTF $ac_have_decl +_ACEOF + + ac_fn_c_check_decl "$LINENO" "strtol" "ac_cv_have_decl_strtol" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtol" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOL $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strtoul" "ac_cv_have_decl_strtoul" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtoul" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOUL $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strtoll" "ac_cv_have_decl_strtoll" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtoll" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOLL $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strtoull" "ac_cv_have_decl_strtoull" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtoull" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOULL $ac_have_decl +_ACEOF + + ac_fn_c_check_decl "$LINENO" "strverscmp" "ac_cv_have_decl_strverscmp" "$ac_includes_default" +if test "x$ac_cv_have_decl_strverscmp" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRVERSCMP $ac_have_decl +_ACEOF + + + +ac_fn_c_check_decl "$LINENO" "perror" "ac_cv_have_decl_perror" "$ac_includes_default" +if test "x$ac_cv_have_decl_perror" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_PERROR $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vasprintf" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VASPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vsnprintf" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VSNPRINTF $ac_have_decl +_ACEOF + + +# See if supports the %fs_base and %gs_bas amd64 segment registers. +# Older amd64 Linux's don't have the fs_base and gs_base members of +# `struct user_regs_struct'. +ac_fn_c_check_member "$LINENO" "struct user_regs_struct" "fs_base" "ac_cv_member_struct_user_regs_struct_fs_base" "#include +#include +" +if test "x$ac_cv_member_struct_user_regs_struct_fs_base" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE 1 +_ACEOF + + +fi +ac_fn_c_check_member "$LINENO" "struct user_regs_struct" "gs_base" "ac_cv_member_struct_user_regs_struct_gs_base" "#include +#include +" +if test "x$ac_cv_member_struct_user_regs_struct_gs_base" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE 1 +_ACEOF + + +fi + + + +ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include +#include + +" +if test "x$ac_cv_type_socklen_t" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKLEN_T 1 +_ACEOF + + +fi + + +case "${target}" in + *-android*) + # Starting with NDK version 9, actually includes definitions + # of Elf32_auxv_t and Elf64_auxv_t. But sadly, includes + # which defines some of the ELF types incorrectly, + # leading to conflicts with the defintions from . + # This makes it impossible for us to include both and + # , which means that, in practice, we do not have + # access to Elf32_auxv_t and Elf64_auxv_t on this platform. + # Therefore, do not try to auto-detect availability, as it would + # get it wrong on this platform. + ;; + *) + ac_fn_c_check_type "$LINENO" "Elf32_auxv_t" "ac_cv_type_Elf32_auxv_t" "#include + +" +if test "x$ac_cv_type_Elf32_auxv_t" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_ELF32_AUXV_T 1 +_ACEOF + + +fi +ac_fn_c_check_type "$LINENO" "Elf64_auxv_t" "ac_cv_type_Elf64_auxv_t" "#include + +" +if test "x$ac_cv_type_Elf64_auxv_t" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_ELF64_AUXV_T 1 +_ACEOF + + +fi + +esac + + + +# Check whether --with-pkgversion was given. +if test "${with_pkgversion+set}" = set; then : + withval=$with_pkgversion; case "$withval" in + yes) as_fn_error $? "package version not specified" "$LINENO" 5 ;; + no) PKGVERSION= ;; + *) PKGVERSION="($withval) " ;; + esac +else + PKGVERSION="(GDB) " + +fi + + + + + +# Check whether --with-bugurl was given. +if test "${with_bugurl+set}" = set; then : + withval=$with_bugurl; case "$withval" in + yes) as_fn_error $? "bug URL not specified" "$LINENO" 5 ;; + no) BUGURL= + ;; + *) BUGURL="$withval" + ;; + esac +else + BUGURL="http://www.gnu.org/software/gdb/bugs/" + +fi + + case ${BUGURL} in + "") + REPORT_BUGS_TO= + REPORT_BUGS_TEXI= + ;; + *) + REPORT_BUGS_TO="<$BUGURL>" + REPORT_BUGS_TEXI=@uref{`echo "$BUGURL" | sed 's/@/@@/g'`} + ;; + esac; + + + + +cat >>confdefs.h <<_ACEOF +#define PKGVERSION "$PKGVERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define REPORT_BUGS_TO "$REPORT_BUGS_TO" +_ACEOF + + +# Check for various supplementary target information (beyond the +# triplet) which might affect the choices in configure.srv. +case "${target}" in + i[34567]86-*-linux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if building for x86-64" >&5 +$as_echo_n "checking if building for x86-64... " >&6; } +if ${gdb_cv_i386_is_x86_64+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $CFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if __x86_64__ +got it +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "got it" >/dev/null 2>&1; then : + gdb_cv_i386_is_x86_64=yes +else + gdb_cv_i386_is_x86_64=no +fi +rm -f conftest* + + CPPFLAGS="$save_CPPFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_i386_is_x86_64" >&5 +$as_echo "$gdb_cv_i386_is_x86_64" >&6; } + ;; + + x86_64-*-linux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if building for x32" >&5 +$as_echo_n "checking if building for x32... " >&6; } +if ${gdb_cv_x86_is_x32+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $CFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if __x86_64__ && __ILP32__ +got it +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "got it" >/dev/null 2>&1; then : + gdb_cv_x86_is_x32=yes +else + gdb_cv_x86_is_x32=no +fi +rm -f conftest* + + CPPFLAGS="$save_CPPFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_x86_is_x32" >&5 +$as_echo "$gdb_cv_x86_is_x32" >&6; } + ;; + + m68k-*-*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if building for Coldfire" >&5 +$as_echo_n "checking if building for Coldfire... " >&6; } +if ${gdb_cv_m68k_is_coldfire+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $CFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef __mcoldfire__ +got it +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "got it" >/dev/null 2>&1; then : + gdb_cv_m68k_is_coldfire=yes +else + gdb_cv_m68k_is_coldfire=no +fi +rm -f conftest* + + CPPFLAGS="$save_CPPFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_m68k_is_coldfire" >&5 +$as_echo "$gdb_cv_m68k_is_coldfire" >&6; } + ;; +esac + +. ${srcdir}/configure.srv + +if test "${srv_mingwce}" = "yes"; then + LIBS="$LIBS -lws2" +elif test "${srv_mingw}" = "yes"; then + # WIN32APILIBS is set by GDB_AC_COMMON. + LIBS="$LIBS $WIN32APILIBS" +elif test "${srv_qnx}" = "yes"; then + LIBS="$LIBS -lsocket" +elif test "${srv_lynxos}" = "yes"; then + LIBS="$LIBS -lnetinet" +fi + +if test "${srv_linux_usrregs}" = "yes"; then + +$as_echo "#define HAVE_LINUX_USRREGS 1" >>confdefs.h + +fi + +if test "${srv_linux_regsets}" = "yes"; then + +$as_echo "#define HAVE_LINUX_REGSETS 1" >>confdefs.h + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTRACE_GETREGS" >&5 +$as_echo_n "checking for PTRACE_GETREGS... " >&6; } + if ${gdbsrv_cv_have_ptrace_getregs+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +PTRACE_GETREGS; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdbsrv_cv_have_ptrace_getregs=yes +else + gdbsrv_cv_have_ptrace_getregs=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_ptrace_getregs" >&5 +$as_echo "$gdbsrv_cv_have_ptrace_getregs" >&6; } + if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then + +$as_echo "#define HAVE_PTRACE_GETREGS 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTRACE_GETFPXREGS" >&5 +$as_echo_n "checking for PTRACE_GETFPXREGS... " >&6; } + if ${gdbsrv_cv_have_ptrace_getfpxregs+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +PTRACE_GETFPXREGS; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdbsrv_cv_have_ptrace_getfpxregs=yes +else + gdbsrv_cv_have_ptrace_getfpxregs=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_ptrace_getfpxregs" >&5 +$as_echo "$gdbsrv_cv_have_ptrace_getfpxregs" >&6; } + if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then + +$as_echo "#define HAVE_PTRACE_GETFPXREGS 1" >>confdefs.h + + fi +fi + +if test "${srv_linux_btrace}" = "yes"; then + +$as_echo "#define HAVE_LINUX_BTRACE 1" >>confdefs.h + +fi + +if test "$bfd_cv_have_sys_procfs_type_lwpid_t" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lwpid_t in thread_db.h" >&5 +$as_echo_n "checking for lwpid_t in thread_db.h... " >&6; } + if ${gdbserver_cv_have_thread_db_type_lwpid_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +int +main () +{ +lwpid_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdbserver_cv_have_thread_db_type_lwpid_t=yes +else + gdbserver_cv_have_thread_db_type_lwpid_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $gdbserver_cv_have_thread_db_type_lwpid_t = yes; then + +$as_echo "#define HAVE_LWPID_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbserver_cv_have_thread_db_type_lwpid_t" >&5 +$as_echo "$gdbserver_cv_have_thread_db_type_lwpid_t" >&6; } + +fi + +if test "$bfd_cv_have_sys_procfs_type_psaddr_t" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for psaddr_t in thread_db.h" >&5 +$as_echo_n "checking for psaddr_t in thread_db.h... " >&6; } + if ${gdbserver_cv_have_thread_db_type_psaddr_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +int +main () +{ +psaddr_t avar + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdbserver_cv_have_thread_db_type_psaddr_t=yes +else + gdbserver_cv_have_thread_db_type_psaddr_t=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test $gdbserver_cv_have_thread_db_type_psaddr_t = yes; then + +$as_echo "#define HAVE_PSADDR_T 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbserver_cv_have_thread_db_type_psaddr_t" >&5 +$as_echo "$gdbserver_cv_have_thread_db_type_psaddr_t" >&6; } + +fi + +old_LIBS="$LIBS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + + LIBS="-ldl $LIBS" + +fi + +LIBS="$old_LIBS" + +srv_thread_depfiles= +srv_libs= + +if test "$srv_linux_thread_db" = "yes"; then + if test "$ac_cv_lib_dl_dlopen" = "yes"; then + srv_libs="-ldl" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the dynamic export flag" >&5 +$as_echo_n "checking for the dynamic export flag... " >&6; } + old_LDFLAGS="$LDFLAGS" + # Older GNU ld supports --export-dynamic but --dynamic-list may not be + # supported there. + RDYNAMIC="-Wl,--dynamic-list=${srcdir}/proc-service.list" + LDFLAGS="$LDFLAGS $RDYNAMIC" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + found="-Wl,--dynamic-list" + RDYNAMIC='-Wl,--dynamic-list=$(srcdir)/proc-service.list' +else + RDYNAMIC="-rdynamic" + LDFLAGS="$old_LDFLAGS $RDYNAMIC" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + found="-rdynamic" +else + found="no" + RDYNAMIC="" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + LDFLAGS="$old_LDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $found" >&5 +$as_echo "$found" >&6; } + else + srv_libs="-lthread_db" + fi + + srv_thread_depfiles="thread-db.o proc-service.o" + +$as_echo "#define USE_THREAD_DB 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TD_VERSION" >&5 +$as_echo_n "checking for TD_VERSION... " >&6; } +if ${gdbsrv_cv_have_td_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +TD_VERSION; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdbsrv_cv_have_td_version=yes +else + gdbsrv_cv_have_td_version=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_td_version" >&5 +$as_echo "$gdbsrv_cv_have_td_version" >&6; } + if test "$gdbsrv_cv_have_td_version" = yes; then + +$as_echo "#define HAVE_TD_VERSION 1" >>confdefs.h + + fi +fi + + +# Check whether --with-libthread-db was given. +if test "${with_libthread_db+set}" = set; then : + withval=$with_libthread_db; srv_libthread_db_path="${withval}" + srv_libs="$srv_libthread_db_path" + +fi + + +if test "$srv_libs" != "" -a "$srv_libs" != "-ldl"; then + +$as_echo "#define USE_LIBTHREAD_DB_DIRECTLY 1" >>confdefs.h + +fi + +if test "$srv_xmlfiles" != ""; then + srv_xmlbuiltin="xml-builtin.o" + +$as_echo "#define USE_XML 1" >>confdefs.h + + + tmp_xmlfiles=$srv_xmlfiles + srv_xmlfiles="" + for f in $tmp_xmlfiles; do + srv_xmlfiles="$srv_xmlfiles \$(XML_DIR)/$f" + done +fi + +GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles $srv_selftest_objs" +GDBSERVER_LIBS="$srv_libs" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports __sync_*_compare_and_swap" >&5 +$as_echo_n "checking whether the target supports __sync_*_compare_and_swap... " >&6; } +if ${gdbsrv_cv_have_sync_builtins+:} false; then : + $as_echo_n "(cached) " >&6 +else + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gdbsrv_cv_have_sync_builtins=yes +else + gdbsrv_cv_have_sync_builtins=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdbsrv_cv_have_sync_builtins" >&5 +$as_echo "$gdbsrv_cv_have_sync_builtins" >&6; } +if test "$gdbsrv_cv_have_sync_builtins" = yes; then + +$as_echo "#define HAVE_SYNC_BUILTINS 1" >>confdefs.h + +fi + +saved_cflags="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdbsrv_cv_have_visibility_hidden=yes +else + gdbsrv_cv_have_visibility_hidden=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$saved_cflags" + +IPA_DEPFILES="" +extra_libraries="" + +# check whether to enable the inprocess agent +if test "$ipa_obj" != "" \ + -a "$gdbsrv_cv_have_sync_builtins" = yes \ + -a "$gdbsrv_cv_have_visibility_hidden" = yes; then + have_ipa=true +else + have_ipa=false +fi + +# Check whether --enable-inprocess-agent was given. +if test "${enable_inprocess_agent+set}" = set; then : + enableval=$enable_inprocess_agent; case "$enableval" in + yes) want_ipa=true ;; + no) want_ipa=false ;; + *) as_fn_error $? "bad value $enableval for inprocess-agent" "$LINENO" 5 ;; +esac +else + want_ipa=$have_ipa +fi + + +if $want_ipa ; then + if $have_ipa ; then + IPA_DEPFILES="$ipa_obj" + extra_libraries="$extra_libraries libinproctrace.so" + else + as_fn_error $? "inprocess agent not supported for this target" "$LINENO" 5 + fi +fi + + + + + + + + +GNULIB=build-gnulib-gdbserver/import + +GNULIB_STDINT_H= +if test x"$STDINT_H" != x; then + GNULIB_STDINT_H=$GNULIB/$STDINT_H +fi + + +ac_config_files="$ac_config_files Makefile" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR +ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR CONFIG_SRC_SUBDIR="$CONFIG_SRC_SUBDIR" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;; + "depdir") CONFIG_COMMANDS="$CONFIG_COMMANDS depdir" ;; + "gdbdepdir") CONFIG_COMMANDS="$CONFIG_COMMANDS gdbdepdir" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "config.h":H) echo > stamp-h ;; + "depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;; + "gdbdepdir":C) + for subdir in ${CONFIG_SRC_SUBDIR} + do + $SHELL $ac_aux_dir/mkinstalldirs $subdir/$DEPDIR + done ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/gdbserver/configure.ac b/gdbserver/configure.ac new file mode 100644 index 00000000000..285a297a1c6 --- /dev/null +++ b/gdbserver/configure.ac @@ -0,0 +1,445 @@ +dnl Autoconf configure script for GDB server. +dnl Copyright (C) 2000-2020 Free Software Foundation, Inc. +dnl +dnl This file is part of GDB. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program. If not, see . + +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(server.c) +AC_CONFIG_HEADERS(config.h:config.in, [echo > stamp-h]) + +AM_MAINTAINER_MODE + +AC_PROG_CC +AC_PROG_CXX +AC_GNU_SOURCE +AC_SYS_LARGEFILE +AM_PROG_INSTALL_STRIP + +AC_CANONICAL_SYSTEM + +AC_PROG_INSTALL +AC_CHECK_TOOL(AR, ar) +AC_PROG_RANLIB + +AC_ARG_PROGRAM + +# We require a C++11 compiler. Check if one is available, and if +# necessary, set CXX_DIALECT to some -std=xxx switch. +AX_CXX_COMPILE_STDCXX(11, , mandatory) + +AC_HEADER_STDC + +# Set the 'development' global. +. $srcdir/../bfd/development.sh + +GDB_AC_SELFTEST([ + srv_selftest_objs="gdbsupport/selftest.o" +]) + +ACX_NONCANONICAL_TARGET +ACX_NONCANONICAL_HOST + +# Dependency checking. +ZW_CREATE_DEPDIR + +# Create sub-directories for objects and dependencies. +CONFIG_SRC_SUBDIR="arch gdbsupport nat target" +AC_SUBST(CONFIG_SRC_SUBDIR) + +AC_CONFIG_COMMANDS([gdbdepdir],[ + for subdir in ${CONFIG_SRC_SUBDIR} + do + $SHELL $ac_aux_dir/mkinstalldirs $subdir/$DEPDIR + done], + [ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR CONFIG_SRC_SUBDIR="$CONFIG_SRC_SUBDIR"]) + +ZW_PROG_COMPILER_DEPENDENCIES([CC]) + +gnulib_extra_configure_args= +# If large-file support is disabled, make sure gnulib does the same. +if test "$enable_largefile" = no; then +gnulib_extra_configure_args="$gnulib_extra_configure_args --disable-largefile" +fi + +# Configure gnulib. We can't use AC_CONFIG_SUBDIRS as that'd expect +# to find the the source subdir to be configured directly under +# gdbserver/. We need to build gnulib under some other directory not +# "gnulib", to avoid the problem of both GDB and GDBserver wanting to +# build it in the same directory, when building in the source dir. +ACX_CONFIGURE_DIR(["../gnulib"], ["build-gnulib-gdbserver"], + ["$gnulib_extra_configure_args"]) + +ACX_CONFIGURE_DIR(["../libiberty"], ["build-libiberty-gdbserver"]) + +AC_CHECK_HEADERS(termios.h sys/reg.h string.h dnl + sys/procfs.h linux/elf.h dnl + fcntl.h signal.h sys/file.h dnl + sys/ioctl.h netinet/in.h sys/socket.h netdb.h dnl + netinet/tcp.h arpa/inet.h) +AC_FUNC_FORK +AC_CHECK_FUNCS(pread pwrite pread64) + +GDB_AC_COMMON + +# Check the return and argument types of ptrace. +GDB_AC_PTRACE + +# Check for UST +ustlibs="" +ustinc="" + +AC_ARG_WITH(ust, [ --with-ust=PATH Specify prefix directory for the installed UST package + Equivalent to --with-ust-include=PATH/include + plus --with-ust-lib=PATH/lib]) +AC_ARG_WITH(ust_include, [ --with-ust-include=PATH Specify directory for installed UST include files]) +AC_ARG_WITH(ust_lib, [ --with-ust-lib=PATH Specify the directory for the installed UST library]) + +case $with_ust in + no) + ustlibs= + ustinc= + ;; + "" | yes) + ustlibs=" -lust " + ustinc="" + ;; + *) + ustlibs="-L$with_ust/lib -lust" + ustinc="-I$with_ust/include " + ;; +esac +if test "x$with_ust_include" != x; then + ustinc="-I$with_ust_include " +fi +if test "x$with_ust_lib" != x; then + ustlibs="-L$with_ust_lib -lust" +fi + +if test "x$with_ust" != "xno"; then + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $ustinc" + AC_MSG_CHECKING([for ust]) + AC_TRY_COMPILE([ +#define CONFIG_UST_GDB_INTEGRATION +#include + ],[], + [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_UST, 1, [Define if UST is available])], + [AC_MSG_RESULT([no]); ustlibs= ; ustinc= ]) + CFLAGS="$saved_CFLAGS" +fi + +# Flags needed for UST +AC_SUBST(ustlibs) +AC_SUBST(ustinc) + +AM_GDB_WARNINGS + +dnl dladdr is glibc-specific. It is used by thread-db.c but only for +dnl debugging messages. It lives in -ldl which is handled below so we don't +dnl use AC_CHECK_LIB (or AC_SEARCH_LIBS) here. Instead we just temporarily +dnl augment LIBS. +old_LIBS="$LIBS" +LIBS="$LIBS -ldl" +AC_CHECK_FUNCS(dladdr) +LIBS="$old_LIBS" + +libiberty_INIT + +AC_CHECK_DECLS([perror, vasprintf, vsnprintf]) + +# See if supports the %fs_base and %gs_bas amd64 segment registers. +# Older amd64 Linux's don't have the fs_base and gs_base members of +# `struct user_regs_struct'. +AC_CHECK_MEMBERS([struct user_regs_struct.fs_base, struct user_regs_struct.gs_base], + [], [], [#include +#include ]) + + +AC_CHECK_TYPES(socklen_t, [], [], +[#include +#include +]) + +case "${target}" in + *-android*) + # Starting with NDK version 9, actually includes definitions + # of Elf32_auxv_t and Elf64_auxv_t. But sadly, includes + # which defines some of the ELF types incorrectly, + # leading to conflicts with the defintions from . + # This makes it impossible for us to include both and + # , which means that, in practice, we do not have + # access to Elf32_auxv_t and Elf64_auxv_t on this platform. + # Therefore, do not try to auto-detect availability, as it would + # get it wrong on this platform. + ;; + *) + AC_CHECK_TYPES([Elf32_auxv_t, Elf64_auxv_t], [], [], + #include + ) +esac + +ACX_PKGVERSION([GDB]) +ACX_BUGURL([http://www.gnu.org/software/gdb/bugs/]) +AC_DEFINE_UNQUOTED([PKGVERSION], ["$PKGVERSION"], [Additional package description]) +AC_DEFINE_UNQUOTED([REPORT_BUGS_TO], ["$REPORT_BUGS_TO"], [Bug reporting address]) + +# Check for various supplementary target information (beyond the +# triplet) which might affect the choices in configure.srv. +case "${target}" in +changequote(,)dnl + i[34567]86-*-linux*) +changequote([,])dnl + AC_CACHE_CHECK([if building for x86-64], [gdb_cv_i386_is_x86_64], + [save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $CFLAGS" + AC_EGREP_CPP([got it], [ +#if __x86_64__ +got it +#endif + ], [gdb_cv_i386_is_x86_64=yes], + [gdb_cv_i386_is_x86_64=no]) + CPPFLAGS="$save_CPPFLAGS"]) + ;; + + x86_64-*-linux*) + AC_CACHE_CHECK([if building for x32], [gdb_cv_x86_is_x32], + [save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $CFLAGS" + AC_EGREP_CPP([got it], [ +#if __x86_64__ && __ILP32__ +got it +#endif + ], [gdb_cv_x86_is_x32=yes], + [gdb_cv_x86_is_x32=no]) + CPPFLAGS="$save_CPPFLAGS"]) + ;; + + m68k-*-*) + AC_CACHE_CHECK([if building for Coldfire], [gdb_cv_m68k_is_coldfire], + [save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $CFLAGS" + AC_EGREP_CPP([got it], [ +#ifdef __mcoldfire__ +got it +#endif + ], [gdb_cv_m68k_is_coldfire=yes], + [gdb_cv_m68k_is_coldfire=no]) + CPPFLAGS="$save_CPPFLAGS"]) + ;; +esac + +. ${srcdir}/configure.srv + +if test "${srv_mingwce}" = "yes"; then + LIBS="$LIBS -lws2" +elif test "${srv_mingw}" = "yes"; then + # WIN32APILIBS is set by GDB_AC_COMMON. + LIBS="$LIBS $WIN32APILIBS" +elif test "${srv_qnx}" = "yes"; then + LIBS="$LIBS -lsocket" +elif test "${srv_lynxos}" = "yes"; then + LIBS="$LIBS -lnetinet" +fi + +if test "${srv_linux_usrregs}" = "yes"; then + AC_DEFINE(HAVE_LINUX_USRREGS, 1, + [Define if the target supports PTRACE_PEEKUSR for register ] + [access.]) +fi + +if test "${srv_linux_regsets}" = "yes"; then + AC_DEFINE(HAVE_LINUX_REGSETS, 1, + [Define if the target supports register sets.]) + + AC_MSG_CHECKING(for PTRACE_GETREGS) + AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getregs, + [AC_TRY_COMPILE([#include ], + [PTRACE_GETREGS;], + [gdbsrv_cv_have_ptrace_getregs=yes], + [gdbsrv_cv_have_ptrace_getregs=no])]) + AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getregs) + if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then + AC_DEFINE(HAVE_PTRACE_GETREGS, 1, + [Define if the target supports PTRACE_GETREGS for register ] + [access.]) + fi + + AC_MSG_CHECKING(for PTRACE_GETFPXREGS) + AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getfpxregs, + [AC_TRY_COMPILE([#include ], + [PTRACE_GETFPXREGS;], + [gdbsrv_cv_have_ptrace_getfpxregs=yes], + [gdbsrv_cv_have_ptrace_getfpxregs=no])]) + AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getfpxregs) + if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then + AC_DEFINE(HAVE_PTRACE_GETFPXREGS, 1, + [Define if the target supports PTRACE_GETFPXREGS for extended ] + [register access.]) + fi +fi + +if test "${srv_linux_btrace}" = "yes"; then + AC_DEFINE(HAVE_LINUX_BTRACE, 1, + [Define if the target supports branch tracing.]) +fi + +dnl Some systems (e.g., Android) have lwpid_t defined in libthread_db.h. +if test "$bfd_cv_have_sys_procfs_type_lwpid_t" != yes; then + GDBSERVER_HAVE_THREAD_DB_TYPE(lwpid_t) +fi + +dnl Some systems (e.g., Android) have psaddr_t defined in libthread_db.h. +if test "$bfd_cv_have_sys_procfs_type_psaddr_t" != yes; then + GDBSERVER_HAVE_THREAD_DB_TYPE(psaddr_t) +fi + +dnl Check for libdl, but do not add it to LIBS as only gdbserver +dnl needs it (and gdbreplay doesn't). +old_LIBS="$LIBS" +AC_CHECK_LIB(dl, dlopen) +LIBS="$old_LIBS" + +srv_thread_depfiles= +srv_libs= + +if test "$srv_linux_thread_db" = "yes"; then + if test "$ac_cv_lib_dl_dlopen" = "yes"; then + srv_libs="-ldl" + AC_MSG_CHECKING(for the dynamic export flag) + old_LDFLAGS="$LDFLAGS" + # Older GNU ld supports --export-dynamic but --dynamic-list may not be + # supported there. + RDYNAMIC="-Wl,--dynamic-list=${srcdir}/proc-service.list" + LDFLAGS="$LDFLAGS $RDYNAMIC" + AC_TRY_LINK([], [], + [found="-Wl,--dynamic-list" + RDYNAMIC='-Wl,--dynamic-list=$(srcdir)/proc-service.list'], + [RDYNAMIC="-rdynamic" + LDFLAGS="$old_LDFLAGS $RDYNAMIC" + AC_TRY_LINK([], [], + [found="-rdynamic"], + [found="no" + RDYNAMIC=""])]) + AC_SUBST(RDYNAMIC) + LDFLAGS="$old_LDFLAGS" + AC_MSG_RESULT($found) + else + srv_libs="-lthread_db" + fi + + srv_thread_depfiles="thread-db.o proc-service.o" + AC_DEFINE(USE_THREAD_DB, 1, [Define if we should use libthread_db.]) + AC_CACHE_CHECK([for TD_VERSION], gdbsrv_cv_have_td_version, + [AC_TRY_COMPILE([#include ], [TD_VERSION;], + [gdbsrv_cv_have_td_version=yes], + [gdbsrv_cv_have_td_version=no])]) + if test "$gdbsrv_cv_have_td_version" = yes; then + AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.]) + fi +fi + +AC_ARG_WITH(libthread-db, +AS_HELP_STRING([--with-libthread-db=PATH], [use given libthread_db directly]), +[srv_libthread_db_path="${withval}" + srv_libs="$srv_libthread_db_path" +]) + +if test "$srv_libs" != "" -a "$srv_libs" != "-ldl"; then + AC_DEFINE(USE_LIBTHREAD_DB_DIRECTLY, 1, [Define if we should use libthread_db directly.]) +fi + +if test "$srv_xmlfiles" != ""; then + srv_xmlbuiltin="xml-builtin.o" + AC_DEFINE(USE_XML, 1, [Define if an XML target description is available.]) + + tmp_xmlfiles=$srv_xmlfiles + srv_xmlfiles="" + for f in $tmp_xmlfiles; do + srv_xmlfiles="$srv_xmlfiles \$(XML_DIR)/$f" + done +fi + +GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles $srv_selftest_objs" +GDBSERVER_LIBS="$srv_libs" + +dnl Check whether the target supports __sync_*_compare_and_swap. +AC_CACHE_CHECK([whether the target supports __sync_*_compare_and_swap], + gdbsrv_cv_have_sync_builtins, [ +AC_TRY_LINK([], [int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1);], + gdbsrv_cv_have_sync_builtins=yes, + gdbsrv_cv_have_sync_builtins=no)]) +if test "$gdbsrv_cv_have_sync_builtins" = yes; then + AC_DEFINE(HAVE_SYNC_BUILTINS, 1, + [Define to 1 if the target supports __sync_*_compare_and_swap]) +fi + +dnl Check for -fvisibility=hidden support in the compiler. +saved_cflags="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], + [gdbsrv_cv_have_visibility_hidden=yes], + [gdbsrv_cv_have_visibility_hidden=no]) +CFLAGS="$saved_cflags" + +IPA_DEPFILES="" +extra_libraries="" + +# check whether to enable the inprocess agent +if test "$ipa_obj" != "" \ + -a "$gdbsrv_cv_have_sync_builtins" = yes \ + -a "$gdbsrv_cv_have_visibility_hidden" = yes; then + have_ipa=true +else + have_ipa=false +fi + +AC_ARG_ENABLE(inprocess-agent, +AS_HELP_STRING([--enable-inprocess-agent], [inprocess agent]), +[case "$enableval" in + yes) want_ipa=true ;; + no) want_ipa=false ;; + *) AC_MSG_ERROR([bad value $enableval for inprocess-agent]) ;; +esac], +[want_ipa=$have_ipa]) + +if $want_ipa ; then + if $have_ipa ; then + IPA_DEPFILES="$ipa_obj" + extra_libraries="$extra_libraries libinproctrace.so" + else + AC_MSG_ERROR([inprocess agent not supported for this target]) + fi +fi + +AC_SUBST(GDBSERVER_DEPFILES) +AC_SUBST(GDBSERVER_LIBS) +AC_SUBST(srv_xmlbuiltin) +AC_SUBST(srv_xmlfiles) +AC_SUBST(IPA_DEPFILES) +AC_SUBST(extra_libraries) + +GNULIB=build-gnulib-gdbserver/import + +GNULIB_STDINT_H= +if test x"$STDINT_H" != x; then + GNULIB_STDINT_H=$GNULIB/$STDINT_H +fi +AC_SUBST(GNULIB_STDINT_H) + +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv new file mode 100644 index 00000000000..2e83cbdc07f --- /dev/null +++ b/gdbserver/configure.srv @@ -0,0 +1,406 @@ +# Mappings from configuration triplets to gdbserver build options. +# This is invoked from the autoconf-generated configure script, to +# produce the appropriate Makefile substitutions. +# It is also sourced by the top level configure script, to determine +# whether gdbserver is supported on a given host. + +# This file sets the following shell variables: +# srv_regobj The register protocol appropriate for this target. +# srv_tgtobj Any other target-specific modules appropriate +# for this target. +# srv_hostio_err The object implementing the hostio_last_error +# target method. +# srv_xmlfiles All XML files which should be available for +# gdbserver in this configuration. +# ipa_obj Any other target-specific modules appropriate +# for this target's in-process agent. +# UNSUPPORTED Set to 1 if the host is unsupported. +# +# In addition, on GNU/Linux the following shell variables will be set: +# srv_linux_regsets Set to "yes" if ptrace(PTRACE_GETREGS) and friends +# may be available on this platform; unset otherwise. +# They will only be used if defines +# PTRACE_GETREGS. +# srv_linux_usrregs Set to "yes" if we can get at registers via +# PTRACE_PEEKUSR / PTRACE_POKEUSR. + +# Default hostio_last_error implementation +srv_hostio_err_objs="hostio-errno.o" + +ipa_ppc_linux_regobj="powerpc-32l-ipa.o powerpc-altivec32l-ipa.o powerpc-vsx32l-ipa.o powerpc-isa205-32l-ipa.o powerpc-isa205-altivec32l-ipa.o powerpc-isa205-vsx32l-ipa.o powerpc-isa205-ppr-dscr-vsx32l-ipa.o powerpc-isa207-vsx32l-ipa.o powerpc-isa207-htm-vsx32l-ipa.o powerpc-e500l-ipa.o powerpc-64l-ipa.o powerpc-altivec64l-ipa.o powerpc-vsx64l-ipa.o powerpc-isa205-64l-ipa.o powerpc-isa205-altivec64l-ipa.o powerpc-isa205-vsx64l-ipa.o powerpc-isa205-ppr-dscr-vsx64l-ipa.o powerpc-isa207-vsx64l-ipa.o powerpc-isa207-htm-vsx64l-ipa.o" + +# Linux object files. This is so we don't have to repeat +# these files over and over again. +srv_linux_obj="linux-low.o nat/linux-osdata.o nat/linux-procfs.o nat/linux-ptrace.o nat/linux-waitpid.o nat/linux-personality.o nat/linux-namespaces.o fork-child.o nat/fork-inferior.o" + +# Input is taken from the "${host}" variable. + +case "${host}" in + aarch64*-*-linux*) srv_tgtobj="linux-aarch64-low.o" + srv_tgtobj="$srv_tgtobj nat/aarch64-linux-hw-point.o" + srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" + srv_tgtobj="$srv_tgtobj linux-aarch32-tdesc.o" + srv_tgtobj="${srv_tgtobj} arch/aarch32.o" + srv_tgtobj="${srv_tgtobj} arch/arm.o" + srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o" + srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o" + srv_tgtobj="$srv_tgtobj arch/aarch64.o" + srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o" + srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o" + srv_tgtobj="${srv_tgtobj} $srv_linux_obj" + srv_linux_regsets=yes + srv_linux_thread_db=yes + ipa_obj="linux-aarch64-ipa.o" + ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o" + ipa_obj="${ipa_obj} arch/aarch64-ipa.o" + ;; + arm*-*-linux*) srv_tgtobj="$srv_linux_obj linux-arm-low.o" + srv_tgtobj="$srv_tgtobj linux-arm-tdesc.o" + srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" + srv_tgtobj="$srv_tgtobj linux-aarch32-tdesc.o" + srv_tgtobj="${srv_tgtobj} arch/aarch32.o" + srv_tgtobj="${srv_tgtobj} arch/arm.o" + srv_tgtobj="${srv_tgtobj} arch/arm-linux.o" + srv_tgtobj="${srv_tgtobj} arch/arm-get-next-pcs.o" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + arm*-*-mingw32ce*) srv_regobj=reg-arm.o + srv_tgtobj="win32-low.o win32-arm-low.o" + srv_tgtobj="${srv_tgtobj} wincecompat.o" + # hostio_last_error implementation is in win32-low.c + srv_hostio_err_objs="" + srv_mingw=yes + srv_mingwce=yes + ;; + bfin-*-*linux*) srv_regobj=reg-bfin.o + srv_tgtobj="$srv_linux_obj linux-bfin-low.o" + srv_linux_usrregs=yes + srv_linux_thread_db=yes + ;; + crisv32-*-linux*) srv_regobj=reg-crisv32.o + srv_tgtobj="$srv_linux_obj linux-crisv32-low.o" + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + cris-*-linux*) srv_regobj=reg-cris.o + srv_tgtobj="$srv_linux_obj linux-cris-low.o" + srv_linux_usrregs=yes + srv_linux_thread_db=yes + ;; + i[34567]86-*-cygwin*) srv_regobj="" + srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o" + srv_tgtobj="${srv_tgtobj} win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch/i386.o" + ;; + i[34567]86-*-linux*) srv_tgtobj="${srv_tgtobj} arch/i386.o" + srv_tgtobj="${srv_tgtobj} $srv_linux_obj" + srv_tgtobj="${srv_tgtobj} linux-x86-low.o x86-low.o" + srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o" + srv_tgtobj="${srv_tgtobj} nat/linux-btrace.o" + srv_tgtobj="${srv_tgtobj} nat/x86-linux.o" + srv_tgtobj="${srv_tgtobj} nat/x86-linux-dregs.o" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + srv_linux_btrace=yes + ipa_obj="linux-i386-ipa.o linux-x86-tdesc-ipa.o" + ipa_obj="${ipa_obj} arch/i386-ipa.o" + ;; + i[34567]86-*-lynxos*) srv_regobj="" + srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o" + srv_tgtobj="${srv_tgtobj} nat/fork-inferior.o" + srv_tgtobj="${srv_tgtobj} arch/i386.o" + srv_lynxos=yes + ;; + i[34567]86-*-mingw32ce*) + srv_regobj="" + srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o" + srv_tgtobj="${srv_tgtobj} win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch/i386.o" + srv_tgtobj="${srv_tgtobj} wincecompat.o" + # hostio_last_error implementation is in win32-low.c + srv_hostio_err_objs="" + srv_mingw=yes + srv_mingwce=yes + ;; + i[34567]86-*-mingw*) srv_regobj="" + srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o" + srv_tgtobj="${srv_tgtobj} win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch/i386.o" + srv_mingw=yes + ;; + i[34567]86-*-nto*) srv_regobj="" + srv_tgtobj="nto-low.o nto-x86-low.o arch/i386.o" + srv_qnx="yes" + ;; + ia64-*-linux*) srv_regobj=reg-ia64.o + srv_tgtobj="$srv_linux_obj linux-ia64-low.o" + srv_linux_usrregs=yes + ;; + m32r*-*-linux*) srv_regobj=reg-m32r.o + srv_tgtobj="$srv_linux_obj linux-m32r-low.o" + srv_linux_usrregs=yes + srv_linux_thread_db=yes + ;; + m68*-*-linux*) if test "$gdb_cv_m68k_is_coldfire" = yes; then + srv_regobj=reg-cf.o + else + srv_regobj=reg-m68k.o + fi + srv_tgtobj="$srv_linux_obj linux-m68k-low.o" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + m68*-*-uclinux*) if test "$gdb_cv_m68k_is_coldfire" = yes; then + srv_regobj=reg-cf.o + else + srv_regobj=reg-m68k.o + fi + srv_tgtobj="$srv_linux_obj linux-m68k-low.o" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + mips*-*-linux*) srv_regobj="mips-linux.o" + srv_regobj="${srv_regobj} mips-dsp-linux.o" + srv_regobj="${srv_regobj} mips64-linux.o" + srv_regobj="${srv_regobj} mips64-dsp-linux.o" + srv_tgtobj="$srv_linux_obj linux-mips-low.o" + srv_tgtobj="${srv_tgtobj} nat/mips-linux-watch.o" + srv_xmlfiles="mips-linux.xml" + srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml" + srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml" + srv_xmlfiles="${srv_xmlfiles} mips-cp0.xml" + srv_xmlfiles="${srv_xmlfiles} mips-fpu.xml" + srv_xmlfiles="${srv_xmlfiles} mips-dsp.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-linux.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-dsp-linux.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-cpu.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-cp0.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-fpu.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-dsp.xml" + srv_linux_regsets=yes + srv_linux_usrregs=yes + srv_linux_thread_db=yes + ;; + nios2*-*-linux*) srv_regobj="nios2-linux.o" + srv_tgtobj="$srv_linux_obj linux-nios2-low.o" + srv_xmlfiles="nios2-linux.xml" + srv_xmlfiles="${srv_xmlfiles} nios2-cpu.xml" + srv_linux_regsets=yes + srv_linux_usrregs=yes + srv_linux_thread_db=yes + ;; + powerpc*-*-linux*) srv_regobj="powerpc-32l.o" + srv_regobj="${srv_regobj} powerpc-altivec32l.o" + srv_regobj="${srv_regobj} powerpc-vsx32l.o" + srv_regobj="${srv_regobj} powerpc-isa205-32l.o" + srv_regobj="${srv_regobj} powerpc-isa205-altivec32l.o" + srv_regobj="${srv_regobj} powerpc-isa205-vsx32l.o" + srv_regobj="${srv_regobj} powerpc-isa205-ppr-dscr-vsx32l.o" + srv_regobj="${srv_regobj} powerpc-isa207-vsx32l.o" + srv_regobj="${srv_regobj} powerpc-isa207-htm-vsx32l.o" + srv_regobj="${srv_regobj} powerpc-e500l.o" + srv_regobj="${srv_regobj} powerpc-64l.o" + srv_regobj="${srv_regobj} powerpc-altivec64l.o" + srv_regobj="${srv_regobj} powerpc-vsx64l.o" + srv_regobj="${srv_regobj} powerpc-isa205-64l.o" + srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o" + srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o" + srv_regobj="${srv_regobj} powerpc-isa205-ppr-dscr-vsx64l.o" + srv_regobj="${srv_regobj} powerpc-isa207-vsx64l.o" + srv_regobj="${srv_regobj} powerpc-isa207-htm-vsx64l.o" + srv_tgtobj="$srv_linux_obj linux-ppc-low.o" + srv_tgtobj="${srv_tgtobj} nat/ppc-linux.o" + srv_tgtobj="${srv_tgtobj} arch/ppc-linux-common.o" + srv_xmlfiles="rs6000/powerpc-32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-altivec32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-vsx32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-ppr-dscr-vsx32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-vsx32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-htm-vsx32l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-altivec.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-vsx.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-linux.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu-isa205.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-dscr.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-ppr.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-tar.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-ebb.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-linux-pmu.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-spr.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-core.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-fpu.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-altivec.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-vsx.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-ppr.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-dscr.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-htm-tar.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-e500l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-vsx64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-altivec64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-vsx64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa205-ppr-dscr-vsx64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-vsx64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-isa207-htm-vsx64l.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power64-core.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power64-linux.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power64-htm-core.xml" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ipa_obj="${ipa_ppc_linux_regobj} linux-ppc-ipa.o" + ;; + powerpc-*-lynxos*) srv_regobj="powerpc-32.o" + srv_tgtobj="lynx-low.o lynx-ppc-low.o" + srv_xmlfiles="rs6000/powerpc-32.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml" + srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml" + srv_lynxos=yes + ;; + s390*-*-linux*) srv_regobj="s390-linux32.o" + srv_regobj="${srv_regobj} s390-linux32v1.o" + srv_regobj="${srv_regobj} s390-linux32v2.o" + srv_regobj="${srv_regobj} s390-linux64.o" + srv_regobj="${srv_regobj} s390-linux64v1.o" + srv_regobj="${srv_regobj} s390-linux64v2.o" + srv_regobj="${srv_regobj} s390-te-linux64.o" + srv_regobj="${srv_regobj} s390-vx-linux64.o" + srv_regobj="${srv_regobj} s390-tevx-linux64.o" + srv_regobj="${srv_regobj} s390-gs-linux64.o" + srv_regobj="${srv_regobj} s390x-linux64.o" + srv_regobj="${srv_regobj} s390x-linux64v1.o" + srv_regobj="${srv_regobj} s390x-linux64v2.o" + srv_regobj="${srv_regobj} s390x-te-linux64.o" + srv_regobj="${srv_regobj} s390x-vx-linux64.o" + srv_regobj="${srv_regobj} s390x-tevx-linux64.o" + srv_regobj="${srv_regobj} s390x-gs-linux64.o" + srv_tgtobj="$srv_linux_obj linux-s390-low.o" + srv_xmlfiles="s390-linux32.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux32v2.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux64v1.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux64v2.xml" + srv_xmlfiles="${srv_xmlfiles} s390-te-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-vx-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-tevx-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-gs-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-linux64v1.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-linux64v2.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-te-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-vx-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-tevx-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-gs-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-core32.xml" + srv_xmlfiles="${srv_xmlfiles} s390-core64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-core64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-acr.xml" + srv_xmlfiles="${srv_xmlfiles} s390-fpr.xml" + srv_xmlfiles="${srv_xmlfiles} s390-tdb.xml" + srv_xmlfiles="${srv_xmlfiles} s390-vx.xml" + srv_xmlfiles="${srv_xmlfiles} s390-gs.xml" + srv_xmlfiles="${srv_xmlfiles} s390-gsbc.xml" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ipa_obj="linux-s390-ipa.o" + ipa_obj="${ipa_obj} s390-linux32-ipa.o" + ipa_obj="${ipa_obj} s390-linux32v1-ipa.o" + ipa_obj="${ipa_obj} s390-linux32v2-ipa.o" + ipa_obj="${ipa_obj} s390-linux64-ipa.o" + ipa_obj="${ipa_obj} s390-linux64v1-ipa.o" + ipa_obj="${ipa_obj} s390-linux64v2-ipa.o" + ipa_obj="${ipa_obj} s390-vx-linux64-ipa.o" + ipa_obj="${ipa_obj} s390-te-linux64-ipa.o" + ipa_obj="${ipa_obj} s390-tevx-linux64-ipa.o" + ipa_obj="${ipa_obj} s390-gs-linux64-ipa.o" + ipa_obj="${ipa_obj} s390x-linux64-ipa.o" + ipa_obj="${ipa_obj} s390x-linux64v1-ipa.o" + ipa_obj="${ipa_obj} s390x-linux64v2-ipa.o" + ipa_obj="${ipa_obj} s390x-vx-linux64-ipa.o" + ipa_obj="${ipa_obj} s390x-te-linux64-ipa.o" + ipa_obj="${ipa_obj} s390x-tevx-linux64-ipa.o" + ipa_obj="${ipa_obj} s390x-gs-linux64-ipa.o" + ;; + sh*-*-linux*) srv_regobj=reg-sh.o + srv_tgtobj="$srv_linux_obj linux-sh-low.o" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + sparc*-*-linux*) srv_regobj=reg-sparc64.o + srv_tgtobj="$srv_linux_obj linux-sparc-low.o" + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + tic6x-*-uclinux) if $development; then + srv_regobj="tic6x-c64xp-linux.o" + srv_regobj="${srv_regobj} tic6x-c64x-linux.o" + srv_regobj="${srv_regobj} tic6x-c62x-linux.o" + else + srv_regobj="" + fi + srv_tgtobj="$srv_linux_obj linux-tic6x-low.o" + srv_tgtobj="${srv_tgtobj} arch/tic6x.o" + srv_linux_regsets=yes + srv_linux_usrregs=yes + srv_linux_thread_db=yes + ;; + x86_64-*-linux*) srv_tgtobj="$srv_linux_obj linux-x86-low.o x86-low.o" + srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} arch/i386.o arch/amd64.o" + srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o" + srv_tgtobj="${srv_tgtobj} nat/linux-btrace.o" + srv_tgtobj="${srv_tgtobj} nat/x86-linux.o" + srv_tgtobj="${srv_tgtobj} nat/x86-linux-dregs.o" + srv_tgtobj="${srv_tgtobj} nat/amd64-linux-siginfo.o" + srv_linux_usrregs=yes # This is for i386 progs. + srv_linux_regsets=yes + srv_linux_thread_db=yes + srv_linux_btrace=yes + ipa_obj="linux-amd64-ipa.o linux-x86-tdesc-ipa.o" + ipa_obj="${ipa_obj} arch/amd64-ipa.o" + ;; + x86_64-*-mingw*) srv_regobj="" + srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch/amd64.o" + srv_mingw=yes + ;; + x86_64-*-cygwin*) srv_regobj="" + srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o" + srv_tgtobj="${srv_tgtobj} arch/amd64.o" + ;; + + xtensa*-*-linux*) srv_regobj=reg-xtensa.o + srv_tgtobj="$srv_linux_obj linux-xtensa-low.o" + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + tilegx-*-linux*) srv_regobj=reg-tilegx.o + srv_regobj="${srv_regobj} reg-tilegx32.o" + srv_tgtobj="$srv_linux_obj linux-tile-low.o" + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; + *) + # Who are you? + UNSUPPORTED=1 + ;; +esac diff --git a/gdbserver/debug.c b/gdbserver/debug.c new file mode 100644 index 00000000000..7bb2504570d --- /dev/null +++ b/gdbserver/debug.c @@ -0,0 +1,140 @@ +/* Debugging routines for the remote server for GDB. + Copyright (C) 2014-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include + +#if !defined (IN_PROCESS_AGENT) +int remote_debug = 0; +#endif + +/* Output file for debugging. Default to standard error. */ +FILE *debug_file = stderr; + +/* See debug.h. */ +int debug_threads; + +/* Include timestamps in debugging output. */ +int debug_timestamp; + +#if !defined (IN_PROCESS_AGENT) + +/* See debug.h. */ + +void +debug_set_output (const char *new_debug_file) +{ + /* Close any existing file and reset to standard error. */ + if (debug_file != stderr) + { + fclose (debug_file); + } + debug_file = stderr; + + /* Catch empty filenames. */ + if (new_debug_file == nullptr || strlen (new_debug_file) == 0) + return; + + FILE *fptr = fopen (new_debug_file, "w"); + + if (fptr == nullptr) + { + debug_printf ("Cannot open %s for writing. %s. Switching to stderr.\n", + new_debug_file, safe_strerror (errno)); + return; + } + + debug_file = fptr; +} + +#endif + +/* Print a debugging message. + If the text begins a new line it is preceded by a timestamp. + We don't get fancy with newline checking, we just check whether the + previous call ended with "\n". */ + +void +debug_vprintf (const char *format, va_list ap) +{ +#if !defined (IN_PROCESS_AGENT) + /* N.B. Not thread safe, and can't be used, as is, with IPA. */ + static int new_line = 1; + + if (debug_timestamp && new_line) + { + using namespace std::chrono; + + steady_clock::time_point now = steady_clock::now (); + seconds s = duration_cast (now.time_since_epoch ()); + microseconds us = duration_cast (now.time_since_epoch ()) - s; + + fprintf (debug_file, "%ld.%06ld ", (long) s.count (), (long) us.count ()); + } +#endif + + vfprintf (debug_file, format, ap); + +#if !defined (IN_PROCESS_AGENT) + if (*format) + new_line = format[strlen (format) - 1] == '\n'; +#endif +} + +/* Flush debugging output. + This is called, for example, when starting an inferior to ensure all debug + output thus far appears before any inferior output. */ + +void +debug_flush (void) +{ + fflush (debug_file); +} + +/* Notify the user that the code is entering FUNCTION_NAME. + FUNCTION_NAME is the name of the calling function, or NULL if unknown. + + This is intended to be called via the debug_enter macro. */ + +void +do_debug_enter (const char *function_name) +{ + if (function_name != NULL) + debug_printf (">>>> entering %s\n", function_name); +} + +/* Notify the user that the code is exiting FUNCTION_NAME. + FUNCTION_NAME is the name of the calling function, or NULL if unknown. + + This is intended to be called via the debug_exit macro. */ + +void +do_debug_exit (const char *function_name) +{ + if (function_name != NULL) + debug_printf ("<<<< exiting %s\n", function_name); +} + +/* See debug.h. */ + +ssize_t +debug_write (const void *buf, size_t nbyte) +{ + int fd = fileno (debug_file); + return write (fd, buf, nbyte); +} diff --git a/gdbserver/debug.h b/gdbserver/debug.h new file mode 100644 index 00000000000..b026ee734f6 --- /dev/null +++ b/gdbserver/debug.h @@ -0,0 +1,65 @@ +/* Debugging routines for the remote server for GDB. + Copyright (C) 2014-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_DEBUG_H +#define GDBSERVER_DEBUG_H + +#if !defined (IN_PROCESS_AGENT) +extern int remote_debug; + +/* Switch all debug output to DEBUG_FILE. If DEBUG_FILE is nullptr or an + empty string, or if the file cannot be opened, then debug output is sent to + stderr. */ +void debug_set_output (const char *debug_file); +#endif + +extern int using_threads; + +/* Enable miscellaneous debugging output. The name is historical - it + was originally used to debug LinuxThreads support. */ + +extern int debug_threads; + +extern int debug_timestamp; + +void debug_flush (void); +void do_debug_enter (const char *function_name); +void do_debug_exit (const char *function_name); + +/* Async signal safe debug output function that calls write directly. */ +ssize_t debug_write (const void *buf, size_t nbyte); + +/* These macros are for use in major functions that produce a lot of + debugging output. They help identify in the mass of debugging output + when these functions enter and exit. debug_enter is intended to be + called at the start of a function, before any other debugging output. + debug_exit is intended to be called at the end of the same function, + after all debugging output. */ +#ifdef FUNCTION_NAME +#define debug_enter() \ + do { do_debug_enter (FUNCTION_NAME); } while (0) +#define debug_exit() \ + do { do_debug_exit (FUNCTION_NAME); } while (0) +#else +#define debug_enter() \ + do { } while (0) +#define debug_exit() \ + do { } while (0) +#endif + +#endif /* GDBSERVER_DEBUG_H */ diff --git a/gdbserver/dll.c b/gdbserver/dll.c new file mode 100644 index 00000000000..fdc7becfbee --- /dev/null +++ b/gdbserver/dll.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "dll.h" + +#include + +/* An "unspecified" CORE_ADDR, for match_dll. */ +#define UNSPECIFIED_CORE_ADDR (~(CORE_ADDR) 0) + +std::list all_dlls; +int dlls_changed; + +/* Record a newly loaded DLL at BASE_ADDR. */ + +void +loaded_dll (const char *name, CORE_ADDR base_addr) +{ + all_dlls.emplace_back (name != NULL ? name : "", base_addr); + dlls_changed = 1; +} + +/* Record that the DLL with NAME and BASE_ADDR has been unloaded. */ + +void +unloaded_dll (const char *name, CORE_ADDR base_addr) +{ + auto pred = [&] (const dll_info &dll) + { + if (base_addr != UNSPECIFIED_CORE_ADDR + && base_addr == dll.base_addr) + return true; + + if (name != NULL && dll.name == name) + return true; + + return false; + }; + + auto iter = std::find_if (all_dlls.begin (), all_dlls.end (), pred); + + if (iter == all_dlls.end ()) + /* For some inferiors we might get unloaded_dll events without having + a corresponding loaded_dll. In that case, the dll cannot be found + in ALL_DLL, and there is nothing further for us to do. + + This has been observed when running 32bit executables on Windows64 + (i.e. through WOW64, the interface between the 32bits and 64bits + worlds). In that case, the inferior always does some strange + unloading of unnamed dll. */ + return; + else + { + /* DLL has been found so remove the entry and free associated + resources. */ + all_dlls.erase (iter); + dlls_changed = 1; + } +} + +void +clear_dlls (void) +{ + all_dlls.clear (); +} diff --git a/gdbserver/dll.h b/gdbserver/dll.h new file mode 100644 index 00000000000..63c1cd44d3b --- /dev/null +++ b/gdbserver/dll.h @@ -0,0 +1,40 @@ +/* Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_DLL_H +#define GDBSERVER_DLL_H + +#include + +struct dll_info +{ + dll_info (const std::string &name_, CORE_ADDR base_addr_) + : name (name_), base_addr (base_addr_) + {} + + std::string name; + CORE_ADDR base_addr; +}; + +extern std::list all_dlls; +extern int dlls_changed; + +extern void clear_dlls (void); +extern void loaded_dll (const char *name, CORE_ADDR base_addr); +extern void unloaded_dll (const char *name, CORE_ADDR base_addr); + +#endif /* GDBSERVER_DLL_H */ diff --git a/gdbserver/event-loop.c b/gdbserver/event-loop.c new file mode 100644 index 00000000000..8827e8a32eb --- /dev/null +++ b/gdbserver/event-loop.c @@ -0,0 +1,567 @@ +/* Event loop machinery for the remote server for GDB. + Copyright (C) 1999-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +/* Based on src/gdb/event-loop.c. */ + +#include "server.h" + +#include +#include "gdbsupport/gdb_sys_time.h" + +#ifdef USE_WIN32API +#include +#include +#endif + +#include +#include + +typedef int (event_handler_func) (gdb_fildes_t); + +/* Tell create_file_handler what events we are interested in. */ + +#define GDB_READABLE (1<<1) +#define GDB_WRITABLE (1<<2) +#define GDB_EXCEPTION (1<<3) + +/* Events are queued by on the event_queue and serviced later + on by do_one_event. An event can be, for instance, a file + descriptor becoming ready to be read. Servicing an event simply + means that the procedure PROC will be called. We have 2 queues, + one for file handlers that we listen to in the event loop, and one + for the file handlers+events that are ready. The procedure PROC + associated with each event is always the same (handle_file_event). + Its duty is to invoke the handler associated with the file + descriptor whose state change generated the event, plus doing other + cleanups and such. */ + +struct gdb_event + { + /* Procedure to call to service this event. */ + event_handler_func *proc; + + /* File descriptor that is ready. */ + gdb_fildes_t fd; + }; + +/* Information about each file descriptor we register with the event + loop. */ + +typedef struct file_handler + { + /* File descriptor. */ + gdb_fildes_t fd; + + /* Events we want to monitor. */ + int mask; + + /* Events that have been seen since the last time. */ + int ready_mask; + + /* Procedure to call when fd is ready. */ + handler_func *proc; + + /* Argument to pass to proc. */ + gdb_client_data client_data; + + /* Was an error detected on this fd? */ + int error; + + /* Next registered file descriptor. */ + struct file_handler *next_file; + } +file_handler; + +typedef gdb::unique_xmalloc_ptr gdb_event_up; + +static std::queue> event_queue; + +/* Gdb_notifier is just a list of file descriptors gdb is interested + in. These are the input file descriptor, and the target file + descriptor. Each of the elements in the gdb_notifier list is + basically a description of what kind of events gdb is interested + in, for each fd. */ + +static struct + { + /* Ptr to head of file handler list. */ + file_handler *first_file_handler; + + /* Masks to be used in the next call to select. Bits are set in + response to calls to create_file_handler. */ + fd_set check_masks[3]; + + /* What file descriptors were found ready by select. */ + fd_set ready_masks[3]; + + /* Number of valid bits (highest fd value + 1). (for select) */ + int num_fds; + } +gdb_notifier; + +/* Callbacks are just routines that are executed before waiting for the + next event. In GDB this is struct gdb_timer. We don't need timers + so rather than copy all that complexity in gdbserver, we provide what + we need, but we do so in a way that if/when the day comes that we need + that complexity, it'll be easier to add - replace callbacks with timers + and use a delta of zero (which is all gdb currently uses timers for anyway). + + PROC will be executed before gdbserver goes to sleep to wait for the + next event. */ + +struct callback_event + { + int id; + callback_handler_func *proc; + gdb_client_data data; + struct callback_event *next; + }; + +/* Table of registered callbacks. */ + +static struct + { + struct callback_event *first; + struct callback_event *last; + + /* Id of the last callback created. */ + int num_callbacks; + } +callback_list; + +void +initialize_event_loop (void) +{ +} + +/* Process one event. If an event was processed, 1 is returned + otherwise 0 is returned. Scan the queue from head to tail, + processing therefore the high priority events first, by invoking + the associated event handler procedure. */ + +static int +process_event (void) +{ + /* Let's get rid of the event from the event queue. We need to + do this now because while processing the event, since the + proc function could end up jumping out to the caller of this + function. In that case, we would have on the event queue an + event which has been processed, but not deleted. */ + if (!event_queue.empty ()) + { + gdb_event_up event_ptr = std::move (event_queue.front ()); + event_queue.pop (); + + event_handler_func *proc = event_ptr->proc; + gdb_fildes_t fd = event_ptr->fd; + + /* Now call the procedure associated with the event. */ + if ((*proc) (fd)) + return -1; + return 1; + } + + /* This is the case if there are no event on the event queue. */ + return 0; +} + +/* Append PROC to the callback list. + The result is the "id" of the callback that can be passed back to + delete_callback_event. */ + +int +append_callback_event (callback_handler_func *proc, gdb_client_data data) +{ + struct callback_event *event_ptr = XNEW (struct callback_event); + + event_ptr->id = callback_list.num_callbacks++; + event_ptr->proc = proc; + event_ptr->data = data; + event_ptr->next = NULL; + if (callback_list.first == NULL) + callback_list.first = event_ptr; + if (callback_list.last != NULL) + callback_list.last->next = event_ptr; + callback_list.last = event_ptr; + return event_ptr->id; +} + +/* Delete callback ID. + It is not an error callback ID doesn't exist. */ + +void +delete_callback_event (int id) +{ + struct callback_event **p; + + for (p = &callback_list.first; *p != NULL; p = &(*p)->next) + { + struct callback_event *event_ptr = *p; + + if (event_ptr->id == id) + { + *p = event_ptr->next; + if (event_ptr == callback_list.last) + callback_list.last = NULL; + free (event_ptr); + break; + } + } +} + +/* Run the next callback. + The result is 1 if a callback was called and event processing + should continue, -1 if the callback wants the event loop to exit, + and 0 if there are no more callbacks. */ + +static int +process_callback (void) +{ + struct callback_event *event_ptr; + + event_ptr = callback_list.first; + if (event_ptr != NULL) + { + callback_handler_func *proc = event_ptr->proc; + gdb_client_data data = event_ptr->data; + + /* Remove the event before calling PROC, + more events may get added by PROC. */ + callback_list.first = event_ptr->next; + if (callback_list.first == NULL) + callback_list.last = NULL; + free (event_ptr); + if ((*proc) (data)) + return -1; + return 1; + } + + return 0; +} + +/* Add a file handler/descriptor to the list of descriptors we are + interested in. FD is the file descriptor for the file/stream to be + listened to. MASK is a combination of READABLE, WRITABLE, + EXCEPTION. PROC is the procedure that will be called when an event + occurs for FD. CLIENT_DATA is the argument to pass to PROC. */ + +static void +create_file_handler (gdb_fildes_t fd, int mask, handler_func *proc, + gdb_client_data client_data) +{ + file_handler *file_ptr; + + /* Do we already have a file handler for this file? (We may be + changing its associated procedure). */ + for (file_ptr = gdb_notifier.first_file_handler; + file_ptr != NULL; + file_ptr = file_ptr->next_file) + if (file_ptr->fd == fd) + break; + + /* It is a new file descriptor. Add it to the list. Otherwise, + just change the data associated with it. */ + if (file_ptr == NULL) + { + file_ptr = XNEW (struct file_handler); + file_ptr->fd = fd; + file_ptr->ready_mask = 0; + file_ptr->next_file = gdb_notifier.first_file_handler; + gdb_notifier.first_file_handler = file_ptr; + + if (mask & GDB_READABLE) + FD_SET (fd, &gdb_notifier.check_masks[0]); + else + FD_CLR (fd, &gdb_notifier.check_masks[0]); + + if (mask & GDB_WRITABLE) + FD_SET (fd, &gdb_notifier.check_masks[1]); + else + FD_CLR (fd, &gdb_notifier.check_masks[1]); + + if (mask & GDB_EXCEPTION) + FD_SET (fd, &gdb_notifier.check_masks[2]); + else + FD_CLR (fd, &gdb_notifier.check_masks[2]); + + if (gdb_notifier.num_fds <= fd) + gdb_notifier.num_fds = fd + 1; + } + + file_ptr->proc = proc; + file_ptr->client_data = client_data; + file_ptr->mask = mask; +} + +/* Wrapper function for create_file_handler. */ + +void +add_file_handler (gdb_fildes_t fd, + handler_func *proc, gdb_client_data client_data) +{ + create_file_handler (fd, GDB_READABLE | GDB_EXCEPTION, proc, client_data); +} + +/* Remove the file descriptor FD from the list of monitored fd's: + i.e. we don't care anymore about events on the FD. */ + +void +delete_file_handler (gdb_fildes_t fd) +{ + file_handler *file_ptr, *prev_ptr = NULL; + int i; + + /* Find the entry for the given file. */ + + for (file_ptr = gdb_notifier.first_file_handler; + file_ptr != NULL; + file_ptr = file_ptr->next_file) + if (file_ptr->fd == fd) + break; + + if (file_ptr == NULL) + return; + + if (file_ptr->mask & GDB_READABLE) + FD_CLR (fd, &gdb_notifier.check_masks[0]); + if (file_ptr->mask & GDB_WRITABLE) + FD_CLR (fd, &gdb_notifier.check_masks[1]); + if (file_ptr->mask & GDB_EXCEPTION) + FD_CLR (fd, &gdb_notifier.check_masks[2]); + + /* Find current max fd. */ + + if ((fd + 1) == gdb_notifier.num_fds) + { + gdb_notifier.num_fds--; + for (i = gdb_notifier.num_fds; i; i--) + { + if (FD_ISSET (i - 1, &gdb_notifier.check_masks[0]) + || FD_ISSET (i - 1, &gdb_notifier.check_masks[1]) + || FD_ISSET (i - 1, &gdb_notifier.check_masks[2])) + break; + } + gdb_notifier.num_fds = i; + } + + /* Deactivate the file descriptor, by clearing its mask, so that it + will not fire again. */ + + file_ptr->mask = 0; + + /* Get rid of the file handler in the file handler list. */ + if (file_ptr == gdb_notifier.first_file_handler) + gdb_notifier.first_file_handler = file_ptr->next_file; + else + { + for (prev_ptr = gdb_notifier.first_file_handler; + prev_ptr->next_file != file_ptr; + prev_ptr = prev_ptr->next_file) + ; + prev_ptr->next_file = file_ptr->next_file; + } + free (file_ptr); +} + +/* Handle the given event by calling the procedure associated to the + corresponding file handler. Called by process_event indirectly, + through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the + event in the front of the event queue. */ + +static int +handle_file_event (gdb_fildes_t event_file_desc) +{ + file_handler *file_ptr; + int mask; + + /* Search the file handler list to find one that matches the fd in + the event. */ + for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL; + file_ptr = file_ptr->next_file) + { + if (file_ptr->fd == event_file_desc) + { + /* See if the desired events (mask) match the received + events (ready_mask). */ + + if (file_ptr->ready_mask & GDB_EXCEPTION) + { + warning ("Exception condition detected on fd %s", + pfildes (file_ptr->fd)); + file_ptr->error = 1; + } + else + file_ptr->error = 0; + mask = file_ptr->ready_mask & file_ptr->mask; + + /* Clear the received events for next time around. */ + file_ptr->ready_mask = 0; + + /* If there was a match, then call the handler. */ + if (mask != 0) + { + if ((*file_ptr->proc) (file_ptr->error, + file_ptr->client_data) < 0) + return -1; + } + break; + } + } + + return 0; +} + +/* Create a file event, to be enqueued in the event queue for + processing. The procedure associated to this event is always + handle_file_event, which will in turn invoke the one that was + associated to FD when it was registered with the event loop. */ + +static gdb_event * +create_file_event (gdb_fildes_t fd) +{ + gdb_event *file_event_ptr; + + file_event_ptr = XNEW (gdb_event); + file_event_ptr->proc = handle_file_event; + file_event_ptr->fd = fd; + + return file_event_ptr; +} + +/* Called by do_one_event to wait for new events on the monitored file + descriptors. Queue file events as they are detected by the poll. + If there are no events, this function will block in the call to + select. Return -1 if there are no files descriptors to monitor, + otherwise return 0. */ + +static int +wait_for_event (void) +{ + file_handler *file_ptr; + int num_found = 0; + + /* Make sure all output is done before getting another event. */ + fflush (stdout); + fflush (stderr); + + if (gdb_notifier.num_fds == 0) + return -1; + + gdb_notifier.ready_masks[0] = gdb_notifier.check_masks[0]; + gdb_notifier.ready_masks[1] = gdb_notifier.check_masks[1]; + gdb_notifier.ready_masks[2] = gdb_notifier.check_masks[2]; + num_found = select (gdb_notifier.num_fds, + &gdb_notifier.ready_masks[0], + &gdb_notifier.ready_masks[1], + &gdb_notifier.ready_masks[2], + NULL); + + /* Clear the masks after an error from select. */ + if (num_found == -1) + { + FD_ZERO (&gdb_notifier.ready_masks[0]); + FD_ZERO (&gdb_notifier.ready_masks[1]); + FD_ZERO (&gdb_notifier.ready_masks[2]); +#ifdef EINTR + /* Dont print anything if we got a signal, let gdb handle + it. */ + if (errno != EINTR) + perror_with_name ("select"); +#endif + } + + /* Enqueue all detected file events. */ + + for (file_ptr = gdb_notifier.first_file_handler; + file_ptr != NULL && num_found > 0; + file_ptr = file_ptr->next_file) + { + int mask = 0; + + if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[0])) + mask |= GDB_READABLE; + if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[1])) + mask |= GDB_WRITABLE; + if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[2])) + mask |= GDB_EXCEPTION; + + if (!mask) + continue; + else + num_found--; + + /* Enqueue an event only if this is still a new event for this + fd. */ + + if (file_ptr->ready_mask == 0) + { + gdb_event *file_event_ptr = create_file_event (file_ptr->fd); + + event_queue.emplace (file_event_ptr); + } + file_ptr->ready_mask = mask; + } + + return 0; +} + +/* Start up the event loop. This is the entry point to the event + loop. */ + +void +start_event_loop (void) +{ + /* Loop until there is nothing to do. This is the entry point to + the event loop engine. If nothing is ready at this time, wait + for something to happen (via wait_for_event), then process it. + Return when there are no longer event sources to wait for. */ + + while (1) + { + /* Any events already waiting in the queue? */ + int res = process_event (); + + /* Did the event handler want the event loop to stop? */ + if (res == -1) + return; + + if (res) + continue; + + /* Process any queued callbacks before we go to sleep. */ + res = process_callback (); + + /* Did the callback want the event loop to stop? */ + if (res == -1) + return; + + if (res) + continue; + + /* Wait for a new event. If wait_for_event returns -1, we + should get out because this means that there are no event + sources left. This will make the event loop stop, and the + application exit. */ + + if (wait_for_event () < 0) + return; + } + + /* We are done with the event loop. There are no more event sources + to listen to. So we exit gdbserver. */ +} diff --git a/gdbserver/event-loop.h b/gdbserver/event-loop.h new file mode 100644 index 00000000000..a49173e867d --- /dev/null +++ b/gdbserver/event-loop.h @@ -0,0 +1,36 @@ +/* Event loop machinery for the remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_EVENT_LOOP_H +#define GDBSERVER_EVENT_LOOP_H + +typedef void *gdb_client_data; +typedef int (handler_func) (int, gdb_client_data); +typedef int (callback_handler_func) (gdb_client_data); + +extern void delete_file_handler (gdb_fildes_t fd); +extern void add_file_handler (gdb_fildes_t fd, handler_func *proc, + gdb_client_data client_data); +extern int append_callback_event (callback_handler_func *proc, + gdb_client_data client_data); +extern void delete_callback_event (int id); + +extern void start_event_loop (void); +extern void initialize_event_loop (void); + +#endif /* GDBSERVER_EVENT_LOOP_H */ diff --git a/gdbserver/fork-child.c b/gdbserver/fork-child.c new file mode 100644 index 00000000000..7a71ec0b1ca --- /dev/null +++ b/gdbserver/fork-child.c @@ -0,0 +1,119 @@ +/* Fork a Unix child process, and set up to debug it, for GDBserver. + Copyright (C) 1989-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "gdbsupport/job-control.h" +#include "nat/fork-inferior.h" +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef SIGTTOU +/* A file descriptor for the controlling terminal. */ +static int terminal_fd; + +/* TERMINAL_FD's original foreground group. */ +static pid_t old_foreground_pgrp; + +/* Hand back terminal ownership to the original foreground group. */ + +static void +restore_old_foreground_pgrp (void) +{ + tcsetpgrp (terminal_fd, old_foreground_pgrp); +} +#endif + +/* See nat/fork-inferior.h. */ + +void +prefork_hook (const char *args) +{ + client_state &cs = get_client_state (); + if (debug_threads) + { + debug_printf ("args: %s\n", args); + debug_flush (); + } + +#ifdef SIGTTOU + signal (SIGTTOU, SIG_DFL); + signal (SIGTTIN, SIG_DFL); +#endif + + /* Clear this so the backend doesn't get confused, thinking + CONT_THREAD died, and it needs to resume all threads. */ + cs.cont_thread = null_ptid; +} + +/* See nat/fork-inferior.h. */ + +void +postfork_hook (pid_t pid) +{ +} + +/* See nat/fork-inferior.h. */ + +void +postfork_child_hook () +{ + /* This is set to the result of setpgrp, which if vforked, will be + visible to you in the parent process. It's only used by humans + for debugging. */ + static int debug_setpgrp = 657473; + + debug_setpgrp = gdb_setpgid (); + if (debug_setpgrp == -1) + perror (_("setpgrp failed in child")); +} + +/* See nat/fork-inferior.h. */ + +void +gdb_flush_out_err () +{ + fflush (stdout); + fflush (stderr); +} + +/* See server.h. */ + +void +post_fork_inferior (int pid, const char *program) +{ + client_state &cs = get_client_state (); +#ifdef SIGTTOU + signal (SIGTTOU, SIG_IGN); + signal (SIGTTIN, SIG_IGN); + terminal_fd = fileno (stderr); + old_foreground_pgrp = tcgetpgrp (terminal_fd); + tcsetpgrp (terminal_fd, pid); + atexit (restore_old_foreground_pgrp); +#endif + + startup_inferior (the_target, pid, + START_INFERIOR_TRAPS_EXPECTED, + &cs.last_status, &cs.last_ptid); + current_thread->last_resume_kind = resume_stop; + current_thread->last_status = cs.last_status; + signal_pid = pid; + target_post_create_inferior (); + fprintf (stderr, "Process %s created; pid = %d\n", program, pid); + fflush (stderr); +} diff --git a/gdbserver/gdb_proc_service.h b/gdbserver/gdb_proc_service.h new file mode 100644 index 00000000000..bf657e76e49 --- /dev/null +++ b/gdbserver/gdb_proc_service.h @@ -0,0 +1,31 @@ +/* replacement for systems that don't have it. + Copyright (C) 2000-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_GDB_PROC_SERVICE_H +#define GDBSERVER_GDB_PROC_SERVICE_H + +#include "gdbsupport/gdb_proc_service.h" + +/* Structure that identifies the target process. */ +struct ps_prochandle +{ + /* We don't need to track anything. All context is served from the + current inferior. */ +}; + +#endif /* GDBSERVER_GDB_PROC_SERVICE_H */ diff --git a/gdbserver/gdbreplay.c b/gdbserver/gdbreplay.c new file mode 100644 index 00000000000..263fb0efeac --- /dev/null +++ b/gdbserver/gdbreplay.c @@ -0,0 +1,532 @@ +/* Replay a remote debug session logfile for GDB. + Copyright (C) 1996-2020 Free Software Foundation, Inc. + Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver. + + 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 3 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, see . */ + +#include "gdbsupport/common-defs.h" + +#undef PACKAGE +#undef PACKAGE_NAME +#undef PACKAGE_VERSION +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME + +#include +#include "gdbsupport/version.h" + +#if HAVE_SYS_FILE_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif +#include +#if HAVE_FCNTL_H +#include +#endif +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#if HAVE_NETINET_TCP_H +#include +#endif + +#if USE_WIN32API +#include +#endif + +#include "gdbsupport/netstuff.h" +#include "gdbsupport/rsp-low.h" + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +/* Sort of a hack... */ +#define EOL (EOF - 1) + +static int remote_desc; + +#ifdef __MINGW32CE__ + +#ifndef COUNTOF +#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0])) +#endif + +#define errno (GetLastError ()) + +char * +strerror (DWORD error) +{ + static char buf[1024]; + WCHAR *msgbuf; + DWORD lasterr = GetLastError (); + DWORD chars = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) + { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' + && msgbuf[chars - 1] == '\n') + { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > ((COUNTOF (buf)) - 1)) + { + chars = COUNTOF (buf) - 1; + msgbuf [chars] = 0; + } + + wcstombs (buf, msgbuf, chars + 1); + LocalFree (msgbuf); + } + else + sprintf (buf, "unknown win32 error (%ld)", error); + + SetLastError (lasterr); + return buf; +} + +#endif /* __MINGW32CE__ */ + +static void +sync_error (FILE *fp, const char *desc, int expect, int got) +{ + fprintf (stderr, "\n%s\n", desc); + fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n", + ftell (fp), expect, got); + fflush (stderr); + exit (1); +} + +static void +remote_error (const char *desc) +{ + fprintf (stderr, "\n%s\n", desc); + fflush (stderr); + exit (1); +} + +static void +remote_close (void) +{ +#ifdef USE_WIN32API + closesocket (remote_desc); +#else + close (remote_desc); +#endif +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static void +remote_open (char *name) +{ + char *last_colon = strrchr (name, ':'); + + if (last_colon == NULL) + { + fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name); + fflush (stderr); + exit (1); + } + +#ifdef USE_WIN32API + static int winsock_initialized; +#endif + int tmp; + int tmp_desc; + struct addrinfo hint; + struct addrinfo *ainfo; + + memset (&hint, 0, sizeof (hint)); + /* Assume no prefix will be passed, therefore we should use + AF_UNSPEC. */ + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = IPPROTO_TCP; + + parsed_connection_spec parsed = parse_connection_spec (name, &hint); + + if (parsed.port_str.empty ()) + error (_("Missing port on hostname '%s'"), name); + +#ifdef USE_WIN32API + if (!winsock_initialized) + { + WSADATA wsad; + + WSAStartup (MAKEWORD (1, 0), &wsad); + winsock_initialized = 1; + } +#endif + + int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (), + &hint, &ainfo); + + if (r != 0) + { + fprintf (stderr, "%s:%s: cannot resolve name: %s\n", + parsed.host_str.c_str (), parsed.port_str.c_str (), + gai_strerror (r)); + fflush (stderr); + exit (1); + } + + scoped_free_addrinfo free_ainfo (ainfo); + + struct addrinfo *p; + + for (p = ainfo; p != NULL; p = p->ai_next) + { + tmp_desc = socket (p->ai_family, p->ai_socktype, p->ai_protocol); + + if (tmp_desc >= 0) + break; + } + + if (p == NULL) + perror_with_name ("Cannot open socket"); + + /* Allow rapid reuse of this port. */ + tmp = 1; + setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, + sizeof (tmp)); + + switch (p->ai_family) + { + case AF_INET: + ((struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr = INADDR_ANY; + break; + case AF_INET6: + ((struct sockaddr_in6 *) p->ai_addr)->sin6_addr = in6addr_any; + break; + default: + fprintf (stderr, "Invalid 'ai_family' %d\n", p->ai_family); + exit (1); + } + + if (bind (tmp_desc, p->ai_addr, p->ai_addrlen) != 0) + perror_with_name ("Can't bind address"); + + if (p->ai_socktype == SOCK_DGRAM) + remote_desc = tmp_desc; + else + { + struct sockaddr_storage sockaddr; + socklen_t sockaddrsize = sizeof (sockaddr); + char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT]; + + if (listen (tmp_desc, 1) != 0) + perror_with_name ("Can't listen on socket"); + + remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, + &sockaddrsize); + + if (remote_desc == -1) + perror_with_name ("Accept failed"); + + /* Enable TCP keep alive process. */ + tmp = 1; + setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, + (char *) &tmp, sizeof (tmp)); + + /* Tell TCP not to delay small packets. This greatly speeds up + interactive response. */ + tmp = 1; + setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (tmp)); + + if (getnameinfo ((struct sockaddr *) &sockaddr, sockaddrsize, + orig_host, sizeof (orig_host), + orig_port, sizeof (orig_port), + NI_NUMERICHOST | NI_NUMERICSERV) == 0) + { + fprintf (stderr, "Remote debugging from host %s, port %s\n", + orig_host, orig_port); + fflush (stderr); + } + +#ifndef USE_WIN32API + close (tmp_desc); /* No longer need this */ + + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then + gdbreplay simply exits when + the remote side dies. */ +#else + closesocket (tmp_desc); /* No longer need this */ +#endif + } + +#if defined(F_SETFL) && defined (FASYNC) + fcntl (remote_desc, F_SETFL, FASYNC); +#endif + + fprintf (stderr, "Replay logfile using %s\n", name); + fflush (stderr); +} + +static int +logchar (FILE *fp) +{ + int ch; + int ch2; + + ch = fgetc (fp); + if (ch != '\r') + { + fputc (ch, stdout); + fflush (stdout); + } + switch (ch) + { + /* Treat \r\n as a newline. */ + case '\r': + ch = fgetc (fp); + if (ch == '\n') + ch = EOL; + else + { + ungetc (ch, fp); + ch = '\r'; + } + fputc (ch == EOL ? '\n' : '\r', stdout); + fflush (stdout); + break; + case '\n': + ch = EOL; + break; + case '\\': + ch = fgetc (fp); + fputc (ch, stdout); + fflush (stdout); + switch (ch) + { + case '\\': + break; + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case 'v': + ch = '\v'; + break; + case 'x': + ch2 = fgetc (fp); + fputc (ch2, stdout); + fflush (stdout); + ch = fromhex (ch2) << 4; + ch2 = fgetc (fp); + fputc (ch2, stdout); + fflush (stdout); + ch |= fromhex (ch2); + break; + default: + /* Treat any other char as just itself */ + break; + } + default: + break; + } + return (ch); +} + +static int +gdbchar (int desc) +{ + unsigned char fromgdb; + + if (read (desc, &fromgdb, 1) != 1) + return -1; + else + return fromgdb; +} + +/* Accept input from gdb and match with chars from fp (after skipping one + blank) up until a \n is read from fp (which is not matched) */ + +static void +expect (FILE *fp) +{ + int fromlog; + int fromgdb; + + if ((fromlog = logchar (fp)) != ' ') + { + sync_error (fp, "Sync error during gdb read of leading blank", ' ', + fromlog); + } + do + { + fromlog = logchar (fp); + if (fromlog == EOL) + break; + fromgdb = gdbchar (remote_desc); + if (fromgdb < 0) + remote_error ("Error during read from gdb"); + } + while (fromlog == fromgdb); + + if (fromlog != EOL) + { + sync_error (fp, "Sync error during read of gdb packet from log", fromlog, + fromgdb); + } +} + +/* Play data back to gdb from fp (after skipping leading blank) up until a + \n is read from fp (which is discarded and not sent to gdb). */ + +static void +play (FILE *fp) +{ + int fromlog; + char ch; + + if ((fromlog = logchar (fp)) != ' ') + { + sync_error (fp, "Sync error skipping blank during write to gdb", ' ', + fromlog); + } + while ((fromlog = logchar (fp)) != EOL) + { + ch = fromlog; + if (write (remote_desc, &ch, 1) != 1) + remote_error ("Error during write to gdb"); + } +} + +static void +gdbreplay_version (void) +{ + printf ("GNU gdbreplay %s%s\n" + "Copyright (C) 2020 Free Software Foundation, Inc.\n" + "gdbreplay is free software, covered by " + "the GNU General Public License.\n" + "This gdbreplay was configured as \"%s\"\n", + PKGVERSION, version, host_name); +} + +static void +gdbreplay_usage (FILE *stream) +{ + fprintf (stream, "Usage:\tgdbreplay LOGFILE HOST:PORT\n"); + if (REPORT_BUGS_TO[0] && stream == stdout) + fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO); +} + +/* Main function. This is called by the real "main" function, + wrapped in a TRY_CATCH that handles any uncaught exceptions. */ + +static void ATTRIBUTE_NORETURN +captured_main (int argc, char *argv[]) +{ + FILE *fp; + int ch; + + if (argc >= 2 && strcmp (argv[1], "--version") == 0) + { + gdbreplay_version (); + exit (0); + } + if (argc >= 2 && strcmp (argv[1], "--help") == 0) + { + gdbreplay_usage (stdout); + exit (0); + } + + if (argc < 3) + { + gdbreplay_usage (stderr); + exit (1); + } + fp = fopen (argv[1], "r"); + if (fp == NULL) + { + perror_with_name (argv[1]); + } + remote_open (argv[2]); + while ((ch = logchar (fp)) != EOF) + { + switch (ch) + { + case 'w': + /* data sent from gdb to gdbreplay, accept and match it */ + expect (fp); + break; + case 'r': + /* data sent from gdbreplay to gdb, play it */ + play (fp); + break; + case 'c': + /* Command executed by gdb */ + while ((ch = logchar (fp)) != EOL); + break; + } + } + remote_close (); + exit (0); +} + +int +main (int argc, char *argv[]) +{ + try + { + captured_main (argc, argv); + } + catch (const gdb_exception &exception) + { + if (exception.reason == RETURN_ERROR) + { + fflush (stdout); + fprintf (stderr, "%s\n", exception.what ()); + } + + exit (1); + } + + gdb_assert_not_reached ("captured_main should never return"); +} diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h new file mode 100644 index 00000000000..68762517c98 --- /dev/null +++ b/gdbserver/gdbthread.h @@ -0,0 +1,227 @@ +/* Multi-thread control defs for remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_GDBTHREAD_H +#define GDBSERVER_GDBTHREAD_H + +#include "gdbsupport/common-gdbthread.h" +#include "inferiors.h" + +#include + +struct btrace_target_info; +struct regcache; + +struct thread_info +{ + /* The id of this thread. */ + ptid_t id; + + void *target_data; + struct regcache *regcache_data; + + /* The last resume GDB requested on this thread. */ + enum resume_kind last_resume_kind; + + /* The last wait status reported for this thread. */ + struct target_waitstatus last_status; + + /* True if LAST_STATUS hasn't been reported to GDB yet. */ + int status_pending_p; + + /* Given `while-stepping', a thread may be collecting data for more + than one tracepoint simultaneously. E.g.: + + ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs + ff0002 INSN2 + ff0003 INSN3 <-- TP2, collect $regs + ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs + ff0005 INSN5 + + Notice that when instruction INSN5 is reached, the while-stepping + actions of both TP1 and TP3 are still being collected, and that TP2 + had been collected meanwhile. The whole range of ff0001-ff0005 + should be single-stepped, due to at least TP1's while-stepping + action covering the whole range. + + On the other hand, the same tracepoint with a while-stepping action + may be hit by more than one thread simultaneously, hence we can't + keep the current step count in the tracepoint itself. + + This is the head of the list of the states of `while-stepping' + tracepoint actions this thread is now collecting; NULL if empty. + Each item in the list holds the current step of the while-stepping + action. */ + struct wstep_state *while_stepping; + + /* Branch trace target information for this thread. */ + struct btrace_target_info *btrace; +}; + +extern std::list all_threads; + +void remove_thread (struct thread_info *thread); +struct thread_info *add_thread (ptid_t ptid, void *target_data); + +/* Return a pointer to the first thread, or NULL if there isn't one. */ + +struct thread_info *get_first_thread (void); + +struct thread_info *find_thread_ptid (ptid_t ptid); + +/* Find any thread of the PID process. Returns NULL if none is + found. */ +struct thread_info *find_any_thread_of_pid (int pid); + +/* Find the first thread for which FUNC returns true. Return NULL if no thread + satisfying FUNC is found. */ + +template +static thread_info * +find_thread (Func func) +{ + std::list::iterator next, cur = all_threads.begin (); + + while (cur != all_threads.end ()) + { + next = cur; + next++; + + if (func (*cur)) + return *cur; + + cur = next; + } + + return NULL; +} + +/* Like the above, but only consider threads with pid PID. */ + +template +static thread_info * +find_thread (int pid, Func func) +{ + return find_thread ([&] (thread_info *thread) + { + return thread->id.pid () == pid && func (thread); + }); +} + +/* Find the first thread that matches FILTER for which FUNC returns true. + Return NULL if no thread satisfying these conditions is found. */ + +template +static thread_info * +find_thread (ptid_t filter, Func func) +{ + return find_thread ([&] (thread_info *thread) { + return thread->id.matches (filter) && func (thread); + }); +} + +/* Invoke FUNC for each thread. */ + +template +static void +for_each_thread (Func func) +{ + std::list::iterator next, cur = all_threads.begin (); + + while (cur != all_threads.end ()) + { + next = cur; + next++; + func (*cur); + cur = next; + } +} + +/* Like the above, but only consider threads with pid PID. */ + +template +static void +for_each_thread (int pid, Func func) +{ + for_each_thread ([&] (thread_info *thread) + { + if (pid == thread->id.pid ()) + func (thread); + }); +} + +/* Find the a random thread for which FUNC (THREAD) returns true. If + no entry is found then return NULL. */ + +template +static thread_info * +find_thread_in_random (Func func) +{ + int count = 0; + int random_selector; + + /* First count how many interesting entries we have. */ + for_each_thread ([&] (thread_info *thread) { + if (func (thread)) + count++; + }); + + if (count == 0) + return NULL; + + /* Now randomly pick an entry out of those. */ + random_selector = (int) + ((count * (double) rand ()) / (RAND_MAX + 1.0)); + + thread_info *thread = find_thread ([&] (thread_info *thr_arg) { + return func (thr_arg) && (random_selector-- == 0); + }); + + gdb_assert (thread != NULL); + + return thread; +} + +/* Get current thread ID (Linux task ID). */ +#define current_ptid (current_thread->id) + +/* Get the ptid of THREAD. */ + +static inline ptid_t +ptid_of (const thread_info *thread) +{ + return thread->id; +} + +/* Get the pid of THREAD. */ + +static inline int +pid_of (const thread_info *thread) +{ + return thread->id.pid (); +} + +/* Get the lwp of THREAD. */ + +static inline long +lwpid_of (const thread_info *thread) +{ + return thread->id.lwp (); +} + +#endif /* GDBSERVER_GDBTHREAD_H */ diff --git a/gdbserver/hostio-errno.c b/gdbserver/hostio-errno.c new file mode 100644 index 00000000000..b75e64d212e --- /dev/null +++ b/gdbserver/hostio-errno.c @@ -0,0 +1,36 @@ +/* Host file transfer support for gdbserver. + Copyright (C) 2007-2020 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 3 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, see . */ + +/* This file implements the hostio_last_error target callback + on top of errno. */ + +#include "server.h" + +#include "hostio.h" + +#include "gdbsupport/fileio.h" + +void +hostio_last_error_from_errno (char *buf) +{ + int error = errno; + int fileio_error = host_to_fileio_error (error); + sprintf (buf, "F-1,%x", fileio_error); +} diff --git a/gdbserver/hostio.c b/gdbserver/hostio.c new file mode 100644 index 00000000000..8af4fbf4087 --- /dev/null +++ b/gdbserver/hostio.c @@ -0,0 +1,620 @@ +/* Host file transfer support for gdbserver. + Copyright (C) 2007-2020 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 3 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, see . */ + +#include "server.h" +#include "gdb/fileio.h" +#include "hostio.h" + +#include +#include +#include +#include +#include +#include "gdbsupport/fileio.h" + +struct fd_list +{ + int fd; + struct fd_list *next; +}; + +static struct fd_list *open_fds; + +static int +safe_fromhex (char a, int *nibble) +{ + if (a >= '0' && a <= '9') + *nibble = a - '0'; + else if (a >= 'a' && a <= 'f') + *nibble = a - 'a' + 10; + else if (a >= 'A' && a <= 'F') + *nibble = a - 'A' + 10; + else + return -1; + + return 0; +} + +/* Filenames are hex encoded, so the maximum we can handle is half the + packet buffer size. Cap to PATH_MAX, if it is shorter. */ +#if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1)) +# define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1) +#else +# define HOSTIO_PATH_MAX PATH_MAX +#endif + +static int +require_filename (char **pp, char *filename) +{ + int count; + char *p; + + p = *pp; + count = 0; + + while (*p && *p != ',') + { + int nib1, nib2; + + /* Don't allow overflow. */ + if (count >= HOSTIO_PATH_MAX - 1) + return -1; + + if (safe_fromhex (p[0], &nib1) + || safe_fromhex (p[1], &nib2)) + return -1; + + filename[count++] = nib1 * 16 + nib2; + p += 2; + } + + filename[count] = '\0'; + *pp = p; + return 0; +} + +static int +require_int (char **pp, int *value) +{ + char *p; + int count, firstdigit; + + p = *pp; + *value = 0; + count = 0; + firstdigit = -1; + + while (*p && *p != ',') + { + int nib; + + if (safe_fromhex (p[0], &nib)) + return -1; + + if (firstdigit == -1) + firstdigit = nib; + + /* Don't allow overflow. */ + if (count >= 8 || (count == 7 && firstdigit >= 0x8)) + return -1; + + *value = *value * 16 + nib; + p++; + count++; + } + + *pp = p; + return 0; +} + +static int +require_data (char *p, int p_len, char **data, int *data_len) +{ + int input_index, output_index, escaped; + + *data = (char *) xmalloc (p_len); + + output_index = 0; + escaped = 0; + for (input_index = 0; input_index < p_len; input_index++) + { + char b = p[input_index]; + + if (escaped) + { + (*data)[output_index++] = b ^ 0x20; + escaped = 0; + } + else if (b == '}') + escaped = 1; + else + (*data)[output_index++] = b; + } + + if (escaped) + { + free (*data); + return -1; + } + + *data_len = output_index; + return 0; +} + +static int +require_comma (char **pp) +{ + if (**pp == ',') + { + (*pp)++; + return 0; + } + else + return -1; +} + +static int +require_end (char *p) +{ + if (*p == '\0') + return 0; + else + return -1; +} + +static int +require_valid_fd (int fd) +{ + struct fd_list *fd_ptr; + + for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next) + if (fd_ptr->fd == fd) + return 0; + + return -1; +} + +/* Fill in own_buf with the last hostio error packet, however it + suitable for the target. */ +static void +hostio_error (char *own_buf) +{ + the_target->hostio_last_error (own_buf); +} + +static void +hostio_packet_error (char *own_buf) +{ + sprintf (own_buf, "F-1,%x", FILEIO_EINVAL); +} + +static void +hostio_reply (char *own_buf, int result) +{ + sprintf (own_buf, "F%x", result); +} + +static int +hostio_reply_with_data (char *own_buf, char *buffer, int len, + int *new_packet_len) +{ + int input_index, output_index, out_maxlen; + + sprintf (own_buf, "F%x;", len); + output_index = strlen (own_buf); + + out_maxlen = PBUFSIZ; + + for (input_index = 0; input_index < len; input_index++) + { + char b = buffer[input_index]; + + if (b == '$' || b == '#' || b == '}' || b == '*') + { + /* These must be escaped. */ + if (output_index + 2 > out_maxlen) + break; + own_buf[output_index++] = '}'; + own_buf[output_index++] = b ^ 0x20; + } + else + { + if (output_index + 1 > out_maxlen) + break; + own_buf[output_index++] = b; + } + } + + *new_packet_len = output_index; + return input_index; +} + +/* Process ID of inferior whose filesystem hostio functions + that take FILENAME arguments will use. Zero means to use + our own filesystem. */ + +static int hostio_fs_pid; + +/* See hostio.h. */ + +void +hostio_handle_new_gdb_connection (void) +{ + hostio_fs_pid = 0; +} + +/* Handle a "vFile:setfs:" packet. */ + +static void +handle_setfs (char *own_buf) +{ + char *p; + int pid; + + /* If the target doesn't have any of the in-filesystem-of methods + then there's no point in GDB sending "vFile:setfs:" packets. We + reply with an empty packet (i.e. we pretend we don't understand + "vFile:setfs:") and that should stop GDB sending any more. */ + if (the_target->multifs_open == NULL + && the_target->multifs_unlink == NULL + && the_target->multifs_readlink == NULL) + { + own_buf[0] = '\0'; + return; + } + + p = own_buf + strlen ("vFile:setfs:"); + + if (require_int (&p, &pid) + || pid < 0 + || require_end (p)) + { + hostio_packet_error (own_buf); + return; + } + + hostio_fs_pid = pid; + + hostio_reply (own_buf, 0); +} + +static void +handle_open (char *own_buf) +{ + char filename[HOSTIO_PATH_MAX]; + char *p; + int fileio_flags, fileio_mode, flags, fd; + mode_t mode; + struct fd_list *new_fd; + + p = own_buf + strlen ("vFile:open:"); + + if (require_filename (&p, filename) + || require_comma (&p) + || require_int (&p, &fileio_flags) + || require_comma (&p) + || require_int (&p, &fileio_mode) + || require_end (p) + || fileio_to_host_openflags (fileio_flags, &flags) + || fileio_to_host_mode (fileio_mode, &mode)) + { + hostio_packet_error (own_buf); + return; + } + + /* We do not need to convert MODE, since the fileio protocol + uses the standard values. */ + if (hostio_fs_pid != 0 && the_target->multifs_open != NULL) + fd = the_target->multifs_open (hostio_fs_pid, filename, + flags, mode); + else + fd = open (filename, flags, mode); + + if (fd == -1) + { + hostio_error (own_buf); + return; + } + + /* Record the new file descriptor. */ + new_fd = XNEW (struct fd_list); + new_fd->fd = fd; + new_fd->next = open_fds; + open_fds = new_fd; + + hostio_reply (own_buf, fd); +} + +static void +handle_pread (char *own_buf, int *new_packet_len) +{ + int fd, ret, len, offset, bytes_sent; + char *p, *data; + static int max_reply_size = -1; + + p = own_buf + strlen ("vFile:pread:"); + + if (require_int (&p, &fd) + || require_comma (&p) + || require_valid_fd (fd) + || require_int (&p, &len) + || require_comma (&p) + || require_int (&p, &offset) + || require_end (p)) + { + hostio_packet_error (own_buf); + return; + } + + /* Do not attempt to read more than the maximum number of bytes + hostio_reply_with_data can fit in a packet. We may still read + too much because of escaping, but this is handled below. */ + if (max_reply_size == -1) + { + sprintf (own_buf, "F%x;", PBUFSIZ); + max_reply_size = PBUFSIZ - strlen (own_buf); + } + if (len > max_reply_size) + len = max_reply_size; + + data = (char *) xmalloc (len); +#ifdef HAVE_PREAD + ret = pread (fd, data, len, offset); +#else + ret = -1; +#endif + /* If we have no pread or it failed for this file, use lseek/read. */ + if (ret == -1) + { + ret = lseek (fd, offset, SEEK_SET); + if (ret != -1) + ret = read (fd, data, len); + } + + if (ret == -1) + { + hostio_error (own_buf); + free (data); + return; + } + + bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len); + + /* If we were using read, and the data did not all fit in the reply, + we would have to back up using lseek here. With pread it does + not matter. But we still have a problem; the return value in the + packet might be wrong, so we must fix it. This time it will + definitely fit. */ + if (bytes_sent < ret) + bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent, + new_packet_len); + + free (data); +} + +static void +handle_pwrite (char *own_buf, int packet_len) +{ + int fd, ret, len, offset; + char *p, *data; + + p = own_buf + strlen ("vFile:pwrite:"); + + if (require_int (&p, &fd) + || require_comma (&p) + || require_valid_fd (fd) + || require_int (&p, &offset) + || require_comma (&p) + || require_data (p, packet_len - (p - own_buf), &data, &len)) + { + hostio_packet_error (own_buf); + return; + } + +#ifdef HAVE_PWRITE + ret = pwrite (fd, data, len, offset); +#else + ret = -1; +#endif + /* If we have no pwrite or it failed for this file, use lseek/write. */ + if (ret == -1) + { + ret = lseek (fd, offset, SEEK_SET); + if (ret != -1) + ret = write (fd, data, len); + } + + if (ret == -1) + { + hostio_error (own_buf); + free (data); + return; + } + + hostio_reply (own_buf, ret); + free (data); +} + +static void +handle_fstat (char *own_buf, int *new_packet_len) +{ + int fd, bytes_sent; + char *p; + struct stat st; + struct fio_stat fst; + + p = own_buf + strlen ("vFile:fstat:"); + + if (require_int (&p, &fd) + || require_valid_fd (fd) + || require_end (p)) + { + hostio_packet_error (own_buf); + return; + } + + if (fstat (fd, &st) == -1) + { + hostio_error (own_buf); + return; + } + + host_to_fileio_stat (&st, &fst); + + bytes_sent = hostio_reply_with_data (own_buf, + (char *) &fst, sizeof (fst), + new_packet_len); + + /* If the response does not fit into a single packet, do not attempt + to return a partial response, but simply fail. */ + if (bytes_sent < sizeof (fst)) + write_enn (own_buf); +} + +static void +handle_close (char *own_buf) +{ + int fd, ret; + char *p; + struct fd_list **open_fd_p, *old_fd; + + p = own_buf + strlen ("vFile:close:"); + + if (require_int (&p, &fd) + || require_valid_fd (fd) + || require_end (p)) + { + hostio_packet_error (own_buf); + return; + } + + ret = close (fd); + + if (ret == -1) + { + hostio_error (own_buf); + return; + } + + open_fd_p = &open_fds; + /* We know that fd is in the list, thanks to require_valid_fd. */ + while ((*open_fd_p)->fd != fd) + open_fd_p = &(*open_fd_p)->next; + + old_fd = *open_fd_p; + *open_fd_p = (*open_fd_p)->next; + free (old_fd); + + hostio_reply (own_buf, ret); +} + +static void +handle_unlink (char *own_buf) +{ + char filename[HOSTIO_PATH_MAX]; + char *p; + int ret; + + p = own_buf + strlen ("vFile:unlink:"); + + if (require_filename (&p, filename) + || require_end (p)) + { + hostio_packet_error (own_buf); + return; + } + + if (hostio_fs_pid != 0 && the_target->multifs_unlink != NULL) + ret = the_target->multifs_unlink (hostio_fs_pid, filename); + else + ret = unlink (filename); + + if (ret == -1) + { + hostio_error (own_buf); + return; + } + + hostio_reply (own_buf, ret); +} + +static void +handle_readlink (char *own_buf, int *new_packet_len) +{ + char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX]; + char *p; + int ret, bytes_sent; + + p = own_buf + strlen ("vFile:readlink:"); + + if (require_filename (&p, filename) + || require_end (p)) + { + hostio_packet_error (own_buf); + return; + } + + if (hostio_fs_pid != 0 && the_target->multifs_readlink != NULL) + ret = the_target->multifs_readlink (hostio_fs_pid, filename, + linkname, + sizeof (linkname) - 1); + else + ret = readlink (filename, linkname, sizeof (linkname) - 1); + + if (ret == -1) + { + hostio_error (own_buf); + return; + } + + bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len); + + /* If the response does not fit into a single packet, do not attempt + to return a partial response, but simply fail. */ + if (bytes_sent < ret) + sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG); +} + +/* Handle all the 'F' file transfer packets. */ + +int +handle_vFile (char *own_buf, int packet_len, int *new_packet_len) +{ + if (startswith (own_buf, "vFile:open:")) + handle_open (own_buf); + else if (startswith (own_buf, "vFile:pread:")) + handle_pread (own_buf, new_packet_len); + else if (startswith (own_buf, "vFile:pwrite:")) + handle_pwrite (own_buf, packet_len); + else if (startswith (own_buf, "vFile:fstat:")) + handle_fstat (own_buf, new_packet_len); + else if (startswith (own_buf, "vFile:close:")) + handle_close (own_buf); + else if (startswith (own_buf, "vFile:unlink:")) + handle_unlink (own_buf); + else if (startswith (own_buf, "vFile:readlink:")) + handle_readlink (own_buf, new_packet_len); + else if (startswith (own_buf, "vFile:setfs:")) + handle_setfs (own_buf); + else + return 0; + + return 1; +} diff --git a/gdbserver/hostio.h b/gdbserver/hostio.h new file mode 100644 index 00000000000..4aca65c90d7 --- /dev/null +++ b/gdbserver/hostio.h @@ -0,0 +1,31 @@ +/* Host file transfer support for gdbserver. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_HOSTIO_H +#define GDBSERVER_HOSTIO_H + +/* Per-connection setup. */ +extern void hostio_handle_new_gdb_connection (void); + +/* Functions from hostio.c. */ +extern int handle_vFile (char *, int, int *); + +/* Functions from hostio-errno.c. */ +extern void hostio_last_error_from_errno (char *own_buf); + +#endif /* GDBSERVER_HOSTIO_H */ diff --git a/gdbserver/i387-fp.c b/gdbserver/i387-fp.c new file mode 100644 index 00000000000..ef7b51303f4 --- /dev/null +++ b/gdbserver/i387-fp.c @@ -0,0 +1,954 @@ +/* i387-specific utility functions, for the remote server for GDB. + Copyright (C) 2000-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "i387-fp.h" +#include "gdbsupport/x86-xstate.h" + +static const int num_mpx_bnd_registers = 4; +static const int num_mpx_cfg_registers = 2; +static const int num_avx512_k_registers = 8; +static const int num_avx512_zmmh_low_registers = 16; +static const int num_avx512_zmmh_high_registers = 16; +static const int num_avx512_ymmh_registers = 16; +static const int num_avx512_xmm_registers = 16; +static const int num_pkeys_registers = 1; + +/* Note: These functions preserve the reserved bits in control registers. + However, gdbserver promptly throws away that information. */ + +/* These structs should have the proper sizes and alignment on both + i386 and x86-64 machines. */ + +struct i387_fsave { + /* All these are only sixteen bits, plus padding, except for fop (which + is only eleven bits), and fooff / fioff (which are 32 bits each). */ + unsigned short fctrl; + unsigned short pad1; + unsigned short fstat; + unsigned short pad2; + unsigned short ftag; + unsigned short pad3; + unsigned int fioff; + unsigned short fiseg; + unsigned short fop; + unsigned int fooff; + unsigned short foseg; + unsigned short pad4; + + /* Space for eight 80-bit FP values. */ + unsigned char st_space[80]; +}; + +struct i387_fxsave { + /* All these are only sixteen bits, plus padding, except for fop (which + is only eleven bits), and fooff / fioff (which are 32 bits each). */ + unsigned short fctrl; + unsigned short fstat; + unsigned short ftag; + unsigned short fop; + unsigned int fioff; + unsigned short fiseg; + unsigned short pad1; + unsigned int fooff; + unsigned short foseg; + unsigned short pad12; + + unsigned int mxcsr; + unsigned int pad3; + + /* Space for eight 80-bit FP values in 128-bit spaces. */ + unsigned char st_space[128]; + + /* Space for eight 128-bit XMM values, or 16 on x86-64. */ + unsigned char xmm_space[256]; +}; + +struct i387_xsave { + /* All these are only sixteen bits, plus padding, except for fop (which + is only eleven bits), and fooff / fioff (which are 32 bits each). */ + unsigned short fctrl; + unsigned short fstat; + unsigned short ftag; + unsigned short fop; + unsigned int fioff; + unsigned short fiseg; + unsigned short pad1; + unsigned int fooff; + unsigned short foseg; + unsigned short pad12; + + unsigned int mxcsr; + unsigned int mxcsr_mask; + + /* Space for eight 80-bit FP values in 128-bit spaces. */ + unsigned char st_space[128]; + + /* Space for eight 128-bit XMM values, or 16 on x86-64. */ + unsigned char xmm_space[256]; + + unsigned char reserved1[48]; + + /* The extended control register 0 (the XFEATURE_ENABLED_MASK + register). */ + unsigned long long xcr0; + + unsigned char reserved2[40]; + + /* The XSTATE_BV bit vector. */ + unsigned long long xstate_bv; + + unsigned char reserved3[56]; + + /* Space for eight upper 128-bit YMM values, or 16 on x86-64. */ + unsigned char ymmh_space[256]; + + unsigned char reserved4[128]; + + /* Space for 4 bound registers values of 128 bits. */ + unsigned char mpx_bnd_space[64]; + + /* Space for 2 MPX configuration registers of 64 bits + plus reserved space. */ + unsigned char mpx_cfg_space[16]; + + unsigned char reserved5[48]; + + /* Space for 8 OpMask register values of 64 bits. */ + unsigned char k_space[64]; + + /* Space for 16 256-bit zmm0-15. */ + unsigned char zmmh_low_space[512]; + + /* Space for 16 512-bit zmm16-31 values. */ + unsigned char zmmh_high_space[1024]; + + /* Space for 1 32-bit PKRU register. The HW XSTATE size for this feature is + actually 64 bits, but WRPKRU/RDPKRU instructions ignore upper 32 bits. */ + unsigned char pkru_space[8]; +}; + +void +i387_cache_to_fsave (struct regcache *regcache, void *buf) +{ + struct i387_fsave *fp = (struct i387_fsave *) buf; + int i; + int st0_regnum = find_regno (regcache->tdesc, "st0"); + unsigned long val2; + + for (i = 0; i < 8; i++) + collect_register (regcache, i + st0_regnum, + ((char *) &fp->st_space[0]) + i * 10); + + fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff"); + fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff"); + + /* This one's 11 bits... */ + val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); + fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); + + /* Some registers are 16-bit. */ + fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); + fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat"); + fp->ftag = regcache_raw_get_unsigned_by_name (regcache, "ftag"); + fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); + fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg"); +} + +void +i387_fsave_to_cache (struct regcache *regcache, const void *buf) +{ + struct i387_fsave *fp = (struct i387_fsave *) buf; + int i; + int st0_regnum = find_regno (regcache->tdesc, "st0"); + unsigned long val; + + for (i = 0; i < 8; i++) + supply_register (regcache, i + st0_regnum, + ((char *) &fp->st_space[0]) + i * 10); + + supply_register_by_name (regcache, "fioff", &fp->fioff); + supply_register_by_name (regcache, "fooff", &fp->fooff); + + /* Some registers are 16-bit. */ + val = fp->fctrl & 0xFFFF; + supply_register_by_name (regcache, "fctrl", &val); + + val = fp->fstat & 0xFFFF; + supply_register_by_name (regcache, "fstat", &val); + + val = fp->ftag & 0xFFFF; + supply_register_by_name (regcache, "ftag", &val); + + val = fp->fiseg & 0xFFFF; + supply_register_by_name (regcache, "fiseg", &val); + + val = fp->foseg & 0xFFFF; + supply_register_by_name (regcache, "foseg", &val); + + /* fop has only 11 valid bits. */ + val = (fp->fop) & 0x7FF; + supply_register_by_name (regcache, "fop", &val); +} + +void +i387_cache_to_fxsave (struct regcache *regcache, void *buf) +{ + struct i387_fxsave *fp = (struct i387_fxsave *) buf; + int i; + int st0_regnum = find_regno (regcache->tdesc, "st0"); + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); + unsigned long val, val2; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; + + for (i = 0; i < 8; i++) + collect_register (regcache, i + st0_regnum, + ((char *) &fp->st_space[0]) + i * 16); + for (i = 0; i < num_xmm_registers; i++) + collect_register (regcache, i + xmm0_regnum, + ((char *) &fp->xmm_space[0]) + i * 16); + + fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff"); + fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff"); + fp->mxcsr = regcache_raw_get_unsigned_by_name (regcache, "mxcsr"); + + /* This one's 11 bits... */ + val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); + fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); + + /* Some registers are 16-bit. */ + fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); + fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat"); + + /* Convert to the simplifed tag form stored in fxsave data. */ + val = regcache_raw_get_unsigned_by_name (regcache, "ftag"); + val2 = 0; + for (i = 7; i >= 0; i--) + { + int tag = (val >> (i * 2)) & 3; + + if (tag != 3) + val2 |= (1 << i); + } + fp->ftag = val2; + + fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); + fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg"); +} + +void +i387_cache_to_xsave (struct regcache *regcache, void *buf) +{ + struct i387_xsave *fp = (struct i387_xsave *) buf; + int i; + unsigned long val, val2; + unsigned long long xstate_bv = 0; + unsigned long long clear_bv = 0; + char raw[64]; + char *p; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; + + /* The supported bits in `xstat_bv' are 8 bytes. Clear part in + vector registers if its bit in xstat_bv is zero. */ + clear_bv = (~fp->xstate_bv) & x86_xcr0; + + /* Clear part in x87 and vector registers if its bit in xstat_bv is + zero. */ + if (clear_bv) + { + if ((clear_bv & X86_XSTATE_X87)) + { + for (i = 0; i < 8; i++) + memset (((char *) &fp->st_space[0]) + i * 16, 0, 10); + + fp->fioff = 0; + fp->fooff = 0; + fp->fctrl = I387_FCTRL_INIT_VAL; + fp->fstat = 0; + fp->ftag = 0; + fp->fiseg = 0; + fp->foseg = 0; + fp->fop = 0; + } + + if ((clear_bv & X86_XSTATE_SSE)) + for (i = 0; i < num_xmm_registers; i++) + memset (((char *) &fp->xmm_space[0]) + i * 16, 0, 16); + + if ((clear_bv & X86_XSTATE_AVX)) + for (i = 0; i < num_xmm_registers; i++) + memset (((char *) &fp->ymmh_space[0]) + i * 16, 0, 16); + + if ((clear_bv & X86_XSTATE_SSE) && (clear_bv & X86_XSTATE_AVX)) + memset (((char *) &fp->mxcsr), 0, 4); + + if ((clear_bv & X86_XSTATE_BNDREGS)) + for (i = 0; i < num_mpx_bnd_registers; i++) + memset (((char *) &fp->mpx_bnd_space[0]) + i * 16, 0, 16); + + if ((clear_bv & X86_XSTATE_BNDCFG)) + for (i = 0; i < num_mpx_cfg_registers; i++) + memset (((char *) &fp->mpx_cfg_space[0]) + i * 8, 0, 8); + + if ((clear_bv & X86_XSTATE_K)) + for (i = 0; i < num_avx512_k_registers; i++) + memset (((char *) &fp->k_space[0]) + i * 8, 0, 8); + + if ((clear_bv & X86_XSTATE_ZMM_H)) + for (i = 0; i < num_avx512_zmmh_low_registers; i++) + memset (((char *) &fp->zmmh_low_space[0]) + i * 32, 0, 32); + + if ((clear_bv & X86_XSTATE_ZMM)) + { + for (i = 0; i < num_avx512_zmmh_high_registers; i++) + memset (((char *) &fp->zmmh_low_space[0]) + 32 + i * 64, 0, 32); + for (i = 0; i < num_avx512_xmm_registers; i++) + memset (((char *) &fp->zmmh_high_space[0]) + i * 64, 0, 16); + for (i = 0; i < num_avx512_ymmh_registers; i++) + memset (((char *) &fp->zmmh_high_space[0]) + 16 + i * 64, 0, 16); + } + + if ((clear_bv & X86_XSTATE_PKRU)) + for (i = 0; i < num_pkeys_registers; i++) + memset (((char *) &fp->pkru_space[0]) + i * 4, 0, 4); + } + + /* Check if any x87 registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_X87)) + { + int st0_regnum = find_regno (regcache->tdesc, "st0"); + + for (i = 0; i < 8; i++) + { + collect_register (regcache, i + st0_regnum, raw); + p = ((char *) &fp->st_space[0]) + i * 16; + if (memcmp (raw, p, 10)) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (p, raw, 10); + } + } + } + + /* Check if any SSE registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_SSE)) + { + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); + + for (i = 0; i < num_xmm_registers; i++) + { + collect_register (regcache, i + xmm0_regnum, raw); + p = ((char *) &fp->xmm_space[0]) + i * 16; + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_SSE; + memcpy (p, raw, 16); + } + } + } + + /* Check if any AVX registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_AVX)) + { + int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); + + for (i = 0; i < num_xmm_registers; i++) + { + collect_register (regcache, i + ymm0h_regnum, raw); + p = ((char *) &fp->ymmh_space[0]) + i * 16; + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_AVX; + memcpy (p, raw, 16); + } + } + } + + /* Check if any bound register has changed. */ + if ((x86_xcr0 & X86_XSTATE_BNDREGS)) + { + int bnd0r_regnum = find_regno (regcache->tdesc, "bnd0raw"); + + for (i = 0; i < num_mpx_bnd_registers; i++) + { + collect_register (regcache, i + bnd0r_regnum, raw); + p = ((char *) &fp->mpx_bnd_space[0]) + i * 16; + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_BNDREGS; + memcpy (p, raw, 16); + } + } + } + + /* Check if any status register has changed. */ + if ((x86_xcr0 & X86_XSTATE_BNDCFG)) + { + int bndcfg_regnum = find_regno (regcache->tdesc, "bndcfgu"); + + for (i = 0; i < num_mpx_cfg_registers; i++) + { + collect_register (regcache, i + bndcfg_regnum, raw); + p = ((char *) &fp->mpx_cfg_space[0]) + i * 8; + if (memcmp (raw, p, 8)) + { + xstate_bv |= X86_XSTATE_BNDCFG; + memcpy (p, raw, 8); + } + } + } + + /* Check if any K registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_K)) + { + int k0_regnum = find_regno (regcache->tdesc, "k0"); + + for (i = 0; i < num_avx512_k_registers; i++) + { + collect_register (regcache, i + k0_regnum, raw); + p = ((char *) &fp->k_space[0]) + i * 8; + if (memcmp (raw, p, 8) != 0) + { + xstate_bv |= X86_XSTATE_K; + memcpy (p, raw, 8); + } + } + } + + /* Check if any of ZMM0H-ZMM15H registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_ZMM_H)) + { + int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); + + for (i = 0; i < num_avx512_zmmh_low_registers; i++) + { + collect_register (regcache, i + zmm0h_regnum, raw); + p = ((char *) &fp->zmmh_low_space[0]) + i * 32; + if (memcmp (raw, p, 32) != 0) + { + xstate_bv |= X86_XSTATE_ZMM_H; + memcpy (p, raw, 32); + } + } + } + + /* Check if any of ZMM16H-ZMM31H registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_ZMM)) + { + int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); + + for (i = 0; i < num_avx512_zmmh_high_registers; i++) + { + collect_register (regcache, i + zmm16h_regnum, raw); + p = ((char *) &fp->zmmh_high_space[0]) + 32 + i * 64; + if (memcmp (raw, p, 32) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 32); + } + } + } + + /* Check if any XMM_AVX512 registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_ZMM)) + { + int xmm_avx512_regnum = find_regno (regcache->tdesc, "xmm16"); + + for (i = 0; i < num_avx512_xmm_registers; i++) + { + collect_register (regcache, i + xmm_avx512_regnum, raw); + p = ((char *) &fp->zmmh_high_space[0]) + i * 64; + if (memcmp (raw, p, 16) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 16); + } + } + } + + /* Check if any YMMH_AVX512 registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_ZMM)) + { + int ymmh_avx512_regnum = find_regno (regcache->tdesc, "ymm16h"); + + for (i = 0; i < num_avx512_ymmh_registers; i++) + { + collect_register (regcache, i + ymmh_avx512_regnum, raw); + p = ((char *) &fp->zmmh_high_space[0]) + 16 + i * 64; + if (memcmp (raw, p, 16) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 16); + } + } + } + + /* Check if any PKEYS registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_PKRU)) + { + int pkru_regnum = find_regno (regcache->tdesc, "pkru"); + + for (i = 0; i < num_pkeys_registers; i++) + { + collect_register (regcache, i + pkru_regnum, raw); + p = ((char *) &fp->pkru_space[0]) + i * 4; + if (memcmp (raw, p, 4) != 0) + { + xstate_bv |= X86_XSTATE_PKRU; + memcpy (p, raw, 4); + } + } + } + + if ((x86_xcr0 & X86_XSTATE_SSE) || (x86_xcr0 & X86_XSTATE_AVX)) + { + collect_register_by_name (regcache, "mxcsr", raw); + if (memcmp (raw, &fp->mxcsr, 4) != 0) + { + if (((fp->xstate_bv | xstate_bv) + & (X86_XSTATE_SSE | X86_XSTATE_AVX)) == 0) + xstate_bv |= X86_XSTATE_SSE; + memcpy (&fp->mxcsr, raw, 4); + } + } + + if (x86_xcr0 & X86_XSTATE_X87) + { + collect_register_by_name (regcache, "fioff", raw); + if (memcmp (raw, &fp->fioff, 4) != 0) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (&fp->fioff, raw, 4); + } + + collect_register_by_name (regcache, "fooff", raw); + if (memcmp (raw, &fp->fooff, 4) != 0) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (&fp->fooff, raw, 4); + } + + /* This one's 11 bits... */ + val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); + val2 = (val2 & 0x7FF) | (fp->fop & 0xF800); + if (fp->fop != val2) + { + xstate_bv |= X86_XSTATE_X87; + fp->fop = val2; + } + + /* Some registers are 16-bit. */ + val = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); + if (fp->fctrl != val) + { + xstate_bv |= X86_XSTATE_X87; + fp->fctrl = val; + } + + val = regcache_raw_get_unsigned_by_name (regcache, "fstat"); + if (fp->fstat != val) + { + xstate_bv |= X86_XSTATE_X87; + fp->fstat = val; + } + + /* Convert to the simplifed tag form stored in fxsave data. */ + val = regcache_raw_get_unsigned_by_name (regcache, "ftag"); + val2 = 0; + for (i = 7; i >= 0; i--) + { + int tag = (val >> (i * 2)) & 3; + + if (tag != 3) + val2 |= (1 << i); + } + if (fp->ftag != val2) + { + xstate_bv |= X86_XSTATE_X87; + fp->ftag = val2; + } + + val = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); + if (fp->fiseg != val) + { + xstate_bv |= X86_XSTATE_X87; + fp->fiseg = val; + } + + val = regcache_raw_get_unsigned_by_name (regcache, "foseg"); + if (fp->foseg != val) + { + xstate_bv |= X86_XSTATE_X87; + fp->foseg = val; + } + } + + /* Update the corresponding bits in xstate_bv if any SSE/AVX + registers are changed. */ + fp->xstate_bv |= xstate_bv; +} + +static int +i387_ftag (struct i387_fxsave *fp, int regno) +{ + unsigned char *raw = &fp->st_space[regno * 16]; + unsigned int exponent; + unsigned long fraction[2]; + int integer; + + integer = raw[7] & 0x80; + exponent = (((raw[9] & 0x7f) << 8) | raw[8]); + fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); + fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) + | (raw[5] << 8) | raw[4]); + + if (exponent == 0x7fff) + { + /* Special. */ + return (2); + } + else if (exponent == 0x0000) + { + if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) + { + /* Zero. */ + return (1); + } + else + { + /* Special. */ + return (2); + } + } + else + { + if (integer) + { + /* Valid. */ + return (0); + } + else + { + /* Special. */ + return (2); + } + } +} + +void +i387_fxsave_to_cache (struct regcache *regcache, const void *buf) +{ + struct i387_fxsave *fp = (struct i387_fxsave *) buf; + int i, top; + int st0_regnum = find_regno (regcache->tdesc, "st0"); + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); + unsigned long val; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; + + for (i = 0; i < 8; i++) + supply_register (regcache, i + st0_regnum, + ((char *) &fp->st_space[0]) + i * 16); + for (i = 0; i < num_xmm_registers; i++) + supply_register (regcache, i + xmm0_regnum, + ((char *) &fp->xmm_space[0]) + i * 16); + + supply_register_by_name (regcache, "fioff", &fp->fioff); + supply_register_by_name (regcache, "fooff", &fp->fooff); + supply_register_by_name (regcache, "mxcsr", &fp->mxcsr); + + /* Some registers are 16-bit. */ + val = fp->fctrl & 0xFFFF; + supply_register_by_name (regcache, "fctrl", &val); + + val = fp->fstat & 0xFFFF; + supply_register_by_name (regcache, "fstat", &val); + + /* Generate the form of ftag data that GDB expects. */ + top = (fp->fstat >> 11) & 0x7; + val = 0; + for (i = 7; i >= 0; i--) + { + int tag; + if (fp->ftag & (1 << i)) + tag = i387_ftag (fp, (i + 8 - top) % 8); + else + tag = 3; + val |= tag << (2 * i); + } + supply_register_by_name (regcache, "ftag", &val); + + val = fp->fiseg & 0xFFFF; + supply_register_by_name (regcache, "fiseg", &val); + + val = fp->foseg & 0xFFFF; + supply_register_by_name (regcache, "foseg", &val); + + val = (fp->fop) & 0x7FF; + supply_register_by_name (regcache, "fop", &val); +} + +void +i387_xsave_to_cache (struct regcache *regcache, const void *buf) +{ + struct i387_xsave *fp = (struct i387_xsave *) buf; + struct i387_fxsave *fxp = (struct i387_fxsave *) buf; + int i, top; + unsigned long val; + unsigned long long clear_bv; + gdb_byte *p; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; + + /* The supported bits in `xstat_bv' are 8 bytes. Clear part in + vector registers if its bit in xstat_bv is zero. */ + clear_bv = (~fp->xstate_bv) & x86_xcr0; + + /* Check if any x87 registers are changed. */ + if ((x86_xcr0 & X86_XSTATE_X87) != 0) + { + int st0_regnum = find_regno (regcache->tdesc, "st0"); + + if ((clear_bv & X86_XSTATE_X87) != 0) + { + for (i = 0; i < 8; i++) + supply_register_zeroed (regcache, i + st0_regnum); + } + else + { + p = (gdb_byte *) &fp->st_space[0]; + for (i = 0; i < 8; i++) + supply_register (regcache, i + st0_regnum, p + i * 16); + } + } + + if ((x86_xcr0 & X86_XSTATE_SSE) != 0) + { + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); + + if ((clear_bv & X86_XSTATE_SSE)) + { + for (i = 0; i < num_xmm_registers; i++) + supply_register_zeroed (regcache, i + xmm0_regnum); + } + else + { + p = (gdb_byte *) &fp->xmm_space[0]; + for (i = 0; i < num_xmm_registers; i++) + supply_register (regcache, i + xmm0_regnum, p + i * 16); + } + } + + if ((x86_xcr0 & X86_XSTATE_AVX) != 0) + { + int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); + + if ((clear_bv & X86_XSTATE_AVX) != 0) + { + for (i = 0; i < num_xmm_registers; i++) + supply_register_zeroed (regcache, i + ymm0h_regnum); + } + else + { + p = (gdb_byte *) &fp->ymmh_space[0]; + for (i = 0; i < num_xmm_registers; i++) + supply_register (regcache, i + ymm0h_regnum, p + i * 16); + } + } + + if ((x86_xcr0 & X86_XSTATE_BNDREGS)) + { + int bnd0r_regnum = find_regno (regcache->tdesc, "bnd0raw"); + + + if ((clear_bv & X86_XSTATE_BNDREGS) != 0) + { + for (i = 0; i < num_mpx_bnd_registers; i++) + supply_register_zeroed (regcache, i + bnd0r_regnum); + } + else + { + p = (gdb_byte *) &fp->mpx_bnd_space[0]; + for (i = 0; i < num_mpx_bnd_registers; i++) + supply_register (regcache, i + bnd0r_regnum, p + i * 16); + } + + } + + if ((x86_xcr0 & X86_XSTATE_BNDCFG)) + { + int bndcfg_regnum = find_regno (regcache->tdesc, "bndcfgu"); + + if ((clear_bv & X86_XSTATE_BNDCFG) != 0) + { + for (i = 0; i < num_mpx_cfg_registers; i++) + supply_register_zeroed (regcache, i + bndcfg_regnum); + } + else + { + p = (gdb_byte *) &fp->mpx_cfg_space[0]; + for (i = 0; i < num_mpx_cfg_registers; i++) + supply_register (regcache, i + bndcfg_regnum, p + i * 8); + } + } + + if ((x86_xcr0 & X86_XSTATE_K) != 0) + { + int k0_regnum = find_regno (regcache->tdesc, "k0"); + + if ((clear_bv & X86_XSTATE_K) != 0) + { + for (i = 0; i < num_avx512_k_registers; i++) + supply_register_zeroed (regcache, i + k0_regnum); + } + else + { + p = (gdb_byte *) &fp->k_space[0]; + for (i = 0; i < num_avx512_k_registers; i++) + supply_register (regcache, i + k0_regnum, p + i * 8); + } + } + + if ((x86_xcr0 & X86_XSTATE_ZMM_H) != 0) + { + int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); + + if ((clear_bv & X86_XSTATE_ZMM_H) != 0) + { + for (i = 0; i < num_avx512_zmmh_low_registers; i++) + supply_register_zeroed (regcache, i + zmm0h_regnum); + } + else + { + p = (gdb_byte *) &fp->zmmh_low_space[0]; + for (i = 0; i < num_avx512_zmmh_low_registers; i++) + supply_register (regcache, i + zmm0h_regnum, p + i * 32); + } + } + + if ((x86_xcr0 & X86_XSTATE_ZMM) != 0) + { + int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); + int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h"); + int xmm16_regnum = find_regno (regcache->tdesc, "xmm16"); + + if ((clear_bv & X86_XSTATE_ZMM) != 0) + { + for (i = 0; i < num_avx512_zmmh_high_registers; i++) + supply_register_zeroed (regcache, i + zmm16h_regnum); + for (i = 0; i < num_avx512_ymmh_registers; i++) + supply_register_zeroed (regcache, i + ymm16h_regnum); + for (i = 0; i < num_avx512_xmm_registers; i++) + supply_register_zeroed (regcache, i + xmm16_regnum); + } + else + { + p = (gdb_byte *) &fp->zmmh_high_space[0]; + for (i = 0; i < num_avx512_zmmh_high_registers; i++) + supply_register (regcache, i + zmm16h_regnum, p + 32 + i * 64); + for (i = 0; i < num_avx512_ymmh_registers; i++) + supply_register (regcache, i + ymm16h_regnum, p + 16 + i * 64); + for (i = 0; i < num_avx512_xmm_registers; i++) + supply_register (regcache, i + xmm16_regnum, p + i * 64); + } + } + + if ((x86_xcr0 & X86_XSTATE_PKRU) != 0) + { + int pkru_regnum = find_regno (regcache->tdesc, "pkru"); + + if ((clear_bv & X86_XSTATE_PKRU) != 0) + { + for (i = 0; i < num_pkeys_registers; i++) + supply_register_zeroed (regcache, i + pkru_regnum); + } + else + { + p = (gdb_byte *) &fp->pkru_space[0]; + for (i = 0; i < num_pkeys_registers; i++) + supply_register (regcache, i + pkru_regnum, p + i * 4); + } + } + + if ((clear_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX)) + == (X86_XSTATE_SSE | X86_XSTATE_AVX)) + { + unsigned int default_mxcsr = I387_MXCSR_INIT_VAL; + supply_register_by_name (regcache, "mxcsr", &default_mxcsr); + } + else + supply_register_by_name (regcache, "mxcsr", &fp->mxcsr); + + if ((clear_bv & X86_XSTATE_X87) != 0) + { + supply_register_by_name_zeroed (regcache, "fioff"); + supply_register_by_name_zeroed (regcache, "fooff"); + + val = I387_FCTRL_INIT_VAL; + supply_register_by_name (regcache, "fctrl", &val); + + supply_register_by_name_zeroed (regcache, "fstat"); + + val = 0xFFFF; + supply_register_by_name (regcache, "ftag", &val); + + supply_register_by_name_zeroed (regcache, "fiseg"); + supply_register_by_name_zeroed (regcache, "foseg"); + supply_register_by_name_zeroed (regcache, "fop"); + } + else + { + supply_register_by_name (regcache, "fioff", &fp->fioff); + supply_register_by_name (regcache, "fooff", &fp->fooff); + + /* Some registers are 16-bit. */ + val = fp->fctrl & 0xFFFF; + supply_register_by_name (regcache, "fctrl", &val); + + val = fp->fstat & 0xFFFF; + supply_register_by_name (regcache, "fstat", &val); + + /* Generate the form of ftag data that GDB expects. */ + top = (fp->fstat >> 11) & 0x7; + val = 0; + for (i = 7; i >= 0; i--) + { + int tag; + if (fp->ftag & (1 << i)) + tag = i387_ftag (fxp, (i + 8 - top) % 8); + else + tag = 3; + val |= tag << (2 * i); + } + supply_register_by_name (regcache, "ftag", &val); + + val = fp->fiseg & 0xFFFF; + supply_register_by_name (regcache, "fiseg", &val); + + val = fp->foseg & 0xFFFF; + supply_register_by_name (regcache, "foseg", &val); + + val = (fp->fop) & 0x7FF; + supply_register_by_name (regcache, "fop", &val); + } +} + +/* Default to SSE. */ +unsigned long long x86_xcr0 = X86_XSTATE_SSE_MASK; diff --git a/gdbserver/i387-fp.h b/gdbserver/i387-fp.h new file mode 100644 index 00000000000..e4e03e7f227 --- /dev/null +++ b/gdbserver/i387-fp.h @@ -0,0 +1,33 @@ +/* i387-specific utility functions, for the remote server for GDB. + Copyright (C) 2000-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_I387_FP_H +#define GDBSERVER_I387_FP_H + +void i387_cache_to_fsave (struct regcache *regcache, void *buf); +void i387_fsave_to_cache (struct regcache *regcache, const void *buf); + +void i387_cache_to_fxsave (struct regcache *regcache, void *buf); +void i387_fxsave_to_cache (struct regcache *regcache, const void *buf); + +void i387_cache_to_xsave (struct regcache *regcache, void *buf); +void i387_xsave_to_cache (struct regcache *regcache, const void *buf); + +extern unsigned long long x86_xcr0; + +#endif /* GDBSERVER_I387_FP_H */ diff --git a/gdbserver/inferiors.c b/gdbserver/inferiors.c new file mode 100644 index 00000000000..88adb16eac2 --- /dev/null +++ b/gdbserver/inferiors.c @@ -0,0 +1,244 @@ +/* Inferior process information for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#include "server.h" +#include "gdbsupport/common-inferior.h" +#include "gdbthread.h" +#include "dll.h" + +std::list all_processes; +std::list all_threads; + +struct thread_info *current_thread; + +/* The current working directory used to start the inferior. */ +static const char *current_inferior_cwd = NULL; + +struct thread_info * +add_thread (ptid_t thread_id, void *target_data) +{ + struct thread_info *new_thread = XCNEW (struct thread_info); + + new_thread->id = thread_id; + new_thread->last_resume_kind = resume_continue; + new_thread->last_status.kind = TARGET_WAITKIND_IGNORE; + + all_threads.push_back (new_thread); + + if (current_thread == NULL) + current_thread = new_thread; + + new_thread->target_data = target_data; + + return new_thread; +} + +/* See gdbthread.h. */ + +struct thread_info * +get_first_thread (void) +{ + if (!all_threads.empty ()) + return all_threads.front (); + else + return NULL; +} + +struct thread_info * +find_thread_ptid (ptid_t ptid) +{ + return find_thread ([&] (thread_info *thread) { + return thread->id == ptid; + }); +} + +/* Find a thread associated with the given PROCESS, or NULL if no + such thread exists. */ + +static struct thread_info * +find_thread_process (const struct process_info *const process) +{ + return find_any_thread_of_pid (process->pid); +} + +/* See gdbthread.h. */ + +struct thread_info * +find_any_thread_of_pid (int pid) +{ + return find_thread (pid, [] (thread_info *thread) { + return true; + }); +} + +static void +free_one_thread (thread_info *thread) +{ + free_register_cache (thread_regcache_data (thread)); + free (thread); +} + +void +remove_thread (struct thread_info *thread) +{ + if (thread->btrace != NULL) + target_disable_btrace (thread->btrace); + + discard_queued_stop_replies (ptid_of (thread)); + all_threads.remove (thread); + free_one_thread (thread); + if (current_thread == thread) + current_thread = NULL; +} + +void * +thread_target_data (struct thread_info *thread) +{ + return thread->target_data; +} + +struct regcache * +thread_regcache_data (struct thread_info *thread) +{ + return thread->regcache_data; +} + +void +set_thread_regcache_data (struct thread_info *thread, struct regcache *data) +{ + thread->regcache_data = data; +} + +void +clear_inferiors (void) +{ + for_each_thread (free_one_thread); + all_threads.clear (); + + clear_dlls (); + + current_thread = NULL; +} + +struct process_info * +add_process (int pid, int attached) +{ + process_info *process = new process_info (pid, attached); + + all_processes.push_back (process); + + return process; +} + +/* Remove a process from the common process list and free the memory + allocated for it. + The caller is responsible for freeing private data first. */ + +void +remove_process (struct process_info *process) +{ + clear_symbol_cache (&process->symbol_cache); + free_all_breakpoints (process); + gdb_assert (find_thread_process (process) == NULL); + all_processes.remove (process); + delete process; +} + +process_info * +find_process_pid (int pid) +{ + return find_process ([&] (process_info *process) { + return process->pid == pid; + }); +} + +/* Get the first process in the process list, or NULL if the list is empty. */ + +process_info * +get_first_process (void) +{ + if (!all_processes.empty ()) + return all_processes.front (); + else + return NULL; +} + +/* Return non-zero if there are any inferiors that we have created + (as opposed to attached-to). */ + +int +have_started_inferiors_p (void) +{ + return find_process ([] (process_info *process) { + return !process->attached; + }) != NULL; +} + +/* Return non-zero if there are any inferiors that we have attached to. */ + +int +have_attached_inferiors_p (void) +{ + return find_process ([] (process_info *process) { + return process->attached; + }) != NULL; +} + +struct process_info * +get_thread_process (const struct thread_info *thread) +{ + return find_process_pid (thread->id.pid ()); +} + +struct process_info * +current_process (void) +{ + gdb_assert (current_thread != NULL); + return get_thread_process (current_thread); +} + +/* See gdbsupport/common-gdbthread.h. */ + +void +switch_to_thread (process_stratum_target *ops, ptid_t ptid) +{ + gdb_assert (ptid != minus_one_ptid); + current_thread = find_thread_ptid (ptid); +} + +/* See gdbsupport/common-inferior.h. */ + +const char * +get_inferior_cwd () +{ + return current_inferior_cwd; +} + +/* See gdbsupport/common-inferior.h. */ + +void +set_inferior_cwd (const char *cwd) +{ + xfree ((void *) current_inferior_cwd); + if (cwd != NULL) + current_inferior_cwd = xstrdup (cwd); + else + current_inferior_cwd = NULL; +} diff --git a/gdbserver/inferiors.h b/gdbserver/inferiors.h new file mode 100644 index 00000000000..4e24b2c7bb2 --- /dev/null +++ b/gdbserver/inferiors.h @@ -0,0 +1,147 @@ +/* Inferior process information for the remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_INFERIORS_H +#define GDBSERVER_INFERIORS_H + +#include "gdbsupport/gdb_vecs.h" +#include + +struct thread_info; +struct regcache; +struct target_desc; +struct sym_cache; +struct breakpoint; +struct raw_breakpoint; +struct fast_tracepoint_jump; +struct process_info_private; + +struct process_info +{ + process_info (int pid_, int attached_) + : pid (pid_), attached (attached_) + {} + + /* This process' pid. */ + int pid; + + /* Nonzero if this child process was attached rather than + spawned. */ + int attached; + + /* True if GDB asked us to detach from this process, but we remained + attached anyway. */ + int gdb_detached = 0; + + /* The symbol cache. */ + struct sym_cache *symbol_cache = NULL; + + /* The list of memory breakpoints. */ + struct breakpoint *breakpoints = NULL; + + /* The list of raw memory breakpoints. */ + struct raw_breakpoint *raw_breakpoints = NULL; + + /* The list of installed fast tracepoints. */ + struct fast_tracepoint_jump *fast_tracepoint_jumps = NULL; + + /* The list of syscalls to report, or just a single element, ANY_SYSCALL, + for unfiltered syscall reporting. */ + std::vector syscalls_to_catch; + + const struct target_desc *tdesc = NULL; + + /* Private target data. */ + struct process_info_private *priv = NULL; +}; + +/* Get the pid of PROC. */ + +static inline int +pid_of (const process_info *proc) +{ + return proc->pid; +} + +/* Return a pointer to the process that corresponds to the current + thread (current_thread). It is an error to call this if there is + no current thread selected. */ + +struct process_info *current_process (void); +struct process_info *get_thread_process (const struct thread_info *); + +extern std::list all_processes; + +/* Invoke FUNC for each process. */ + +template +static void +for_each_process (Func func) +{ + std::list::iterator next, cur = all_processes.begin (); + + while (cur != all_processes.end ()) + { + next = cur; + next++; + func (*cur); + cur = next; + } +} + +/* Find the first process for which FUNC returns true. Return NULL if no + process satisfying FUNC is found. */ + +template +static process_info * +find_process (Func func) +{ + std::list::iterator next, cur = all_processes.begin (); + + while (cur != all_processes.end ()) + { + next = cur; + next++; + + if (func (*cur)) + return *cur; + + cur = next; + } + + return NULL; +} + +extern struct thread_info *current_thread; + +/* Return the first process in the processes list. */ +struct process_info *get_first_process (void); + +struct process_info *add_process (int pid, int attached); +void remove_process (struct process_info *process); +struct process_info *find_process_pid (int pid); +int have_started_inferiors_p (void); +int have_attached_inferiors_p (void); + +void clear_inferiors (void); + +void *thread_target_data (struct thread_info *); +struct regcache *thread_regcache_data (struct thread_info *); +void set_thread_regcache_data (struct thread_info *, struct regcache *); + +#endif /* GDBSERVER_INFERIORS_H */ diff --git a/gdbserver/linux-aarch32-low.c b/gdbserver/linux-aarch32-low.c new file mode 100644 index 00000000000..c6a70249d3b --- /dev/null +++ b/gdbserver/linux-aarch32-low.c @@ -0,0 +1,303 @@ +/* Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "arch/arm.h" +#include "arch/arm-linux.h" +#include "linux-low.h" +#include "linux-aarch32-low.h" + +#include +/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h. + On Bionic elf.h and linux/elf.h have conflicting definitions. */ +#ifndef ELFMAG0 +#include +#endif + +/* Correct in either endianness. */ +#define arm_abi_breakpoint 0xef9f0001UL + +/* For new EABI binaries. We recognize it regardless of which ABI + is used for gdbserver, so single threaded debugging should work + OK, but for multi-threaded debugging we only insert the current + ABI's breakpoint instruction. For now at least. */ +#define arm_eabi_breakpoint 0xe7f001f0UL + +#if (defined __ARM_EABI__ || defined __aarch64__) +static const unsigned long arm_breakpoint = arm_eabi_breakpoint; +#else +static const unsigned long arm_breakpoint = arm_abi_breakpoint; +#endif + +#define arm_breakpoint_len 4 +static const unsigned short thumb_breakpoint = 0xde01; +#define thumb_breakpoint_len 2 +static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 }; +#define thumb2_breakpoint_len 4 + +/* Some older versions of GNU/Linux and Android do not define + the following macros. */ +#ifndef NT_ARM_VFP +#define NT_ARM_VFP 0x400 +#endif + +/* Collect GP registers from REGCACHE to buffer BUF. */ + +void +arm_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + uint32_t *regs = (uint32_t *) buf; + uint32_t cpsr = regs[ARM_CPSR_GREGNUM]; + + for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++) + collect_register (regcache, i, ®s[i]); + + collect_register (regcache, ARM_PS_REGNUM, ®s[ARM_CPSR_GREGNUM]); + /* Keep reserved bits bit 20 to bit 23. */ + regs[ARM_CPSR_GREGNUM] = ((regs[ARM_CPSR_GREGNUM] & 0xff0fffff) + | (cpsr & 0x00f00000)); +} + +/* Supply GP registers contents, stored in BUF, to REGCACHE. */ + +void +arm_store_gregset (struct regcache *regcache, const void *buf) +{ + int i; + char zerobuf[8]; + const uint32_t *regs = (const uint32_t *) buf; + uint32_t cpsr = regs[ARM_CPSR_GREGNUM]; + + memset (zerobuf, 0, 8); + for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++) + supply_register (regcache, i, ®s[i]); + + for (; i < ARM_PS_REGNUM; i++) + supply_register (regcache, i, zerobuf); + + /* Clear reserved bits bit 20 to bit 23. */ + cpsr &= 0xff0fffff; + supply_register (regcache, ARM_PS_REGNUM, &cpsr); +} + +/* Collect NUM number of VFP registers from REGCACHE to buffer BUF. */ + +void +arm_fill_vfpregset_num (struct regcache *regcache, void *buf, int num) +{ + int i, base; + + gdb_assert (num == 16 || num == 32); + + base = find_regno (regcache->tdesc, "d0"); + for (i = 0; i < num; i++) + collect_register (regcache, base + i, (char *) buf + i * 8); + + collect_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8); +} + +/* Supply NUM number of VFP registers contents, stored in BUF, to + REGCACHE. */ + +void +arm_store_vfpregset_num (struct regcache *regcache, const void *buf, int num) +{ + int i, base; + + gdb_assert (num == 16 || num == 32); + + base = find_regno (regcache->tdesc, "d0"); + for (i = 0; i < num; i++) + supply_register (regcache, base + i, (char *) buf + i * 8); + + supply_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8); +} + +static void +arm_fill_vfpregset (struct regcache *regcache, void *buf) +{ + arm_fill_vfpregset_num (regcache, buf, 32); +} + +static void +arm_store_vfpregset (struct regcache *regcache, const void *buf) +{ + arm_store_vfpregset_num (regcache, buf, 32); +} + +/* Register sets with using PTRACE_GETREGSET. */ + +static struct regset_info aarch32_regsets[] = { + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, + ARM_CORE_REGS_SIZE + ARM_INT_REGISTER_SIZE, GENERAL_REGS, + arm_fill_gregset, arm_store_gregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_VFP, ARM_VFP3_REGS_SIZE, + EXTENDED_REGS, + arm_fill_vfpregset, arm_store_vfpregset }, + NULL_REGSET +}; + +static struct regsets_info aarch32_regsets_info = + { + aarch32_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +struct regs_info regs_info_aarch32 = + { + NULL, /* regset_bitmap */ + NULL, /* usrregs */ + &aarch32_regsets_info + }; + +/* Returns 1 if the current instruction set is thumb, 0 otherwise. */ + +int +arm_is_thumb_mode (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 1); + unsigned long cpsr; + + collect_register_by_name (regcache, "cpsr", &cpsr); + + if (cpsr & 0x20) + return 1; + else + return 0; +} + +/* Returns 1 if there is a software breakpoint at location. */ + +int +arm_breakpoint_at (CORE_ADDR where) +{ + if (arm_is_thumb_mode ()) + { + /* Thumb mode. */ + unsigned short insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 2); + if (insn == thumb_breakpoint) + return 1; + + if (insn == thumb2_breakpoint[0]) + { + (*the_target->read_memory) (where + 2, (unsigned char *) &insn, 2); + if (insn == thumb2_breakpoint[1]) + return 1; + } + } + else + { + /* ARM mode. */ + unsigned long insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 4); + if (insn == arm_abi_breakpoint) + return 1; + + if (insn == arm_eabi_breakpoint) + return 1; + } + + return 0; +} + +/* Implementation of linux_target_ops method "breakpoint_kind_from_pc". + + Determine the type and size of breakpoint to insert at PCPTR. Uses the + program counter value to determine whether a 16-bit or 32-bit breakpoint + should be used. It returns the breakpoint's kind, and adjusts the program + counter (if necessary) to point to the actual memory location where the + breakpoint should be inserted. */ + +int +arm_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + if (IS_THUMB_ADDR (*pcptr)) + { + gdb_byte buf[2]; + + *pcptr = UNMAKE_THUMB_ADDR (*pcptr); + + /* Check whether we are replacing a thumb2 32-bit instruction. */ + if (target_read_memory (*pcptr, buf, 2) == 0) + { + unsigned short inst1 = 0; + + target_read_memory (*pcptr, (gdb_byte *) &inst1, 2); + if (thumb_insn_size (inst1) == 4) + return ARM_BP_KIND_THUMB2; + } + return ARM_BP_KIND_THUMB; + } + else + return ARM_BP_KIND_ARM; +} + +/* Implementation of the linux_target_ops method "sw_breakpoint_from_kind". */ + +const gdb_byte * +arm_sw_breakpoint_from_kind (int kind , int *size) +{ + *size = arm_breakpoint_len; + /* Define an ARM-mode breakpoint; we only set breakpoints in the C + library, which is most likely to be ARM. If the kernel supports + clone events, we will never insert a breakpoint, so even a Thumb + C library will work; so will mixing EABI/non-EABI gdbserver and + application. */ + switch (kind) + { + case ARM_BP_KIND_THUMB: + *size = thumb_breakpoint_len; + return (gdb_byte *) &thumb_breakpoint; + case ARM_BP_KIND_THUMB2: + *size = thumb2_breakpoint_len; + return (gdb_byte *) &thumb2_breakpoint; + case ARM_BP_KIND_ARM: + *size = arm_breakpoint_len; + return (const gdb_byte *) &arm_breakpoint; + default: + return NULL; + } + return NULL; +} + +/* Implementation of the linux_target_ops method + "breakpoint_kind_from_current_state". */ + +int +arm_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) +{ + if (arm_is_thumb_mode ()) + { + *pcptr = MAKE_THUMB_ADDR (*pcptr); + return arm_breakpoint_kind_from_pc (pcptr); + } + else + { + return arm_breakpoint_kind_from_pc (pcptr); + } +} + +void +initialize_low_arch_aarch32 (void) +{ + initialize_regsets_info (&aarch32_regsets_info); +} diff --git a/gdbserver/linux-aarch32-low.h b/gdbserver/linux-aarch32-low.h new file mode 100644 index 00000000000..85eda5cbc8c --- /dev/null +++ b/gdbserver/linux-aarch32-low.h @@ -0,0 +1,39 @@ +/* Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_AARCH32_LOW_H +#define GDBSERVER_LINUX_AARCH32_LOW_H + +extern struct regs_info regs_info_aarch32; + +void arm_fill_gregset (struct regcache *regcache, void *buf); +void arm_store_gregset (struct regcache *regcache, const void *buf); +void arm_fill_vfpregset_num (struct regcache *regcache, void *buf, int num); +void arm_store_vfpregset_num (struct regcache *regcache, const void *buf, + int num); + +int arm_breakpoint_kind_from_pc (CORE_ADDR *pcptr); +const gdb_byte *arm_sw_breakpoint_from_kind (int kind , int *size); +int arm_breakpoint_kind_from_current_state (CORE_ADDR *pcptr); +int arm_breakpoint_at (CORE_ADDR where); + +void initialize_low_arch_aarch32 (void); + +void init_registers_arm_with_neon (void); +int arm_is_thumb_mode (void); + +#endif /* GDBSERVER_LINUX_AARCH32_LOW_H */ diff --git a/gdbserver/linux-aarch32-tdesc.c b/gdbserver/linux-aarch32-tdesc.c new file mode 100644 index 00000000000..b0dffe27e71 --- /dev/null +++ b/gdbserver/linux-aarch32-tdesc.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2019-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" + +#include "linux-aarch32-tdesc.h" + +#include "tdesc.h" +#include "arch/aarch32.h" +#include + +static struct target_desc *tdesc_aarch32; + +/* See linux-aarch32-tdesc.h. */ + +const target_desc * +aarch32_linux_read_description () +{ + if (tdesc_aarch32 == nullptr) + { + tdesc_aarch32 = aarch32_create_target_description (); + + static const char *expedite_regs[] = { "r11", "sp", "pc", 0 }; + init_target_desc (tdesc_aarch32, expedite_regs); + } + return tdesc_aarch32; +} + +/* See linux-aarch32-tdesc.h. */ + +bool +is_aarch32_linux_description (const target_desc *tdesc) +{ + gdb_assert (tdesc != nullptr); + return tdesc == tdesc_aarch32; +} diff --git a/gdbserver/linux-aarch32-tdesc.h b/gdbserver/linux-aarch32-tdesc.h new file mode 100644 index 00000000000..67d3f696190 --- /dev/null +++ b/gdbserver/linux-aarch32-tdesc.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2019-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_AARCH32_TDESC_H +#define GDBSERVER_LINUX_AARCH32_TDESC_H + +/* Return the AArch32 target description. */ + +const target_desc * aarch32_linux_read_description (); + +/* Return true if TDESC is the AArch32 target description. */ + +bool is_aarch32_linux_description (const target_desc *tdesc); + +#endif /* linux-aarch32-tdesc.h. */ diff --git a/gdbserver/linux-aarch64-ipa.c b/gdbserver/linux-aarch64-ipa.c new file mode 100644 index 00000000000..694dfd77dfa --- /dev/null +++ b/gdbserver/linux-aarch64-ipa.c @@ -0,0 +1,209 @@ +/* GNU/Linux/AArch64 specific low level interface, for the in-process + agent library for GDB. + + Copyright (C) 2015-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include +#include "tracepoint.h" +#include +#ifdef HAVE_GETAUXVAL +#include +#endif +#include "linux-aarch64-tdesc.h" + +/* Each register saved by the jump pad is in a 16 byte cell. */ +#define FT_CR_SIZE 16 + +#define FT_CR_FPCR 0 +#define FT_CR_FPSR 1 +#define FT_CR_CPSR 2 +#define FT_CR_PC 3 +#define FT_CR_SP 4 +#define FT_CR_X0 5 +#define FT_CR_GPR(n) (FT_CR_X0 + (n)) +#define FT_CR_FPR(n) (FT_CR_GPR (31) + (n)) + +/* Mapping between registers collected by the jump pad and GDB's register + array layout used by regcache. + + See linux-aarch64-low.c (aarch64_install_fast_tracepoint_jump_pad) for + more details. */ + +static const int aarch64_ft_collect_regmap[] = { + FT_CR_GPR (0), + FT_CR_GPR (1), + FT_CR_GPR (2), + FT_CR_GPR (3), + FT_CR_GPR (4), + FT_CR_GPR (5), + FT_CR_GPR (6), + FT_CR_GPR (7), + FT_CR_GPR (8), + FT_CR_GPR (9), + FT_CR_GPR (10), + FT_CR_GPR (11), + FT_CR_GPR (12), + FT_CR_GPR (13), + FT_CR_GPR (14), + FT_CR_GPR (15), + FT_CR_GPR (16), + FT_CR_GPR (17), + FT_CR_GPR (18), + FT_CR_GPR (19), + FT_CR_GPR (20), + FT_CR_GPR (21), + FT_CR_GPR (22), + FT_CR_GPR (23), + FT_CR_GPR (24), + FT_CR_GPR (25), + FT_CR_GPR (26), + FT_CR_GPR (27), + FT_CR_GPR (28), + /* FP */ + FT_CR_GPR (29), + /* LR */ + FT_CR_GPR (30), + FT_CR_SP, + FT_CR_PC, + FT_CR_CPSR, + FT_CR_FPR (0), + FT_CR_FPR (1), + FT_CR_FPR (2), + FT_CR_FPR (3), + FT_CR_FPR (4), + FT_CR_FPR (5), + FT_CR_FPR (6), + FT_CR_FPR (7), + FT_CR_FPR (8), + FT_CR_FPR (9), + FT_CR_FPR (10), + FT_CR_FPR (11), + FT_CR_FPR (12), + FT_CR_FPR (13), + FT_CR_FPR (14), + FT_CR_FPR (15), + FT_CR_FPR (16), + FT_CR_FPR (17), + FT_CR_FPR (18), + FT_CR_FPR (19), + FT_CR_FPR (20), + FT_CR_FPR (21), + FT_CR_FPR (22), + FT_CR_FPR (23), + FT_CR_FPR (24), + FT_CR_FPR (25), + FT_CR_FPR (26), + FT_CR_FPR (27), + FT_CR_FPR (28), + FT_CR_FPR (29), + FT_CR_FPR (30), + FT_CR_FPR (31), + FT_CR_FPSR, + FT_CR_FPCR +}; + +#define AARCH64_NUM_FT_COLLECT_GREGS \ + (sizeof (aarch64_ft_collect_regmap) / sizeof(aarch64_ft_collect_regmap[0])) + +/* Fill in REGCACHE with registers saved by the jump pad in BUF. */ + +void +supply_fast_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf) +{ + int i; + + for (i = 0; i < AARCH64_NUM_FT_COLLECT_GREGS; i++) + supply_register (regcache, i, + ((char *) buf) + + (aarch64_ft_collect_regmap[i] * FT_CR_SIZE)); +} + +ULONGEST +get_raw_reg (const unsigned char *raw_regs, int regnum) +{ + if (regnum >= AARCH64_NUM_FT_COLLECT_GREGS) + return 0; + + return *(ULONGEST *) (raw_regs + + aarch64_ft_collect_regmap[regnum] * FT_CR_SIZE); +} + +/* Return target_desc to use for IPA, given the tdesc index passed by + gdbserver. Index is ignored, since we have only one tdesc + at the moment. SVE and pauth not yet supported. */ + +const struct target_desc * +get_ipa_tdesc (int idx) +{ + return aarch64_linux_read_description (0, false); +} + +/* Allocate buffer for the jump pads. The branch instruction has a reach + of +/- 128MiB, and the executable is loaded at 0x400000 (4MiB). + To maximize the area of executable that can use tracepoints, try + allocating at 0x400000 - size initially, decreasing until we hit + a free area. */ + +void * +alloc_jump_pad_buffer (size_t size) +{ + uintptr_t addr; + uintptr_t exec_base = getauxval (AT_PHDR); + int pagesize; + void *res; + + if (exec_base == 0) + exec_base = 0x400000; + + pagesize = sysconf (_SC_PAGE_SIZE); + if (pagesize == -1) + perror_with_name ("sysconf"); + + addr = exec_base - size; + + /* size should already be page-aligned, but this can't hurt. */ + addr &= ~(pagesize - 1); + + /* Search for a free area. If we hit 0, we're out of luck. */ + for (; addr; addr -= pagesize) + { + /* No MAP_FIXED - we don't want to zap someone's mapping. */ + res = mmap ((void *) addr, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* If we got what we wanted, return. */ + if ((uintptr_t) res == addr) + return res; + + /* If we got a mapping, but at a wrong address, undo it. */ + if (res != MAP_FAILED) + munmap (res, size); + } + + return NULL; +} + +void +initialize_low_tracepoint (void) +{ + /* SVE and pauth not yet supported. */ + aarch64_linux_read_description (0, false); +} diff --git a/gdbserver/linux-aarch64-low.c b/gdbserver/linux-aarch64-low.c new file mode 100644 index 00000000000..961fd5b3cc4 --- /dev/null +++ b/gdbserver/linux-aarch64-low.c @@ -0,0 +1,3098 @@ +/* GNU/Linux/AArch64 specific low level interface, for the remote server for + GDB. + + Copyright (C) 2009-2020 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + 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 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "nat/aarch64-linux.h" +#include "nat/aarch64-linux-hw-point.h" +#include "arch/aarch64-insn.h" +#include "linux-aarch32-low.h" +#include "elf/common.h" +#include "ax.h" +#include "tracepoint.h" +#include "debug.h" + +#include +#include +#include "nat/gdb_ptrace.h" +#include +#include +#include +#include + +#include "gdb_proc_service.h" +#include "arch/aarch64.h" +#include "linux-aarch32-tdesc.h" +#include "linux-aarch64-tdesc.h" +#include "nat/aarch64-sve-linux-ptrace.h" +#include "tdesc.h" + +#ifdef HAVE_SYS_REG_H +#include +#endif + +/* Per-process arch-specific data we want to keep. */ + +struct arch_process_info +{ + /* Hardware breakpoint/watchpoint data. + The reason for them to be per-process rather than per-thread is + due to the lack of information in the gdbserver environment; + gdbserver is not told that whether a requested hardware + breakpoint/watchpoint is thread specific or not, so it has to set + each hw bp/wp for every thread in the current process. The + higher level bp/wp management in gdb will resume a thread if a hw + bp/wp trap is not expected for it. Since the hw bp/wp setting is + same for each thread, it is reasonable for the data to live here. + */ + struct aarch64_debug_reg_state debug_reg_state; +}; + +/* Return true if the size of register 0 is 8 byte. */ + +static int +is_64bit_tdesc (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + + return register_size (regcache->tdesc, 0) == 8; +} + +/* Return true if the regcache contains the number of SVE registers. */ + +static bool +is_sve_tdesc (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + + return tdesc_contains_feature (regcache->tdesc, "org.gnu.gdb.aarch64.sve"); +} + +static void +aarch64_fill_gregset (struct regcache *regcache, void *buf) +{ + struct user_pt_regs *regset = (struct user_pt_regs *) buf; + int i; + + for (i = 0; i < AARCH64_X_REGS_NUM; i++) + collect_register (regcache, AARCH64_X0_REGNUM + i, ®set->regs[i]); + collect_register (regcache, AARCH64_SP_REGNUM, ®set->sp); + collect_register (regcache, AARCH64_PC_REGNUM, ®set->pc); + collect_register (regcache, AARCH64_CPSR_REGNUM, ®set->pstate); +} + +static void +aarch64_store_gregset (struct regcache *regcache, const void *buf) +{ + const struct user_pt_regs *regset = (const struct user_pt_regs *) buf; + int i; + + for (i = 0; i < AARCH64_X_REGS_NUM; i++) + supply_register (regcache, AARCH64_X0_REGNUM + i, ®set->regs[i]); + supply_register (regcache, AARCH64_SP_REGNUM, ®set->sp); + supply_register (regcache, AARCH64_PC_REGNUM, ®set->pc); + supply_register (regcache, AARCH64_CPSR_REGNUM, ®set->pstate); +} + +static void +aarch64_fill_fpregset (struct regcache *regcache, void *buf) +{ + struct user_fpsimd_state *regset = (struct user_fpsimd_state *) buf; + int i; + + for (i = 0; i < AARCH64_V_REGS_NUM; i++) + collect_register (regcache, AARCH64_V0_REGNUM + i, ®set->vregs[i]); + collect_register (regcache, AARCH64_FPSR_REGNUM, ®set->fpsr); + collect_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr); +} + +static void +aarch64_store_fpregset (struct regcache *regcache, const void *buf) +{ + const struct user_fpsimd_state *regset + = (const struct user_fpsimd_state *) buf; + int i; + + for (i = 0; i < AARCH64_V_REGS_NUM; i++) + supply_register (regcache, AARCH64_V0_REGNUM + i, ®set->vregs[i]); + supply_register (regcache, AARCH64_FPSR_REGNUM, ®set->fpsr); + supply_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr); +} + +/* Store the pauth registers to regcache. */ + +static void +aarch64_store_pauthregset (struct regcache *regcache, const void *buf) +{ + uint64_t *pauth_regset = (uint64_t *) buf; + int pauth_base = find_regno (regcache->tdesc, "pauth_dmask"); + + if (pauth_base == 0) + return; + + supply_register (regcache, AARCH64_PAUTH_DMASK_REGNUM (pauth_base), + &pauth_regset[0]); + supply_register (regcache, AARCH64_PAUTH_CMASK_REGNUM (pauth_base), + &pauth_regset[1]); +} + +/* Implementation of linux_target_ops method "get_pc". */ + +static CORE_ADDR +aarch64_get_pc (struct regcache *regcache) +{ + if (register_size (regcache->tdesc, 0) == 8) + return linux_get_pc_64bit (regcache); + else + return linux_get_pc_32bit (regcache); +} + +/* Implementation of linux_target_ops method "set_pc". */ + +static void +aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc) +{ + if (register_size (regcache->tdesc, 0) == 8) + linux_set_pc_64bit (regcache, pc); + else + linux_set_pc_32bit (regcache, pc); +} + +#define aarch64_breakpoint_len 4 + +/* AArch64 BRK software debug mode instruction. + This instruction needs to match gdb/aarch64-tdep.c + (aarch64_default_breakpoint). */ +static const gdb_byte aarch64_breakpoint[] = {0x00, 0x00, 0x20, 0xd4}; + +/* Implementation of linux_target_ops method "breakpoint_at". */ + +static int +aarch64_breakpoint_at (CORE_ADDR where) +{ + if (is_64bit_tdesc ()) + { + gdb_byte insn[aarch64_breakpoint_len]; + + (*the_target->read_memory) (where, (unsigned char *) &insn, + aarch64_breakpoint_len); + if (memcmp (insn, aarch64_breakpoint, aarch64_breakpoint_len) == 0) + return 1; + + return 0; + } + else + return arm_breakpoint_at (where); +} + +static void +aarch64_init_debug_reg_state (struct aarch64_debug_reg_state *state) +{ + int i; + + for (i = 0; i < AARCH64_HBP_MAX_NUM; ++i) + { + state->dr_addr_bp[i] = 0; + state->dr_ctrl_bp[i] = 0; + state->dr_ref_count_bp[i] = 0; + } + + for (i = 0; i < AARCH64_HWP_MAX_NUM; ++i) + { + state->dr_addr_wp[i] = 0; + state->dr_ctrl_wp[i] = 0; + state->dr_ref_count_wp[i] = 0; + } +} + +/* Return the pointer to the debug register state structure in the + current process' arch-specific data area. */ + +struct aarch64_debug_reg_state * +aarch64_get_debug_reg_state (pid_t pid) +{ + struct process_info *proc = find_process_pid (pid); + + return &proc->priv->arch_private->debug_reg_state; +} + +/* Implementation of linux_target_ops method "supports_z_point_type". */ + +static int +aarch64_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + case Z_PACKET_HW_BP: + case Z_PACKET_WRITE_WP: + case Z_PACKET_READ_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + return 0; + } +} + +/* Implementation of linux_target_ops method "insert_point". + + It actually only records the info of the to-be-inserted bp/wp; + the actual insertion will happen when threads are resumed. */ + +static int +aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + int ret; + enum target_hw_bp_type targ_type; + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (pid_of (current_thread)); + + if (show_debug_regs) + fprintf (stderr, "insert_point on entry (addr=0x%08lx, len=%d)\n", + (unsigned long) addr, len); + + /* Determine the type from the raw breakpoint type. */ + targ_type = raw_bkpt_type_to_target_hw_bp_type (type); + + if (targ_type != hw_execute) + { + if (aarch64_linux_region_ok_for_watchpoint (addr, len)) + ret = aarch64_handle_watchpoint (targ_type, addr, len, + 1 /* is_insert */, state); + else + ret = -1; + } + else + { + if (len == 3) + { + /* LEN is 3 means the breakpoint is set on a 32-bit thumb + instruction. Set it to 2 to correctly encode length bit + mask in hardware/watchpoint control register. */ + len = 2; + } + ret = aarch64_handle_breakpoint (targ_type, addr, len, + 1 /* is_insert */, state); + } + + if (show_debug_regs) + aarch64_show_debug_reg_state (state, "insert_point", addr, len, + targ_type); + + return ret; +} + +/* Implementation of linux_target_ops method "remove_point". + + It actually only records the info of the to-be-removed bp/wp, + the actual removal will be done when threads are resumed. */ + +static int +aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + int ret; + enum target_hw_bp_type targ_type; + struct aarch64_debug_reg_state *state + = aarch64_get_debug_reg_state (pid_of (current_thread)); + + if (show_debug_regs) + fprintf (stderr, "remove_point on entry (addr=0x%08lx, len=%d)\n", + (unsigned long) addr, len); + + /* Determine the type from the raw breakpoint type. */ + targ_type = raw_bkpt_type_to_target_hw_bp_type (type); + + /* Set up state pointers. */ + if (targ_type != hw_execute) + ret = + aarch64_handle_watchpoint (targ_type, addr, len, 0 /* is_insert */, + state); + else + { + if (len == 3) + { + /* LEN is 3 means the breakpoint is set on a 32-bit thumb + instruction. Set it to 2 to correctly encode length bit + mask in hardware/watchpoint control register. */ + len = 2; + } + ret = aarch64_handle_breakpoint (targ_type, addr, len, + 0 /* is_insert */, state); + } + + if (show_debug_regs) + aarch64_show_debug_reg_state (state, "remove_point", addr, len, + targ_type); + + return ret; +} + +/* Implementation of linux_target_ops method "stopped_data_address". */ + +static CORE_ADDR +aarch64_stopped_data_address (void) +{ + siginfo_t siginfo; + int pid, i; + struct aarch64_debug_reg_state *state; + + pid = lwpid_of (current_thread); + + /* Get the siginfo. */ + if (ptrace (PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) + return (CORE_ADDR) 0; + + /* Need to be a hardware breakpoint/watchpoint trap. */ + if (siginfo.si_signo != SIGTRAP + || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) + return (CORE_ADDR) 0; + + /* Check if the address matches any watched address. */ + state = aarch64_get_debug_reg_state (pid_of (current_thread)); + for (i = aarch64_num_wp_regs - 1; i >= 0; --i) + { + const unsigned int offset + = aarch64_watchpoint_offset (state->dr_ctrl_wp[i]); + const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]); + const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr; + const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset; + const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8); + const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i]; + + if (state->dr_ref_count_wp[i] + && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i]) + && addr_trap >= addr_watch_aligned + && addr_trap < addr_watch + len) + { + /* ADDR_TRAP reports the first address of the memory range + accessed by the CPU, regardless of what was the memory + range watched. Thus, a large CPU access that straddles + the ADDR_WATCH..ADDR_WATCH+LEN range may result in an + ADDR_TRAP that is lower than the + ADDR_WATCH..ADDR_WATCH+LEN range. E.g.: + + addr: | 4 | 5 | 6 | 7 | 8 | + |---- range watched ----| + |----------- range accessed ------------| + + In this case, ADDR_TRAP will be 4. + + To match a watchpoint known to GDB core, we must never + report *ADDR_P outside of any ADDR_WATCH..ADDR_WATCH+LEN + range. ADDR_WATCH <= ADDR_TRAP < ADDR_ORIG is a false + positive on kernels older than 4.10. See PR + external/20207. */ + return addr_orig; + } + } + + return (CORE_ADDR) 0; +} + +/* Implementation of linux_target_ops method "stopped_by_watchpoint". */ + +static int +aarch64_stopped_by_watchpoint (void) +{ + if (aarch64_stopped_data_address () != 0) + return 1; + else + return 0; +} + +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + return aarch64_ps_get_thread_area (ph, lwpid, idx, base, + is_64bit_tdesc ()); +} + +/* Implementation of linux_target_ops method "siginfo_fixup". */ + +static int +aarch64_linux_siginfo_fixup (siginfo_t *native, gdb_byte *inf, int direction) +{ + /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ + if (!is_64bit_tdesc ()) + { + if (direction == 0) + aarch64_compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, + native); + else + aarch64_siginfo_from_compat_siginfo (native, + (struct compat_siginfo *) inf); + + return 1; + } + + return 0; +} + +/* Implementation of linux_target_ops method "new_process". */ + +static struct arch_process_info * +aarch64_linux_new_process (void) +{ + struct arch_process_info *info = XCNEW (struct arch_process_info); + + aarch64_init_debug_reg_state (&info->debug_reg_state); + + return info; +} + +/* Implementation of linux_target_ops method "delete_process". */ + +static void +aarch64_linux_delete_process (struct arch_process_info *info) +{ + xfree (info); +} + +/* Implementation of linux_target_ops method "linux_new_fork". */ + +static void +aarch64_linux_new_fork (struct process_info *parent, + struct process_info *child) +{ + /* These are allocated by linux_add_process. */ + gdb_assert (parent->priv != NULL + && parent->priv->arch_private != NULL); + gdb_assert (child->priv != NULL + && child->priv->arch_private != NULL); + + /* Linux kernel before 2.6.33 commit + 72f674d203cd230426437cdcf7dd6f681dad8b0d + will inherit hardware debug registers from parent + on fork/vfork/clone. Newer Linux kernels create such tasks with + zeroed debug registers. + + GDB core assumes the child inherits the watchpoints/hw + breakpoints of the parent, and will remove them all from the + forked off process. Copy the debug registers mirrors into the + new process so that all breakpoints and watchpoints can be + removed together. The debug registers mirror will become zeroed + in the end before detaching the forked off process, thus making + this compatible with older Linux kernels too. */ + + *child->priv->arch_private = *parent->priv->arch_private; +} + +/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h. */ +#define AARCH64_HWCAP_PACA (1 << 30) + +/* Implementation of linux_target_ops method "arch_setup". */ + +static void +aarch64_arch_setup (void) +{ + unsigned int machine; + int is_elf64; + int tid; + + tid = lwpid_of (current_thread); + + is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); + + if (is_elf64) + { + uint64_t vq = aarch64_sve_get_vq (tid); + unsigned long hwcap = linux_get_hwcap (8); + bool pauth_p = hwcap & AARCH64_HWCAP_PACA; + + current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p); + } + else + current_process ()->tdesc = aarch32_linux_read_description (); + + aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread)); +} + +/* Wrapper for aarch64_sve_regs_copy_to_reg_buf. */ + +static void +aarch64_sve_regs_copy_to_regcache (struct regcache *regcache, const void *buf) +{ + return aarch64_sve_regs_copy_to_reg_buf (regcache, buf); +} + +/* Wrapper for aarch64_sve_regs_copy_from_reg_buf. */ + +static void +aarch64_sve_regs_copy_from_regcache (struct regcache *regcache, void *buf) +{ + return aarch64_sve_regs_copy_from_reg_buf (regcache, buf); +} + +static struct regset_info aarch64_regsets[] = +{ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, + sizeof (struct user_pt_regs), GENERAL_REGS, + aarch64_fill_gregset, aarch64_store_gregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, + sizeof (struct user_fpsimd_state), FP_REGS, + aarch64_fill_fpregset, aarch64_store_fpregset + }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK, + AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS, + NULL, aarch64_store_pauthregset }, + NULL_REGSET +}; + +static struct regsets_info aarch64_regsets_info = + { + aarch64_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info_aarch64 = + { + NULL, /* regset_bitmap */ + NULL, /* usrregs */ + &aarch64_regsets_info, + }; + +static struct regset_info aarch64_sve_regsets[] = +{ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, + sizeof (struct user_pt_regs), GENERAL_REGS, + aarch64_fill_gregset, aarch64_store_gregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_SVE, + SVE_PT_SIZE (AARCH64_MAX_SVE_VQ, SVE_PT_REGS_SVE), EXTENDED_REGS, + aarch64_sve_regs_copy_from_regcache, aarch64_sve_regs_copy_to_regcache + }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK, + AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS, + NULL, aarch64_store_pauthregset }, + NULL_REGSET +}; + +static struct regsets_info aarch64_sve_regsets_info = + { + aarch64_sve_regsets, /* regsets. */ + 0, /* num_regsets. */ + NULL, /* disabled_regsets. */ + }; + +static struct regs_info regs_info_aarch64_sve = + { + NULL, /* regset_bitmap. */ + NULL, /* usrregs. */ + &aarch64_sve_regsets_info, + }; + +/* Implementation of linux_target_ops method "regs_info". */ + +static const struct regs_info * +aarch64_regs_info (void) +{ + if (!is_64bit_tdesc ()) + return ®s_info_aarch32; + + if (is_sve_tdesc ()) + return ®s_info_aarch64_sve; + + return ®s_info_aarch64; +} + +/* Implementation of linux_target_ops method "supports_tracepoints". */ + +static int +aarch64_supports_tracepoints (void) +{ + if (current_thread == NULL) + return 1; + else + { + /* We don't support tracepoints on aarch32 now. */ + return is_64bit_tdesc (); + } +} + +/* Implementation of linux_target_ops method "get_thread_area". */ + +static int +aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp) +{ + struct iovec iovec; + uint64_t reg; + + iovec.iov_base = ® + iovec.iov_len = sizeof (reg); + + if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0) + return -1; + + *addrp = reg; + + return 0; +} + +/* Implementation of linux_target_ops method "get_syscall_trapinfo". */ + +static void +aarch64_get_syscall_trapinfo (struct regcache *regcache, int *sysno) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + long l_sysno; + + collect_register_by_name (regcache, "x8", &l_sysno); + *sysno = (int) l_sysno; + } + else + collect_register_by_name (regcache, "r7", sysno); +} + +/* List of condition codes that we need. */ + +enum aarch64_condition_codes +{ + EQ = 0x0, + NE = 0x1, + LO = 0x3, + GE = 0xa, + LT = 0xb, + GT = 0xc, + LE = 0xd, +}; + +enum aarch64_operand_type +{ + OPERAND_IMMEDIATE, + OPERAND_REGISTER, +}; + +/* Representation of an operand. At this time, it only supports register + and immediate types. */ + +struct aarch64_operand +{ + /* Type of the operand. */ + enum aarch64_operand_type type; + + /* Value of the operand according to the type. */ + union + { + uint32_t imm; + struct aarch64_register reg; + }; +}; + +/* List of registers that we are currently using, we can add more here as + we need to use them. */ + +/* General purpose scratch registers (64 bit). */ +static const struct aarch64_register x0 = { 0, 1 }; +static const struct aarch64_register x1 = { 1, 1 }; +static const struct aarch64_register x2 = { 2, 1 }; +static const struct aarch64_register x3 = { 3, 1 }; +static const struct aarch64_register x4 = { 4, 1 }; + +/* General purpose scratch registers (32 bit). */ +static const struct aarch64_register w0 = { 0, 0 }; +static const struct aarch64_register w2 = { 2, 0 }; + +/* Intra-procedure scratch registers. */ +static const struct aarch64_register ip0 = { 16, 1 }; + +/* Special purpose registers. */ +static const struct aarch64_register fp = { 29, 1 }; +static const struct aarch64_register lr = { 30, 1 }; +static const struct aarch64_register sp = { 31, 1 }; +static const struct aarch64_register xzr = { 31, 1 }; + +/* Dynamically allocate a new register. If we know the register + statically, we should make it a global as above instead of using this + helper function. */ + +static struct aarch64_register +aarch64_register (unsigned num, int is64) +{ + return (struct aarch64_register) { num, is64 }; +} + +/* Helper function to create a register operand, for instructions with + different types of operands. + + For example: + p += emit_mov (p, x0, register_operand (x1)); */ + +static struct aarch64_operand +register_operand (struct aarch64_register reg) +{ + struct aarch64_operand operand; + + operand.type = OPERAND_REGISTER; + operand.reg = reg; + + return operand; +} + +/* Helper function to create an immediate operand, for instructions with + different types of operands. + + For example: + p += emit_mov (p, x0, immediate_operand (12)); */ + +static struct aarch64_operand +immediate_operand (uint32_t imm) +{ + struct aarch64_operand operand; + + operand.type = OPERAND_IMMEDIATE; + operand.imm = imm; + + return operand; +} + +/* Helper function to create an offset memory operand. + + For example: + p += emit_ldr (p, x0, sp, offset_memory_operand (16)); */ + +static struct aarch64_memory_operand +offset_memory_operand (int32_t offset) +{ + return (struct aarch64_memory_operand) { MEMORY_OPERAND_OFFSET, offset }; +} + +/* Helper function to create a pre-index memory operand. + + For example: + p += emit_ldr (p, x0, sp, preindex_memory_operand (16)); */ + +static struct aarch64_memory_operand +preindex_memory_operand (int32_t index) +{ + return (struct aarch64_memory_operand) { MEMORY_OPERAND_PREINDEX, index }; +} + +/* Helper function to create a post-index memory operand. + + For example: + p += emit_ldr (p, x0, sp, postindex_memory_operand (16)); */ + +static struct aarch64_memory_operand +postindex_memory_operand (int32_t index) +{ + return (struct aarch64_memory_operand) { MEMORY_OPERAND_POSTINDEX, index }; +} + +/* System control registers. These special registers can be written and + read with the MRS and MSR instructions. + + - NZCV: Condition flags. GDB refers to this register under the CPSR + name. + - FPSR: Floating-point status register. + - FPCR: Floating-point control registers. + - TPIDR_EL0: Software thread ID register. */ + +enum aarch64_system_control_registers +{ + /* op0 op1 crn crm op2 */ + NZCV = (0x1 << 14) | (0x3 << 11) | (0x4 << 7) | (0x2 << 3) | 0x0, + FPSR = (0x1 << 14) | (0x3 << 11) | (0x4 << 7) | (0x4 << 3) | 0x1, + FPCR = (0x1 << 14) | (0x3 << 11) | (0x4 << 7) | (0x4 << 3) | 0x0, + TPIDR_EL0 = (0x1 << 14) | (0x3 << 11) | (0xd << 7) | (0x0 << 3) | 0x2 +}; + +/* Write a BLR instruction into *BUF. + + BLR rn + + RN is the register to branch to. */ + +static int +emit_blr (uint32_t *buf, struct aarch64_register rn) +{ + return aarch64_emit_insn (buf, BLR | ENCODE (rn.num, 5, 5)); +} + +/* Write a RET instruction into *BUF. + + RET xn + + RN is the register to branch to. */ + +static int +emit_ret (uint32_t *buf, struct aarch64_register rn) +{ + return aarch64_emit_insn (buf, RET | ENCODE (rn.num, 5, 5)); +} + +static int +emit_load_store_pair (uint32_t *buf, enum aarch64_opcodes opcode, + struct aarch64_register rt, + struct aarch64_register rt2, + struct aarch64_register rn, + struct aarch64_memory_operand operand) +{ + uint32_t opc; + uint32_t pre_index; + uint32_t write_back; + + if (rt.is64) + opc = ENCODE (2, 2, 30); + else + opc = ENCODE (0, 2, 30); + + switch (operand.type) + { + case MEMORY_OPERAND_OFFSET: + { + pre_index = ENCODE (1, 1, 24); + write_back = ENCODE (0, 1, 23); + break; + } + case MEMORY_OPERAND_POSTINDEX: + { + pre_index = ENCODE (0, 1, 24); + write_back = ENCODE (1, 1, 23); + break; + } + case MEMORY_OPERAND_PREINDEX: + { + pre_index = ENCODE (1, 1, 24); + write_back = ENCODE (1, 1, 23); + break; + } + default: + return 0; + } + + return aarch64_emit_insn (buf, opcode | opc | pre_index | write_back + | ENCODE (operand.index >> 3, 7, 15) + | ENCODE (rt2.num, 5, 10) + | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); +} + +/* Write a STP instruction into *BUF. + + STP rt, rt2, [rn, #offset] + STP rt, rt2, [rn, #index]! + STP rt, rt2, [rn], #index + + RT and RT2 are the registers to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to a + -512 .. 504 range (7 bits << 3). */ + +static int +emit_stp (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rt2, struct aarch64_register rn, + struct aarch64_memory_operand operand) +{ + return emit_load_store_pair (buf, STP, rt, rt2, rn, operand); +} + +/* Write a LDP instruction into *BUF. + + LDP rt, rt2, [rn, #offset] + LDP rt, rt2, [rn, #index]! + LDP rt, rt2, [rn], #index + + RT and RT2 are the registers to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to a + -512 .. 504 range (7 bits << 3). */ + +static int +emit_ldp (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rt2, struct aarch64_register rn, + struct aarch64_memory_operand operand) +{ + return emit_load_store_pair (buf, LDP, rt, rt2, rn, operand); +} + +/* Write a LDP (SIMD&VFP) instruction using Q registers into *BUF. + + LDP qt, qt2, [rn, #offset] + + RT and RT2 are the Q registers to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + -1024 .. 1008 range (7 bits << 4). */ + +static int +emit_ldp_q_offset (uint32_t *buf, unsigned rt, unsigned rt2, + struct aarch64_register rn, int32_t offset) +{ + uint32_t opc = ENCODE (2, 2, 30); + uint32_t pre_index = ENCODE (1, 1, 24); + + return aarch64_emit_insn (buf, LDP_SIMD_VFP | opc | pre_index + | ENCODE (offset >> 4, 7, 15) + | ENCODE (rt2, 5, 10) + | ENCODE (rn.num, 5, 5) | ENCODE (rt, 5, 0)); +} + +/* Write a STP (SIMD&VFP) instruction using Q registers into *BUF. + + STP qt, qt2, [rn, #offset] + + RT and RT2 are the Q registers to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + -1024 .. 1008 range (7 bits << 4). */ + +static int +emit_stp_q_offset (uint32_t *buf, unsigned rt, unsigned rt2, + struct aarch64_register rn, int32_t offset) +{ + uint32_t opc = ENCODE (2, 2, 30); + uint32_t pre_index = ENCODE (1, 1, 24); + + return aarch64_emit_insn (buf, STP_SIMD_VFP | opc | pre_index + | ENCODE (offset >> 4, 7, 15) + | ENCODE (rt2, 5, 10) + | ENCODE (rn.num, 5, 5) | ENCODE (rt, 5, 0)); +} + +/* Write a LDRH instruction into *BUF. + + LDRH wt, [xn, #offset] + LDRH wt, [xn, #index]! + LDRH wt, [xn], #index + + RT is the register to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + 0 .. 32760 range (12 bits << 3). */ + +static int +emit_ldrh (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rn, + struct aarch64_memory_operand operand) +{ + return aarch64_emit_load_store (buf, 1, LDR, rt, rn, operand); +} + +/* Write a LDRB instruction into *BUF. + + LDRB wt, [xn, #offset] + LDRB wt, [xn, #index]! + LDRB wt, [xn], #index + + RT is the register to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + 0 .. 32760 range (12 bits << 3). */ + +static int +emit_ldrb (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rn, + struct aarch64_memory_operand operand) +{ + return aarch64_emit_load_store (buf, 0, LDR, rt, rn, operand); +} + + + +/* Write a STR instruction into *BUF. + + STR rt, [rn, #offset] + STR rt, [rn, #index]! + STR rt, [rn], #index + + RT is the register to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + 0 .. 32760 range (12 bits << 3). */ + +static int +emit_str (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rn, + struct aarch64_memory_operand operand) +{ + return aarch64_emit_load_store (buf, rt.is64 ? 3 : 2, STR, rt, rn, operand); +} + +/* Helper function emitting an exclusive load or store instruction. */ + +static int +emit_load_store_exclusive (uint32_t *buf, uint32_t size, + enum aarch64_opcodes opcode, + struct aarch64_register rs, + struct aarch64_register rt, + struct aarch64_register rt2, + struct aarch64_register rn) +{ + return aarch64_emit_insn (buf, opcode | ENCODE (size, 2, 30) + | ENCODE (rs.num, 5, 16) | ENCODE (rt2.num, 5, 10) + | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); +} + +/* Write a LAXR instruction into *BUF. + + LDAXR rt, [xn] + + RT is the destination register. + RN is the base address register. */ + +static int +emit_ldaxr (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rn) +{ + return emit_load_store_exclusive (buf, rt.is64 ? 3 : 2, LDAXR, xzr, rt, + xzr, rn); +} + +/* Write a STXR instruction into *BUF. + + STXR ws, rt, [xn] + + RS is the result register, it indicates if the store succeeded or not. + RT is the destination register. + RN is the base address register. */ + +static int +emit_stxr (uint32_t *buf, struct aarch64_register rs, + struct aarch64_register rt, struct aarch64_register rn) +{ + return emit_load_store_exclusive (buf, rt.is64 ? 3 : 2, STXR, rs, rt, + xzr, rn); +} + +/* Write a STLR instruction into *BUF. + + STLR rt, [xn] + + RT is the register to store. + RN is the base address register. */ + +static int +emit_stlr (uint32_t *buf, struct aarch64_register rt, + struct aarch64_register rn) +{ + return emit_load_store_exclusive (buf, rt.is64 ? 3 : 2, STLR, xzr, rt, + xzr, rn); +} + +/* Helper function for data processing instructions with register sources. */ + +static int +emit_data_processing_reg (uint32_t *buf, uint32_t opcode, + struct aarch64_register rd, + struct aarch64_register rn, + struct aarch64_register rm) +{ + uint32_t size = ENCODE (rd.is64, 1, 31); + + return aarch64_emit_insn (buf, opcode | size | ENCODE (rm.num, 5, 16) + | ENCODE (rn.num, 5, 5) | ENCODE (rd.num, 5, 0)); +} + +/* Helper function for data processing instructions taking either a register + or an immediate. */ + +static int +emit_data_processing (uint32_t *buf, enum aarch64_opcodes opcode, + struct aarch64_register rd, + struct aarch64_register rn, + struct aarch64_operand operand) +{ + uint32_t size = ENCODE (rd.is64, 1, 31); + /* The opcode is different for register and immediate source operands. */ + uint32_t operand_opcode; + + if (operand.type == OPERAND_IMMEDIATE) + { + /* xxx1 000x xxxx xxxx xxxx xxxx xxxx xxxx */ + operand_opcode = ENCODE (8, 4, 25); + + return aarch64_emit_insn (buf, opcode | operand_opcode | size + | ENCODE (operand.imm, 12, 10) + | ENCODE (rn.num, 5, 5) + | ENCODE (rd.num, 5, 0)); + } + else + { + /* xxx0 101x xxxx xxxx xxxx xxxx xxxx xxxx */ + operand_opcode = ENCODE (5, 4, 25); + + return emit_data_processing_reg (buf, opcode | operand_opcode, rd, + rn, operand.reg); + } +} + +/* Write an ADD instruction into *BUF. + + ADD rd, rn, #imm + ADD rd, rn, rm + + This function handles both an immediate and register add. + + RD is the destination register. + RN is the input register. + OPERAND is the source operand, either of type OPERAND_IMMEDIATE or + OPERAND_REGISTER. */ + +static int +emit_add (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_operand operand) +{ + return emit_data_processing (buf, ADD, rd, rn, operand); +} + +/* Write a SUB instruction into *BUF. + + SUB rd, rn, #imm + SUB rd, rn, rm + + This function handles both an immediate and register sub. + + RD is the destination register. + RN is the input register. + IMM is the immediate to substract to RN. */ + +static int +emit_sub (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_operand operand) +{ + return emit_data_processing (buf, SUB, rd, rn, operand); +} + +/* Write a MOV instruction into *BUF. + + MOV rd, #imm + MOV rd, rm + + This function handles both a wide immediate move and a register move, + with the condition that the source register is not xzr. xzr and the + stack pointer share the same encoding and this function only supports + the stack pointer. + + RD is the destination register. + OPERAND is the source operand, either of type OPERAND_IMMEDIATE or + OPERAND_REGISTER. */ + +static int +emit_mov (uint32_t *buf, struct aarch64_register rd, + struct aarch64_operand operand) +{ + if (operand.type == OPERAND_IMMEDIATE) + { + uint32_t size = ENCODE (rd.is64, 1, 31); + /* Do not shift the immediate. */ + uint32_t shift = ENCODE (0, 2, 21); + + return aarch64_emit_insn (buf, MOV | size | shift + | ENCODE (operand.imm, 16, 5) + | ENCODE (rd.num, 5, 0)); + } + else + return emit_add (buf, rd, operand.reg, immediate_operand (0)); +} + +/* Write a MOVK instruction into *BUF. + + MOVK rd, #imm, lsl #shift + + RD is the destination register. + IMM is the immediate. + SHIFT is the logical shift left to apply to IMM. */ + +static int +emit_movk (uint32_t *buf, struct aarch64_register rd, uint32_t imm, + unsigned shift) +{ + uint32_t size = ENCODE (rd.is64, 1, 31); + + return aarch64_emit_insn (buf, MOVK | size | ENCODE (shift, 2, 21) | + ENCODE (imm, 16, 5) | ENCODE (rd.num, 5, 0)); +} + +/* Write instructions into *BUF in order to move ADDR into a register. + ADDR can be a 64-bit value. + + This function will emit a series of MOV and MOVK instructions, such as: + + MOV xd, #(addr) + MOVK xd, #(addr >> 16), lsl #16 + MOVK xd, #(addr >> 32), lsl #32 + MOVK xd, #(addr >> 48), lsl #48 */ + +static int +emit_mov_addr (uint32_t *buf, struct aarch64_register rd, CORE_ADDR addr) +{ + uint32_t *p = buf; + + /* The MOV (wide immediate) instruction clears to top bits of the + register. */ + p += emit_mov (p, rd, immediate_operand (addr & 0xffff)); + + if ((addr >> 16) != 0) + p += emit_movk (p, rd, (addr >> 16) & 0xffff, 1); + else + return p - buf; + + if ((addr >> 32) != 0) + p += emit_movk (p, rd, (addr >> 32) & 0xffff, 2); + else + return p - buf; + + if ((addr >> 48) != 0) + p += emit_movk (p, rd, (addr >> 48) & 0xffff, 3); + + return p - buf; +} + +/* Write a SUBS instruction into *BUF. + + SUBS rd, rn, rm + + This instruction update the condition flags. + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_subs (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_operand operand) +{ + return emit_data_processing (buf, SUBS, rd, rn, operand); +} + +/* Write a CMP instruction into *BUF. + + CMP rn, rm + + This instruction is an alias of SUBS xzr, rn, rm. + + RN and RM are the registers to compare. */ + +static int +emit_cmp (uint32_t *buf, struct aarch64_register rn, + struct aarch64_operand operand) +{ + return emit_subs (buf, xzr, rn, operand); +} + +/* Write a AND instruction into *BUF. + + AND rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_and (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, AND, rd, rn, rm); +} + +/* Write a ORR instruction into *BUF. + + ORR rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_orr (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, ORR, rd, rn, rm); +} + +/* Write a ORN instruction into *BUF. + + ORN rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_orn (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, ORN, rd, rn, rm); +} + +/* Write a EOR instruction into *BUF. + + EOR rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_eor (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, EOR, rd, rn, rm); +} + +/* Write a MVN instruction into *BUF. + + MVN rd, rm + + This is an alias for ORN rd, xzr, rm. + + RD is the destination register. + RM is the source register. */ + +static int +emit_mvn (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rm) +{ + return emit_orn (buf, rd, xzr, rm); +} + +/* Write a LSLV instruction into *BUF. + + LSLV rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_lslv (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, LSLV, rd, rn, rm); +} + +/* Write a LSRV instruction into *BUF. + + LSRV rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_lsrv (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, LSRV, rd, rn, rm); +} + +/* Write a ASRV instruction into *BUF. + + ASRV rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_asrv (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, ASRV, rd, rn, rm); +} + +/* Write a MUL instruction into *BUF. + + MUL rd, rn, rm + + RD is the destination register. + RN and RM are the source registers. */ + +static int +emit_mul (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm) +{ + return emit_data_processing_reg (buf, MUL, rd, rn, rm); +} + +/* Write a MRS instruction into *BUF. The register size is 64-bit. + + MRS xt, system_reg + + RT is the destination register. + SYSTEM_REG is special purpose register to read. */ + +static int +emit_mrs (uint32_t *buf, struct aarch64_register rt, + enum aarch64_system_control_registers system_reg) +{ + return aarch64_emit_insn (buf, MRS | ENCODE (system_reg, 15, 5) + | ENCODE (rt.num, 5, 0)); +} + +/* Write a MSR instruction into *BUF. The register size is 64-bit. + + MSR system_reg, xt + + SYSTEM_REG is special purpose register to write. + RT is the input register. */ + +static int +emit_msr (uint32_t *buf, enum aarch64_system_control_registers system_reg, + struct aarch64_register rt) +{ + return aarch64_emit_insn (buf, MSR | ENCODE (system_reg, 15, 5) + | ENCODE (rt.num, 5, 0)); +} + +/* Write a SEVL instruction into *BUF. + + This is a hint instruction telling the hardware to trigger an event. */ + +static int +emit_sevl (uint32_t *buf) +{ + return aarch64_emit_insn (buf, SEVL); +} + +/* Write a WFE instruction into *BUF. + + This is a hint instruction telling the hardware to wait for an event. */ + +static int +emit_wfe (uint32_t *buf) +{ + return aarch64_emit_insn (buf, WFE); +} + +/* Write a SBFM instruction into *BUF. + + SBFM rd, rn, #immr, #imms + + This instruction moves the bits from #immr to #imms into the + destination, sign extending the result. + + RD is the destination register. + RN is the source register. + IMMR is the bit number to start at (least significant bit). + IMMS is the bit number to stop at (most significant bit). */ + +static int +emit_sbfm (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, uint32_t immr, uint32_t imms) +{ + uint32_t size = ENCODE (rd.is64, 1, 31); + uint32_t n = ENCODE (rd.is64, 1, 22); + + return aarch64_emit_insn (buf, SBFM | size | n | ENCODE (immr, 6, 16) + | ENCODE (imms, 6, 10) | ENCODE (rn.num, 5, 5) + | ENCODE (rd.num, 5, 0)); +} + +/* Write a SBFX instruction into *BUF. + + SBFX rd, rn, #lsb, #width + + This instruction moves #width bits from #lsb into the destination, sign + extending the result. This is an alias for: + + SBFM rd, rn, #lsb, #(lsb + width - 1) + + RD is the destination register. + RN is the source register. + LSB is the bit number to start at (least significant bit). + WIDTH is the number of bits to move. */ + +static int +emit_sbfx (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, uint32_t lsb, uint32_t width) +{ + return emit_sbfm (buf, rd, rn, lsb, lsb + width - 1); +} + +/* Write a UBFM instruction into *BUF. + + UBFM rd, rn, #immr, #imms + + This instruction moves the bits from #immr to #imms into the + destination, extending the result with zeros. + + RD is the destination register. + RN is the source register. + IMMR is the bit number to start at (least significant bit). + IMMS is the bit number to stop at (most significant bit). */ + +static int +emit_ubfm (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, uint32_t immr, uint32_t imms) +{ + uint32_t size = ENCODE (rd.is64, 1, 31); + uint32_t n = ENCODE (rd.is64, 1, 22); + + return aarch64_emit_insn (buf, UBFM | size | n | ENCODE (immr, 6, 16) + | ENCODE (imms, 6, 10) | ENCODE (rn.num, 5, 5) + | ENCODE (rd.num, 5, 0)); +} + +/* Write a UBFX instruction into *BUF. + + UBFX rd, rn, #lsb, #width + + This instruction moves #width bits from #lsb into the destination, + extending the result with zeros. This is an alias for: + + UBFM rd, rn, #lsb, #(lsb + width - 1) + + RD is the destination register. + RN is the source register. + LSB is the bit number to start at (least significant bit). + WIDTH is the number of bits to move. */ + +static int +emit_ubfx (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, uint32_t lsb, uint32_t width) +{ + return emit_ubfm (buf, rd, rn, lsb, lsb + width - 1); +} + +/* Write a CSINC instruction into *BUF. + + CSINC rd, rn, rm, cond + + This instruction conditionally increments rn or rm and places the result + in rd. rn is chosen is the condition is true. + + RD is the destination register. + RN and RM are the source registers. + COND is the encoded condition. */ + +static int +emit_csinc (uint32_t *buf, struct aarch64_register rd, + struct aarch64_register rn, struct aarch64_register rm, + unsigned cond) +{ + uint32_t size = ENCODE (rd.is64, 1, 31); + + return aarch64_emit_insn (buf, CSINC | size | ENCODE (rm.num, 5, 16) + | ENCODE (cond, 4, 12) | ENCODE (rn.num, 5, 5) + | ENCODE (rd.num, 5, 0)); +} + +/* Write a CSET instruction into *BUF. + + CSET rd, cond + + This instruction conditionally write 1 or 0 in the destination register. + 1 is written if the condition is true. This is an alias for: + + CSINC rd, xzr, xzr, !cond + + Note that the condition needs to be inverted. + + RD is the destination register. + RN and RM are the source registers. + COND is the encoded condition. */ + +static int +emit_cset (uint32_t *buf, struct aarch64_register rd, unsigned cond) +{ + /* The least significant bit of the condition needs toggling in order to + invert it. */ + return emit_csinc (buf, rd, xzr, xzr, cond ^ 0x1); +} + +/* Write LEN instructions from BUF into the inferior memory at *TO. + + Note instructions are always little endian on AArch64, unlike data. */ + +static void +append_insns (CORE_ADDR *to, size_t len, const uint32_t *buf) +{ + size_t byte_len = len * sizeof (uint32_t); +#if (__BYTE_ORDER == __BIG_ENDIAN) + uint32_t *le_buf = (uint32_t *) xmalloc (byte_len); + size_t i; + + for (i = 0; i < len; i++) + le_buf[i] = htole32 (buf[i]); + + target_write_memory (*to, (const unsigned char *) le_buf, byte_len); + + xfree (le_buf); +#else + target_write_memory (*to, (const unsigned char *) buf, byte_len); +#endif + + *to += byte_len; +} + +/* Sub-class of struct aarch64_insn_data, store information of + instruction relocation for fast tracepoint. Visitor can + relocate an instruction from BASE.INSN_ADDR to NEW_ADDR and save + the relocated instructions in buffer pointed by INSN_PTR. */ + +struct aarch64_insn_relocation_data +{ + struct aarch64_insn_data base; + + /* The new address the instruction is relocated to. */ + CORE_ADDR new_addr; + /* Pointer to the buffer of relocated instruction(s). */ + uint32_t *insn_ptr; +}; + +/* Implementation of aarch64_insn_visitor method "b". */ + +static void +aarch64_ftrace_insn_reloc_b (const int is_bl, const int32_t offset, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + int64_t new_offset + = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; + + if (can_encode_int32 (new_offset, 28)) + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, is_bl, new_offset); +} + +/* Implementation of aarch64_insn_visitor method "b_cond". */ + +static void +aarch64_ftrace_insn_reloc_b_cond (const unsigned cond, const int32_t offset, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + int64_t new_offset + = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; + + if (can_encode_int32 (new_offset, 21)) + { + insn_reloc->insn_ptr += emit_bcond (insn_reloc->insn_ptr, cond, + new_offset); + } + else if (can_encode_int32 (new_offset, 28)) + { + /* The offset is out of range for a conditional branch + instruction but not for a unconditional branch. We can use + the following instructions instead: + + B.COND TAKEN ; If cond is true, then jump to TAKEN. + B NOT_TAKEN ; Else jump over TAKEN and continue. + TAKEN: + B #(offset - 8) + NOT_TAKEN: + + */ + + insn_reloc->insn_ptr += emit_bcond (insn_reloc->insn_ptr, cond, 8); + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, 8); + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, new_offset - 8); + } +} + +/* Implementation of aarch64_insn_visitor method "cb". */ + +static void +aarch64_ftrace_insn_reloc_cb (const int32_t offset, const int is_cbnz, + const unsigned rn, int is64, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + int64_t new_offset + = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; + + if (can_encode_int32 (new_offset, 21)) + { + insn_reloc->insn_ptr += emit_cb (insn_reloc->insn_ptr, is_cbnz, + aarch64_register (rn, is64), new_offset); + } + else if (can_encode_int32 (new_offset, 28)) + { + /* The offset is out of range for a compare and branch + instruction but not for a unconditional branch. We can use + the following instructions instead: + + CBZ xn, TAKEN ; xn == 0, then jump to TAKEN. + B NOT_TAKEN ; Else jump over TAKEN and continue. + TAKEN: + B #(offset - 8) + NOT_TAKEN: + + */ + insn_reloc->insn_ptr += emit_cb (insn_reloc->insn_ptr, is_cbnz, + aarch64_register (rn, is64), 8); + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, 8); + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, new_offset - 8); + } +} + +/* Implementation of aarch64_insn_visitor method "tb". */ + +static void +aarch64_ftrace_insn_reloc_tb (const int32_t offset, int is_tbnz, + const unsigned rt, unsigned bit, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + int64_t new_offset + = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset; + + if (can_encode_int32 (new_offset, 16)) + { + insn_reloc->insn_ptr += emit_tb (insn_reloc->insn_ptr, is_tbnz, bit, + aarch64_register (rt, 1), new_offset); + } + else if (can_encode_int32 (new_offset, 28)) + { + /* The offset is out of range for a test bit and branch + instruction but not for a unconditional branch. We can use + the following instructions instead: + + TBZ xn, #bit, TAKEN ; xn[bit] == 0, then jump to TAKEN. + B NOT_TAKEN ; Else jump over TAKEN and continue. + TAKEN: + B #(offset - 8) + NOT_TAKEN: + + */ + insn_reloc->insn_ptr += emit_tb (insn_reloc->insn_ptr, is_tbnz, bit, + aarch64_register (rt, 1), 8); + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, 8); + insn_reloc->insn_ptr += emit_b (insn_reloc->insn_ptr, 0, + new_offset - 8); + } +} + +/* Implementation of aarch64_insn_visitor method "adr". */ + +static void +aarch64_ftrace_insn_reloc_adr (const int32_t offset, const unsigned rd, + const int is_adrp, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + /* We know exactly the address the ADR{P,} instruction will compute. + We can just write it to the destination register. */ + CORE_ADDR address = data->insn_addr + offset; + + if (is_adrp) + { + /* Clear the lower 12 bits of the offset to get the 4K page. */ + insn_reloc->insn_ptr += emit_mov_addr (insn_reloc->insn_ptr, + aarch64_register (rd, 1), + address & ~0xfff); + } + else + insn_reloc->insn_ptr += emit_mov_addr (insn_reloc->insn_ptr, + aarch64_register (rd, 1), address); +} + +/* Implementation of aarch64_insn_visitor method "ldr_literal". */ + +static void +aarch64_ftrace_insn_reloc_ldr_literal (const int32_t offset, const int is_sw, + const unsigned rt, const int is64, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + CORE_ADDR address = data->insn_addr + offset; + + insn_reloc->insn_ptr += emit_mov_addr (insn_reloc->insn_ptr, + aarch64_register (rt, 1), address); + + /* We know exactly what address to load from, and what register we + can use: + + MOV xd, #(oldloc + offset) + MOVK xd, #((oldloc + offset) >> 16), lsl #16 + ... + + LDR xd, [xd] ; or LDRSW xd, [xd] + + */ + + if (is_sw) + insn_reloc->insn_ptr += emit_ldrsw (insn_reloc->insn_ptr, + aarch64_register (rt, 1), + aarch64_register (rt, 1), + offset_memory_operand (0)); + else + insn_reloc->insn_ptr += emit_ldr (insn_reloc->insn_ptr, + aarch64_register (rt, is64), + aarch64_register (rt, 1), + offset_memory_operand (0)); +} + +/* Implementation of aarch64_insn_visitor method "others". */ + +static void +aarch64_ftrace_insn_reloc_others (const uint32_t insn, + struct aarch64_insn_data *data) +{ + struct aarch64_insn_relocation_data *insn_reloc + = (struct aarch64_insn_relocation_data *) data; + + /* The instruction is not PC relative. Just re-emit it at the new + location. */ + insn_reloc->insn_ptr += aarch64_emit_insn (insn_reloc->insn_ptr, insn); +} + +static const struct aarch64_insn_visitor visitor = +{ + aarch64_ftrace_insn_reloc_b, + aarch64_ftrace_insn_reloc_b_cond, + aarch64_ftrace_insn_reloc_cb, + aarch64_ftrace_insn_reloc_tb, + aarch64_ftrace_insn_reloc_adr, + aarch64_ftrace_insn_reloc_ldr_literal, + aarch64_ftrace_insn_reloc_others, +}; + +/* Implementation of linux_target_ops method + "install_fast_tracepoint_jump_pad". */ + +static int +aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, + CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + uint32_t buf[256]; + uint32_t *p = buf; + int64_t offset; + int i; + uint32_t insn; + CORE_ADDR buildaddr = *jump_entry; + struct aarch64_insn_relocation_data insn_data; + + /* We need to save the current state on the stack both to restore it + later and to collect register values when the tracepoint is hit. + + The saved registers are pushed in a layout that needs to be in sync + with aarch64_ft_collect_regmap (see linux-aarch64-ipa.c). Later on + the supply_fast_tracepoint_registers function will fill in the + register cache from a pointer to saved registers on the stack we build + here. + + For simplicity, we set the size of each cell on the stack to 16 bytes. + This way one cell can hold any register type, from system registers + to the 128 bit SIMD&FP registers. Furthermore, the stack pointer + has to be 16 bytes aligned anyway. + + Note that the CPSR register does not exist on AArch64. Instead we + can access system bits describing the process state with the + MRS/MSR instructions, namely the condition flags. We save them as + if they are part of a CPSR register because that's how GDB + interprets these system bits. At the moment, only the condition + flags are saved in CPSR (NZCV). + + Stack layout, each cell is 16 bytes (descending): + + High *-------- SIMD&FP registers from 31 down to 0. --------* + | q31 | + . . + . . 32 cells + . . + | q0 | + *---- General purpose registers from 30 down to 0. ----* + | x30 | + . . + . . 31 cells + . . + | x0 | + *------------- Special purpose registers. -------------* + | SP | + | PC | + | CPSR (NZCV) | 5 cells + | FPSR | + | FPCR | <- SP + 16 + *------------- collecting_t object --------------------* + | TPIDR_EL0 | struct tracepoint * | + Low *------------------------------------------------------* + + After this stack is set up, we issue a call to the collector, passing + it the saved registers at (SP + 16). */ + + /* Push SIMD&FP registers on the stack: + + SUB sp, sp, #(32 * 16) + + STP q30, q31, [sp, #(30 * 16)] + ... + STP q0, q1, [sp] + + */ + p += emit_sub (p, sp, sp, immediate_operand (32 * 16)); + for (i = 30; i >= 0; i -= 2) + p += emit_stp_q_offset (p, i, i + 1, sp, i * 16); + + /* Push general purpose registers on the stack. Note that we do not need + to push x31 as it represents the xzr register and not the stack + pointer in a STR instruction. + + SUB sp, sp, #(31 * 16) + + STR x30, [sp, #(30 * 16)] + ... + STR x0, [sp] + + */ + p += emit_sub (p, sp, sp, immediate_operand (31 * 16)); + for (i = 30; i >= 0; i -= 1) + p += emit_str (p, aarch64_register (i, 1), sp, + offset_memory_operand (i * 16)); + + /* Make space for 5 more cells. + + SUB sp, sp, #(5 * 16) + + */ + p += emit_sub (p, sp, sp, immediate_operand (5 * 16)); + + + /* Save SP: + + ADD x4, sp, #((32 + 31 + 5) * 16) + STR x4, [sp, #(4 * 16)] + + */ + p += emit_add (p, x4, sp, immediate_operand ((32 + 31 + 5) * 16)); + p += emit_str (p, x4, sp, offset_memory_operand (4 * 16)); + + /* Save PC (tracepoint address): + + MOV x3, #(tpaddr) + ... + + STR x3, [sp, #(3 * 16)] + + */ + + p += emit_mov_addr (p, x3, tpaddr); + p += emit_str (p, x3, sp, offset_memory_operand (3 * 16)); + + /* Save CPSR (NZCV), FPSR and FPCR: + + MRS x2, nzcv + MRS x1, fpsr + MRS x0, fpcr + + STR x2, [sp, #(2 * 16)] + STR x1, [sp, #(1 * 16)] + STR x0, [sp, #(0 * 16)] + + */ + p += emit_mrs (p, x2, NZCV); + p += emit_mrs (p, x1, FPSR); + p += emit_mrs (p, x0, FPCR); + p += emit_str (p, x2, sp, offset_memory_operand (2 * 16)); + p += emit_str (p, x1, sp, offset_memory_operand (1 * 16)); + p += emit_str (p, x0, sp, offset_memory_operand (0 * 16)); + + /* Push the collecting_t object. It consist of the address of the + tracepoint and an ID for the current thread. We get the latter by + reading the tpidr_el0 system register. It corresponds to the + NT_ARM_TLS register accessible with ptrace. + + MOV x0, #(tpoint) + ... + + MRS x1, tpidr_el0 + + STP x0, x1, [sp, #-16]! + + */ + + p += emit_mov_addr (p, x0, tpoint); + p += emit_mrs (p, x1, TPIDR_EL0); + p += emit_stp (p, x0, x1, sp, preindex_memory_operand (-16)); + + /* Spin-lock: + + The shared memory for the lock is at lockaddr. It will hold zero + if no-one is holding the lock, otherwise it contains the address of + the collecting_t object on the stack of the thread which acquired it. + + At this stage, the stack pointer points to this thread's collecting_t + object. + + We use the following registers: + - x0: Address of the lock. + - x1: Pointer to collecting_t object. + - x2: Scratch register. + + MOV x0, #(lockaddr) + ... + MOV x1, sp + + ; Trigger an event local to this core. So the following WFE + ; instruction is ignored. + SEVL + again: + ; Wait for an event. The event is triggered by either the SEVL + ; or STLR instructions (store release). + WFE + + ; Atomically read at lockaddr. This marks the memory location as + ; exclusive. This instruction also has memory constraints which + ; make sure all previous data reads and writes are done before + ; executing it. + LDAXR x2, [x0] + + ; Try again if another thread holds the lock. + CBNZ x2, again + + ; We can lock it! Write the address of the collecting_t object. + ; This instruction will fail if the memory location is not marked + ; as exclusive anymore. If it succeeds, it will remove the + ; exclusive mark on the memory location. This way, if another + ; thread executes this instruction before us, we will fail and try + ; all over again. + STXR w2, x1, [x0] + CBNZ w2, again + + */ + + p += emit_mov_addr (p, x0, lockaddr); + p += emit_mov (p, x1, register_operand (sp)); + + p += emit_sevl (p); + p += emit_wfe (p); + p += emit_ldaxr (p, x2, x0); + p += emit_cb (p, 1, w2, -2 * 4); + p += emit_stxr (p, w2, x1, x0); + p += emit_cb (p, 1, x2, -4 * 4); + + /* Call collector (struct tracepoint *, unsigned char *): + + MOV x0, #(tpoint) + ... + + ; Saved registers start after the collecting_t object. + ADD x1, sp, #16 + + ; We use an intra-procedure-call scratch register. + MOV ip0, #(collector) + ... + + ; And call back to C! + BLR ip0 + + */ + + p += emit_mov_addr (p, x0, tpoint); + p += emit_add (p, x1, sp, immediate_operand (16)); + + p += emit_mov_addr (p, ip0, collector); + p += emit_blr (p, ip0); + + /* Release the lock. + + MOV x0, #(lockaddr) + ... + + ; This instruction is a normal store with memory ordering + ; constraints. Thanks to this we do not have to put a data + ; barrier instruction to make sure all data read and writes are done + ; before this instruction is executed. Furthermore, this instruction + ; will trigger an event, letting other threads know they can grab + ; the lock. + STLR xzr, [x0] + + */ + p += emit_mov_addr (p, x0, lockaddr); + p += emit_stlr (p, xzr, x0); + + /* Free collecting_t object: + + ADD sp, sp, #16 + + */ + p += emit_add (p, sp, sp, immediate_operand (16)); + + /* Restore CPSR (NZCV), FPSR and FPCR. And free all special purpose + registers from the stack. + + LDR x2, [sp, #(2 * 16)] + LDR x1, [sp, #(1 * 16)] + LDR x0, [sp, #(0 * 16)] + + MSR NZCV, x2 + MSR FPSR, x1 + MSR FPCR, x0 + + ADD sp, sp #(5 * 16) + + */ + p += emit_ldr (p, x2, sp, offset_memory_operand (2 * 16)); + p += emit_ldr (p, x1, sp, offset_memory_operand (1 * 16)); + p += emit_ldr (p, x0, sp, offset_memory_operand (0 * 16)); + p += emit_msr (p, NZCV, x2); + p += emit_msr (p, FPSR, x1); + p += emit_msr (p, FPCR, x0); + + p += emit_add (p, sp, sp, immediate_operand (5 * 16)); + + /* Pop general purpose registers: + + LDR x0, [sp] + ... + LDR x30, [sp, #(30 * 16)] + + ADD sp, sp, #(31 * 16) + + */ + for (i = 0; i <= 30; i += 1) + p += emit_ldr (p, aarch64_register (i, 1), sp, + offset_memory_operand (i * 16)); + p += emit_add (p, sp, sp, immediate_operand (31 * 16)); + + /* Pop SIMD&FP registers: + + LDP q0, q1, [sp] + ... + LDP q30, q31, [sp, #(30 * 16)] + + ADD sp, sp, #(32 * 16) + + */ + for (i = 0; i <= 30; i += 2) + p += emit_ldp_q_offset (p, i, i + 1, sp, i * 16); + p += emit_add (p, sp, sp, immediate_operand (32 * 16)); + + /* Write the code into the inferior memory. */ + append_insns (&buildaddr, p - buf, buf); + + /* Now emit the relocated instruction. */ + *adjusted_insn_addr = buildaddr; + target_read_uint32 (tpaddr, &insn); + + insn_data.base.insn_addr = tpaddr; + insn_data.new_addr = buildaddr; + insn_data.insn_ptr = buf; + + aarch64_relocate_instruction (insn, &visitor, + (struct aarch64_insn_data *) &insn_data); + + /* We may not have been able to relocate the instruction. */ + if (insn_data.insn_ptr == buf) + { + sprintf (err, + "E.Could not relocate instruction from %s to %s.", + core_addr_to_string_nz (tpaddr), + core_addr_to_string_nz (buildaddr)); + return 1; + } + else + append_insns (&buildaddr, insn_data.insn_ptr - buf, buf); + *adjusted_insn_addr_end = buildaddr; + + /* Go back to the start of the buffer. */ + p = buf; + + /* Emit a branch back from the jump pad. */ + offset = (tpaddr + orig_size - buildaddr); + if (!can_encode_int32 (offset, 28)) + { + sprintf (err, + "E.Jump back from jump pad too far from tracepoint " + "(offset 0x%" PRIx64 " cannot be encoded in 28 bits).", + offset); + return 1; + } + + p += emit_b (p, 0, offset); + append_insns (&buildaddr, p - buf, buf); + + /* Give the caller a branch instruction into the jump pad. */ + offset = (*jump_entry - tpaddr); + if (!can_encode_int32 (offset, 28)) + { + sprintf (err, + "E.Jump pad too far from tracepoint " + "(offset 0x%" PRIx64 " cannot be encoded in 28 bits).", + offset); + return 1; + } + + emit_b ((uint32_t *) jjump_pad_insn, 0, offset); + *jjump_pad_insn_size = 4; + + /* Return the end address of our pad. */ + *jump_entry = buildaddr; + + return 0; +} + +/* Helper function writing LEN instructions from START into + current_insn_ptr. */ + +static void +emit_ops_insns (const uint32_t *start, int len) +{ + CORE_ADDR buildaddr = current_insn_ptr; + + if (debug_threads) + debug_printf ("Adding %d instrucions at %s\n", + len, paddress (buildaddr)); + + append_insns (&buildaddr, len, start); + current_insn_ptr = buildaddr; +} + +/* Pop a register from the stack. */ + +static int +emit_pop (uint32_t *buf, struct aarch64_register rt) +{ + return emit_ldr (buf, rt, sp, postindex_memory_operand (1 * 16)); +} + +/* Push a register on the stack. */ + +static int +emit_push (uint32_t *buf, struct aarch64_register rt) +{ + return emit_str (buf, rt, sp, preindex_memory_operand (-1 * 16)); +} + +/* Implementation of emit_ops method "emit_prologue". */ + +static void +aarch64_emit_prologue (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* This function emit a prologue for the following function prototype: + + enum eval_result_type f (unsigned char *regs, + ULONGEST *value); + + The first argument is a buffer of raw registers. The second + argument is the result of + evaluating the expression, which will be set to whatever is on top of + the stack at the end. + + The stack set up by the prologue is as such: + + High *------------------------------------------------------* + | LR | + | FP | <- FP + | x1 (ULONGEST *value) | + | x0 (unsigned char *regs) | + Low *------------------------------------------------------* + + As we are implementing a stack machine, each opcode can expand the + stack so we never know how far we are from the data saved by this + prologue. In order to be able refer to value and regs later, we save + the current stack pointer in the frame pointer. This way, it is not + clobbered when calling C functions. + + Finally, throughout every operation, we are using register x0 as the + top of the stack, and x1 as a scratch register. */ + + p += emit_stp (p, x0, x1, sp, preindex_memory_operand (-2 * 16)); + p += emit_str (p, lr, sp, offset_memory_operand (3 * 8)); + p += emit_str (p, fp, sp, offset_memory_operand (2 * 8)); + + p += emit_add (p, fp, sp, immediate_operand (2 * 8)); + + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_epilogue". */ + +static void +aarch64_emit_epilogue (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* Store the result of the expression (x0) in *value. */ + p += emit_sub (p, x1, fp, immediate_operand (1 * 8)); + p += emit_ldr (p, x1, x1, offset_memory_operand (0)); + p += emit_str (p, x0, x1, offset_memory_operand (0)); + + /* Restore the previous state. */ + p += emit_add (p, sp, fp, immediate_operand (2 * 8)); + p += emit_ldp (p, fp, lr, fp, offset_memory_operand (0)); + + /* Return expr_eval_no_error. */ + p += emit_mov (p, x0, immediate_operand (expr_eval_no_error)); + p += emit_ret (p, lr); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_add". */ + +static void +aarch64_emit_add (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_add (p, x0, x1, register_operand (x0)); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_sub". */ + +static void +aarch64_emit_sub (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_sub (p, x0, x1, register_operand (x0)); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_mul". */ + +static void +aarch64_emit_mul (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_mul (p, x0, x1, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_lsh". */ + +static void +aarch64_emit_lsh (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_lslv (p, x0, x1, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_rsh_signed". */ + +static void +aarch64_emit_rsh_signed (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_asrv (p, x0, x1, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_rsh_unsigned". */ + +static void +aarch64_emit_rsh_unsigned (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_lsrv (p, x0, x1, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_ext". */ + +static void +aarch64_emit_ext (int arg) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_sbfx (p, x0, x0, 0, arg); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_log_not". */ + +static void +aarch64_emit_log_not (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* If the top of the stack is 0, replace it with 1. Else replace it with + 0. */ + + p += emit_cmp (p, x0, immediate_operand (0)); + p += emit_cset (p, x0, EQ); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_bit_and". */ + +static void +aarch64_emit_bit_and (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_and (p, x0, x0, x1); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_bit_or". */ + +static void +aarch64_emit_bit_or (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_orr (p, x0, x0, x1); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_bit_xor". */ + +static void +aarch64_emit_bit_xor (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_eor (p, x0, x0, x1); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_bit_not". */ + +static void +aarch64_emit_bit_not (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_mvn (p, x0, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_equal". */ + +static void +aarch64_emit_equal (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x0, register_operand (x1)); + p += emit_cset (p, x0, EQ); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_less_signed". */ + +static void +aarch64_emit_less_signed (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + p += emit_cset (p, x0, LT); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_less_unsigned". */ + +static void +aarch64_emit_less_unsigned (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + p += emit_cset (p, x0, LO); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_ref". */ + +static void +aarch64_emit_ref (int size) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + switch (size) + { + case 1: + p += emit_ldrb (p, w0, x0, offset_memory_operand (0)); + break; + case 2: + p += emit_ldrh (p, w0, x0, offset_memory_operand (0)); + break; + case 4: + p += emit_ldr (p, w0, x0, offset_memory_operand (0)); + break; + case 8: + p += emit_ldr (p, x0, x0, offset_memory_operand (0)); + break; + default: + /* Unknown size, bail on compilation. */ + emit_error = 1; + break; + } + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_if_goto". */ + +static void +aarch64_emit_if_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* The Z flag is set or cleared here. */ + p += emit_cmp (p, x0, immediate_operand (0)); + /* This instruction must not change the Z flag. */ + p += emit_pop (p, x0); + /* Branch over the next instruction if x0 == 0. */ + p += emit_bcond (p, EQ, 8); + + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_goto". */ + +static void +aarch64_emit_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = 0; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "write_goto_address". */ + +static void +aarch64_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) +{ + uint32_t insn; + + emit_b (&insn, 0, to - from); + append_insns (&from, 1, &insn); +} + +/* Implementation of emit_ops method "emit_const". */ + +static void +aarch64_emit_const (LONGEST num) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_mov_addr (p, x0, num); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_call". */ + +static void +aarch64_emit_call (CORE_ADDR fn) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_mov_addr (p, ip0, fn); + p += emit_blr (p, ip0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_reg". */ + +static void +aarch64_emit_reg (int reg) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* Set x0 to unsigned char *regs. */ + p += emit_sub (p, x0, fp, immediate_operand (2 * 8)); + p += emit_ldr (p, x0, x0, offset_memory_operand (0)); + p += emit_mov (p, x1, immediate_operand (reg)); + + emit_ops_insns (buf, p - buf); + + aarch64_emit_call (get_raw_reg_func_addr ()); +} + +/* Implementation of emit_ops method "emit_pop". */ + +static void +aarch64_emit_pop (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_stack_flush". */ + +static void +aarch64_emit_stack_flush (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_push (p, x0); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_zero_ext". */ + +static void +aarch64_emit_zero_ext (int arg) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_ubfx (p, x0, x0, 0, arg); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_swap". */ + +static void +aarch64_emit_swap (void) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_ldr (p, x1, sp, offset_memory_operand (0 * 16)); + p += emit_str (p, x0, sp, offset_memory_operand (0 * 16)); + p += emit_mov (p, x0, register_operand (x1)); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_stack_adjust". */ + +static void +aarch64_emit_stack_adjust (int n) +{ + /* This is not needed with our design. */ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_add (p, sp, sp, immediate_operand (n * 16)); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_int_call_1". */ + +static void +aarch64_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_mov (p, x0, immediate_operand (arg1)); + + emit_ops_insns (buf, p - buf); + + aarch64_emit_call (fn); +} + +/* Implementation of emit_ops method "emit_void_call_2". */ + +static void +aarch64_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + /* Push x0 on the stack. */ + aarch64_emit_stack_flush (); + + /* Setup arguments for the function call: + + x0: arg1 + x1: top of the stack + + MOV x1, x0 + MOV x0, #arg1 */ + + p += emit_mov (p, x1, register_operand (x0)); + p += emit_mov (p, x0, immediate_operand (arg1)); + + emit_ops_insns (buf, p - buf); + + aarch64_emit_call (fn); + + /* Restore x0. */ + aarch64_emit_pop (); +} + +/* Implementation of emit_ops method "emit_eq_goto". */ + +static void +aarch64_emit_eq_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + /* Branch over the next instruction if x0 != x1. */ + p += emit_bcond (p, NE, 8); + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_ne_goto". */ + +static void +aarch64_emit_ne_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + /* Branch over the next instruction if x0 == x1. */ + p += emit_bcond (p, EQ, 8); + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_lt_goto". */ + +static void +aarch64_emit_lt_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + /* Branch over the next instruction if x0 >= x1. */ + p += emit_bcond (p, GE, 8); + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_le_goto". */ + +static void +aarch64_emit_le_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + /* Branch over the next instruction if x0 > x1. */ + p += emit_bcond (p, GT, 8); + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_gt_goto". */ + +static void +aarch64_emit_gt_goto (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + /* Branch over the next instruction if x0 <= x1. */ + p += emit_bcond (p, LE, 8); + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +/* Implementation of emit_ops method "emit_ge_got". */ + +static void +aarch64_emit_ge_got (int *offset_p, int *size_p) +{ + uint32_t buf[16]; + uint32_t *p = buf; + + p += emit_pop (p, x1); + p += emit_cmp (p, x1, register_operand (x0)); + /* Branch over the next instruction if x0 <= x1. */ + p += emit_bcond (p, LT, 8); + /* The NOP instruction will be patched with an unconditional branch. */ + if (offset_p) + *offset_p = (p - buf) * 4; + if (size_p) + *size_p = 4; + p += emit_nop (p); + + emit_ops_insns (buf, p - buf); +} + +static struct emit_ops aarch64_emit_ops_impl = +{ + aarch64_emit_prologue, + aarch64_emit_epilogue, + aarch64_emit_add, + aarch64_emit_sub, + aarch64_emit_mul, + aarch64_emit_lsh, + aarch64_emit_rsh_signed, + aarch64_emit_rsh_unsigned, + aarch64_emit_ext, + aarch64_emit_log_not, + aarch64_emit_bit_and, + aarch64_emit_bit_or, + aarch64_emit_bit_xor, + aarch64_emit_bit_not, + aarch64_emit_equal, + aarch64_emit_less_signed, + aarch64_emit_less_unsigned, + aarch64_emit_ref, + aarch64_emit_if_goto, + aarch64_emit_goto, + aarch64_write_goto_address, + aarch64_emit_const, + aarch64_emit_call, + aarch64_emit_reg, + aarch64_emit_pop, + aarch64_emit_stack_flush, + aarch64_emit_zero_ext, + aarch64_emit_swap, + aarch64_emit_stack_adjust, + aarch64_emit_int_call_1, + aarch64_emit_void_call_2, + aarch64_emit_eq_goto, + aarch64_emit_ne_goto, + aarch64_emit_lt_goto, + aarch64_emit_le_goto, + aarch64_emit_gt_goto, + aarch64_emit_ge_got, +}; + +/* Implementation of linux_target_ops method "emit_ops". */ + +static struct emit_ops * +aarch64_emit_ops (void) +{ + return &aarch64_emit_ops_impl; +} + +/* Implementation of linux_target_ops method + "get_min_fast_tracepoint_insn_len". */ + +static int +aarch64_get_min_fast_tracepoint_insn_len (void) +{ + return 4; +} + +/* Implementation of linux_target_ops method "supports_range_stepping". */ + +static int +aarch64_supports_range_stepping (void) +{ + return 1; +} + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +aarch64_sw_breakpoint_from_kind (int kind, int *size) +{ + if (is_64bit_tdesc ()) + { + *size = aarch64_breakpoint_len; + return aarch64_breakpoint; + } + else + return arm_sw_breakpoint_from_kind (kind, size); +} + +/* Implementation of linux_target_ops method "breakpoint_kind_from_pc". */ + +static int +aarch64_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + if (is_64bit_tdesc ()) + return aarch64_breakpoint_len; + else + return arm_breakpoint_kind_from_pc (pcptr); +} + +/* Implementation of the linux_target_ops method + "breakpoint_kind_from_current_state". */ + +static int +aarch64_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) +{ + if (is_64bit_tdesc ()) + return aarch64_breakpoint_len; + else + return arm_breakpoint_kind_from_current_state (pcptr); +} + +/* Support for hardware single step. */ + +static int +aarch64_supports_hardware_single_step (void) +{ + return 1; +} + +struct linux_target_ops the_low_target = +{ + aarch64_arch_setup, + aarch64_regs_info, + NULL, /* cannot_fetch_register */ + NULL, /* cannot_store_register */ + NULL, /* fetch_register */ + aarch64_get_pc, + aarch64_set_pc, + aarch64_breakpoint_kind_from_pc, + aarch64_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 0, /* decr_pc_after_break */ + aarch64_breakpoint_at, + aarch64_supports_z_point_type, + aarch64_insert_point, + aarch64_remove_point, + aarch64_stopped_by_watchpoint, + aarch64_stopped_data_address, + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + aarch64_linux_siginfo_fixup, + aarch64_linux_new_process, + aarch64_linux_delete_process, + aarch64_linux_new_thread, + aarch64_linux_delete_thread, + aarch64_linux_new_fork, + aarch64_linux_prepare_to_resume, + NULL, /* process_qsupported */ + aarch64_supports_tracepoints, + aarch64_get_thread_area, + aarch64_install_fast_tracepoint_jump_pad, + aarch64_emit_ops, + aarch64_get_min_fast_tracepoint_insn_len, + aarch64_supports_range_stepping, + aarch64_breakpoint_kind_from_current_state, + aarch64_supports_hardware_single_step, + aarch64_get_syscall_trapinfo, +}; + +void +initialize_low_arch (void) +{ + initialize_low_arch_aarch32 (); + + initialize_regsets_info (&aarch64_regsets_info); + initialize_regsets_info (&aarch64_sve_regsets_info); +} diff --git a/gdbserver/linux-aarch64-tdesc.c b/gdbserver/linux-aarch64-tdesc.c new file mode 100644 index 00000000000..897fbb43bd2 --- /dev/null +++ b/gdbserver/linux-aarch64-tdesc.c @@ -0,0 +1,60 @@ +/* GNU/Linux/aarch64 specific target description, for the remote server + for GDB. + Copyright (C) 2017-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" + +#include "linux-aarch64-tdesc.h" + +#include "tdesc.h" +#include "arch/aarch64.h" +#include "linux-aarch32-low.h" +#include + +/* All possible aarch64 target descriptors. */ +struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/]; + +/* Create the aarch64 target description. */ + +const target_desc * +aarch64_linux_read_description (uint64_t vq, bool pauth_p) +{ + if (vq > AARCH64_MAX_SVE_VQ) + error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq, + AARCH64_MAX_SVE_VQ); + + struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p]; + + if (tdesc == NULL) + { + tdesc = aarch64_create_target_description (vq, pauth_p); + + static const char *expedite_regs_aarch64[] = { "x29", "sp", "pc", NULL }; + static const char *expedite_regs_aarch64_sve[] = { "x29", "sp", "pc", + "vg", NULL }; + + if (vq == 0) + init_target_desc (tdesc, expedite_regs_aarch64); + else + init_target_desc (tdesc, expedite_regs_aarch64_sve); + + tdesc_aarch64_list[vq][pauth_p] = tdesc; + } + + return tdesc; +} diff --git a/gdbserver/linux-aarch64-tdesc.h b/gdbserver/linux-aarch64-tdesc.h new file mode 100644 index 00000000000..0165e633d4c --- /dev/null +++ b/gdbserver/linux-aarch64-tdesc.h @@ -0,0 +1,25 @@ +/* Low level support for aarch64, shared between gdbserver and IPA. + + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_AARCH64_TDESC_H +#define GDBSERVER_LINUX_AARCH64_TDESC_H + +const target_desc * aarch64_linux_read_description (uint64_t vq, bool pauth_p); + +#endif /* GDBSERVER_LINUX_AARCH64_TDESC_H */ diff --git a/gdbserver/linux-amd64-ipa.c b/gdbserver/linux-amd64-ipa.c new file mode 100644 index 00000000000..53d98f26121 --- /dev/null +++ b/gdbserver/linux-amd64-ipa.c @@ -0,0 +1,289 @@ +/* GNU/Linux/x86-64 specific low level interface, for the in-process + agent library for GDB. + + Copyright (C) 2010-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include +#include "tracepoint.h" +#include "linux-x86-tdesc.h" +#include "gdbsupport/x86-xstate.h" + +/* Defined in auto-generated file amd64-linux.c. */ +void init_registers_amd64_linux (void); +extern const struct target_desc *tdesc_amd64_linux; + +/* fast tracepoints collect registers. */ + +#define FT_CR_RIP 0 +#define FT_CR_EFLAGS 1 +#define FT_CR_R8 2 +#define FT_CR_R9 3 +#define FT_CR_R10 4 +#define FT_CR_R11 5 +#define FT_CR_R12 6 +#define FT_CR_R13 7 +#define FT_CR_R14 8 +#define FT_CR_R15 9 +#define FT_CR_RAX 10 +#define FT_CR_RBX 11 +#define FT_CR_RCX 12 +#define FT_CR_RDX 13 +#define FT_CR_RSI 14 +#define FT_CR_RDI 15 +#define FT_CR_RBP 16 +#define FT_CR_RSP 17 + +static const int x86_64_ft_collect_regmap[] = { + FT_CR_RAX * 8, FT_CR_RBX * 8, FT_CR_RCX * 8, FT_CR_RDX * 8, + FT_CR_RSI * 8, FT_CR_RDI * 8, FT_CR_RBP * 8, FT_CR_RSP * 8, + FT_CR_R8 * 8, FT_CR_R9 * 8, FT_CR_R10 * 8, FT_CR_R11 * 8, + FT_CR_R12 * 8, FT_CR_R13 * 8, FT_CR_R14 * 8, FT_CR_R15 * 8, + FT_CR_RIP * 8, FT_CR_EFLAGS * 8 +}; + +#define X86_64_NUM_FT_COLLECT_GREGS \ + (sizeof (x86_64_ft_collect_regmap) / sizeof(x86_64_ft_collect_regmap[0])) + +void +supply_fast_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf) +{ + int i; + + for (i = 0; i < X86_64_NUM_FT_COLLECT_GREGS; i++) + supply_register (regcache, i, + ((char *) buf) + x86_64_ft_collect_regmap[i]); +} + +ULONGEST +get_raw_reg (const unsigned char *raw_regs, int regnum) +{ + if (regnum >= X86_64_NUM_FT_COLLECT_GREGS) + return 0; + + return *(ULONGEST *) (raw_regs + x86_64_ft_collect_regmap[regnum]); +} + +#ifdef HAVE_UST + +#include + +/* "struct registers" is the UST object type holding the registers at + the time of the static tracepoint marker call. This doesn't + contain RIP, but we know what it must have been (the marker + address). */ + +#define ST_REGENTRY(REG) \ + { \ + offsetof (struct registers, REG), \ + sizeof (((struct registers *) NULL)->REG) \ + } + +static struct +{ + int offset; + int size; +} x86_64_st_collect_regmap[] = + { + ST_REGENTRY(rax), + ST_REGENTRY(rbx), + ST_REGENTRY(rcx), + ST_REGENTRY(rdx), + ST_REGENTRY(rsi), + ST_REGENTRY(rdi), + ST_REGENTRY(rbp), + ST_REGENTRY(rsp), + ST_REGENTRY(r8), + ST_REGENTRY(r9), + ST_REGENTRY(r10), + ST_REGENTRY(r11), + ST_REGENTRY(r12), + ST_REGENTRY(r13), + ST_REGENTRY(r14), + ST_REGENTRY(r15), + { -1, 0 }, + ST_REGENTRY(rflags), + ST_REGENTRY(cs), + ST_REGENTRY(ss), + }; + +#define X86_64_NUM_ST_COLLECT_GREGS \ + (sizeof (x86_64_st_collect_regmap) / sizeof (x86_64_st_collect_regmap[0])) + +/* GDB's RIP register number. */ +#define AMD64_RIP_REGNUM 16 + +void +supply_static_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf, + CORE_ADDR pc) +{ + int i; + unsigned long newpc = pc; + + supply_register (regcache, AMD64_RIP_REGNUM, &newpc); + + for (i = 0; i < X86_64_NUM_ST_COLLECT_GREGS; i++) + if (x86_64_st_collect_regmap[i].offset != -1) + { + switch (x86_64_st_collect_regmap[i].size) + { + case 8: + supply_register (regcache, i, + ((char *) buf) + + x86_64_st_collect_regmap[i].offset); + break; + case 2: + { + unsigned long reg + = * (short *) (((char *) buf) + + x86_64_st_collect_regmap[i].offset); + reg &= 0xffff; + supply_register (regcache, i, ®); + } + break; + default: + internal_error (__FILE__, __LINE__, + "unhandled register size: %d", + x86_64_st_collect_regmap[i].size); + break; + } + } +} + +#endif /* HAVE_UST */ + +#if !defined __ILP32__ +/* Map the tdesc index to xcr0 mask. */ +static uint64_t idx2mask[X86_TDESC_LAST] = { + X86_XSTATE_X87_MASK, + X86_XSTATE_SSE_MASK, + X86_XSTATE_AVX_MASK, + X86_XSTATE_MPX_MASK, + X86_XSTATE_AVX_MPX_MASK, + X86_XSTATE_AVX_AVX512_MASK, + X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, +}; +#endif + +/* Return target_desc to use for IPA, given the tdesc index passed by + gdbserver. */ + +const struct target_desc * +get_ipa_tdesc (int idx) +{ + if (idx >= X86_TDESC_LAST) + { + internal_error (__FILE__, __LINE__, + "unknown ipa tdesc index: %d", idx); + } + +#if defined __ILP32__ + switch (idx) + { + case X86_TDESC_SSE: + return amd64_linux_read_description (X86_XSTATE_SSE_MASK, true); + case X86_TDESC_AVX: + return amd64_linux_read_description (X86_XSTATE_AVX_MASK, true); + case X86_TDESC_AVX_AVX512: + return amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true); + default: + break; + } +#else + return amd64_linux_read_description (idx2mask[idx], false); +#endif + + internal_error (__FILE__, __LINE__, + "unknown ipa tdesc index: %d", idx); +} + +/* Allocate buffer for the jump pads. The branch instruction has a + reach of +/- 31-bit, and the executable is loaded at low addresses. + + 64-bit: Use MAP_32BIT to allocate in the first 2GB. Shared + libraries, being allocated at the top, are unfortunately out of + luck. + + x32: Since MAP_32BIT is 64-bit only, do the placement manually. + Try allocating at '0x80000000 - SIZE' initially, decreasing until + we hit a free area. This ensures the executable is fully covered, + and is as close as possible to the shared libraries, which are + usually mapped at the top of the first 4GB of the address space. +*/ + +void * +alloc_jump_pad_buffer (size_t size) +{ +#if __ILP32__ + uintptr_t addr; + int pagesize; + + pagesize = sysconf (_SC_PAGE_SIZE); + if (pagesize == -1) + perror_with_name ("sysconf"); + + addr = 0x80000000 - size; + + /* size should already be page-aligned, but this can't hurt. */ + addr &= ~(pagesize - 1); + + /* Search for a free area. If we hit 0, we're out of luck. */ + for (; addr; addr -= pagesize) + { + void *res; + + /* No MAP_FIXED - we don't want to zap someone's mapping. */ + res = mmap ((void *) addr, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* If we got what we wanted, return. */ + if ((uintptr_t) res == addr) + return res; + + /* If we got a mapping, but at a wrong address, undo it. */ + if (res != MAP_FAILED) + munmap (res, size); + } + + return NULL; +#else + void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); + + if (res == MAP_FAILED) + return NULL; + + return res; +#endif +} + +void +initialize_low_tracepoint (void) +{ +#if defined __ILP32__ + amd64_linux_read_description (X86_XSTATE_SSE_MASK, true); + amd64_linux_read_description (X86_XSTATE_AVX_MASK, true); + amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true); +#else + for (auto i = 0; i < X86_TDESC_LAST; i++) + amd64_linux_read_description (idx2mask[i], false); +#endif +} diff --git a/gdbserver/linux-arm-low.c b/gdbserver/linux-arm-low.c new file mode 100644 index 00000000000..9f046c098bf --- /dev/null +++ b/gdbserver/linux-arm-low.c @@ -0,0 +1,1052 @@ +/* GNU/Linux/ARM specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "arch/arm.h" +#include "arch/arm-linux.h" +#include "arch/arm-get-next-pcs.h" +#include "linux-aarch32-low.h" +#include "linux-aarch32-tdesc.h" +#include "linux-arm-tdesc.h" + +#include +/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h. + On Bionic elf.h and linux/elf.h have conflicting definitions. */ +#ifndef ELFMAG0 +#include +#endif +#include "nat/gdb_ptrace.h" +#include +#include + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 22 +#endif + +#ifndef PTRACE_GETWMMXREGS +# define PTRACE_GETWMMXREGS 18 +# define PTRACE_SETWMMXREGS 19 +#endif + +#ifndef PTRACE_GETVFPREGS +# define PTRACE_GETVFPREGS 27 +# define PTRACE_SETVFPREGS 28 +#endif + +#ifndef PTRACE_GETHBPREGS +#define PTRACE_GETHBPREGS 29 +#define PTRACE_SETHBPREGS 30 +#endif + +/* Information describing the hardware breakpoint capabilities. */ +static struct +{ + unsigned char arch; + unsigned char max_wp_length; + unsigned char wp_count; + unsigned char bp_count; +} arm_linux_hwbp_cap; + +/* Enum describing the different types of ARM hardware break-/watch-points. */ +typedef enum +{ + arm_hwbp_break = 0, + arm_hwbp_load = 1, + arm_hwbp_store = 2, + arm_hwbp_access = 3 +} arm_hwbp_type; + +/* Type describing an ARM Hardware Breakpoint Control register value. */ +typedef unsigned int arm_hwbp_control_t; + +/* Structure used to keep track of hardware break-/watch-points. */ +struct arm_linux_hw_breakpoint +{ + /* Address to break on, or being watched. */ + unsigned int address; + /* Control register for break-/watch- point. */ + arm_hwbp_control_t control; +}; + +/* Since we cannot dynamically allocate subfields of arch_process_info, + assume a maximum number of supported break-/watchpoints. */ +#define MAX_BPTS 32 +#define MAX_WPTS 32 + +/* Per-process arch-specific data we want to keep. */ +struct arch_process_info +{ + /* Hardware breakpoints for this process. */ + struct arm_linux_hw_breakpoint bpts[MAX_BPTS]; + /* Hardware watchpoints for this process. */ + struct arm_linux_hw_breakpoint wpts[MAX_WPTS]; +}; + +/* Per-thread arch-specific data we want to keep. */ +struct arch_lwp_info +{ + /* Non-zero if our copy differs from what's recorded in the thread. */ + char bpts_changed[MAX_BPTS]; + char wpts_changed[MAX_WPTS]; + /* Cached stopped data address. */ + CORE_ADDR stopped_data_address; +}; + +/* These are in in current kernels. */ +#define HWCAP_VFP 64 +#define HWCAP_IWMMXT 512 +#define HWCAP_NEON 4096 +#define HWCAP_VFPv3 8192 +#define HWCAP_VFPv3D16 16384 + +#ifdef HAVE_SYS_REG_H +#include +#endif + +#define arm_num_regs 26 + +static int arm_regmap[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, + -1, -1, -1, -1, -1, -1, -1, -1, -1, + 64 +}; + +/* Forward declarations needed for get_next_pcs ops. */ +static ULONGEST get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, + int len, + int byte_order); + +static CORE_ADDR get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, + CORE_ADDR val); + +static CORE_ADDR get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self); + +static int get_next_pcs_is_thumb (struct arm_get_next_pcs *self); + +/* get_next_pcs operations. */ +static struct arm_get_next_pcs_ops get_next_pcs_ops = { + get_next_pcs_read_memory_unsigned_integer, + get_next_pcs_syscall_next_pc, + get_next_pcs_addr_bits_remove, + get_next_pcs_is_thumb, + arm_linux_get_next_pcs_fixup, +}; + +static int +arm_cannot_store_register (int regno) +{ + return (regno >= arm_num_regs); +} + +static int +arm_cannot_fetch_register (int regno) +{ + return (regno >= arm_num_regs); +} + +static void +arm_fill_wmmxregset (struct regcache *regcache, void *buf) +{ + if (arm_linux_get_tdesc_fp_type (regcache->tdesc) != ARM_FP_TYPE_IWMMXT) + return; + + for (int i = 0; i < 16; i++) + collect_register (regcache, arm_num_regs + i, (char *) buf + i * 8); + + /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */ + for (int i = 0; i < 6; i++) + collect_register (regcache, arm_num_regs + i + 16, + (char *) buf + 16 * 8 + i * 4); +} + +static void +arm_store_wmmxregset (struct regcache *regcache, const void *buf) +{ + if (arm_linux_get_tdesc_fp_type (regcache->tdesc) != ARM_FP_TYPE_IWMMXT) + return; + + for (int i = 0; i < 16; i++) + supply_register (regcache, arm_num_regs + i, (char *) buf + i * 8); + + /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */ + for (int i = 0; i < 6; i++) + supply_register (regcache, arm_num_regs + i + 16, + (char *) buf + 16 * 8 + i * 4); +} + +static void +arm_fill_vfpregset (struct regcache *regcache, void *buf) +{ + int num; + + if (is_aarch32_linux_description (regcache->tdesc)) + num = 32; + else + { + arm_fp_type fp_type = arm_linux_get_tdesc_fp_type (regcache->tdesc); + + if (fp_type == ARM_FP_TYPE_VFPV3) + num = 32; + else if (fp_type == ARM_FP_TYPE_VFPV2) + num = 16; + else + return; + } + + arm_fill_vfpregset_num (regcache, buf, num); +} + +/* Wrapper of UNMAKE_THUMB_ADDR for get_next_pcs. */ +static CORE_ADDR +get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val) +{ + return UNMAKE_THUMB_ADDR (val); +} + +static void +arm_store_vfpregset (struct regcache *regcache, const void *buf) +{ + int num; + + if (is_aarch32_linux_description (regcache->tdesc)) + num = 32; + else + { + arm_fp_type fp_type = arm_linux_get_tdesc_fp_type (regcache->tdesc); + + if (fp_type == ARM_FP_TYPE_VFPV3) + num = 32; + else if (fp_type == ARM_FP_TYPE_VFPV2) + num = 16; + else + return; + } + + arm_store_vfpregset_num (regcache, buf, num); +} + +/* Wrapper of arm_is_thumb_mode for get_next_pcs. */ +static int +get_next_pcs_is_thumb (struct arm_get_next_pcs *self) +{ + return arm_is_thumb_mode (); +} + +/* Read memory from the inferior. + BYTE_ORDER is ignored and there to keep compatiblity with GDB's + read_memory_unsigned_integer. */ +static ULONGEST +get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, + int len, + int byte_order) +{ + ULONGEST res; + + res = 0; + target_read_memory (memaddr, (unsigned char *) &res, len); + + return res; +} + +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *)*base - idx); + + return PS_OK; +} + + +/* Query Hardware Breakpoint information for the target we are attached to + (using PID as ptrace argument) and set up arm_linux_hwbp_cap. */ +static void +arm_linux_init_hwbp_cap (int pid) +{ + unsigned int val; + + if (ptrace (PTRACE_GETHBPREGS, pid, 0, &val) < 0) + return; + + arm_linux_hwbp_cap.arch = (unsigned char)((val >> 24) & 0xff); + if (arm_linux_hwbp_cap.arch == 0) + return; + + arm_linux_hwbp_cap.max_wp_length = (unsigned char)((val >> 16) & 0xff); + arm_linux_hwbp_cap.wp_count = (unsigned char)((val >> 8) & 0xff); + arm_linux_hwbp_cap.bp_count = (unsigned char)(val & 0xff); + + if (arm_linux_hwbp_cap.wp_count > MAX_WPTS) + internal_error (__FILE__, __LINE__, "Unsupported number of watchpoints"); + if (arm_linux_hwbp_cap.bp_count > MAX_BPTS) + internal_error (__FILE__, __LINE__, "Unsupported number of breakpoints"); +} + +/* How many hardware breakpoints are available? */ +static int +arm_linux_get_hw_breakpoint_count (void) +{ + return arm_linux_hwbp_cap.bp_count; +} + +/* How many hardware watchpoints are available? */ +static int +arm_linux_get_hw_watchpoint_count (void) +{ + return arm_linux_hwbp_cap.wp_count; +} + +/* Maximum length of area watched by hardware watchpoint. */ +static int +arm_linux_get_hw_watchpoint_max_length (void) +{ + return arm_linux_hwbp_cap.max_wp_length; +} + +/* Initialize an ARM hardware break-/watch-point control register value. + BYTE_ADDRESS_SELECT is the mask of bytes to trigger on; HWBP_TYPE is the + type of break-/watch-point; ENABLE indicates whether the point is enabled. + */ +static arm_hwbp_control_t +arm_hwbp_control_initialize (unsigned byte_address_select, + arm_hwbp_type hwbp_type, + int enable) +{ + gdb_assert ((byte_address_select & ~0xffU) == 0); + gdb_assert (hwbp_type != arm_hwbp_break + || ((byte_address_select & 0xfU) != 0)); + + return (byte_address_select << 5) | (hwbp_type << 3) | (3 << 1) | enable; +} + +/* Does the breakpoint control value CONTROL have the enable bit set? */ +static int +arm_hwbp_control_is_enabled (arm_hwbp_control_t control) +{ + return control & 0x1; +} + +/* Is the breakpoint control value CONTROL initialized? */ +static int +arm_hwbp_control_is_initialized (arm_hwbp_control_t control) +{ + return control != 0; +} + +/* Change a breakpoint control word so that it is in the disabled state. */ +static arm_hwbp_control_t +arm_hwbp_control_disable (arm_hwbp_control_t control) +{ + return control & ~0x1; +} + +/* Are two break-/watch-points equal? */ +static int +arm_linux_hw_breakpoint_equal (const struct arm_linux_hw_breakpoint *p1, + const struct arm_linux_hw_breakpoint *p2) +{ + return p1->address == p2->address && p1->control == p2->control; +} + +/* Convert a raw breakpoint type to an enum arm_hwbp_type. */ + +static arm_hwbp_type +raw_bkpt_type_to_arm_hwbp_type (enum raw_bkpt_type raw_type) +{ + switch (raw_type) + { + case raw_bkpt_type_hw: + return arm_hwbp_break; + case raw_bkpt_type_write_wp: + return arm_hwbp_store; + case raw_bkpt_type_read_wp: + return arm_hwbp_load; + case raw_bkpt_type_access_wp: + return arm_hwbp_access; + default: + gdb_assert_not_reached ("unhandled raw type"); + } +} + +/* Initialize the hardware breakpoint structure P for a breakpoint or + watchpoint at ADDR to LEN. The type of watchpoint is given in TYPE. + Returns -1 if TYPE is unsupported, or -2 if the particular combination + of ADDR and LEN cannot be implemented. Otherwise, returns 0 if TYPE + represents a breakpoint and 1 if type represents a watchpoint. */ +static int +arm_linux_hw_point_initialize (enum raw_bkpt_type raw_type, CORE_ADDR addr, + int len, struct arm_linux_hw_breakpoint *p) +{ + arm_hwbp_type hwbp_type; + unsigned mask; + + hwbp_type = raw_bkpt_type_to_arm_hwbp_type (raw_type); + + if (hwbp_type == arm_hwbp_break) + { + /* For breakpoints, the length field encodes the mode. */ + switch (len) + { + case 2: /* 16-bit Thumb mode breakpoint */ + case 3: /* 32-bit Thumb mode breakpoint */ + mask = 0x3; + addr &= ~1; + break; + case 4: /* 32-bit ARM mode breakpoint */ + mask = 0xf; + addr &= ~3; + break; + default: + /* Unsupported. */ + return -2; + } + } + else + { + CORE_ADDR max_wp_length = arm_linux_get_hw_watchpoint_max_length (); + CORE_ADDR aligned_addr; + + /* Can not set watchpoints for zero or negative lengths. */ + if (len <= 0) + return -2; + /* The current ptrace interface can only handle watchpoints that are a + power of 2. */ + if ((len & (len - 1)) != 0) + return -2; + + /* Test that the range [ADDR, ADDR + LEN) fits into the largest address + range covered by a watchpoint. */ + aligned_addr = addr & ~(max_wp_length - 1); + if (aligned_addr + max_wp_length < addr + len) + return -2; + + mask = (1 << len) - 1; + } + + p->address = (unsigned int) addr; + p->control = arm_hwbp_control_initialize (mask, hwbp_type, 1); + + return hwbp_type != arm_hwbp_break; +} + +/* Callback to mark a watch-/breakpoint to be updated in all threads of + the current process. */ + +static void +update_registers_callback (thread_info *thread, int watch, int i) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + /* The actual update is done later just before resuming the lwp, + we just mark that the registers need updating. */ + if (watch) + lwp->arch_private->wpts_changed[i] = 1; + else + lwp->arch_private->bpts_changed[i] = 1; + + /* If the lwp isn't stopped, force it to momentarily pause, so + we can update its breakpoint registers. */ + if (!lwp->stopped) + linux_stop_lwp (lwp); +} + +static int +arm_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + case Z_PACKET_HW_BP: + case Z_PACKET_WRITE_WP: + case Z_PACKET_READ_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + /* Leave the handling of sw breakpoints with the gdb client. */ + return 0; + } +} + +/* Insert hardware break-/watchpoint. */ +static int +arm_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + struct process_info *proc = current_process (); + struct arm_linux_hw_breakpoint p, *pts; + int watch, i, count; + + watch = arm_linux_hw_point_initialize (type, addr, len, &p); + if (watch < 0) + { + /* Unsupported. */ + return watch == -1 ? 1 : -1; + } + + if (watch) + { + count = arm_linux_get_hw_watchpoint_count (); + pts = proc->priv->arch_private->wpts; + } + else + { + count = arm_linux_get_hw_breakpoint_count (); + pts = proc->priv->arch_private->bpts; + } + + for (i = 0; i < count; i++) + if (!arm_hwbp_control_is_enabled (pts[i].control)) + { + pts[i] = p; + + /* Only update the threads of the current process. */ + for_each_thread (current_thread->id.pid (), [&] (thread_info *thread) + { + update_registers_callback (thread, watch, i); + }); + + return 0; + } + + /* We're out of watchpoints. */ + return -1; +} + +/* Remove hardware break-/watchpoint. */ +static int +arm_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + struct process_info *proc = current_process (); + struct arm_linux_hw_breakpoint p, *pts; + int watch, i, count; + + watch = arm_linux_hw_point_initialize (type, addr, len, &p); + if (watch < 0) + { + /* Unsupported. */ + return -1; + } + + if (watch) + { + count = arm_linux_get_hw_watchpoint_count (); + pts = proc->priv->arch_private->wpts; + } + else + { + count = arm_linux_get_hw_breakpoint_count (); + pts = proc->priv->arch_private->bpts; + } + + for (i = 0; i < count; i++) + if (arm_linux_hw_breakpoint_equal (&p, pts + i)) + { + pts[i].control = arm_hwbp_control_disable (pts[i].control); + + /* Only update the threads of the current process. */ + for_each_thread (current_thread->id.pid (), [&] (thread_info *thread) + { + update_registers_callback (thread, watch, i); + }); + + return 0; + } + + /* No watchpoint matched. */ + return -1; +} + +/* Return whether current thread is stopped due to a watchpoint. */ +static int +arm_stopped_by_watchpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + siginfo_t siginfo; + + /* We must be able to set hardware watchpoints. */ + if (arm_linux_get_hw_watchpoint_count () == 0) + return 0; + + /* Retrieve siginfo. */ + errno = 0; + ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), 0, &siginfo); + if (errno != 0) + return 0; + + /* This must be a hardware breakpoint. */ + if (siginfo.si_signo != SIGTRAP + || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) + return 0; + + /* If we are in a positive slot then we're looking at a breakpoint and not + a watchpoint. */ + if (siginfo.si_errno >= 0) + return 0; + + /* Cache stopped data address for use by arm_stopped_data_address. */ + lwp->arch_private->stopped_data_address + = (CORE_ADDR) (uintptr_t) siginfo.si_addr; + + return 1; +} + +/* Return data address that triggered watchpoint. Called only if + arm_stopped_by_watchpoint returned true. */ +static CORE_ADDR +arm_stopped_data_address (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + return lwp->arch_private->stopped_data_address; +} + +/* Called when a new process is created. */ +static struct arch_process_info * +arm_new_process (void) +{ + struct arch_process_info *info = XCNEW (struct arch_process_info); + return info; +} + +/* Called when a process is being deleted. */ + +static void +arm_delete_process (struct arch_process_info *info) +{ + xfree (info); +} + +/* Called when a new thread is detected. */ +static void +arm_new_thread (struct lwp_info *lwp) +{ + struct arch_lwp_info *info = XCNEW (struct arch_lwp_info); + int i; + + for (i = 0; i < MAX_BPTS; i++) + info->bpts_changed[i] = 1; + for (i = 0; i < MAX_WPTS; i++) + info->wpts_changed[i] = 1; + + lwp->arch_private = info; +} + +/* Function to call when a thread is being deleted. */ + +static void +arm_delete_thread (struct arch_lwp_info *arch_lwp) +{ + xfree (arch_lwp); +} + +static void +arm_new_fork (struct process_info *parent, struct process_info *child) +{ + struct arch_process_info *parent_proc_info; + struct arch_process_info *child_proc_info; + struct lwp_info *child_lwp; + struct arch_lwp_info *child_lwp_info; + int i; + + /* These are allocated by linux_add_process. */ + gdb_assert (parent->priv != NULL + && parent->priv->arch_private != NULL); + gdb_assert (child->priv != NULL + && child->priv->arch_private != NULL); + + parent_proc_info = parent->priv->arch_private; + child_proc_info = child->priv->arch_private; + + /* Linux kernel before 2.6.33 commit + 72f674d203cd230426437cdcf7dd6f681dad8b0d + will inherit hardware debug registers from parent + on fork/vfork/clone. Newer Linux kernels create such tasks with + zeroed debug registers. + + GDB core assumes the child inherits the watchpoints/hw + breakpoints of the parent, and will remove them all from the + forked off process. Copy the debug registers mirrors into the + new process so that all breakpoints and watchpoints can be + removed together. The debug registers mirror will become zeroed + in the end before detaching the forked off process, thus making + this compatible with older Linux kernels too. */ + + *child_proc_info = *parent_proc_info; + + /* Mark all the hardware breakpoints and watchpoints as changed to + make sure that the registers will be updated. */ + child_lwp = find_lwp_pid (ptid_t (child->pid)); + child_lwp_info = child_lwp->arch_private; + for (i = 0; i < MAX_BPTS; i++) + child_lwp_info->bpts_changed[i] = 1; + for (i = 0; i < MAX_WPTS; i++) + child_lwp_info->wpts_changed[i] = 1; +} + +/* Called when resuming a thread. + If the debug regs have changed, update the thread's copies. */ +static void +arm_prepare_to_resume (struct lwp_info *lwp) +{ + struct thread_info *thread = get_lwp_thread (lwp); + int pid = lwpid_of (thread); + struct process_info *proc = find_process_pid (pid_of (thread)); + struct arch_process_info *proc_info = proc->priv->arch_private; + struct arch_lwp_info *lwp_info = lwp->arch_private; + int i; + + for (i = 0; i < arm_linux_get_hw_breakpoint_count (); i++) + if (lwp_info->bpts_changed[i]) + { + errno = 0; + + if (arm_hwbp_control_is_enabled (proc_info->bpts[i].control)) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) ((i << 1) + 1), + &proc_info->bpts[i].address) < 0) + perror_with_name ("Unexpected error setting breakpoint address"); + + if (arm_hwbp_control_is_initialized (proc_info->bpts[i].control)) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) ((i << 1) + 2), + &proc_info->bpts[i].control) < 0) + perror_with_name ("Unexpected error setting breakpoint"); + + lwp_info->bpts_changed[i] = 0; + } + + for (i = 0; i < arm_linux_get_hw_watchpoint_count (); i++) + if (lwp_info->wpts_changed[i]) + { + errno = 0; + + if (arm_hwbp_control_is_enabled (proc_info->wpts[i].control)) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) -((i << 1) + 1), + &proc_info->wpts[i].address) < 0) + perror_with_name ("Unexpected error setting watchpoint address"); + + if (arm_hwbp_control_is_initialized (proc_info->wpts[i].control)) + if (ptrace (PTRACE_SETHBPREGS, pid, + (PTRACE_TYPE_ARG3) -((i << 1) + 2), + &proc_info->wpts[i].control) < 0) + perror_with_name ("Unexpected error setting watchpoint"); + + lwp_info->wpts_changed[i] = 0; + } +} + +/* Find the next pc for a sigreturn or rt_sigreturn syscall. In + addition, set IS_THUMB depending on whether we will return to ARM + or Thumb code. + See arm-linux.h for stack layout details. */ +static CORE_ADDR +arm_sigreturn_next_pc (struct regcache *regcache, int svc_number, + int *is_thumb) +{ + unsigned long sp; + unsigned long sp_data; + /* Offset of PC register. */ + int pc_offset = 0; + CORE_ADDR next_pc = 0; + uint32_t cpsr; + + gdb_assert (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn); + + collect_register_by_name (regcache, "sp", &sp); + (*the_target->read_memory) (sp, (unsigned char *) &sp_data, 4); + + pc_offset = arm_linux_sigreturn_next_pc_offset + (sp, sp_data, svc_number, __NR_sigreturn == svc_number ? 1 : 0); + + (*the_target->read_memory) (sp + pc_offset, (unsigned char *) &next_pc, 4); + + /* Set IS_THUMB according the CPSR saved on the stack. */ + (*the_target->read_memory) (sp + pc_offset + 4, (unsigned char *) &cpsr, 4); + *is_thumb = ((cpsr & CPSR_T) != 0); + + return next_pc; +} + +/* When PC is at a syscall instruction, return the PC of the next + instruction to be executed. */ +static CORE_ADDR +get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self) +{ + CORE_ADDR next_pc = 0; + CORE_ADDR pc = regcache_read_pc (self->regcache); + int is_thumb = arm_is_thumb_mode (); + ULONGEST svc_number = 0; + struct regcache *regcache = self->regcache; + + if (is_thumb) + { + collect_register (regcache, 7, &svc_number); + next_pc = pc + 2; + } + else + { + unsigned long this_instr; + unsigned long svc_operand; + + target_read_memory (pc, (unsigned char *) &this_instr, 4); + svc_operand = (0x00ffffff & this_instr); + + if (svc_operand) /* OABI. */ + { + svc_number = svc_operand - 0x900000; + } + else /* EABI. */ + { + collect_register (regcache, 7, &svc_number); + } + + next_pc = pc + 4; + } + + /* This is a sigreturn or sigreturn_rt syscall. */ + if (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn) + { + /* SIGRETURN or RT_SIGRETURN may affect the arm thumb mode, so + update IS_THUMB. */ + next_pc = arm_sigreturn_next_pc (regcache, svc_number, &is_thumb); + } + + /* Addresses for calling Thumb functions have the bit 0 set. */ + if (is_thumb) + next_pc = MAKE_THUMB_ADDR (next_pc); + + return next_pc; +} + +static const struct target_desc * +arm_read_description (void) +{ + unsigned long arm_hwcap = linux_get_hwcap (4); + + if (arm_hwcap & HWCAP_IWMMXT) + return arm_linux_read_description (ARM_FP_TYPE_IWMMXT); + + if (arm_hwcap & HWCAP_VFP) + { + /* Make sure that the kernel supports reading VFP registers. Support was + added in 2.6.30. */ + int pid = lwpid_of (current_thread); + errno = 0; + char *buf = (char *) alloca (ARM_VFP3_REGS_SIZE); + if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0 && errno == EIO) + return arm_linux_read_description (ARM_FP_TYPE_NONE); + + /* NEON implies either no VFP, or VFPv3-D32. We only support + it with VFP. */ + if (arm_hwcap & HWCAP_NEON) + return aarch32_linux_read_description (); + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) + return arm_linux_read_description (ARM_FP_TYPE_VFPV3); + else + return arm_linux_read_description (ARM_FP_TYPE_VFPV2); + } + + /* The default configuration uses legacy FPA registers, probably + simulated. */ + return arm_linux_read_description (ARM_FP_TYPE_NONE); +} + +static void +arm_arch_setup (void) +{ + int tid = lwpid_of (current_thread); + int gpregs[18]; + struct iovec iov; + + /* Query hardware watchpoint/breakpoint capabilities. */ + arm_linux_init_hwbp_cap (tid); + + current_process ()->tdesc = arm_read_description (); + + iov.iov_base = gpregs; + iov.iov_len = sizeof (gpregs); + + /* Check if PTRACE_GETREGSET works. */ + if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) == 0) + have_ptrace_getregset = 1; + else + have_ptrace_getregset = 0; +} + +/* Fetch the next possible PCs after the current instruction executes. */ + +static std::vector +arm_gdbserver_get_next_pcs (struct regcache *regcache) +{ + struct arm_get_next_pcs next_pcs_ctx; + + arm_get_next_pcs_ctor (&next_pcs_ctx, + &get_next_pcs_ops, + /* Byte order is ignored assumed as host. */ + 0, + 0, + 1, + regcache); + + return arm_get_next_pcs (&next_pcs_ctx); +} + +/* Support for hardware single step. */ + +static int +arm_supports_hardware_single_step (void) +{ + return 0; +} + +/* Implementation of linux_target_ops method "get_syscall_trapinfo". */ + +static void +arm_get_syscall_trapinfo (struct regcache *regcache, int *sysno) +{ + if (arm_is_thumb_mode ()) + collect_register_by_name (regcache, "r7", sysno); + else + { + unsigned long pc; + unsigned long insn; + + collect_register_by_name (regcache, "pc", &pc); + + if ((*the_target->read_memory) (pc - 4, (unsigned char *) &insn, 4)) + *sysno = UNKNOWN_SYSCALL; + else + { + unsigned long svc_operand = (0x00ffffff & insn); + + if (svc_operand) + { + /* OABI */ + *sysno = svc_operand - 0x900000; + } + else + { + /* EABI */ + collect_register_by_name (regcache, "r7", sysno); + } + } + } +} + +/* Register sets without using PTRACE_GETREGSET. */ + +static struct regset_info arm_regsets[] = { + { PTRACE_GETREGS, PTRACE_SETREGS, 0, + ARM_CORE_REGS_SIZE + ARM_INT_REGISTER_SIZE, GENERAL_REGS, + arm_fill_gregset, arm_store_gregset }, + { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 0, IWMMXT_REGS_SIZE, EXTENDED_REGS, + arm_fill_wmmxregset, arm_store_wmmxregset }, + { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 0, ARM_VFP3_REGS_SIZE, EXTENDED_REGS, + arm_fill_vfpregset, arm_store_vfpregset }, + NULL_REGSET +}; + +static struct regsets_info arm_regsets_info = + { + arm_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info arm_usrregs_info = + { + arm_num_regs, + arm_regmap, + }; + +static struct regs_info regs_info_arm = + { + NULL, /* regset_bitmap */ + &arm_usrregs_info, + &arm_regsets_info + }; + +static const struct regs_info * +arm_regs_info (void) +{ + const struct target_desc *tdesc = current_process ()->tdesc; + + if (have_ptrace_getregset == 1 + && (is_aarch32_linux_description (tdesc) + || arm_linux_get_tdesc_fp_type (tdesc) == ARM_FP_TYPE_VFPV3)) + return ®s_info_aarch32; + + return ®s_info_arm; +} + +struct linux_target_ops the_low_target = { + arm_arch_setup, + arm_regs_info, + arm_cannot_fetch_register, + arm_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + arm_breakpoint_kind_from_pc, + arm_sw_breakpoint_from_kind, + arm_gdbserver_get_next_pcs, + 0, + arm_breakpoint_at, + arm_supports_z_point_type, + arm_insert_point, + arm_remove_point, + arm_stopped_by_watchpoint, + arm_stopped_data_address, + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + arm_new_process, + arm_delete_process, + arm_new_thread, + arm_delete_thread, + arm_new_fork, + arm_prepare_to_resume, + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + arm_breakpoint_kind_from_current_state, + arm_supports_hardware_single_step, + arm_get_syscall_trapinfo, +}; + +void +initialize_low_arch (void) +{ + initialize_low_arch_aarch32 (); + initialize_regsets_info (&arm_regsets_info); +} diff --git a/gdbserver/linux-arm-tdesc.c b/gdbserver/linux-arm-tdesc.c new file mode 100644 index 00000000000..2c9fac83cd5 --- /dev/null +++ b/gdbserver/linux-arm-tdesc.c @@ -0,0 +1,65 @@ +/* Copyright (C) 2019-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" + +#include "linux-arm-tdesc.h" + +#include "tdesc.h" +#include "arch/arm.h" +#include + +/* All possible Arm target descriptors. */ +static struct target_desc *tdesc_arm_list[ARM_FP_TYPE_INVALID]; + +/* See linux-arm-tdesc.h. */ + +const target_desc * +arm_linux_read_description (arm_fp_type fp_type) +{ + struct target_desc *tdesc = tdesc_arm_list[fp_type]; + + if (tdesc == nullptr) + { + tdesc = arm_create_target_description (fp_type); + + static const char *expedite_regs[] = { "r11", "sp", "pc", 0 }; + init_target_desc (tdesc, expedite_regs); + + tdesc_arm_list[fp_type] = tdesc; + } + + return tdesc; +} + +/* See linux-arm-tdesc.h. */ + +arm_fp_type +arm_linux_get_tdesc_fp_type (const target_desc *tdesc) +{ + gdb_assert (tdesc != nullptr); + + /* Many of the tdesc_arm_list entries may not have been initialised yet. This + is ok, because tdesc must be one of the initialised ones. */ + for (int i = ARM_FP_TYPE_NONE; i < ARM_FP_TYPE_INVALID; i++) + { + if (tdesc == tdesc_arm_list[i]) + return (arm_fp_type) i; + } + + return ARM_FP_TYPE_INVALID; +} diff --git a/gdbserver/linux-arm-tdesc.h b/gdbserver/linux-arm-tdesc.h new file mode 100644 index 00000000000..5e8c6a3be57 --- /dev/null +++ b/gdbserver/linux-arm-tdesc.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2019-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_ARM_TDESC_H +#define GDBSERVER_LINUX_ARM_TDESC_H + +#include "arch/arm.h" + +/* Return the Arm target description with fp registers FP_TYPE. */ + +const target_desc * arm_linux_read_description (arm_fp_type fp_type); + +/* For a target description TDESC, return its fp type. */ + +arm_fp_type arm_linux_get_tdesc_fp_type (const target_desc *tdesc); + +#endif /* linux-arm-tdesc.h. */ diff --git a/gdbserver/linux-bfin-low.c b/gdbserver/linux-bfin-low.c new file mode 100644 index 00000000000..5bfc8868bd9 --- /dev/null +++ b/gdbserver/linux-bfin-low.c @@ -0,0 +1,159 @@ +/* GNU/Linux/BFIN specific low level interface, for the remote server for GDB. + + Copyright (C) 2005-2020 Free Software Foundation, Inc. + + Contributed by Analog Devices, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include + +/* Defined in auto-generated file reg-bfin.c. */ +void init_registers_bfin (void); +extern const struct target_desc *tdesc_bfin; + +static int bfin_regmap[] = +{ + PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, + PT_P0, PT_P1, PT_P2, PT_P3, PT_P4, PT_P5, PT_USP, PT_FP, + PT_I0, PT_I1, PT_I2, PT_I3, PT_M0, PT_M1, PT_M2, PT_M3, + PT_B0, PT_B1, PT_B2, PT_B3, PT_L0, PT_L1, PT_L2, PT_L3, + PT_A0X, PT_A0W, PT_A1X, PT_A1W, PT_ASTAT, PT_RETS, + PT_LC0, PT_LT0, PT_LB0, PT_LC1, PT_LT1, PT_LB1, + -1 /* PT_CYCLES */, -1 /* PT_CYCLES2 */, + -1 /* PT_USP */, PT_SEQSTAT, PT_SYSCFG, PT_PC, PT_RETX, PT_RETN, PT_RETE, + PT_PC, +}; + +#define bfin_num_regs ARRAY_SIZE (bfin_regmap) + +static int +bfin_cannot_store_register (int regno) +{ + return (regno >= bfin_num_regs); +} + +static int +bfin_cannot_fetch_register (int regno) +{ + return (regno >= bfin_num_regs); +} + +#define bfin_breakpoint_len 2 +static const gdb_byte bfin_breakpoint[bfin_breakpoint_len] = {0xa1, 0x00}; + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +bfin_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = bfin_breakpoint_len; + return bfin_breakpoint; +} + +static int +bfin_breakpoint_at (CORE_ADDR where) +{ + unsigned char insn[bfin_breakpoint_len]; + + read_inferior_memory(where, insn, bfin_breakpoint_len); + if (insn[0] == bfin_breakpoint[0] + && insn[1] == bfin_breakpoint[1]) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +static void +bfin_arch_setup (void) +{ + current_process ()->tdesc = tdesc_bfin; +} + +/* Support for hardware single step. */ + +static int +bfin_supports_hardware_single_step (void) +{ + return 1; +} + +static struct usrregs_info bfin_usrregs_info = + { + bfin_num_regs, + bfin_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &bfin_usrregs_info, + }; + +static const struct regs_info * +bfin_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + bfin_arch_setup, + bfin_regs_info, + bfin_cannot_fetch_register, + bfin_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + bfin_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 2, + bfin_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + bfin_supports_hardware_single_step, +}; + + +void +initialize_low_arch (void) +{ + init_registers_bfin (); +} diff --git a/gdbserver/linux-cris-low.c b/gdbserver/linux-cris-low.c new file mode 100644 index 00000000000..8ea5af92e31 --- /dev/null +++ b/gdbserver/linux-cris-low.c @@ -0,0 +1,132 @@ +/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "nat/gdb_ptrace.h" + +/* Defined in auto-generated file reg-cris.c. */ +void init_registers_cris (void); +extern const struct target_desc *tdesc_cris; + +/* CRISv10 */ +#define cris_num_regs 32 + +/* Locations need to match . */ +static int cris_regmap[] = { + 15*4, 14*4, 13*4, 12*4, + 11*4, 10*4, 9*4, 8*4, + 7*4, 6*4, 5*4, 4*4, + 3*4, 2*4, 23*4, 19*4, + + -1, -1, -1, -1, + -1, 17*4, -1, 16*4, + -1, -1, -1, 18*4, + -1, 17*4, -1, -1 + +}; + +static int +cris_cannot_store_register (int regno) +{ + if (cris_regmap[regno] == -1) + return 1; + + return (regno >= cris_num_regs); +} + +static int +cris_cannot_fetch_register (int regno) +{ + if (cris_regmap[regno] == -1) + return 1; + + return (regno >= cris_num_regs); +} + +static const unsigned short cris_breakpoint = 0xe938; +#define cris_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +cris_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = cris_breakpoint_len; + return (const gdb_byte *) &cris_breakpoint; +} + +static int +cris_breakpoint_at (CORE_ADDR where) +{ + unsigned short insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, + cris_breakpoint_len); + if (insn == cris_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +static void +cris_arch_setup (void) +{ + current_process ()->tdesc = tdesc_cris; +} + +static struct usrregs_info cris_usrregs_info = + { + cris_num_regs, + cris_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &cris_usrregs_info, + }; + +static const struct regs_info * +cris_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + cris_arch_setup, + cris_regs_info, + cris_cannot_fetch_register, + cris_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + cris_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 0, + cris_breakpoint_at, +}; + +void +initialize_low_arch (void) +{ + init_registers_cris (); +} diff --git a/gdbserver/linux-crisv32-low.c b/gdbserver/linux-crisv32-low.c new file mode 100644 index 00000000000..facb5c5c274 --- /dev/null +++ b/gdbserver/linux-crisv32-low.c @@ -0,0 +1,440 @@ +/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "nat/gdb_ptrace.h" + +/* Defined in auto-generated file reg-crisv32.c. */ +void init_registers_crisv32 (void); +extern const struct target_desc *tdesc_crisv32; + +/* CRISv32 */ +#define cris_num_regs 49 + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +/* Note: Ignoring USP (having the stack pointer in two locations causes trouble + without any significant gain). */ + +/* Locations need to match . */ +static int cris_regmap[] = { + 1*4, 2*4, 3*4, 4*4, + 5*4, 6*4, 7*4, 8*4, + 9*4, 10*4, 11*4, 12*4, + 13*4, 14*4, 24*4, 15*4, + + -1, -1, -1, 16*4, + -1, 22*4, 23*4, 17*4, + -1, -1, 21*4, 20*4, + -1, 19*4, -1, 18*4, + + 25*4, + + 26*4, -1, -1, 29*4, + 30*4, 31*4, 32*4, 33*4, + 34*4, 35*4, 36*4, 37*4, + 38*4, 39*4, 40*4, -1 + +}; + +static const unsigned short cris_breakpoint = 0xe938; +#define cris_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +cris_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = cris_breakpoint_len; + return (const gdb_byte *) &cris_breakpoint; +} + +static int +cris_breakpoint_at (CORE_ADDR where) +{ + unsigned short insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, + cris_breakpoint_len); + if (insn == cris_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +static void +cris_write_data_breakpoint (struct regcache *regcache, + int bp, unsigned long start, unsigned long end) +{ + switch (bp) + { + case 0: + supply_register_by_name (regcache, "s3", &start); + supply_register_by_name (regcache, "s4", &end); + break; + case 1: + supply_register_by_name (regcache, "s5", &start); + supply_register_by_name (regcache, "s6", &end); + break; + case 2: + supply_register_by_name (regcache, "s7", &start); + supply_register_by_name (regcache, "s8", &end); + break; + case 3: + supply_register_by_name (regcache, "s9", &start); + supply_register_by_name (regcache, "s10", &end); + break; + case 4: + supply_register_by_name (regcache, "s11", &start); + supply_register_by_name (regcache, "s12", &end); + break; + case 5: + supply_register_by_name (regcache, "s13", &start); + supply_register_by_name (regcache, "s14", &end); + break; + } +} + +static int +cris_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_WRITE_WP: + case Z_PACKET_READ_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + return 0; + } +} + +static int +cris_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + int bp; + unsigned long bp_ctrl; + unsigned long start, end; + unsigned long ccs; + struct regcache *regcache; + + regcache = get_thread_regcache (current_thread, 1); + + /* Read watchpoints are set as access watchpoints, because of GDB's + inability to deal with pure read watchpoints. */ + if (type == raw_bkpt_type_read_wp) + type = raw_bkpt_type_access_wp; + + /* Get the configuration register. */ + collect_register_by_name (regcache, "s0", &bp_ctrl); + + /* The watchpoint allocation scheme is the simplest possible. + For example, if a region is watched for read and + a write watch is requested, a new watchpoint will + be used. Also, if a watch for a region that is already + covered by one or more existing watchpoints, a new + watchpoint will be used. */ + + /* First, find a free data watchpoint. */ + for (bp = 0; bp < 6; bp++) + { + /* Each data watchpoint's control registers occupy 2 bits + (hence the 3), starting at bit 2 for D0 (hence the 2) + with 4 bits between for each watchpoint (yes, the 4). */ + if (!(bp_ctrl & (0x3 << (2 + (bp * 4))))) + break; + } + + if (bp > 5) + { + /* We're out of watchpoints. */ + return -1; + } + + /* Configure the control register first. */ + if (type == raw_bkpt_type_read_wp || type == raw_bkpt_type_access_wp) + { + /* Trigger on read. */ + bp_ctrl |= (1 << (2 + bp * 4)); + } + if (type == raw_bkpt_type_write_wp || type == raw_bkpt_type_access_wp) + { + /* Trigger on write. */ + bp_ctrl |= (2 << (2 + bp * 4)); + } + + /* Setup the configuration register. */ + supply_register_by_name (regcache, "s0", &bp_ctrl); + + /* Setup the range. */ + start = addr; + end = addr + len - 1; + + /* Configure the watchpoint register. */ + cris_write_data_breakpoint (regcache, bp, start, end); + + collect_register_by_name (regcache, "ccs", &ccs); + /* Set the S1 flag to enable watchpoints. */ + ccs |= (1 << 19); + supply_register_by_name (regcache, "ccs", &ccs); + + return 0; +} + +static int +cris_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, int len, + struct raw_breakpoint *bp) +{ + int bp; + unsigned long bp_ctrl; + unsigned long start, end; + struct regcache *regcache; + unsigned long bp_d_regs[12]; + + regcache = get_thread_regcache (current_thread, 1); + + /* Read watchpoints are set as access watchpoints, because of GDB's + inability to deal with pure read watchpoints. */ + if (type == raw_bkpt_type_read_wp) + type = raw_bkpt_type_access_wp; + + /* Get the configuration register. */ + collect_register_by_name (regcache, "s0", &bp_ctrl); + + /* Try to find a watchpoint that is configured for the + specified range, then check that read/write also matches. */ + + /* Ugly pointer arithmetic, since I cannot rely on a + single switch (addr) as there may be several watchpoints with + the same start address for example. */ + + /* Get all range registers to simplify search. */ + collect_register_by_name (regcache, "s3", &bp_d_regs[0]); + collect_register_by_name (regcache, "s4", &bp_d_regs[1]); + collect_register_by_name (regcache, "s5", &bp_d_regs[2]); + collect_register_by_name (regcache, "s6", &bp_d_regs[3]); + collect_register_by_name (regcache, "s7", &bp_d_regs[4]); + collect_register_by_name (regcache, "s8", &bp_d_regs[5]); + collect_register_by_name (regcache, "s9", &bp_d_regs[6]); + collect_register_by_name (regcache, "s10", &bp_d_regs[7]); + collect_register_by_name (regcache, "s11", &bp_d_regs[8]); + collect_register_by_name (regcache, "s12", &bp_d_regs[9]); + collect_register_by_name (regcache, "s13", &bp_d_regs[10]); + collect_register_by_name (regcache, "s14", &bp_d_regs[11]); + + for (bp = 0; bp < 6; bp++) + { + if (bp_d_regs[bp * 2] == addr + && bp_d_regs[bp * 2 + 1] == (addr + len - 1)) { + /* Matching range. */ + int bitpos = 2 + bp * 4; + int rw_bits; + + /* Read/write bits for this BP. */ + rw_bits = (bp_ctrl & (0x3 << bitpos)) >> bitpos; + + if ((type == raw_bkpt_type_read_wp && rw_bits == 0x1) + || (type == raw_bkpt_type_write_wp && rw_bits == 0x2) + || (type == raw_bkpt_type_access_wp && rw_bits == 0x3)) + { + /* Read/write matched. */ + break; + } + } + } + + if (bp > 5) + { + /* No watchpoint matched. */ + return -1; + } + + /* Found a matching watchpoint. Now, deconfigure it by + both disabling read/write in bp_ctrl and zeroing its + start/end addresses. */ + bp_ctrl &= ~(3 << (2 + (bp * 4))); + /* Setup the configuration register. */ + supply_register_by_name (regcache, "s0", &bp_ctrl); + + start = end = 0; + /* Configure the watchpoint register. */ + cris_write_data_breakpoint (regcache, bp, start, end); + + /* Note that we don't clear the S1 flag here. It's done when continuing. */ + return 0; +} + +static int +cris_stopped_by_watchpoint (void) +{ + unsigned long exs; + struct regcache *regcache = get_thread_regcache (current_thread, 1); + + collect_register_by_name (regcache, "exs", &exs); + + return (((exs & 0xff00) >> 8) == 0xc); +} + +static CORE_ADDR +cris_stopped_data_address (void) +{ + unsigned long eda; + struct regcache *regcache = get_thread_regcache (current_thread, 1); + + collect_register_by_name (regcache, "eda", &eda); + + /* FIXME: Possibly adjust to match watched range. */ + return eda; +} + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *) *base - idx); + return PS_OK; +} + +static void +cris_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + + for (i = 0; i < cris_num_regs; i++) + { + if (cris_regmap[i] != -1) + collect_register (regcache, i, ((char *) buf) + cris_regmap[i]); + } +} + +static void +cris_store_gregset (struct regcache *regcache, const void *buf) +{ + int i; + + for (i = 0; i < cris_num_regs; i++) + { + if (cris_regmap[i] != -1) + supply_register (regcache, i, ((char *) buf) + cris_regmap[i]); + } +} + +static void +cris_arch_setup (void) +{ + current_process ()->tdesc = tdesc_crisv32; +} + +/* Support for hardware single step. */ + +static int +cris_supports_hardware_single_step (void) +{ + return 1; +} + +static struct regset_info cris_regsets[] = { + { PTRACE_GETREGS, PTRACE_SETREGS, 0, cris_num_regs * 4, + GENERAL_REGS, cris_fill_gregset, cris_store_gregset }, + NULL_REGSET +}; + + +static struct regsets_info cris_regsets_info = + { + cris_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info cris_usrregs_info = + { + cris_num_regs, + cris_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &cris_usrregs_info, + &cris_regsets_info + }; + +static const struct regs_info * +cris_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + cris_arch_setup, + cris_regs_info, + NULL, + NULL, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + cris_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 0, + cris_breakpoint_at, + cris_supports_z_point_type, + cris_insert_point, + cris_remove_point, + cris_stopped_by_watchpoint, + cris_stopped_data_address, + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + cris_supports_hardware_single_step, +}; + +void +initialize_low_arch (void) +{ + init_registers_crisv32 (); + + initialize_regsets_info (&cris_regsets_info); +} diff --git a/gdbserver/linux-i386-ipa.c b/gdbserver/linux-i386-ipa.c new file mode 100644 index 00000000000..41f77c8deac --- /dev/null +++ b/gdbserver/linux-i386-ipa.c @@ -0,0 +1,294 @@ +/* GNU/Linux/x86 specific low level interface, for the in-process + agent library for GDB. + + Copyright (C) 2010-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include +#include "tracepoint.h" +#include "linux-x86-tdesc.h" +#include "gdbsupport/x86-xstate.h" + +/* GDB register numbers. */ + +enum i386_gdb_regnum +{ + I386_EAX_REGNUM, /* %eax */ + I386_ECX_REGNUM, /* %ecx */ + I386_EDX_REGNUM, /* %edx */ + I386_EBX_REGNUM, /* %ebx */ + I386_ESP_REGNUM, /* %esp */ + I386_EBP_REGNUM, /* %ebp */ + I386_ESI_REGNUM, /* %esi */ + I386_EDI_REGNUM, /* %edi */ + I386_EIP_REGNUM, /* %eip */ + I386_EFLAGS_REGNUM, /* %eflags */ + I386_CS_REGNUM, /* %cs */ + I386_SS_REGNUM, /* %ss */ + I386_DS_REGNUM, /* %ds */ + I386_ES_REGNUM, /* %es */ + I386_FS_REGNUM, /* %fs */ + I386_GS_REGNUM, /* %gs */ + I386_ST0_REGNUM /* %st(0) */ +}; + +#define i386_num_regs 16 + +#define FT_CR_EAX 15 +#define FT_CR_ECX 14 +#define FT_CR_EDX 13 +#define FT_CR_EBX 12 +#define FT_CR_UESP 11 +#define FT_CR_EBP 10 +#define FT_CR_ESI 9 +#define FT_CR_EDI 8 +#define FT_CR_EIP 7 +#define FT_CR_EFL 6 +#define FT_CR_DS 5 +#define FT_CR_ES 4 +#define FT_CR_FS 3 +#define FT_CR_GS 2 +#define FT_CR_SS 1 +#define FT_CR_CS 0 + +/* Mapping between the general-purpose registers in jump tracepoint + format and GDB's register array layout. */ + +static const int i386_ft_collect_regmap[] = +{ + FT_CR_EAX * 4, FT_CR_ECX * 4, FT_CR_EDX * 4, FT_CR_EBX * 4, + FT_CR_UESP * 4, FT_CR_EBP * 4, FT_CR_ESI * 4, FT_CR_EDI * 4, + FT_CR_EIP * 4, FT_CR_EFL * 4, FT_CR_CS * 4, FT_CR_SS * 4, + FT_CR_DS * 4, FT_CR_ES * 4, FT_CR_FS * 4, FT_CR_GS * 4 +}; + +void +supply_fast_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf) +{ + int i; + + for (i = 0; i < i386_num_regs; i++) + { + int regval; + + if (i >= I386_CS_REGNUM && i <= I386_GS_REGNUM) + regval = *(short *) (((char *) buf) + i386_ft_collect_regmap[i]); + else + regval = *(int *) (((char *) buf) + i386_ft_collect_regmap[i]); + + supply_register (regcache, i, ®val); + } +} + +ULONGEST +get_raw_reg (const unsigned char *raw_regs, int regnum) +{ + /* This should maybe be allowed to return an error code, or perhaps + better, have the emit_reg detect this, and emit a constant zero, + or something. */ + + if (regnum > i386_num_regs) + return 0; + else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM) + return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]); + else + return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]); +} + +#ifdef HAVE_UST + +#include + +/* "struct registers" is the UST object type holding the registers at + the time of the static tracepoint marker call. This doesn't + contain EIP, but we know what it must have been (the marker + address). */ + +#define ST_REGENTRY(REG) \ + { \ + offsetof (struct registers, REG), \ + sizeof (((struct registers *) NULL)->REG) \ + } + +static struct +{ + int offset; + int size; +} i386_st_collect_regmap[] = + { + ST_REGENTRY(eax), + ST_REGENTRY(ecx), + ST_REGENTRY(edx), + ST_REGENTRY(ebx), + ST_REGENTRY(esp), + ST_REGENTRY(ebp), + ST_REGENTRY(esi), + ST_REGENTRY(edi), + { -1, 0 }, /* eip */ + ST_REGENTRY(eflags), + ST_REGENTRY(cs), + ST_REGENTRY(ss), + }; + +#define i386_NUM_ST_COLLECT_GREGS \ + (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0])) + +void +supply_static_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf, + CORE_ADDR pc) +{ + int i; + unsigned int newpc = pc; + + supply_register (regcache, I386_EIP_REGNUM, &newpc); + + for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++) + if (i386_st_collect_regmap[i].offset != -1) + { + switch (i386_st_collect_regmap[i].size) + { + case 4: + supply_register (regcache, i, + ((char *) buf) + + i386_st_collect_regmap[i].offset); + break; + case 2: + { + unsigned long reg + = * (short *) (((char *) buf) + + i386_st_collect_regmap[i].offset); + reg &= 0xffff; + supply_register (regcache, i, ®); + } + break; + default: + internal_error (__FILE__, __LINE__, "unhandled register size: %d", + i386_st_collect_regmap[i].size); + } + } +} + +#endif /* HAVE_UST */ + + +/* This is only needed because reg-i386-linux-lib.o references it. We + may use it proper at some point. */ +const char *gdbserver_xmltarget; + +/* Attempt to allocate memory for trampolines in the first 64 KiB of + memory to enable smaller jump patches. */ + +static void +initialize_fast_tracepoint_trampoline_buffer (void) +{ + const CORE_ADDR buffer_end = 64 * 1024; + /* Ensure that the buffer will be at least 1 KiB in size, which is + enough space for over 200 fast tracepoints. */ + const int min_buffer_size = 1024; + char buf[IPA_BUFSIZ]; + CORE_ADDR mmap_min_addr = buffer_end + 1; + ULONGEST buffer_size; + FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r"); + + if (!f) + { + snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s", + safe_strerror (errno)); + set_trampoline_buffer_space (0, 0, buf); + return; + } + + if (fgets (buf, IPA_BUFSIZ, f)) + sscanf (buf, "%llu", &mmap_min_addr); + + fclose (f); + + buffer_size = buffer_end - mmap_min_addr; + + if (buffer_size >= min_buffer_size) + { + if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size, + PROT_READ | PROT_EXEC | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0) + != MAP_FAILED) + set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL); + else + { + snprintf (buf, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s", + safe_strerror (errno)); + set_trampoline_buffer_space (0, 0, buf); + } + } + else + { + snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less", + (int) mmap_min_addr, (int) buffer_end - min_buffer_size); + set_trampoline_buffer_space (0, 0, buf); + } +} + +/* Map the tdesc index to xcr0 mask. */ +static uint64_t idx2mask[X86_TDESC_LAST] = { + X86_XSTATE_X87_MASK, + X86_XSTATE_SSE_MASK, + X86_XSTATE_AVX_MASK, + X86_XSTATE_MPX_MASK, + X86_XSTATE_AVX_MPX_MASK, + X86_XSTATE_AVX_AVX512_MASK, + X86_XSTATE_AVX_MPX_AVX512_PKU_MASK, +}; + +/* Return target_desc to use for IPA, given the tdesc index passed by + gdbserver. */ + +const struct target_desc * +get_ipa_tdesc (int idx) +{ + if (idx >= X86_TDESC_LAST) + { + internal_error (__FILE__, __LINE__, + "unknown ipa tdesc index: %d", idx); + } + return i386_linux_read_description (idx2mask[idx]); +} + +/* Allocate buffer for the jump pads. On i386, we can reach an arbitrary + address with a jump instruction, so just allocate normally. */ + +void * +alloc_jump_pad_buffer (size_t size) +{ + void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (res == MAP_FAILED) + return NULL; + + return res; +} + +void +initialize_low_tracepoint (void) +{ + initialize_fast_tracepoint_trampoline_buffer (); + for (auto i = 0; i < X86_TDESC_LAST; i++) + i386_linux_read_description (idx2mask[i]); +} diff --git a/gdbserver/linux-ia64-low.c b/gdbserver/linux-ia64-low.c new file mode 100644 index 00000000000..2399e58b366 --- /dev/null +++ b/gdbserver/linux-ia64-low.c @@ -0,0 +1,360 @@ +/* GNU/Linux/IA64 specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +#ifdef HAVE_SYS_REG_H +#include +#endif + +/* Defined in auto-generated file reg-ia64.c. */ +void init_registers_ia64 (void); +extern const struct target_desc *tdesc_ia64; + +#define ia64_num_regs 462 + +#include + +static int ia64_regmap[] = + { + /* general registers */ + -1, /* gr0 not available; i.e, it's always zero */ + PT_R1, + PT_R2, + PT_R3, + PT_R4, + PT_R5, + PT_R6, + PT_R7, + PT_R8, + PT_R9, + PT_R10, + PT_R11, + PT_R12, + PT_R13, + PT_R14, + PT_R15, + PT_R16, + PT_R17, + PT_R18, + PT_R19, + PT_R20, + PT_R21, + PT_R22, + PT_R23, + PT_R24, + PT_R25, + PT_R26, + PT_R27, + PT_R28, + PT_R29, + PT_R30, + PT_R31, + /* gr32 through gr127 not directly available via the ptrace interface */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* Floating point registers */ + -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */ + PT_F2, + PT_F3, + PT_F4, + PT_F5, + PT_F6, + PT_F7, + PT_F8, + PT_F9, + PT_F10, + PT_F11, + PT_F12, + PT_F13, + PT_F14, + PT_F15, + PT_F16, + PT_F17, + PT_F18, + PT_F19, + PT_F20, + PT_F21, + PT_F22, + PT_F23, + PT_F24, + PT_F25, + PT_F26, + PT_F27, + PT_F28, + PT_F29, + PT_F30, + PT_F31, + PT_F32, + PT_F33, + PT_F34, + PT_F35, + PT_F36, + PT_F37, + PT_F38, + PT_F39, + PT_F40, + PT_F41, + PT_F42, + PT_F43, + PT_F44, + PT_F45, + PT_F46, + PT_F47, + PT_F48, + PT_F49, + PT_F50, + PT_F51, + PT_F52, + PT_F53, + PT_F54, + PT_F55, + PT_F56, + PT_F57, + PT_F58, + PT_F59, + PT_F60, + PT_F61, + PT_F62, + PT_F63, + PT_F64, + PT_F65, + PT_F66, + PT_F67, + PT_F68, + PT_F69, + PT_F70, + PT_F71, + PT_F72, + PT_F73, + PT_F74, + PT_F75, + PT_F76, + PT_F77, + PT_F78, + PT_F79, + PT_F80, + PT_F81, + PT_F82, + PT_F83, + PT_F84, + PT_F85, + PT_F86, + PT_F87, + PT_F88, + PT_F89, + PT_F90, + PT_F91, + PT_F92, + PT_F93, + PT_F94, + PT_F95, + PT_F96, + PT_F97, + PT_F98, + PT_F99, + PT_F100, + PT_F101, + PT_F102, + PT_F103, + PT_F104, + PT_F105, + PT_F106, + PT_F107, + PT_F108, + PT_F109, + PT_F110, + PT_F111, + PT_F112, + PT_F113, + PT_F114, + PT_F115, + PT_F116, + PT_F117, + PT_F118, + PT_F119, + PT_F120, + PT_F121, + PT_F122, + PT_F123, + PT_F124, + PT_F125, + PT_F126, + PT_F127, + /* predicate registers - we don't fetch these individually */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + /* branch registers */ + PT_B0, + PT_B1, + PT_B2, + PT_B3, + PT_B4, + PT_B5, + PT_B6, + PT_B7, + /* virtual frame pointer and virtual return address pointer */ + -1, -1, + /* other registers */ + PT_PR, + PT_CR_IIP, /* ip */ + PT_CR_IPSR, /* psr */ + PT_CFM, /* cfm */ + /* kernel registers not visible via ptrace interface (?) */ + -1, -1, -1, -1, -1, -1, -1, -1, + /* hole */ + -1, -1, -1, -1, -1, -1, -1, -1, + PT_AR_RSC, + PT_AR_BSP, + PT_AR_BSPSTORE, + PT_AR_RNAT, + -1, + -1, /* Not available: FCR, IA32 floating control register */ + -1, -1, + -1, /* Not available: EFLAG */ + -1, /* Not available: CSD */ + -1, /* Not available: SSD */ + -1, /* Not available: CFLG */ + -1, /* Not available: FSR */ + -1, /* Not available: FIR */ + -1, /* Not available: FDR */ + -1, + PT_AR_CCV, + -1, -1, -1, + PT_AR_UNAT, + -1, -1, -1, + PT_AR_FPSR, + -1, -1, -1, + -1, /* Not available: ITC */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, + PT_AR_PFS, + PT_AR_LC, + PT_AR_EC, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, + }; + +static int +ia64_cannot_store_register (int regno) +{ + return 0; +} + +static int +ia64_cannot_fetch_register (int regno) +{ + return 0; +} + +/* GDB register numbers. */ +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR1_REGNUM 129 + +static int +ia64_fetch_register (struct regcache *regcache, int regnum) +{ + /* r0 cannot be fetched but is always zero. */ + if (regnum == IA64_GR0_REGNUM) + { + const gdb_byte zero[8] = { 0 }; + + gdb_assert (sizeof (zero) == register_size (regcache->tdesc, regnum)); + supply_register (regcache, regnum, zero); + return 1; + } + + /* fr0 cannot be fetched but is always zero. */ + if (regnum == IA64_FR0_REGNUM) + { + const gdb_byte f_zero[16] = { 0 }; + + gdb_assert (sizeof (f_zero) == register_size (regcache->tdesc, regnum)); + supply_register (regcache, regnum, f_zero); + return 1; + } + + /* fr1 cannot be fetched but is always one (1.0). */ + if (regnum == IA64_FR1_REGNUM) + { + const gdb_byte f_one[16] = + { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0 }; + + gdb_assert (sizeof (f_one) == register_size (regcache->tdesc, regnum)); + supply_register (regcache, regnum, f_one); + return 1; + } + + return 0; +} + +static struct usrregs_info ia64_usrregs_info = + { + ia64_num_regs, + ia64_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &ia64_usrregs_info + }; + +static const struct regs_info * +ia64_regs_info (void) +{ + return ®s_info; +} + +static void +ia64_arch_setup (void) +{ + current_process ()->tdesc = tdesc_ia64; +} + + +struct linux_target_ops the_low_target = { + ia64_arch_setup, + ia64_regs_info, + ia64_cannot_fetch_register, + ia64_cannot_store_register, + ia64_fetch_register, +}; + +void +initialize_low_arch (void) +{ + init_registers_ia64 (); +} diff --git a/gdbserver/linux-low.c b/gdbserver/linux-low.c new file mode 100644 index 00000000000..676dea26c63 --- /dev/null +++ b/gdbserver/linux-low.c @@ -0,0 +1,7492 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "nat/linux-osdata.h" +#include "gdbsupport/agent.h" +#include "tdesc.h" +#include "gdbsupport/rsp-low.h" +#include "gdbsupport/signals-state-save-restore.h" +#include "nat/linux-nat.h" +#include "nat/linux-waitpid.h" +#include "gdbsupport/gdb_wait.h" +#include "nat/gdb_ptrace.h" +#include "nat/linux-ptrace.h" +#include "nat/linux-procfs.h" +#include "nat/linux-personality.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gdbsupport/filestuff.h" +#include "tracepoint.h" +#include "hostio.h" +#include +#include "gdbsupport/common-inferior.h" +#include "nat/fork-inferior.h" +#include "gdbsupport/environ.h" +#include "gdbsupport/gdb-sigmask.h" +#include "gdbsupport/scoped_restore.h" +#ifndef ELFMAG0 +/* Don't include here. If it got included by gdb_proc_service.h + then ELFMAG0 will have been defined. If it didn't get included by + gdb_proc_service.h then including it will likely introduce a duplicate + definition of elf_fpregset_t. */ +#include +#endif +#include "nat/linux-namespaces.h" + +#ifdef HAVE_PERSONALITY +# include +# if !HAVE_DECL_ADDR_NO_RANDOMIZE +# define ADDR_NO_RANDOMIZE 0x0040000 +# endif +#endif + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +#ifndef AT_HWCAP2 +#define AT_HWCAP2 26 +#endif + +/* Some targets did not define these ptrace constants from the start, + so gdbserver defines them locally here. In the future, these may + be removed after they are added to asm/ptrace.h. */ +#if !(defined(PT_TEXT_ADDR) \ + || defined(PT_DATA_ADDR) \ + || defined(PT_TEXT_END_ADDR)) +#if defined(__mcoldfire__) +/* These are still undefined in 3.10 kernels. */ +#define PT_TEXT_ADDR 49*4 +#define PT_DATA_ADDR 50*4 +#define PT_TEXT_END_ADDR 51*4 +/* BFIN already defines these since at least 2.6.32 kernels. */ +#elif defined(BFIN) +#define PT_TEXT_ADDR 220 +#define PT_TEXT_END_ADDR 224 +#define PT_DATA_ADDR 228 +/* These are still undefined in 3.10 kernels. */ +#elif defined(__TMS320C6X__) +#define PT_TEXT_ADDR (0x10000*4) +#define PT_DATA_ADDR (0x10004*4) +#define PT_TEXT_END_ADDR (0x10008*4) +#endif +#endif + +#ifdef HAVE_LINUX_BTRACE +# include "nat/linux-btrace.h" +# include "gdbsupport/btrace-common.h" +#endif + +#ifndef HAVE_ELF32_AUXV_T +/* Copied from glibc's elf.h. */ +typedef struct +{ + uint32_t a_type; /* Entry type */ + union + { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; +#endif + +#ifndef HAVE_ELF64_AUXV_T +/* Copied from glibc's elf.h. */ +typedef struct +{ + uint64_t a_type; /* Entry type */ + union + { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; +#endif + +/* Does the current host support PTRACE_GETREGSET? */ +int have_ptrace_getregset = -1; + +/* LWP accessors. */ + +/* See nat/linux-nat.h. */ + +ptid_t +ptid_of_lwp (struct lwp_info *lwp) +{ + return ptid_of (get_lwp_thread (lwp)); +} + +/* See nat/linux-nat.h. */ + +void +lwp_set_arch_private_info (struct lwp_info *lwp, + struct arch_lwp_info *info) +{ + lwp->arch_private = info; +} + +/* See nat/linux-nat.h. */ + +struct arch_lwp_info * +lwp_arch_private_info (struct lwp_info *lwp) +{ + return lwp->arch_private; +} + +/* See nat/linux-nat.h. */ + +int +lwp_is_stopped (struct lwp_info *lwp) +{ + return lwp->stopped; +} + +/* See nat/linux-nat.h. */ + +enum target_stop_reason +lwp_stop_reason (struct lwp_info *lwp) +{ + return lwp->stop_reason; +} + +/* See nat/linux-nat.h. */ + +int +lwp_is_stepping (struct lwp_info *lwp) +{ + return lwp->stepping; +} + +/* A list of all unknown processes which receive stop signals. Some + other process will presumably claim each of these as forked + children momentarily. */ + +struct simple_pid_list +{ + /* The process ID. */ + int pid; + + /* The status as reported by waitpid. */ + int status; + + /* Next in chain. */ + struct simple_pid_list *next; +}; +struct simple_pid_list *stopped_pids; + +/* Trivial list manipulation functions to keep track of a list of new + stopped processes. */ + +static void +add_to_pid_list (struct simple_pid_list **listp, int pid, int status) +{ + struct simple_pid_list *new_pid = XNEW (struct simple_pid_list); + + new_pid->pid = pid; + new_pid->status = status; + new_pid->next = *listp; + *listp = new_pid; +} + +static int +pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp) +{ + struct simple_pid_list **p; + + for (p = listp; *p != NULL; p = &(*p)->next) + if ((*p)->pid == pid) + { + struct simple_pid_list *next = (*p)->next; + + *statusp = (*p)->status; + xfree (*p); + *p = next; + return 1; + } + return 0; +} + +enum stopping_threads_kind + { + /* Not stopping threads presently. */ + NOT_STOPPING_THREADS, + + /* Stopping threads. */ + STOPPING_THREADS, + + /* Stopping and suspending threads. */ + STOPPING_AND_SUSPENDING_THREADS + }; + +/* This is set while stop_all_lwps is in effect. */ +enum stopping_threads_kind stopping_threads = NOT_STOPPING_THREADS; + +/* FIXME make into a target method? */ +int using_threads = 1; + +/* True if we're presently stabilizing threads (moving them out of + jump pads). */ +static int stabilizing_threads; + +static void linux_resume_one_lwp (struct lwp_info *lwp, + int step, int signal, siginfo_t *info); +static void linux_resume (struct thread_resume *resume_info, size_t n); +static void stop_all_lwps (int suspend, struct lwp_info *except); +static void unstop_all_lwps (int unsuspend, struct lwp_info *except); +static void unsuspend_all_lwps (struct lwp_info *except); +static int linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, + int *wstat, int options); +static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); +static struct lwp_info *add_lwp (ptid_t ptid); +static void linux_mourn (struct process_info *process); +static int linux_stopped_by_watchpoint (void); +static void mark_lwp_dead (struct lwp_info *lwp, int wstat); +static int lwp_is_marked_dead (struct lwp_info *lwp); +static void proceed_all_lwps (void); +static int finish_step_over (struct lwp_info *lwp); +static int kill_lwp (unsigned long lwpid, int signo); +static void enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info); +static void complete_ongoing_step_over (void); +static int linux_low_ptrace_options (int attached); +static int check_ptrace_stopped_lwp_gone (struct lwp_info *lp); +static void proceed_one_lwp (thread_info *thread, lwp_info *except); + +/* When the event-loop is doing a step-over, this points at the thread + being stepped. */ +ptid_t step_over_bkpt; + +/* True if the low target can hardware single-step. */ + +static int +can_hardware_single_step (void) +{ + if (the_low_target.supports_hardware_single_step != NULL) + return the_low_target.supports_hardware_single_step (); + else + return 0; +} + +/* True if the low target can software single-step. Such targets + implement the GET_NEXT_PCS callback. */ + +static int +can_software_single_step (void) +{ + return (the_low_target.get_next_pcs != NULL); +} + +/* True if the low target supports memory breakpoints. If so, we'll + have a GET_PC implementation. */ + +static int +supports_breakpoints (void) +{ + return (the_low_target.get_pc != NULL); +} + +/* Returns true if this target can support fast tracepoints. This + does not mean that the in-process agent has been loaded in the + inferior. */ + +static int +supports_fast_tracepoints (void) +{ + return the_low_target.install_fast_tracepoint_jump_pad != NULL; +} + +/* True if LWP is stopped in its stepping range. */ + +static int +lwp_in_step_range (struct lwp_info *lwp) +{ + CORE_ADDR pc = lwp->stop_pc; + + return (pc >= lwp->step_range_start && pc < lwp->step_range_end); +} + +struct pending_signals +{ + int signal; + siginfo_t info; + struct pending_signals *prev; +}; + +/* The read/write ends of the pipe registered as waitable file in the + event loop. */ +static int linux_event_pipe[2] = { -1, -1 }; + +/* True if we're currently in async mode. */ +#define target_is_async_p() (linux_event_pipe[0] != -1) + +static void send_sigstop (struct lwp_info *lwp); +static void wait_for_sigstop (void); + +/* Return non-zero if HEADER is a 64-bit ELF file. */ + +static int +elf_64_header_p (const Elf64_Ehdr *header, unsigned int *machine) +{ + if (header->e_ident[EI_MAG0] == ELFMAG0 + && header->e_ident[EI_MAG1] == ELFMAG1 + && header->e_ident[EI_MAG2] == ELFMAG2 + && header->e_ident[EI_MAG3] == ELFMAG3) + { + *machine = header->e_machine; + return header->e_ident[EI_CLASS] == ELFCLASS64; + + } + *machine = EM_NONE; + return -1; +} + +/* Return non-zero if FILE is a 64-bit ELF file, + zero if the file is not a 64-bit ELF file, + and -1 if the file is not accessible or doesn't exist. */ + +static int +elf_64_file_p (const char *file, unsigned int *machine) +{ + Elf64_Ehdr header; + int fd; + + fd = open (file, O_RDONLY); + if (fd < 0) + return -1; + + if (read (fd, &header, sizeof (header)) != sizeof (header)) + { + close (fd); + return 0; + } + close (fd); + + return elf_64_header_p (&header, machine); +} + +/* Accepts an integer PID; Returns true if the executable PID is + running is a 64-bit ELF file.. */ + +int +linux_pid_exe_is_elf_64_file (int pid, unsigned int *machine) +{ + char file[PATH_MAX]; + + sprintf (file, "/proc/%d/exe", pid); + return elf_64_file_p (file, machine); +} + +static void +delete_lwp (struct lwp_info *lwp) +{ + struct thread_info *thr = get_lwp_thread (lwp); + + if (debug_threads) + debug_printf ("deleting %ld\n", lwpid_of (thr)); + + remove_thread (thr); + + if (the_low_target.delete_thread != NULL) + the_low_target.delete_thread (lwp->arch_private); + else + gdb_assert (lwp->arch_private == NULL); + + free (lwp); +} + +/* Add a process to the common process list, and set its private + data. */ + +static struct process_info * +linux_add_process (int pid, int attached) +{ + struct process_info *proc; + + proc = add_process (pid, attached); + proc->priv = XCNEW (struct process_info_private); + + if (the_low_target.new_process != NULL) + proc->priv->arch_private = the_low_target.new_process (); + + return proc; +} + +static CORE_ADDR get_pc (struct lwp_info *lwp); + +/* Call the target arch_setup function on the current thread. */ + +static void +linux_arch_setup (void) +{ + the_low_target.arch_setup (); +} + +/* Call the target arch_setup function on THREAD. */ + +static void +linux_arch_setup_thread (struct thread_info *thread) +{ + struct thread_info *saved_thread; + + saved_thread = current_thread; + current_thread = thread; + + linux_arch_setup (); + + current_thread = saved_thread; +} + +/* Handle a GNU/Linux extended wait response. If we see a clone, + fork, or vfork event, we need to add the new LWP to our list + (and return 0 so as not to report the trap to higher layers). + If we see an exec event, we will modify ORIG_EVENT_LWP to point + to a new LWP representing the new program. */ + +static int +handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) +{ + client_state &cs = get_client_state (); + struct lwp_info *event_lwp = *orig_event_lwp; + int event = linux_ptrace_get_extended_event (wstat); + struct thread_info *event_thr = get_lwp_thread (event_lwp); + struct lwp_info *new_lwp; + + gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + + /* All extended events we currently use are mid-syscall. Only + PTRACE_EVENT_STOP is delivered more like a signal-stop, but + you have to be using PTRACE_SEIZE to get that. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) + || (event == PTRACE_EVENT_CLONE)) + { + ptid_t ptid; + unsigned long new_pid; + int ret, status; + + /* Get the pid of the new lwp. */ + ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_thr), (PTRACE_TYPE_ARG3) 0, + &new_pid); + + /* If we haven't already seen the new PID stop, wait for it now. */ + if (!pull_pid_from_list (&stopped_pids, new_pid, &status)) + { + /* The new child has a pending SIGSTOP. We can't affect it until it + hits the SIGSTOP, but we're already attached. */ + + ret = my_waitpid (new_pid, &status, __WALL); + + if (ret == -1) + perror_with_name ("waiting for new child"); + else if (ret != new_pid) + warning ("wait returned unexpected PID %d", ret); + else if (!WIFSTOPPED (status)) + warning ("wait returned unexpected status 0x%x", status); + } + + if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK) + { + struct process_info *parent_proc; + struct process_info *child_proc; + struct lwp_info *child_lwp; + struct thread_info *child_thr; + struct target_desc *tdesc; + + ptid = ptid_t (new_pid, new_pid, 0); + + if (debug_threads) + { + debug_printf ("HEW: Got fork event from LWP %ld, " + "new child is %d\n", + ptid_of (event_thr).lwp (), + ptid.pid ()); + } + + /* Add the new process to the tables and clone the breakpoint + lists of the parent. We need to do this even if the new process + will be detached, since we will need the process object and the + breakpoints to remove any breakpoints from memory when we + detach, and the client side will access registers. */ + child_proc = linux_add_process (new_pid, 0); + gdb_assert (child_proc != NULL); + child_lwp = add_lwp (ptid); + gdb_assert (child_lwp != NULL); + child_lwp->stopped = 1; + child_lwp->must_set_ptrace_flags = 1; + child_lwp->status_pending_p = 0; + child_thr = get_lwp_thread (child_lwp); + child_thr->last_resume_kind = resume_stop; + child_thr->last_status.kind = TARGET_WAITKIND_STOPPED; + + /* If we're suspending all threads, leave this one suspended + too. If the fork/clone parent is stepping over a breakpoint, + all other threads have been suspended already. Leave the + child suspended too. */ + if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS + || event_lwp->bp_reinsert != 0) + { + if (debug_threads) + debug_printf ("HEW: leaving child suspended\n"); + child_lwp->suspended = 1; + } + + parent_proc = get_thread_process (event_thr); + child_proc->attached = parent_proc->attached; + + if (event_lwp->bp_reinsert != 0 + && can_software_single_step () + && event == PTRACE_EVENT_VFORK) + { + /* If we leave single-step breakpoints there, child will + hit it, so uninsert single-step breakpoints from parent + (and child). Once vfork child is done, reinsert + them back to parent. */ + uninsert_single_step_breakpoints (event_thr); + } + + clone_all_breakpoints (child_thr, event_thr); + + tdesc = allocate_target_description (); + copy_target_description (tdesc, parent_proc->tdesc); + child_proc->tdesc = tdesc; + + /* Clone arch-specific process data. */ + if (the_low_target.new_fork != NULL) + the_low_target.new_fork (parent_proc, child_proc); + + /* Save fork info in the parent thread. */ + if (event == PTRACE_EVENT_FORK) + event_lwp->waitstatus.kind = TARGET_WAITKIND_FORKED; + else if (event == PTRACE_EVENT_VFORK) + event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORKED; + + event_lwp->waitstatus.value.related_pid = ptid; + + /* The status_pending field contains bits denoting the + extended event, so when the pending event is handled, + the handler will look at lwp->waitstatus. */ + event_lwp->status_pending_p = 1; + event_lwp->status_pending = wstat; + + /* Link the threads until the parent event is passed on to + higher layers. */ + event_lwp->fork_relative = child_lwp; + child_lwp->fork_relative = event_lwp; + + /* If the parent thread is doing step-over with single-step + breakpoints, the list of single-step breakpoints are cloned + from the parent's. Remove them from the child process. + In case of vfork, we'll reinsert them back once vforked + child is done. */ + if (event_lwp->bp_reinsert != 0 + && can_software_single_step ()) + { + /* The child process is forked and stopped, so it is safe + to access its memory without stopping all other threads + from other processes. */ + delete_single_step_breakpoints (child_thr); + + gdb_assert (has_single_step_breakpoints (event_thr)); + gdb_assert (!has_single_step_breakpoints (child_thr)); + } + + /* Report the event. */ + return 0; + } + + if (debug_threads) + debug_printf ("HEW: Got clone event " + "from LWP %ld, new child is LWP %ld\n", + lwpid_of (event_thr), new_pid); + + ptid = ptid_t (pid_of (event_thr), new_pid, 0); + new_lwp = add_lwp (ptid); + + /* Either we're going to immediately resume the new thread + or leave it stopped. linux_resume_one_lwp is a nop if it + thinks the thread is currently running, so set this first + before calling linux_resume_one_lwp. */ + new_lwp->stopped = 1; + + /* If we're suspending all threads, leave this one suspended + too. If the fork/clone parent is stepping over a breakpoint, + all other threads have been suspended already. Leave the + child suspended too. */ + if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS + || event_lwp->bp_reinsert != 0) + new_lwp->suspended = 1; + + /* Normally we will get the pending SIGSTOP. But in some cases + we might get another signal delivered to the group first. + If we do get another signal, be sure not to lose it. */ + if (WSTOPSIG (status) != SIGSTOP) + { + new_lwp->stop_expected = 1; + new_lwp->status_pending_p = 1; + new_lwp->status_pending = status; + } + else if (cs.report_thread_events) + { + new_lwp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED; + new_lwp->status_pending_p = 1; + new_lwp->status_pending = status; + } + +#ifdef USE_THREAD_DB + thread_db_notice_clone (event_thr, ptid); +#endif + + /* Don't report the event. */ + return 1; + } + else if (event == PTRACE_EVENT_VFORK_DONE) + { + event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE; + + if (event_lwp->bp_reinsert != 0 && can_software_single_step ()) + { + reinsert_single_step_breakpoints (event_thr); + + gdb_assert (has_single_step_breakpoints (event_thr)); + } + + /* Report the event. */ + return 0; + } + else if (event == PTRACE_EVENT_EXEC && cs.report_exec_events) + { + struct process_info *proc; + std::vector syscalls_to_catch; + ptid_t event_ptid; + pid_t event_pid; + + if (debug_threads) + { + debug_printf ("HEW: Got exec event from LWP %ld\n", + lwpid_of (event_thr)); + } + + /* Get the event ptid. */ + event_ptid = ptid_of (event_thr); + event_pid = event_ptid.pid (); + + /* Save the syscall list from the execing process. */ + proc = get_thread_process (event_thr); + syscalls_to_catch = std::move (proc->syscalls_to_catch); + + /* Delete the execing process and all its threads. */ + linux_mourn (proc); + current_thread = NULL; + + /* Create a new process/lwp/thread. */ + proc = linux_add_process (event_pid, 0); + event_lwp = add_lwp (event_ptid); + event_thr = get_lwp_thread (event_lwp); + gdb_assert (current_thread == event_thr); + linux_arch_setup_thread (event_thr); + + /* Set the event status. */ + event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD; + event_lwp->waitstatus.value.execd_pathname + = xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr))); + + /* Mark the exec status as pending. */ + event_lwp->stopped = 1; + event_lwp->status_pending_p = 1; + event_lwp->status_pending = wstat; + event_thr->last_resume_kind = resume_continue; + event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; + + /* Update syscall state in the new lwp, effectively mid-syscall too. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + + /* Restore the list to catch. Don't rely on the client, which is free + to avoid sending a new list when the architecture doesn't change. + Also, for ANY_SYSCALL, the architecture doesn't really matter. */ + proc->syscalls_to_catch = std::move (syscalls_to_catch); + + /* Report the event. */ + *orig_event_lwp = event_lwp; + return 0; + } + + internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); +} + +/* Return the PC as read from the regcache of LWP, without any + adjustment. */ + +static CORE_ADDR +get_pc (struct lwp_info *lwp) +{ + struct thread_info *saved_thread; + struct regcache *regcache; + CORE_ADDR pc; + + if (the_low_target.get_pc == NULL) + return 0; + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_thread, 1); + pc = (*the_low_target.get_pc) (regcache); + + if (debug_threads) + debug_printf ("pc is 0x%lx\n", (long) pc); + + current_thread = saved_thread; + return pc; +} + +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. + Fill *SYSNO with the syscall nr trapped. */ + +static void +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno) +{ + struct thread_info *saved_thread; + struct regcache *regcache; + + if (the_low_target.get_syscall_trapinfo == NULL) + { + /* If we cannot get the syscall trapinfo, report an unknown + system call number. */ + *sysno = UNKNOWN_SYSCALL; + return; + } + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_thread, 1); + (*the_low_target.get_syscall_trapinfo) (regcache, sysno); + + if (debug_threads) + debug_printf ("get_syscall_trapinfo sysno %d\n", *sysno); + + current_thread = saved_thread; +} + +static int check_stopped_by_watchpoint (struct lwp_info *child); + +/* Called when the LWP stopped for a signal/trap. If it stopped for a + trap check what caused it (breakpoint, watchpoint, trace, etc.), + and save the result in the LWP's stop_reason field. If it stopped + for a breakpoint, decrement the PC if necessary on the lwp's + architecture. Returns true if we now have the LWP's stop PC. */ + +static int +save_stop_reason (struct lwp_info *lwp) +{ + CORE_ADDR pc; + CORE_ADDR sw_breakpoint_pc; + struct thread_info *saved_thread; +#if USE_SIGTRAP_SIGINFO + siginfo_t siginfo; +#endif + + if (the_low_target.get_pc == NULL) + return 0; + + pc = get_pc (lwp); + sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break; + + /* breakpoint_at reads from the current thread. */ + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + +#if USE_SIGTRAP_SIGINFO + if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), + (PTRACE_TYPE_ARG3) 0, &siginfo) == 0) + { + if (siginfo.si_signo == SIGTRAP) + { + if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code) + && GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code)) + { + /* The si_code is ambiguous on this arch -- check debug + registers. */ + if (!check_stopped_by_watchpoint (lwp)) + lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; + } + else if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code)) + { + /* If we determine the LWP stopped for a SW breakpoint, + trust it. Particularly don't check watchpoint + registers, because at least on s390, we'd find + stopped-by-watchpoint as long as there's a watchpoint + set. */ + lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; + } + else if (GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code)) + { + /* This can indicate either a hardware breakpoint or + hardware watchpoint. Check debug registers. */ + if (!check_stopped_by_watchpoint (lwp)) + lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; + } + else if (siginfo.si_code == TRAP_TRACE) + { + /* We may have single stepped an instruction that + triggered a watchpoint. In that case, on some + architectures (such as x86), instead of TRAP_HWBKPT, + si_code indicates TRAP_TRACE, and we need to check + the debug registers separately. */ + if (!check_stopped_by_watchpoint (lwp)) + lwp->stop_reason = TARGET_STOPPED_BY_SINGLE_STEP; + } + } + } +#else + /* We may have just stepped a breakpoint instruction. E.g., in + non-stop mode, GDB first tells the thread A to step a range, and + then the user inserts a breakpoint inside the range. In that + case we need to report the breakpoint PC. */ + if ((!lwp->stepping || lwp->stop_pc == sw_breakpoint_pc) + && (*the_low_target.breakpoint_at) (sw_breakpoint_pc)) + lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; + + if (hardware_breakpoint_inserted_here (pc)) + lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; + + if (lwp->stop_reason == TARGET_STOPPED_BY_NO_REASON) + check_stopped_by_watchpoint (lwp); +#endif + + if (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: %s stopped by software breakpoint\n", + target_pid_to_str (ptid_of (thr))); + } + + /* Back up the PC if necessary. */ + if (pc != sw_breakpoint_pc) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + (*the_low_target.set_pc) (regcache, sw_breakpoint_pc); + } + + /* Update this so we record the correct stop PC below. */ + pc = sw_breakpoint_pc; + } + else if (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: %s stopped by hardware breakpoint\n", + target_pid_to_str (ptid_of (thr))); + } + } + else if (lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: %s stopped by hardware watchpoint\n", + target_pid_to_str (ptid_of (thr))); + } + } + else if (lwp->stop_reason == TARGET_STOPPED_BY_SINGLE_STEP) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: %s stopped by trace\n", + target_pid_to_str (ptid_of (thr))); + } + } + + lwp->stop_pc = pc; + current_thread = saved_thread; + return 1; +} + +static struct lwp_info * +add_lwp (ptid_t ptid) +{ + struct lwp_info *lwp; + + lwp = XCNEW (struct lwp_info); + + lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE; + + lwp->thread = add_thread (ptid, lwp); + + if (the_low_target.new_thread != NULL) + the_low_target.new_thread (lwp); + + return lwp; +} + +/* Callback to be used when calling fork_inferior, responsible for + actually initiating the tracing of the inferior. */ + +static void +linux_ptrace_fun () +{ + if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) 0) < 0) + trace_start_error_with_name ("ptrace"); + + if (setpgid (0, 0) < 0) + trace_start_error_with_name ("setpgid"); + + /* If GDBserver is connected to gdb via stdio, redirect the inferior's + stdout to stderr so that inferior i/o doesn't corrupt the connection. + Also, redirect stdin to /dev/null. */ + if (remote_connection_is_stdio ()) + { + if (close (0) < 0) + trace_start_error_with_name ("close"); + if (open ("/dev/null", O_RDONLY) < 0) + trace_start_error_with_name ("open"); + if (dup2 (2, 1) < 0) + trace_start_error_with_name ("dup2"); + if (write (2, "stdin/stdout redirected\n", + sizeof ("stdin/stdout redirected\n") - 1) < 0) + { + /* Errors ignored. */; + } + } +} + +/* Start an inferior process and returns its pid. + PROGRAM is the name of the program to be started, and PROGRAM_ARGS + are its arguments. */ + +static int +linux_create_inferior (const char *program, + const std::vector &program_args) +{ + client_state &cs = get_client_state (); + struct lwp_info *new_lwp; + int pid; + ptid_t ptid; + + { + maybe_disable_address_space_randomization restore_personality + (cs.disable_randomization); + std::string str_program_args = stringify_argv (program_args); + + pid = fork_inferior (program, + str_program_args.c_str (), + get_environ ()->envp (), linux_ptrace_fun, + NULL, NULL, NULL, NULL); + } + + linux_add_process (pid, 0); + + ptid = ptid_t (pid, pid, 0); + new_lwp = add_lwp (ptid); + new_lwp->must_set_ptrace_flags = 1; + + post_fork_inferior (pid, program); + + return pid; +} + +/* Implement the post_create_inferior target_ops method. */ + +static void +linux_post_create_inferior (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + linux_arch_setup (); + + if (lwp->must_set_ptrace_flags) + { + struct process_info *proc = current_process (); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid_of (current_thread), options); + lwp->must_set_ptrace_flags = 0; + } +} + +/* Attach to an inferior process. Returns 0 on success, ERRNO on + error. */ + +int +linux_attach_lwp (ptid_t ptid) +{ + struct lwp_info *new_lwp; + int lwpid = ptid.lwp (); + + if (ptrace (PTRACE_ATTACH, lwpid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0) + != 0) + return errno; + + new_lwp = add_lwp (ptid); + + /* We need to wait for SIGSTOP before being able to make the next + ptrace call on this LWP. */ + new_lwp->must_set_ptrace_flags = 1; + + if (linux_proc_pid_is_stopped (lwpid)) + { + if (debug_threads) + debug_printf ("Attached to a stopped process\n"); + + /* The process is definitely stopped. It is in a job control + stop, unless the kernel predates the TASK_STOPPED / + TASK_TRACED distinction, in which case it might be in a + ptrace stop. Make sure it is in a ptrace stop; from there we + can kill it, signal it, et cetera. + + First make sure there is a pending SIGSTOP. Since we are + already attached, the process can not transition from stopped + to running without a PTRACE_CONT; so we know this signal will + go into the queue. The SIGSTOP generated by PTRACE_ATTACH is + probably already in the queue (unless this kernel is old + enough to use TASK_STOPPED for ptrace stops); but since + SIGSTOP is not an RT signal, it can only be queued once. */ + kill_lwp (lwpid, SIGSTOP); + + /* Finally, resume the stopped process. This will deliver the + SIGSTOP (or a higher priority signal, just like normal + PTRACE_ATTACH), which we'll catch later on. */ + ptrace (PTRACE_CONT, lwpid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); + } + + /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH + brings it to a halt. + + There are several cases to consider here: + + 1) gdbserver has already attached to the process and is being notified + of a new thread that is being created. + In this case we should ignore that SIGSTOP and resume the + process. This is handled below by setting stop_expected = 1, + and the fact that add_thread sets last_resume_kind == + resume_continue. + + 2) This is the first thread (the process thread), and we're attaching + to it via attach_inferior. + In this case we want the process thread to stop. + This is handled by having linux_attach set last_resume_kind == + resume_stop after we return. + + If the pid we are attaching to is also the tgid, we attach to and + stop all the existing threads. Otherwise, we attach to pid and + ignore any other threads in the same group as this pid. + + 3) GDB is connecting to gdbserver and is requesting an enumeration of all + existing threads. + In this case we want the thread to stop. + FIXME: This case is currently not properly handled. + We should wait for the SIGSTOP but don't. Things work apparently + because enough time passes between when we ptrace (ATTACH) and when + gdb makes the next ptrace call on the thread. + + On the other hand, if we are currently trying to stop all threads, we + should treat the new thread as if we had sent it a SIGSTOP. This works + because we are guaranteed that the add_lwp call above added us to the + end of the list, and so the new thread has not yet reached + wait_for_sigstop (but will). */ + new_lwp->stop_expected = 1; + + return 0; +} + +/* Callback for linux_proc_attach_tgid_threads. Attach to PTID if not + already attached. Returns true if a new LWP is found, false + otherwise. */ + +static int +attach_proc_task_lwp_callback (ptid_t ptid) +{ + /* Is this a new thread? */ + if (find_thread_ptid (ptid) == NULL) + { + int lwpid = ptid.lwp (); + int err; + + if (debug_threads) + debug_printf ("Found new lwp %d\n", lwpid); + + err = linux_attach_lwp (ptid); + + /* Be quiet if we simply raced with the thread exiting. EPERM + is returned if the thread's task still exists, and is marked + as exited or zombie, as well as other conditions, so in that + case, confirm the status in /proc/PID/status. */ + if (err == ESRCH + || (err == EPERM && linux_proc_pid_is_gone (lwpid))) + { + if (debug_threads) + { + debug_printf ("Cannot attach to lwp %d: " + "thread is gone (%d: %s)\n", + lwpid, err, safe_strerror (err)); + } + } + else if (err != 0) + { + std::string reason + = linux_ptrace_attach_fail_reason_string (ptid, err); + + warning (_("Cannot attach to lwp %d: %s"), lwpid, reason.c_str ()); + } + + return 1; + } + return 0; +} + +static void async_file_mark (void); + +/* Attach to PID. If PID is the tgid, attach to it and all + of its threads. */ + +static int +linux_attach (unsigned long pid) +{ + struct process_info *proc; + struct thread_info *initial_thread; + ptid_t ptid = ptid_t (pid, pid, 0); + int err; + + proc = linux_add_process (pid, 1); + + /* Attach to PID. We will check for other threads + soon. */ + err = linux_attach_lwp (ptid); + if (err != 0) + { + remove_process (proc); + + std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err); + error ("Cannot attach to process %ld: %s", pid, reason.c_str ()); + } + + /* Don't ignore the initial SIGSTOP if we just attached to this + process. It will be collected by wait shortly. */ + initial_thread = find_thread_ptid (ptid_t (pid, pid, 0)); + initial_thread->last_resume_kind = resume_stop; + + /* We must attach to every LWP. If /proc is mounted, use that to + find them now. On the one hand, the inferior may be using raw + clone instead of using pthreads. On the other hand, even if it + is using pthreads, GDB may not be connected yet (thread_db needs + to do symbol lookups, through qSymbol). Also, thread_db walks + structures in the inferior's address space to find the list of + threads/LWPs, and those structures may well be corrupted. Note + that once thread_db is loaded, we'll still use it to list threads + and associate pthread info with each LWP. */ + linux_proc_attach_tgid_threads (pid, attach_proc_task_lwp_callback); + + /* GDB will shortly read the xml target description for this + process, to figure out the process' architecture. But the target + description is only filled in when the first process/thread in + the thread group reports its initial PTRACE_ATTACH SIGSTOP. Do + that now, otherwise, if GDB is fast enough, it could read the + target description _before_ that initial stop. */ + if (non_stop) + { + struct lwp_info *lwp; + int wstat, lwpid; + ptid_t pid_ptid = ptid_t (pid); + + lwpid = linux_wait_for_event_filtered (pid_ptid, pid_ptid, + &wstat, __WALL); + gdb_assert (lwpid > 0); + + lwp = find_lwp_pid (ptid_t (lwpid)); + + if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGSTOP) + { + lwp->status_pending_p = 1; + lwp->status_pending = wstat; + } + + initial_thread->last_resume_kind = resume_continue; + + async_file_mark (); + + gdb_assert (proc->tdesc != NULL); + } + + return 0; +} + +static int +last_thread_of_process_p (int pid) +{ + bool seen_one = false; + + thread_info *thread = find_thread (pid, [&] (thread_info *thr_arg) + { + if (!seen_one) + { + /* This is the first thread of this process we see. */ + seen_one = true; + return false; + } + else + { + /* This is the second thread of this process we see. */ + return true; + } + }); + + return thread == NULL; +} + +/* Kill LWP. */ + +static void +linux_kill_one_lwp (struct lwp_info *lwp) +{ + struct thread_info *thr = get_lwp_thread (lwp); + int pid = lwpid_of (thr); + + /* PTRACE_KILL is unreliable. After stepping into a signal handler, + there is no signal context, and ptrace(PTRACE_KILL) (or + ptrace(PTRACE_CONT, SIGKILL), pretty much the same) acts like + ptrace(CONT, pid, 0,0) and just resumes the tracee. A better + alternative is to kill with SIGKILL. We only need one SIGKILL + per process, not one for each thread. But since we still support + support debugging programs using raw clone without CLONE_THREAD, + we send one for each thread. For years, we used PTRACE_KILL + only, so we're being a bit paranoid about some old kernels where + PTRACE_KILL might work better (dubious if there are any such, but + that's why it's paranoia), so we try SIGKILL first, PTRACE_KILL + second, and so we're fine everywhere. */ + + errno = 0; + kill_lwp (pid, SIGKILL); + if (debug_threads) + { + int save_errno = errno; + + debug_printf ("LKL: kill_lwp (SIGKILL) %s, 0, 0 (%s)\n", + target_pid_to_str (ptid_of (thr)), + save_errno ? safe_strerror (save_errno) : "OK"); + } + + errno = 0; + ptrace (PTRACE_KILL, pid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); + if (debug_threads) + { + int save_errno = errno; + + debug_printf ("LKL: PTRACE_KILL %s, 0, 0 (%s)\n", + target_pid_to_str (ptid_of (thr)), + save_errno ? safe_strerror (save_errno) : "OK"); + } +} + +/* Kill LWP and wait for it to die. */ + +static void +kill_wait_lwp (struct lwp_info *lwp) +{ + struct thread_info *thr = get_lwp_thread (lwp); + int pid = ptid_of (thr).pid (); + int lwpid = ptid_of (thr).lwp (); + int wstat; + int res; + + if (debug_threads) + debug_printf ("kwl: killing lwp %d, for pid: %d\n", lwpid, pid); + + do + { + linux_kill_one_lwp (lwp); + + /* Make sure it died. Notes: + + - The loop is most likely unnecessary. + + - We don't use linux_wait_for_event as that could delete lwps + while we're iterating over them. We're not interested in + any pending status at this point, only in making sure all + wait status on the kernel side are collected until the + process is reaped. + + - We don't use __WALL here as the __WALL emulation relies on + SIGCHLD, and killing a stopped process doesn't generate + one, nor an exit status. + */ + res = my_waitpid (lwpid, &wstat, 0); + if (res == -1 && errno == ECHILD) + res = my_waitpid (lwpid, &wstat, __WCLONE); + } while (res > 0 && WIFSTOPPED (wstat)); + + /* Even if it was stopped, the child may have already disappeared. + E.g., if it was killed by SIGKILL. */ + if (res < 0 && errno != ECHILD) + perror_with_name ("kill_wait_lwp"); +} + +/* Callback for `for_each_thread'. Kills an lwp of a given process, + except the leader. */ + +static void +kill_one_lwp_callback (thread_info *thread, int pid) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + /* We avoid killing the first thread here, because of a Linux kernel (at + least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before + the children get a chance to be reaped, it will remain a zombie + forever. */ + + if (lwpid_of (thread) == pid) + { + if (debug_threads) + debug_printf ("lkop: is last of process %s\n", + target_pid_to_str (thread->id)); + return; + } + + kill_wait_lwp (lwp); +} + +static int +linux_kill (process_info *process) +{ + int pid = process->pid; + + /* If we're killing a running inferior, make sure it is stopped + first, as PTRACE_KILL will not work otherwise. */ + stop_all_lwps (0, NULL); + + for_each_thread (pid, [&] (thread_info *thread) + { + kill_one_lwp_callback (thread, pid); + }); + + /* See the comment in linux_kill_one_lwp. We did not kill the first + thread in the list, so do so now. */ + lwp_info *lwp = find_lwp_pid (ptid_t (pid)); + + if (lwp == NULL) + { + if (debug_threads) + debug_printf ("lk_1: cannot find lwp for pid: %d\n", + pid); + } + else + kill_wait_lwp (lwp); + + the_target->mourn (process); + + /* Since we presently can only stop all lwps of all processes, we + need to unstop lwps of other processes. */ + unstop_all_lwps (0, NULL); + return 0; +} + +/* Get pending signal of THREAD, for detaching purposes. This is the + signal the thread last stopped for, which we need to deliver to the + thread when detaching, otherwise, it'd be suppressed/lost. */ + +static int +get_detach_signal (struct thread_info *thread) +{ + client_state &cs = get_client_state (); + enum gdb_signal signo = GDB_SIGNAL_0; + int status; + struct lwp_info *lp = get_thread_lwp (thread); + + if (lp->status_pending_p) + status = lp->status_pending; + else + { + /* If the thread had been suspended by gdbserver, and it stopped + cleanly, then it'll have stopped with SIGSTOP. But we don't + want to deliver that SIGSTOP. */ + if (thread->last_status.kind != TARGET_WAITKIND_STOPPED + || thread->last_status.value.sig == GDB_SIGNAL_0) + return 0; + + /* Otherwise, we may need to deliver the signal we + intercepted. */ + status = lp->last_status; + } + + if (!WIFSTOPPED (status)) + { + if (debug_threads) + debug_printf ("GPS: lwp %s hasn't stopped: no pending signal\n", + target_pid_to_str (ptid_of (thread))); + return 0; + } + + /* Extended wait statuses aren't real SIGTRAPs. */ + if (WSTOPSIG (status) == SIGTRAP && linux_is_extended_waitstatus (status)) + { + if (debug_threads) + debug_printf ("GPS: lwp %s had stopped with extended " + "status: no pending signal\n", + target_pid_to_str (ptid_of (thread))); + return 0; + } + + signo = gdb_signal_from_host (WSTOPSIG (status)); + + if (cs.program_signals_p && !cs.program_signals[signo]) + { + if (debug_threads) + debug_printf ("GPS: lwp %s had signal %s, but it is in nopass state\n", + target_pid_to_str (ptid_of (thread)), + gdb_signal_to_string (signo)); + return 0; + } + else if (!cs.program_signals_p + /* If we have no way to know which signals GDB does not + want to have passed to the program, assume + SIGTRAP/SIGINT, which is GDB's default. */ + && (signo == GDB_SIGNAL_TRAP || signo == GDB_SIGNAL_INT)) + { + if (debug_threads) + debug_printf ("GPS: lwp %s had signal %s, " + "but we don't know if we should pass it. " + "Default to not.\n", + target_pid_to_str (ptid_of (thread)), + gdb_signal_to_string (signo)); + return 0; + } + else + { + if (debug_threads) + debug_printf ("GPS: lwp %s has pending signal %s: delivering it.\n", + target_pid_to_str (ptid_of (thread)), + gdb_signal_to_string (signo)); + + return WSTOPSIG (status); + } +} + +/* Detach from LWP. */ + +static void +linux_detach_one_lwp (struct lwp_info *lwp) +{ + struct thread_info *thread = get_lwp_thread (lwp); + int sig; + int lwpid; + + /* If there is a pending SIGSTOP, get rid of it. */ + if (lwp->stop_expected) + { + if (debug_threads) + debug_printf ("Sending SIGCONT to %s\n", + target_pid_to_str (ptid_of (thread))); + + kill_lwp (lwpid_of (thread), SIGCONT); + lwp->stop_expected = 0; + } + + /* Pass on any pending signal for this thread. */ + sig = get_detach_signal (thread); + + /* Preparing to resume may try to write registers, and fail if the + lwp is zombie. If that happens, ignore the error. We'll handle + it below, when detach fails with ESRCH. */ + try + { + /* Flush any pending changes to the process's registers. */ + regcache_invalidate_thread (thread); + + /* Finally, let it resume. */ + if (the_low_target.prepare_to_resume != NULL) + the_low_target.prepare_to_resume (lwp); + } + catch (const gdb_exception_error &ex) + { + if (!check_ptrace_stopped_lwp_gone (lwp)) + throw; + } + + lwpid = lwpid_of (thread); + if (ptrace (PTRACE_DETACH, lwpid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) (long) sig) < 0) + { + int save_errno = errno; + + /* We know the thread exists, so ESRCH must mean the lwp is + zombie. This can happen if one of the already-detached + threads exits the whole thread group. In that case we're + still attached, and must reap the lwp. */ + if (save_errno == ESRCH) + { + int ret, status; + + ret = my_waitpid (lwpid, &status, __WALL); + if (ret == -1) + { + warning (_("Couldn't reap LWP %d while detaching: %s"), + lwpid, safe_strerror (errno)); + } + else if (!WIFEXITED (status) && !WIFSIGNALED (status)) + { + warning (_("Reaping LWP %d while detaching " + "returned unexpected status 0x%x"), + lwpid, status); + } + } + else + { + error (_("Can't detach %s: %s"), + target_pid_to_str (ptid_of (thread)), + safe_strerror (save_errno)); + } + } + else if (debug_threads) + { + debug_printf ("PTRACE_DETACH (%s, %s, 0) (OK)\n", + target_pid_to_str (ptid_of (thread)), + strsignal (sig)); + } + + delete_lwp (lwp); +} + +/* Callback for for_each_thread. Detaches from non-leader threads of a + given process. */ + +static void +linux_detach_lwp_callback (thread_info *thread) +{ + /* We don't actually detach from the thread group leader just yet. + If the thread group exits, we must reap the zombie clone lwps + before we're able to reap the leader. */ + if (thread->id.pid () == thread->id.lwp ()) + return; + + lwp_info *lwp = get_thread_lwp (thread); + linux_detach_one_lwp (lwp); +} + +static int +linux_detach (process_info *process) +{ + struct lwp_info *main_lwp; + + /* As there's a step over already in progress, let it finish first, + otherwise nesting a stabilize_threads operation on top gets real + messy. */ + complete_ongoing_step_over (); + + /* Stop all threads before detaching. First, ptrace requires that + the thread is stopped to successfully detach. Second, thread_db + may need to uninstall thread event breakpoints from memory, which + only works with a stopped process anyway. */ + stop_all_lwps (0, NULL); + +#ifdef USE_THREAD_DB + thread_db_detach (process); +#endif + + /* Stabilize threads (move out of jump pads). */ + stabilize_threads (); + + /* Detach from the clone lwps first. If the thread group exits just + while we're detaching, we must reap the clone lwps before we're + able to reap the leader. */ + for_each_thread (process->pid, linux_detach_lwp_callback); + + main_lwp = find_lwp_pid (ptid_t (process->pid)); + linux_detach_one_lwp (main_lwp); + + the_target->mourn (process); + + /* Since we presently can only stop all lwps of all processes, we + need to unstop lwps of other processes. */ + unstop_all_lwps (0, NULL); + return 0; +} + +/* Remove all LWPs that belong to process PROC from the lwp list. */ + +static void +linux_mourn (struct process_info *process) +{ + struct process_info_private *priv; + +#ifdef USE_THREAD_DB + thread_db_mourn (process); +#endif + + for_each_thread (process->pid, [] (thread_info *thread) + { + delete_lwp (get_thread_lwp (thread)); + }); + + /* Freeing all private data. */ + priv = process->priv; + if (the_low_target.delete_process != NULL) + the_low_target.delete_process (priv->arch_private); + else + gdb_assert (priv->arch_private == NULL); + free (priv); + process->priv = NULL; + + remove_process (process); +} + +static void +linux_join (int pid) +{ + int status, ret; + + do { + ret = my_waitpid (pid, &status, 0); + if (WIFEXITED (status) || WIFSIGNALED (status)) + break; + } while (ret != -1 || errno != ECHILD); +} + +/* Return nonzero if the given thread is still alive. */ +static int +linux_thread_alive (ptid_t ptid) +{ + struct lwp_info *lwp = find_lwp_pid (ptid); + + /* We assume we always know if a thread exits. If a whole process + exited but we still haven't been able to report it to GDB, we'll + hold on to the last lwp of the dead process. */ + if (lwp != NULL) + return !lwp_is_marked_dead (lwp); + else + return 0; +} + +/* Return 1 if this lwp still has an interesting status pending. If + not (e.g., it had stopped for a breakpoint that is gone), return + false. */ + +static int +thread_still_has_status_pending_p (struct thread_info *thread) +{ + struct lwp_info *lp = get_thread_lwp (thread); + + if (!lp->status_pending_p) + return 0; + + if (thread->last_resume_kind != resume_stop + && (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + || lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) + { + struct thread_info *saved_thread; + CORE_ADDR pc; + int discard = 0; + + gdb_assert (lp->last_status != 0); + + pc = get_pc (lp); + + saved_thread = current_thread; + current_thread = thread; + + if (pc != lp->stop_pc) + { + if (debug_threads) + debug_printf ("PC of %ld changed\n", + lwpid_of (thread)); + discard = 1; + } + +#if !USE_SIGTRAP_SIGINFO + else if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && !(*the_low_target.breakpoint_at) (pc)) + { + if (debug_threads) + debug_printf ("previous SW breakpoint of %ld gone\n", + lwpid_of (thread)); + discard = 1; + } + else if (lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT + && !hardware_breakpoint_inserted_here (pc)) + { + if (debug_threads) + debug_printf ("previous HW breakpoint of %ld gone\n", + lwpid_of (thread)); + discard = 1; + } +#endif + + current_thread = saved_thread; + + if (discard) + { + if (debug_threads) + debug_printf ("discarding pending breakpoint status\n"); + lp->status_pending_p = 0; + return 0; + } + } + + return 1; +} + +/* Returns true if LWP is resumed from the client's perspective. */ + +static int +lwp_resumed (struct lwp_info *lwp) +{ + struct thread_info *thread = get_lwp_thread (lwp); + + if (thread->last_resume_kind != resume_stop) + return 1; + + /* Did gdb send us a `vCont;t', but we haven't reported the + corresponding stop to gdb yet? If so, the thread is still + resumed/running from gdb's perspective. */ + if (thread->last_resume_kind == resume_stop + && thread->last_status.kind == TARGET_WAITKIND_IGNORE) + return 1; + + return 0; +} + +/* Return true if this lwp has an interesting status pending. */ +static bool +status_pending_p_callback (thread_info *thread, ptid_t ptid) +{ + struct lwp_info *lp = get_thread_lwp (thread); + + /* Check if we're only interested in events from a specific process + or a specific LWP. */ + if (!thread->id.matches (ptid)) + return 0; + + if (!lwp_resumed (lp)) + return 0; + + if (lp->status_pending_p + && !thread_still_has_status_pending_p (thread)) + { + linux_resume_one_lwp (lp, lp->stepping, GDB_SIGNAL_0, NULL); + return 0; + } + + return lp->status_pending_p; +} + +struct lwp_info * +find_lwp_pid (ptid_t ptid) +{ + thread_info *thread = find_thread ([&] (thread_info *thr_arg) + { + int lwp = ptid.lwp () != 0 ? ptid.lwp () : ptid.pid (); + return thr_arg->id.lwp () == lwp; + }); + + if (thread == NULL) + return NULL; + + return get_thread_lwp (thread); +} + +/* Return the number of known LWPs in the tgid given by PID. */ + +static int +num_lwps (int pid) +{ + int count = 0; + + for_each_thread (pid, [&] (thread_info *thread) + { + count++; + }); + + return count; +} + +/* See nat/linux-nat.h. */ + +struct lwp_info * +iterate_over_lwps (ptid_t filter, + gdb::function_view callback) +{ + thread_info *thread = find_thread (filter, [&] (thread_info *thr_arg) + { + lwp_info *lwp = get_thread_lwp (thr_arg); + + return callback (lwp); + }); + + if (thread == NULL) + return NULL; + + return get_thread_lwp (thread); +} + +/* Detect zombie thread group leaders, and "exit" them. We can't reap + their exits until all other threads in the group have exited. */ + +static void +check_zombie_leaders (void) +{ + for_each_process ([] (process_info *proc) { + pid_t leader_pid = pid_of (proc); + struct lwp_info *leader_lp; + + leader_lp = find_lwp_pid (ptid_t (leader_pid)); + + if (debug_threads) + debug_printf ("leader_pid=%d, leader_lp!=NULL=%d, " + "num_lwps=%d, zombie=%d\n", + leader_pid, leader_lp!= NULL, num_lwps (leader_pid), + linux_proc_pid_is_zombie (leader_pid)); + + if (leader_lp != NULL && !leader_lp->stopped + /* Check if there are other threads in the group, as we may + have raced with the inferior simply exiting. */ + && !last_thread_of_process_p (leader_pid) + && linux_proc_pid_is_zombie (leader_pid)) + { + /* A leader zombie can mean one of two things: + + - It exited, and there's an exit status pending + available, or only the leader exited (not the whole + program). In the latter case, we can't waitpid the + leader's exit status until all other threads are gone. + + - There are 3 or more threads in the group, and a thread + other than the leader exec'd. On an exec, the Linux + kernel destroys all other threads (except the execing + one) in the thread group, and resets the execing thread's + tid to the tgid. No exit notification is sent for the + execing thread -- from the ptracer's perspective, it + appears as though the execing thread just vanishes. + Until we reap all other threads except the leader and the + execing thread, the leader will be zombie, and the + execing thread will be in `D (disc sleep)'. As soon as + all other threads are reaped, the execing thread changes + it's tid to the tgid, and the previous (zombie) leader + vanishes, giving place to the "new" leader. We could try + distinguishing the exit and exec cases, by waiting once + more, and seeing if something comes out, but it doesn't + sound useful. The previous leader _does_ go away, and + we'll re-add the new one once we see the exec event + (which is just the same as what would happen if the + previous leader did exit voluntarily before some other + thread execs). */ + + if (debug_threads) + debug_printf ("CZL: Thread group leader %d zombie " + "(it exited, or another thread execd).\n", + leader_pid); + + delete_lwp (leader_lp); + } + }); +} + +/* Callback for `find_thread'. Returns the first LWP that is not + stopped. */ + +static bool +not_stopped_callback (thread_info *thread, ptid_t filter) +{ + if (!thread->id.matches (filter)) + return false; + + lwp_info *lwp = get_thread_lwp (thread); + + return !lwp->stopped; +} + +/* Increment LWP's suspend count. */ + +static void +lwp_suspended_inc (struct lwp_info *lwp) +{ + lwp->suspended++; + + if (debug_threads && lwp->suspended > 4) + { + struct thread_info *thread = get_lwp_thread (lwp); + + debug_printf ("LWP %ld has a suspiciously high suspend count," + " suspended=%d\n", lwpid_of (thread), lwp->suspended); + } +} + +/* Decrement LWP's suspend count. */ + +static void +lwp_suspended_decr (struct lwp_info *lwp) +{ + lwp->suspended--; + + if (lwp->suspended < 0) + { + struct thread_info *thread = get_lwp_thread (lwp); + + internal_error (__FILE__, __LINE__, + "unsuspend LWP %ld, suspended=%d\n", lwpid_of (thread), + lwp->suspended); + } +} + +/* This function should only be called if the LWP got a SIGTRAP. + + Handle any tracepoint steps or hits. Return true if a tracepoint + event was handled, 0 otherwise. */ + +static int +handle_tracepoints (struct lwp_info *lwp) +{ + struct thread_info *tinfo = get_lwp_thread (lwp); + int tpoint_related_event = 0; + + gdb_assert (lwp->suspended == 0); + + /* If this tracepoint hit causes a tracing stop, we'll immediately + uninsert tracepoints. To do this, we temporarily pause all + threads, unpatch away, and then unpause threads. We need to make + sure the unpausing doesn't resume LWP too. */ + lwp_suspended_inc (lwp); + + /* And we need to be sure that any all-threads-stopping doesn't try + to move threads out of the jump pads, as it could deadlock the + inferior (LWP could be in the jump pad, maybe even holding the + lock.) */ + + /* Do any necessary step collect actions. */ + tpoint_related_event |= tracepoint_finished_step (tinfo, lwp->stop_pc); + + tpoint_related_event |= handle_tracepoint_bkpts (tinfo, lwp->stop_pc); + + /* See if we just hit a tracepoint and do its main collect + actions. */ + tpoint_related_event |= tracepoint_was_hit (tinfo, lwp->stop_pc); + + lwp_suspended_decr (lwp); + + gdb_assert (lwp->suspended == 0); + gdb_assert (!stabilizing_threads + || (lwp->collecting_fast_tracepoint + != fast_tpoint_collect_result::not_collecting)); + + if (tpoint_related_event) + { + if (debug_threads) + debug_printf ("got a tracepoint event\n"); + return 1; + } + + return 0; +} + +/* Convenience wrapper. Returns information about LWP's fast tracepoint + collection status. */ + +static fast_tpoint_collect_result +linux_fast_tracepoint_collecting (struct lwp_info *lwp, + struct fast_tpoint_collect_status *status) +{ + CORE_ADDR thread_area; + struct thread_info *thread = get_lwp_thread (lwp); + + if (the_low_target.get_thread_area == NULL) + return fast_tpoint_collect_result::not_collecting; + + /* Get the thread area address. This is used to recognize which + thread is which when tracing with the in-process agent library. + We don't read anything from the address, and treat it as opaque; + it's the address itself that we assume is unique per-thread. */ + if ((*the_low_target.get_thread_area) (lwpid_of (thread), &thread_area) == -1) + return fast_tpoint_collect_result::not_collecting; + + return fast_tracepoint_collecting (thread_area, lwp->stop_pc, status); +} + +/* The reason we resume in the caller, is because we want to be able + to pass lwp->status_pending as WSTAT, and we need to clear + status_pending_p before resuming, otherwise, linux_resume_one_lwp + refuses to resume. */ + +static int +maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) +{ + struct thread_info *saved_thread; + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + if ((wstat == NULL + || (WIFSTOPPED (*wstat) && WSTOPSIG (*wstat) != SIGTRAP)) + && supports_fast_tracepoints () + && agent_loaded_p ()) + { + struct fast_tpoint_collect_status status; + + if (debug_threads) + debug_printf ("Checking whether LWP %ld needs to move out of the " + "jump pad.\n", + lwpid_of (current_thread)); + + fast_tpoint_collect_result r + = linux_fast_tracepoint_collecting (lwp, &status); + + if (wstat == NULL + || (WSTOPSIG (*wstat) != SIGILL + && WSTOPSIG (*wstat) != SIGFPE + && WSTOPSIG (*wstat) != SIGSEGV + && WSTOPSIG (*wstat) != SIGBUS)) + { + lwp->collecting_fast_tracepoint = r; + + if (r != fast_tpoint_collect_result::not_collecting) + { + if (r == fast_tpoint_collect_result::before_insn + && lwp->exit_jump_pad_bkpt == NULL) + { + /* Haven't executed the original instruction yet. + Set breakpoint there, and wait till it's hit, + then single-step until exiting the jump pad. */ + lwp->exit_jump_pad_bkpt + = set_breakpoint_at (status.adjusted_insn_addr, NULL); + } + + if (debug_threads) + debug_printf ("Checking whether LWP %ld needs to move out of " + "the jump pad...it does\n", + lwpid_of (current_thread)); + current_thread = saved_thread; + + return 1; + } + } + else + { + /* If we get a synchronous signal while collecting, *and* + while executing the (relocated) original instruction, + reset the PC to point at the tpoint address, before + reporting to GDB. Otherwise, it's an IPA lib bug: just + report the signal to GDB, and pray for the best. */ + + lwp->collecting_fast_tracepoint + = fast_tpoint_collect_result::not_collecting; + + if (r != fast_tpoint_collect_result::not_collecting + && (status.adjusted_insn_addr <= lwp->stop_pc + && lwp->stop_pc < status.adjusted_insn_addr_end)) + { + siginfo_t info; + struct regcache *regcache; + + /* The si_addr on a few signals references the address + of the faulting instruction. Adjust that as + well. */ + if ((WSTOPSIG (*wstat) == SIGILL + || WSTOPSIG (*wstat) == SIGFPE + || WSTOPSIG (*wstat) == SIGBUS + || WSTOPSIG (*wstat) == SIGSEGV) + && ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), + (PTRACE_TYPE_ARG3) 0, &info) == 0 + /* Final check just to make sure we don't clobber + the siginfo of non-kernel-sent signals. */ + && (uintptr_t) info.si_addr == lwp->stop_pc) + { + info.si_addr = (void *) (uintptr_t) status.tpoint_addr; + ptrace (PTRACE_SETSIGINFO, lwpid_of (current_thread), + (PTRACE_TYPE_ARG3) 0, &info); + } + + regcache = get_thread_regcache (current_thread, 1); + (*the_low_target.set_pc) (regcache, status.tpoint_addr); + lwp->stop_pc = status.tpoint_addr; + + /* Cancel any fast tracepoint lock this thread was + holding. */ + force_unlock_trace_buffer (); + } + + if (lwp->exit_jump_pad_bkpt != NULL) + { + if (debug_threads) + debug_printf ("Cancelling fast exit-jump-pad: removing bkpt. " + "stopping all threads momentarily.\n"); + + stop_all_lwps (1, lwp); + + delete_breakpoint (lwp->exit_jump_pad_bkpt); + lwp->exit_jump_pad_bkpt = NULL; + + unstop_all_lwps (1, lwp); + + gdb_assert (lwp->suspended >= 0); + } + } + } + + if (debug_threads) + debug_printf ("Checking whether LWP %ld needs to move out of the " + "jump pad...no\n", + lwpid_of (current_thread)); + + current_thread = saved_thread; + return 0; +} + +/* Enqueue one signal in the "signals to report later when out of the + jump pad" list. */ + +static void +enqueue_one_deferred_signal (struct lwp_info *lwp, int *wstat) +{ + struct pending_signals *p_sig; + struct thread_info *thread = get_lwp_thread (lwp); + + if (debug_threads) + debug_printf ("Deferring signal %d for LWP %ld.\n", + WSTOPSIG (*wstat), lwpid_of (thread)); + + if (debug_threads) + { + struct pending_signals *sig; + + for (sig = lwp->pending_signals_to_report; + sig != NULL; + sig = sig->prev) + debug_printf (" Already queued %d\n", + sig->signal); + + debug_printf (" (no more currently queued signals)\n"); + } + + /* Don't enqueue non-RT signals if they are already in the deferred + queue. (SIGSTOP being the easiest signal to see ending up here + twice) */ + if (WSTOPSIG (*wstat) < __SIGRTMIN) + { + struct pending_signals *sig; + + for (sig = lwp->pending_signals_to_report; + sig != NULL; + sig = sig->prev) + { + if (sig->signal == WSTOPSIG (*wstat)) + { + if (debug_threads) + debug_printf ("Not requeuing already queued non-RT signal %d" + " for LWP %ld\n", + sig->signal, + lwpid_of (thread)); + return; + } + } + } + + p_sig = XCNEW (struct pending_signals); + p_sig->prev = lwp->pending_signals_to_report; + p_sig->signal = WSTOPSIG (*wstat); + + ptrace (PTRACE_GETSIGINFO, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, + &p_sig->info); + + lwp->pending_signals_to_report = p_sig; +} + +/* Dequeue one signal from the "signals to report later when out of + the jump pad" list. */ + +static int +dequeue_one_deferred_signal (struct lwp_info *lwp, int *wstat) +{ + struct thread_info *thread = get_lwp_thread (lwp); + + if (lwp->pending_signals_to_report != NULL) + { + struct pending_signals **p_sig; + + p_sig = &lwp->pending_signals_to_report; + while ((*p_sig)->prev != NULL) + p_sig = &(*p_sig)->prev; + + *wstat = W_STOPCODE ((*p_sig)->signal); + if ((*p_sig)->info.si_signo != 0) + ptrace (PTRACE_SETSIGINFO, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, + &(*p_sig)->info); + free (*p_sig); + *p_sig = NULL; + + if (debug_threads) + debug_printf ("Reporting deferred signal %d for LWP %ld.\n", + WSTOPSIG (*wstat), lwpid_of (thread)); + + if (debug_threads) + { + struct pending_signals *sig; + + for (sig = lwp->pending_signals_to_report; + sig != NULL; + sig = sig->prev) + debug_printf (" Still queued %d\n", + sig->signal); + + debug_printf (" (no more queued signals)\n"); + } + + return 1; + } + + return 0; +} + +/* Fetch the possibly triggered data watchpoint info and store it in + CHILD. + + On some archs, like x86, that use debug registers to set + watchpoints, it's possible that the way to know which watched + address trapped, is to check the register that is used to select + which address to watch. Problem is, between setting the watchpoint + and reading back which data address trapped, the user may change + the set of watchpoints, and, as a consequence, GDB changes the + debug registers in the inferior. To avoid reading back a stale + stopped-data-address when that happens, we cache in LP the fact + that a watchpoint trapped, and the corresponding data address, as + soon as we see CHILD stop with a SIGTRAP. If GDB changes the debug + registers meanwhile, we have the cached data we can rely on. */ + +static int +check_stopped_by_watchpoint (struct lwp_info *child) +{ + if (the_low_target.stopped_by_watchpoint != NULL) + { + struct thread_info *saved_thread; + + saved_thread = current_thread; + current_thread = get_lwp_thread (child); + + if (the_low_target.stopped_by_watchpoint ()) + { + child->stop_reason = TARGET_STOPPED_BY_WATCHPOINT; + + if (the_low_target.stopped_data_address != NULL) + child->stopped_data_address + = the_low_target.stopped_data_address (); + else + child->stopped_data_address = 0; + } + + current_thread = saved_thread; + } + + return child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT; +} + +/* Return the ptrace options that we want to try to enable. */ + +static int +linux_low_ptrace_options (int attached) +{ + client_state &cs = get_client_state (); + int options = 0; + + if (!attached) + options |= PTRACE_O_EXITKILL; + + if (cs.report_fork_events) + options |= PTRACE_O_TRACEFORK; + + if (cs.report_vfork_events) + options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE); + + if (cs.report_exec_events) + options |= PTRACE_O_TRACEEXEC; + + options |= PTRACE_O_TRACESYSGOOD; + + return options; +} + +/* Do low-level handling of the event, and check if we should go on + and pass it to caller code. Return the affected lwp if we are, or + NULL otherwise. */ + +static struct lwp_info * +linux_low_filter_event (int lwpid, int wstat) +{ + client_state &cs = get_client_state (); + struct lwp_info *child; + struct thread_info *thread; + int have_stop_pc = 0; + + child = find_lwp_pid (ptid_t (lwpid)); + + /* Check for stop events reported by a process we didn't already + know about - anything not already in our LWP list. + + If we're expecting to receive stopped processes after + fork, vfork, and clone events, then we'll just add the + new one to our list and go back to waiting for the event + to be reported - the stopped process might be returned + from waitpid before or after the event is. + + But note the case of a non-leader thread exec'ing after the + leader having exited, and gone from our lists (because + check_zombie_leaders deleted it). The non-leader thread + changes its tid to the tgid. */ + + if (WIFSTOPPED (wstat) && child == NULL && WSTOPSIG (wstat) == SIGTRAP + && linux_ptrace_get_extended_event (wstat) == PTRACE_EVENT_EXEC) + { + ptid_t child_ptid; + + /* A multi-thread exec after we had seen the leader exiting. */ + if (debug_threads) + { + debug_printf ("LLW: Re-adding thread group leader LWP %d" + "after exec.\n", lwpid); + } + + child_ptid = ptid_t (lwpid, lwpid, 0); + child = add_lwp (child_ptid); + child->stopped = 1; + current_thread = child->thread; + } + + /* If we didn't find a process, one of two things presumably happened: + - A process we started and then detached from has exited. Ignore it. + - A process we are controlling has forked and the new child's stop + was reported to us by the kernel. Save its PID. */ + if (child == NULL && WIFSTOPPED (wstat)) + { + add_to_pid_list (&stopped_pids, lwpid, wstat); + return NULL; + } + else if (child == NULL) + return NULL; + + thread = get_lwp_thread (child); + + child->stopped = 1; + + child->last_status = wstat; + + /* Check if the thread has exited. */ + if ((WIFEXITED (wstat) || WIFSIGNALED (wstat))) + { + if (debug_threads) + debug_printf ("LLFE: %d exited.\n", lwpid); + + if (finish_step_over (child)) + { + /* Unsuspend all other LWPs, and set them back running again. */ + unsuspend_all_lwps (child); + } + + /* If there is at least one more LWP, then the exit signal was + not the end of the debugged application and should be + ignored, unless GDB wants to hear about thread exits. */ + if (cs.report_thread_events + || last_thread_of_process_p (pid_of (thread))) + { + /* Since events are serialized to GDB core, and we can't + report this one right now. Leave the status pending for + the next time we're able to report it. */ + mark_lwp_dead (child, wstat); + return child; + } + else + { + delete_lwp (child); + return NULL; + } + } + + gdb_assert (WIFSTOPPED (wstat)); + + if (WIFSTOPPED (wstat)) + { + struct process_info *proc; + + /* Architecture-specific setup after inferior is running. */ + proc = find_process_pid (pid_of (thread)); + if (proc->tdesc == NULL) + { + if (proc->attached) + { + /* This needs to happen after we have attached to the + inferior and it is stopped for the first time, but + before we access any inferior registers. */ + linux_arch_setup_thread (thread); + } + else + { + /* The process is started, but GDBserver will do + architecture-specific setup after the program stops at + the first instruction. */ + child->status_pending_p = 1; + child->status_pending = wstat; + return child; + } + } + } + + if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) + { + struct process_info *proc = find_process_pid (pid_of (thread)); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid, options); + child->must_set_ptrace_flags = 0; + } + + /* Always update syscall_state, even if it will be filtered later. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) + { + child->syscall_state + = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY + ? TARGET_WAITKIND_SYSCALL_RETURN + : TARGET_WAITKIND_SYSCALL_ENTRY); + } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in handle_extended_wait. */ + child->syscall_state = TARGET_WAITKIND_IGNORE; + } + + /* Be careful to not overwrite stop_pc until save_stop_reason is + called. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP + && linux_is_extended_waitstatus (wstat)) + { + child->stop_pc = get_pc (child); + if (handle_extended_wait (&child, wstat)) + { + /* The event has been handled, so just return without + reporting it. */ + return NULL; + } + } + + if (linux_wstatus_maybe_breakpoint (wstat)) + { + if (save_stop_reason (child)) + have_stop_pc = 1; + } + + if (!have_stop_pc) + child->stop_pc = get_pc (child); + + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP + && child->stop_expected) + { + if (debug_threads) + debug_printf ("Expected stop.\n"); + child->stop_expected = 0; + + if (thread->last_resume_kind == resume_stop) + { + /* We want to report the stop to the core. Treat the + SIGSTOP as a normal event. */ + if (debug_threads) + debug_printf ("LLW: resume_stop SIGSTOP caught for %s.\n", + target_pid_to_str (ptid_of (thread))); + } + else if (stopping_threads != NOT_STOPPING_THREADS) + { + /* Stopping threads. We don't want this SIGSTOP to end up + pending. */ + if (debug_threads) + debug_printf ("LLW: SIGSTOP caught for %s " + "while stopping threads.\n", + target_pid_to_str (ptid_of (thread))); + return NULL; + } + else + { + /* This is a delayed SIGSTOP. Filter out the event. */ + if (debug_threads) + debug_printf ("LLW: %s %s, 0, 0 (discard delayed SIGSTOP)\n", + child->stepping ? "step" : "continue", + target_pid_to_str (ptid_of (thread))); + + linux_resume_one_lwp (child, child->stepping, 0, NULL); + return NULL; + } + } + + child->status_pending_p = 1; + child->status_pending = wstat; + return child; +} + +/* Return true if THREAD is doing hardware single step. */ + +static int +maybe_hw_step (struct thread_info *thread) +{ + if (can_hardware_single_step ()) + return 1; + else + { + /* GDBserver must insert single-step breakpoint for software + single step. */ + gdb_assert (has_single_step_breakpoints (thread)); + return 0; + } +} + +/* Resume LWPs that are currently stopped without any pending status + to report, but are resumed from the core's perspective. */ + +static void +resume_stopped_resumed_lwps (thread_info *thread) +{ + struct lwp_info *lp = get_thread_lwp (thread); + + if (lp->stopped + && !lp->suspended + && !lp->status_pending_p + && thread->last_status.kind == TARGET_WAITKIND_IGNORE) + { + int step = 0; + + if (thread->last_resume_kind == resume_step) + step = maybe_hw_step (thread); + + if (debug_threads) + debug_printf ("RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n", + target_pid_to_str (ptid_of (thread)), + paddress (lp->stop_pc), + step); + + linux_resume_one_lwp (lp, step, GDB_SIGNAL_0, NULL); + } +} + +/* Wait for an event from child(ren) WAIT_PTID, and return any that + match FILTER_PTID (leaving others pending). The PTIDs can be: + minus_one_ptid, to specify any child; a pid PTID, specifying all + lwps of a thread group; or a PTID representing a single lwp. Store + the stop status through the status pointer WSTAT. OPTIONS is + passed to the waitpid call. Return 0 if no event was found and + OPTIONS contains WNOHANG. Return -1 if no unwaited-for children + was found. Return the PID of the stopped child otherwise. */ + +static int +linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, + int *wstatp, int options) +{ + struct thread_info *event_thread; + struct lwp_info *event_child, *requested_child; + sigset_t block_mask, prev_mask; + + retry: + /* N.B. event_thread points to the thread_info struct that contains + event_child. Keep them in sync. */ + event_thread = NULL; + event_child = NULL; + requested_child = NULL; + + /* Check for a lwp with a pending status. */ + + if (filter_ptid == minus_one_ptid || filter_ptid.is_pid ()) + { + event_thread = find_thread_in_random ([&] (thread_info *thread) + { + return status_pending_p_callback (thread, filter_ptid); + }); + + if (event_thread != NULL) + event_child = get_thread_lwp (event_thread); + if (debug_threads && event_thread) + debug_printf ("Got a pending child %ld\n", lwpid_of (event_thread)); + } + else if (filter_ptid != null_ptid) + { + requested_child = find_lwp_pid (filter_ptid); + + if (stopping_threads == NOT_STOPPING_THREADS + && requested_child->status_pending_p + && (requested_child->collecting_fast_tracepoint + != fast_tpoint_collect_result::not_collecting)) + { + enqueue_one_deferred_signal (requested_child, + &requested_child->status_pending); + requested_child->status_pending_p = 0; + requested_child->status_pending = 0; + linux_resume_one_lwp (requested_child, 0, 0, NULL); + } + + if (requested_child->suspended + && requested_child->status_pending_p) + { + internal_error (__FILE__, __LINE__, + "requesting an event out of a" + " suspended child?"); + } + + if (requested_child->status_pending_p) + { + event_child = requested_child; + event_thread = get_lwp_thread (event_child); + } + } + + if (event_child != NULL) + { + if (debug_threads) + debug_printf ("Got an event from pending child %ld (%04x)\n", + lwpid_of (event_thread), event_child->status_pending); + *wstatp = event_child->status_pending; + event_child->status_pending_p = 0; + event_child->status_pending = 0; + current_thread = event_thread; + return lwpid_of (event_thread); + } + + /* But if we don't find a pending event, we'll have to wait. + + We only enter this loop if no process has a pending wait status. + Thus any action taken in response to a wait status inside this + loop is responding as soon as we detect the status, not after any + pending events. */ + + /* Make sure SIGCHLD is blocked until the sigsuspend below. Block + all signals while here. */ + sigfillset (&block_mask); + gdb_sigmask (SIG_BLOCK, &block_mask, &prev_mask); + + /* Always pull all events out of the kernel. We'll randomly select + an event LWP out of all that have events, to prevent + starvation. */ + while (event_child == NULL) + { + pid_t ret = 0; + + /* Always use -1 and WNOHANG, due to couple of a kernel/ptrace + quirks: + + - If the thread group leader exits while other threads in the + thread group still exist, waitpid(TGID, ...) hangs. That + waitpid won't return an exit status until the other threads + in the group are reaped. + + - When a non-leader thread execs, that thread just vanishes + without reporting an exit (so we'd hang if we waited for it + explicitly in that case). The exec event is reported to + the TGID pid. */ + errno = 0; + ret = my_waitpid (-1, wstatp, options | WNOHANG); + + if (debug_threads) + debug_printf ("LWFE: waitpid(-1, ...) returned %d, %s\n", + ret, errno ? safe_strerror (errno) : "ERRNO-OK"); + + if (ret > 0) + { + if (debug_threads) + { + debug_printf ("LLW: waitpid %ld received %s\n", + (long) ret, status_to_str (*wstatp)); + } + + /* Filter all events. IOW, leave all events pending. We'll + randomly select an event LWP out of all that have events + below. */ + linux_low_filter_event (ret, *wstatp); + /* Retry until nothing comes out of waitpid. A single + SIGCHLD can indicate more than one child stopped. */ + continue; + } + + /* Now that we've pulled all events out of the kernel, resume + LWPs that don't have an interesting event to report. */ + if (stopping_threads == NOT_STOPPING_THREADS) + for_each_thread (resume_stopped_resumed_lwps); + + /* ... and find an LWP with a status to report to the core, if + any. */ + event_thread = find_thread_in_random ([&] (thread_info *thread) + { + return status_pending_p_callback (thread, filter_ptid); + }); + + if (event_thread != NULL) + { + event_child = get_thread_lwp (event_thread); + *wstatp = event_child->status_pending; + event_child->status_pending_p = 0; + event_child->status_pending = 0; + break; + } + + /* Check for zombie thread group leaders. Those can't be reaped + until all other threads in the thread group are. */ + check_zombie_leaders (); + + auto not_stopped = [&] (thread_info *thread) + { + return not_stopped_callback (thread, wait_ptid); + }; + + /* If there are no resumed children left in the set of LWPs we + want to wait for, bail. We can't just block in + waitpid/sigsuspend, because lwps might have been left stopped + in trace-stop state, and we'd be stuck forever waiting for + their status to change (which would only happen if we resumed + them). Even if WNOHANG is set, this return code is preferred + over 0 (below), as it is more detailed. */ + if (find_thread (not_stopped) == NULL) + { + if (debug_threads) + debug_printf ("LLW: exit (no unwaited-for LWP)\n"); + gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); + return -1; + } + + /* No interesting event to report to the caller. */ + if ((options & WNOHANG)) + { + if (debug_threads) + debug_printf ("WNOHANG set, no event found\n"); + + gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); + return 0; + } + + /* Block until we get an event reported with SIGCHLD. */ + if (debug_threads) + debug_printf ("sigsuspend'ing\n"); + + sigsuspend (&prev_mask); + gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); + goto retry; + } + + gdb_sigmask (SIG_SETMASK, &prev_mask, NULL); + + current_thread = event_thread; + + return lwpid_of (event_thread); +} + +/* Wait for an event from child(ren) PTID. PTIDs can be: + minus_one_ptid, to specify any child; a pid PTID, specifying all + lwps of a thread group; or a PTID representing a single lwp. Store + the stop status through the status pointer WSTAT. OPTIONS is + passed to the waitpid call. Return 0 if no event was found and + OPTIONS contains WNOHANG. Return -1 if no unwaited-for children + was found. Return the PID of the stopped child otherwise. */ + +static int +linux_wait_for_event (ptid_t ptid, int *wstatp, int options) +{ + return linux_wait_for_event_filtered (ptid, ptid, wstatp, options); +} + +/* Select one LWP out of those that have events pending. */ + +static void +select_event_lwp (struct lwp_info **orig_lp) +{ + struct thread_info *event_thread = NULL; + + /* In all-stop, give preference to the LWP that is being + single-stepped. There will be at most one, and it's the LWP that + the core is most interested in. If we didn't do this, then we'd + have to handle pending step SIGTRAPs somehow in case the core + later continues the previously-stepped thread, otherwise we'd + report the pending SIGTRAP, and the core, not having stepped the + thread, wouldn't understand what the trap was for, and therefore + would report it to the user as a random signal. */ + if (!non_stop) + { + event_thread = find_thread ([] (thread_info *thread) + { + lwp_info *lp = get_thread_lwp (thread); + + return (thread->last_status.kind == TARGET_WAITKIND_IGNORE + && thread->last_resume_kind == resume_step + && lp->status_pending_p); + }); + + if (event_thread != NULL) + { + if (debug_threads) + debug_printf ("SEL: Select single-step %s\n", + target_pid_to_str (ptid_of (event_thread))); + } + } + if (event_thread == NULL) + { + /* No single-stepping LWP. Select one at random, out of those + which have had events. */ + + event_thread = find_thread_in_random ([&] (thread_info *thread) + { + lwp_info *lp = get_thread_lwp (thread); + + /* Only resumed LWPs that have an event pending. */ + return (thread->last_status.kind == TARGET_WAITKIND_IGNORE + && lp->status_pending_p); + }); + } + + if (event_thread != NULL) + { + struct lwp_info *event_lp = get_thread_lwp (event_thread); + + /* Switch the event LWP. */ + *orig_lp = event_lp; + } +} + +/* Decrement the suspend count of all LWPs, except EXCEPT, if non + NULL. */ + +static void +unsuspend_all_lwps (struct lwp_info *except) +{ + for_each_thread ([&] (thread_info *thread) + { + lwp_info *lwp = get_thread_lwp (thread); + + if (lwp != except) + lwp_suspended_decr (lwp); + }); +} + +static void move_out_of_jump_pad_callback (thread_info *thread); +static bool stuck_in_jump_pad_callback (thread_info *thread); +static bool lwp_running (thread_info *thread); +static ptid_t linux_wait_1 (ptid_t ptid, + struct target_waitstatus *ourstatus, + int target_options); + +/* Stabilize threads (move out of jump pads). + + If a thread is midway collecting a fast tracepoint, we need to + finish the collection and move it out of the jump pad before + reporting the signal. + + This avoids recursion while collecting (when a signal arrives + midway, and the signal handler itself collects), which would trash + the trace buffer. In case the user set a breakpoint in a signal + handler, this avoids the backtrace showing the jump pad, etc.. + Most importantly, there are certain things we can't do safely if + threads are stopped in a jump pad (or in its callee's). For + example: + + - starting a new trace run. A thread still collecting the + previous run, could trash the trace buffer when resumed. The trace + buffer control structures would have been reset but the thread had + no way to tell. The thread could even midway memcpy'ing to the + buffer, which would mean that when resumed, it would clobber the + trace buffer that had been set for a new run. + + - we can't rewrite/reuse the jump pads for new tracepoints + safely. Say you do tstart while a thread is stopped midway while + collecting. When the thread is later resumed, it finishes the + collection, and returns to the jump pad, to execute the original + instruction that was under the tracepoint jump at the time the + older run had been started. If the jump pad had been rewritten + since for something else in the new run, the thread would now + execute the wrong / random instructions. */ + +static void +linux_stabilize_threads (void) +{ + thread_info *thread_stuck = find_thread (stuck_in_jump_pad_callback); + + if (thread_stuck != NULL) + { + if (debug_threads) + debug_printf ("can't stabilize, LWP %ld is stuck in jump pad\n", + lwpid_of (thread_stuck)); + return; + } + + thread_info *saved_thread = current_thread; + + stabilizing_threads = 1; + + /* Kick 'em all. */ + for_each_thread (move_out_of_jump_pad_callback); + + /* Loop until all are stopped out of the jump pads. */ + while (find_thread (lwp_running) != NULL) + { + struct target_waitstatus ourstatus; + struct lwp_info *lwp; + int wstat; + + /* Note that we go through the full wait even loop. While + moving threads out of jump pad, we need to be able to step + over internal breakpoints and such. */ + linux_wait_1 (minus_one_ptid, &ourstatus, 0); + + if (ourstatus.kind == TARGET_WAITKIND_STOPPED) + { + lwp = get_thread_lwp (current_thread); + + /* Lock it. */ + lwp_suspended_inc (lwp); + + if (ourstatus.value.sig != GDB_SIGNAL_0 + || current_thread->last_resume_kind == resume_stop) + { + wstat = W_STOPCODE (gdb_signal_to_host (ourstatus.value.sig)); + enqueue_one_deferred_signal (lwp, &wstat); + } + } + } + + unsuspend_all_lwps (NULL); + + stabilizing_threads = 0; + + current_thread = saved_thread; + + if (debug_threads) + { + thread_stuck = find_thread (stuck_in_jump_pad_callback); + + if (thread_stuck != NULL) + debug_printf ("couldn't stabilize, LWP %ld got stuck in jump pad\n", + lwpid_of (thread_stuck)); + } +} + +/* Convenience function that is called when the kernel reports an + event that is not passed out to GDB. */ + +static ptid_t +ignore_event (struct target_waitstatus *ourstatus) +{ + /* If we got an event, there may still be others, as a single + SIGCHLD can indicate more than one child stopped. This forces + another target_wait call. */ + async_file_mark (); + + ourstatus->kind = TARGET_WAITKIND_IGNORE; + return null_ptid; +} + +/* Convenience function that is called when the kernel reports an exit + event. This decides whether to report the event to GDB as a + process exit event, a thread exit event, or to suppress the + event. */ + +static ptid_t +filter_exit_event (struct lwp_info *event_child, + struct target_waitstatus *ourstatus) +{ + client_state &cs = get_client_state (); + struct thread_info *thread = get_lwp_thread (event_child); + ptid_t ptid = ptid_of (thread); + + if (!last_thread_of_process_p (pid_of (thread))) + { + if (cs.report_thread_events) + ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED; + else + ourstatus->kind = TARGET_WAITKIND_IGNORE; + + delete_lwp (event_child); + } + return ptid; +} + +/* Returns 1 if GDB is interested in any event_child syscalls. */ + +static int +gdb_catching_syscalls_p (struct lwp_info *event_child) +{ + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + return !proc->syscalls_to_catch.empty (); +} + +/* Returns 1 if GDB is interested in the event_child syscall. + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ + +static int +gdb_catch_this_syscall_p (struct lwp_info *event_child) +{ + int sysno; + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + if (proc->syscalls_to_catch.empty ()) + return 0; + + if (proc->syscalls_to_catch[0] == ANY_SYSCALL) + return 1; + + get_syscall_trapinfo (event_child, &sysno); + + for (int iter : proc->syscalls_to_catch) + if (iter == sysno) + return 1; + + return 0; +} + +/* Wait for process, returns status. */ + +static ptid_t +linux_wait_1 (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) +{ + client_state &cs = get_client_state (); + int w; + struct lwp_info *event_child; + int options; + int pid; + int step_over_finished; + int bp_explains_trap; + int maybe_internal_trap; + int report_to_gdb; + int trace_event; + int in_step_range; + int any_resumed; + + if (debug_threads) + { + debug_enter (); + debug_printf ("linux_wait_1: [%s]\n", target_pid_to_str (ptid)); + } + + /* Translate generic target options into linux options. */ + options = __WALL; + if (target_options & TARGET_WNOHANG) + options |= WNOHANG; + + bp_explains_trap = 0; + trace_event = 0; + in_step_range = 0; + ourstatus->kind = TARGET_WAITKIND_IGNORE; + + auto status_pending_p_any = [&] (thread_info *thread) + { + return status_pending_p_callback (thread, minus_one_ptid); + }; + + auto not_stopped = [&] (thread_info *thread) + { + return not_stopped_callback (thread, minus_one_ptid); + }; + + /* Find a resumed LWP, if any. */ + if (find_thread (status_pending_p_any) != NULL) + any_resumed = 1; + else if (find_thread (not_stopped) != NULL) + any_resumed = 1; + else + any_resumed = 0; + + if (step_over_bkpt == null_ptid) + pid = linux_wait_for_event (ptid, &w, options); + else + { + if (debug_threads) + debug_printf ("step_over_bkpt set [%s], doing a blocking wait\n", + target_pid_to_str (step_over_bkpt)); + pid = linux_wait_for_event (step_over_bkpt, &w, options & ~WNOHANG); + } + + if (pid == 0 || (pid == -1 && !any_resumed)) + { + gdb_assert (target_options & TARGET_WNOHANG); + + if (debug_threads) + { + debug_printf ("linux_wait_1 ret = null_ptid, " + "TARGET_WAITKIND_IGNORE\n"); + debug_exit (); + } + + ourstatus->kind = TARGET_WAITKIND_IGNORE; + return null_ptid; + } + else if (pid == -1) + { + if (debug_threads) + { + debug_printf ("linux_wait_1 ret = null_ptid, " + "TARGET_WAITKIND_NO_RESUMED\n"); + debug_exit (); + } + + ourstatus->kind = TARGET_WAITKIND_NO_RESUMED; + return null_ptid; + } + + event_child = get_thread_lwp (current_thread); + + /* linux_wait_for_event only returns an exit status for the last + child of a process. Report it. */ + if (WIFEXITED (w) || WIFSIGNALED (w)) + { + if (WIFEXITED (w)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (w); + + if (debug_threads) + { + debug_printf ("linux_wait_1 ret = %s, exited with " + "retcode %d\n", + target_pid_to_str (ptid_of (current_thread)), + WEXITSTATUS (w)); + debug_exit (); + } + } + else + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (w)); + + if (debug_threads) + { + debug_printf ("linux_wait_1 ret = %s, terminated with " + "signal %d\n", + target_pid_to_str (ptid_of (current_thread)), + WTERMSIG (w)); + debug_exit (); + } + } + + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + return filter_exit_event (event_child, ourstatus); + + return ptid_of (current_thread); + } + + /* If step-over executes a breakpoint instruction, in the case of a + hardware single step it means a gdb/gdbserver breakpoint had been + planted on top of a permanent breakpoint, in the case of a software + single step it may just mean that gdbserver hit the reinsert breakpoint. + The PC has been adjusted by save_stop_reason to point at + the breakpoint address. + So in the case of the hardware single step advance the PC manually + past the breakpoint and in the case of software single step advance only + if it's not the single_step_breakpoint we are hitting. + This avoids that a program would keep trapping a permanent breakpoint + forever. */ + if (step_over_bkpt != null_ptid + && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && (event_child->stepping + || !single_step_breakpoint_inserted_here (event_child->stop_pc))) + { + int increment_pc = 0; + int breakpoint_kind = 0; + CORE_ADDR stop_pc = event_child->stop_pc; + + breakpoint_kind = + the_target->breakpoint_kind_from_current_state (&stop_pc); + the_target->sw_breakpoint_from_kind (breakpoint_kind, &increment_pc); + + if (debug_threads) + { + debug_printf ("step-over for %s executed software breakpoint\n", + target_pid_to_str (ptid_of (current_thread))); + } + + if (increment_pc != 0) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + + event_child->stop_pc += increment_pc; + (*the_low_target.set_pc) (regcache, event_child->stop_pc); + + if (!(*the_low_target.breakpoint_at) (event_child->stop_pc)) + event_child->stop_reason = TARGET_STOPPED_BY_NO_REASON; + } + } + + /* If this event was not handled before, and is not a SIGTRAP, we + report it. SIGILL and SIGSEGV are also treated as traps in case + a breakpoint is inserted at the current PC. If this target does + not support internal breakpoints at all, we also report the + SIGTRAP without further processing; it's of no concern to us. */ + maybe_internal_trap + = (supports_breakpoints () + && (WSTOPSIG (w) == SIGTRAP + || ((WSTOPSIG (w) == SIGILL + || WSTOPSIG (w) == SIGSEGV) + && (*the_low_target.breakpoint_at) (event_child->stop_pc)))); + + if (maybe_internal_trap) + { + /* Handle anything that requires bookkeeping before deciding to + report the event or continue waiting. */ + + /* First check if we can explain the SIGTRAP with an internal + breakpoint, or if we should possibly report the event to GDB. + Do this before anything that may remove or insert a + breakpoint. */ + bp_explains_trap = breakpoint_inserted_here (event_child->stop_pc); + + /* We have a SIGTRAP, possibly a step-over dance has just + finished. If so, tweak the state machine accordingly, + reinsert breakpoints and delete any single-step + breakpoints. */ + step_over_finished = finish_step_over (event_child); + + /* Now invoke the callbacks of any internal breakpoints there. */ + check_breakpoints (event_child->stop_pc); + + /* Handle tracepoint data collecting. This may overflow the + trace buffer, and cause a tracing stop, removing + breakpoints. */ + trace_event = handle_tracepoints (event_child); + + if (bp_explains_trap) + { + if (debug_threads) + debug_printf ("Hit a gdbserver breakpoint.\n"); + } + } + else + { + /* We have some other signal, possibly a step-over dance was in + progress, and it should be cancelled too. */ + step_over_finished = finish_step_over (event_child); + } + + /* We have all the data we need. Either report the event to GDB, or + resume threads and keep waiting for more. */ + + /* If we're collecting a fast tracepoint, finish the collection and + move out of the jump pad before delivering a signal. See + linux_stabilize_threads. */ + + if (WIFSTOPPED (w) + && WSTOPSIG (w) != SIGTRAP + && supports_fast_tracepoints () + && agent_loaded_p ()) + { + if (debug_threads) + debug_printf ("Got signal %d for LWP %ld. Check if we need " + "to defer or adjust it.\n", + WSTOPSIG (w), lwpid_of (current_thread)); + + /* Allow debugging the jump pad itself. */ + if (current_thread->last_resume_kind != resume_step + && maybe_move_out_of_jump_pad (event_child, &w)) + { + enqueue_one_deferred_signal (event_child, &w); + + if (debug_threads) + debug_printf ("Signal %d for LWP %ld deferred (in jump pad)\n", + WSTOPSIG (w), lwpid_of (current_thread)); + + linux_resume_one_lwp (event_child, 0, 0, NULL); + + if (debug_threads) + debug_exit (); + return ignore_event (ourstatus); + } + } + + if (event_child->collecting_fast_tracepoint + != fast_tpoint_collect_result::not_collecting) + { + if (debug_threads) + debug_printf ("LWP %ld was trying to move out of the jump pad (%d). " + "Check if we're already there.\n", + lwpid_of (current_thread), + (int) event_child->collecting_fast_tracepoint); + + trace_event = 1; + + event_child->collecting_fast_tracepoint + = linux_fast_tracepoint_collecting (event_child, NULL); + + if (event_child->collecting_fast_tracepoint + != fast_tpoint_collect_result::before_insn) + { + /* No longer need this breakpoint. */ + if (event_child->exit_jump_pad_bkpt != NULL) + { + if (debug_threads) + debug_printf ("No longer need exit-jump-pad bkpt; removing it." + "stopping all threads momentarily.\n"); + + /* Other running threads could hit this breakpoint. + We don't handle moribund locations like GDB does, + instead we always pause all threads when removing + breakpoints, so that any step-over or + decr_pc_after_break adjustment is always taken + care of while the breakpoint is still + inserted. */ + stop_all_lwps (1, event_child); + + delete_breakpoint (event_child->exit_jump_pad_bkpt); + event_child->exit_jump_pad_bkpt = NULL; + + unstop_all_lwps (1, event_child); + + gdb_assert (event_child->suspended >= 0); + } + } + + if (event_child->collecting_fast_tracepoint + == fast_tpoint_collect_result::not_collecting) + { + if (debug_threads) + debug_printf ("fast tracepoint finished " + "collecting successfully.\n"); + + /* We may have a deferred signal to report. */ + if (dequeue_one_deferred_signal (event_child, &w)) + { + if (debug_threads) + debug_printf ("dequeued one signal.\n"); + } + else + { + if (debug_threads) + debug_printf ("no deferred signals.\n"); + + if (stabilizing_threads) + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = GDB_SIGNAL_0; + + if (debug_threads) + { + debug_printf ("linux_wait_1 ret = %s, stopped " + "while stabilizing threads\n", + target_pid_to_str (ptid_of (current_thread))); + debug_exit (); + } + + return ptid_of (current_thread); + } + } + } + } + + /* Check whether GDB would be interested in this event. */ + + /* Check if GDB is interested in this syscall. */ + if (WIFSTOPPED (w) + && WSTOPSIG (w) == SYSCALL_SIGTRAP + && !gdb_catch_this_syscall_p (event_child)) + { + if (debug_threads) + { + debug_printf ("Ignored syscall for LWP %ld.\n", + lwpid_of (current_thread)); + } + + linux_resume_one_lwp (event_child, event_child->stepping, + 0, NULL); + + if (debug_threads) + debug_exit (); + return ignore_event (ourstatus); + } + + /* If GDB is not interested in this signal, don't stop other + threads, and don't report it to GDB. Just resume the inferior + right away. We do this for threading-related signals as well as + any that GDB specifically requested we ignore. But never ignore + SIGSTOP if we sent it ourselves, and do not ignore signals when + stepping - they may require special handling to skip the signal + handler. Also never ignore signals that could be caused by a + breakpoint. */ + if (WIFSTOPPED (w) + && current_thread->last_resume_kind != resume_step + && ( +#if defined (USE_THREAD_DB) && !defined (__ANDROID__) + (current_process ()->priv->thread_db != NULL + && (WSTOPSIG (w) == __SIGRTMIN + || WSTOPSIG (w) == __SIGRTMIN + 1)) + || +#endif + (cs.pass_signals[gdb_signal_from_host (WSTOPSIG (w))] + && !(WSTOPSIG (w) == SIGSTOP + && current_thread->last_resume_kind == resume_stop) + && !linux_wstatus_maybe_breakpoint (w)))) + { + siginfo_t info, *info_p; + + if (debug_threads) + debug_printf ("Ignored signal %d for LWP %ld.\n", + WSTOPSIG (w), lwpid_of (current_thread)); + + if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), + (PTRACE_TYPE_ARG3) 0, &info) == 0) + info_p = &info; + else + info_p = NULL; + + if (step_over_finished) + { + /* We cancelled this thread's step-over above. We still + need to unsuspend all other LWPs, and set them back + running again while the signal handler runs. */ + unsuspend_all_lwps (event_child); + + /* Enqueue the pending signal info so that proceed_all_lwps + doesn't lose it. */ + enqueue_pending_signal (event_child, WSTOPSIG (w), info_p); + + proceed_all_lwps (); + } + else + { + linux_resume_one_lwp (event_child, event_child->stepping, + WSTOPSIG (w), info_p); + } + + if (debug_threads) + debug_exit (); + + return ignore_event (ourstatus); + } + + /* Note that all addresses are always "out of the step range" when + there's no range to begin with. */ + in_step_range = lwp_in_step_range (event_child); + + /* If GDB wanted this thread to single step, and the thread is out + of the step range, we always want to report the SIGTRAP, and let + GDB handle it. Watchpoints should always be reported. So should + signals we can't explain. A SIGTRAP we can't explain could be a + GDB breakpoint --- we may or not support Z0 breakpoints. If we + do, we're be able to handle GDB breakpoints on top of internal + breakpoints, by handling the internal breakpoint and still + reporting the event to GDB. If we don't, we're out of luck, GDB + won't see the breakpoint hit. If we see a single-step event but + the thread should be continuing, don't pass the trap to gdb. + That indicates that we had previously finished a single-step but + left the single-step pending -- see + complete_ongoing_step_over. */ + report_to_gdb = (!maybe_internal_trap + || (current_thread->last_resume_kind == resume_step + && !in_step_range) + || event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT + || (!in_step_range + && !bp_explains_trap + && !trace_event + && !step_over_finished + && !(current_thread->last_resume_kind == resume_continue + && event_child->stop_reason == TARGET_STOPPED_BY_SINGLE_STEP)) + || (gdb_breakpoint_here (event_child->stop_pc) + && gdb_condition_true_at_breakpoint (event_child->stop_pc) + && gdb_no_commands_at_breakpoint (event_child->stop_pc)) + || event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE); + + run_breakpoint_commands (event_child->stop_pc); + + /* We found no reason GDB would want us to stop. We either hit one + of our own breakpoints, or finished an internal step GDB + shouldn't know about. */ + if (!report_to_gdb) + { + if (debug_threads) + { + if (bp_explains_trap) + debug_printf ("Hit a gdbserver breakpoint.\n"); + if (step_over_finished) + debug_printf ("Step-over finished.\n"); + if (trace_event) + debug_printf ("Tracepoint event.\n"); + if (lwp_in_step_range (event_child)) + debug_printf ("Range stepping pc 0x%s [0x%s, 0x%s).\n", + paddress (event_child->stop_pc), + paddress (event_child->step_range_start), + paddress (event_child->step_range_end)); + } + + /* We're not reporting this breakpoint to GDB, so apply the + decr_pc_after_break adjustment to the inferior's regcache + ourselves. */ + + if (the_low_target.set_pc != NULL) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + (*the_low_target.set_pc) (regcache, event_child->stop_pc); + } + + if (step_over_finished) + { + /* If we have finished stepping over a breakpoint, we've + stopped and suspended all LWPs momentarily except the + stepping one. This is where we resume them all again. + We're going to keep waiting, so use proceed, which + handles stepping over the next breakpoint. */ + unsuspend_all_lwps (event_child); + } + else + { + /* Remove the single-step breakpoints if any. Note that + there isn't single-step breakpoint if we finished stepping + over. */ + if (can_software_single_step () + && has_single_step_breakpoints (current_thread)) + { + stop_all_lwps (0, event_child); + delete_single_step_breakpoints (current_thread); + unstop_all_lwps (0, event_child); + } + } + + if (debug_threads) + debug_printf ("proceeding all threads.\n"); + proceed_all_lwps (); + + if (debug_threads) + debug_exit (); + + return ignore_event (ourstatus); + } + + if (debug_threads) + { + if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) + { + std::string str + = target_waitstatus_to_string (&event_child->waitstatus); + + debug_printf ("LWP %ld: extended event with waitstatus %s\n", + lwpid_of (get_lwp_thread (event_child)), str.c_str ()); + } + if (current_thread->last_resume_kind == resume_step) + { + if (event_child->step_range_start == event_child->step_range_end) + debug_printf ("GDB wanted to single-step, reporting event.\n"); + else if (!lwp_in_step_range (event_child)) + debug_printf ("Out of step range, reporting event.\n"); + } + if (event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT) + debug_printf ("Stopped by watchpoint.\n"); + else if (gdb_breakpoint_here (event_child->stop_pc)) + debug_printf ("Stopped by GDB breakpoint.\n"); + if (debug_threads) + debug_printf ("Hit a non-gdbserver trap event.\n"); + } + + /* Alright, we're going to report a stop. */ + + /* Remove single-step breakpoints. */ + if (can_software_single_step ()) + { + /* Remove single-step breakpoints or not. It it is true, stop all + lwps, so that other threads won't hit the breakpoint in the + staled memory. */ + int remove_single_step_breakpoints_p = 0; + + if (non_stop) + { + remove_single_step_breakpoints_p + = has_single_step_breakpoints (current_thread); + } + else + { + /* In all-stop, a stop reply cancels all previous resume + requests. Delete all single-step breakpoints. */ + + find_thread ([&] (thread_info *thread) { + if (has_single_step_breakpoints (thread)) + { + remove_single_step_breakpoints_p = 1; + return true; + } + + return false; + }); + } + + if (remove_single_step_breakpoints_p) + { + /* If we remove single-step breakpoints from memory, stop all lwps, + so that other threads won't hit the breakpoint in the staled + memory. */ + stop_all_lwps (0, event_child); + + if (non_stop) + { + gdb_assert (has_single_step_breakpoints (current_thread)); + delete_single_step_breakpoints (current_thread); + } + else + { + for_each_thread ([] (thread_info *thread){ + if (has_single_step_breakpoints (thread)) + delete_single_step_breakpoints (thread); + }); + } + + unstop_all_lwps (0, event_child); + } + } + + if (!stabilizing_threads) + { + /* In all-stop, stop all threads. */ + if (!non_stop) + stop_all_lwps (0, NULL); + + if (step_over_finished) + { + if (!non_stop) + { + /* If we were doing a step-over, all other threads but + the stepping one had been paused in start_step_over, + with their suspend counts incremented. We don't want + to do a full unstop/unpause, because we're in + all-stop mode (so we want threads stopped), but we + still need to unsuspend the other threads, to + decrement their `suspended' count back. */ + unsuspend_all_lwps (event_child); + } + else + { + /* If we just finished a step-over, then all threads had + been momentarily paused. In all-stop, that's fine, + we want threads stopped by now anyway. In non-stop, + we need to re-resume threads that GDB wanted to be + running. */ + unstop_all_lwps (1, event_child); + } + } + + /* If we're not waiting for a specific LWP, choose an event LWP + from among those that have had events. Giving equal priority + to all LWPs that have had events helps prevent + starvation. */ + if (ptid == minus_one_ptid) + { + event_child->status_pending_p = 1; + event_child->status_pending = w; + + select_event_lwp (&event_child); + + /* current_thread and event_child must stay in sync. */ + current_thread = get_lwp_thread (event_child); + + event_child->status_pending_p = 0; + w = event_child->status_pending; + } + + + /* Stabilize threads (move out of jump pads). */ + if (!non_stop) + stabilize_threads (); + } + else + { + /* If we just finished a step-over, then all threads had been + momentarily paused. In all-stop, that's fine, we want + threads stopped by now anyway. In non-stop, we need to + re-resume threads that GDB wanted to be running. */ + if (step_over_finished) + unstop_all_lwps (1, event_child); + } + + if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) + { + /* If the reported event is an exit, fork, vfork or exec, let + GDB know. */ + + /* Break the unreported fork relationship chain. */ + if (event_child->waitstatus.kind == TARGET_WAITKIND_FORKED + || event_child->waitstatus.kind == TARGET_WAITKIND_VFORKED) + { + event_child->fork_relative->fork_relative = NULL; + event_child->fork_relative = NULL; + } + + *ourstatus = event_child->waitstatus; + /* Clear the event lwp's waitstatus since we handled it already. */ + event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE; + } + else + ourstatus->kind = TARGET_WAITKIND_STOPPED; + + /* Now that we've selected our final event LWP, un-adjust its PC if + it was a software breakpoint, and the client doesn't know we can + adjust the breakpoint ourselves. */ + if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && !cs.swbreak_feature) + { + int decr_pc = the_low_target.decr_pc_after_break; + + if (decr_pc != 0) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + (*the_low_target.set_pc) (regcache, event_child->stop_pc + decr_pc); + } + } + + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) + { + get_syscall_trapinfo (event_child, + &ourstatus->value.syscall_number); + ourstatus->kind = event_child->syscall_state; + } + else if (current_thread->last_resume_kind == resume_stop + && WSTOPSIG (w) == SIGSTOP) + { + /* A thread that has been requested to stop by GDB with vCont;t, + and it stopped cleanly, so report as SIG0. The use of + SIGSTOP is an implementation detail. */ + ourstatus->value.sig = GDB_SIGNAL_0; + } + else if (current_thread->last_resume_kind == resume_stop + && WSTOPSIG (w) != SIGSTOP) + { + /* A thread that has been requested to stop by GDB with vCont;t, + but, it stopped for other reasons. */ + ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w)); + } + else if (ourstatus->kind == TARGET_WAITKIND_STOPPED) + { + ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w)); + } + + gdb_assert (step_over_bkpt == null_ptid); + + if (debug_threads) + { + debug_printf ("linux_wait_1 ret = %s, %d, %d\n", + target_pid_to_str (ptid_of (current_thread)), + ourstatus->kind, ourstatus->value.sig); + debug_exit (); + } + + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + return filter_exit_event (event_child, ourstatus); + + return ptid_of (current_thread); +} + +/* Get rid of any pending event in the pipe. */ +static void +async_file_flush (void) +{ + int ret; + char buf; + + do + ret = read (linux_event_pipe[0], &buf, 1); + while (ret >= 0 || (ret == -1 && errno == EINTR)); +} + +/* Put something in the pipe, so the event loop wakes up. */ +static void +async_file_mark (void) +{ + int ret; + + async_file_flush (); + + do + ret = write (linux_event_pipe[1], "+", 1); + while (ret == 0 || (ret == -1 && errno == EINTR)); + + /* Ignore EAGAIN. If the pipe is full, the event loop will already + be awakened anyway. */ +} + +static ptid_t +linux_wait (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) +{ + ptid_t event_ptid; + + /* Flush the async file first. */ + if (target_is_async_p ()) + async_file_flush (); + + do + { + event_ptid = linux_wait_1 (ptid, ourstatus, target_options); + } + while ((target_options & TARGET_WNOHANG) == 0 + && event_ptid == null_ptid + && ourstatus->kind == TARGET_WAITKIND_IGNORE); + + /* If at least one stop was reported, there may be more. A single + SIGCHLD can signal more than one child stop. */ + if (target_is_async_p () + && (target_options & TARGET_WNOHANG) != 0 + && event_ptid != null_ptid) + async_file_mark (); + + return event_ptid; +} + +/* Send a signal to an LWP. */ + +static int +kill_lwp (unsigned long lwpid, int signo) +{ + int ret; + + errno = 0; + ret = syscall (__NR_tkill, lwpid, signo); + if (errno == ENOSYS) + { + /* If tkill fails, then we are not using nptl threads, a + configuration we no longer support. */ + perror_with_name (("tkill")); + } + return ret; +} + +void +linux_stop_lwp (struct lwp_info *lwp) +{ + send_sigstop (lwp); +} + +static void +send_sigstop (struct lwp_info *lwp) +{ + int pid; + + pid = lwpid_of (get_lwp_thread (lwp)); + + /* If we already have a pending stop signal for this process, don't + send another. */ + if (lwp->stop_expected) + { + if (debug_threads) + debug_printf ("Have pending sigstop for lwp %d\n", pid); + + return; + } + + if (debug_threads) + debug_printf ("Sending sigstop to lwp %d\n", pid); + + lwp->stop_expected = 1; + kill_lwp (pid, SIGSTOP); +} + +static void +send_sigstop (thread_info *thread, lwp_info *except) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + /* Ignore EXCEPT. */ + if (lwp == except) + return; + + if (lwp->stopped) + return; + + send_sigstop (lwp); +} + +/* Increment the suspend count of an LWP, and stop it, if not stopped + yet. */ +static void +suspend_and_send_sigstop (thread_info *thread, lwp_info *except) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + /* Ignore EXCEPT. */ + if (lwp == except) + return; + + lwp_suspended_inc (lwp); + + send_sigstop (thread, except); +} + +static void +mark_lwp_dead (struct lwp_info *lwp, int wstat) +{ + /* Store the exit status for later. */ + lwp->status_pending_p = 1; + lwp->status_pending = wstat; + + /* Store in waitstatus as well, as there's nothing else to process + for this event. */ + if (WIFEXITED (wstat)) + { + lwp->waitstatus.kind = TARGET_WAITKIND_EXITED; + lwp->waitstatus.value.integer = WEXITSTATUS (wstat); + } + else if (WIFSIGNALED (wstat)) + { + lwp->waitstatus.kind = TARGET_WAITKIND_SIGNALLED; + lwp->waitstatus.value.sig = gdb_signal_from_host (WTERMSIG (wstat)); + } + + /* Prevent trying to stop it. */ + lwp->stopped = 1; + + /* No further stops are expected from a dead lwp. */ + lwp->stop_expected = 0; +} + +/* Return true if LWP has exited already, and has a pending exit event + to report to GDB. */ + +static int +lwp_is_marked_dead (struct lwp_info *lwp) +{ + return (lwp->status_pending_p + && (WIFEXITED (lwp->status_pending) + || WIFSIGNALED (lwp->status_pending))); +} + +/* Wait for all children to stop for the SIGSTOPs we just queued. */ + +static void +wait_for_sigstop (void) +{ + struct thread_info *saved_thread; + ptid_t saved_tid; + int wstat; + int ret; + + saved_thread = current_thread; + if (saved_thread != NULL) + saved_tid = saved_thread->id; + else + saved_tid = null_ptid; /* avoid bogus unused warning */ + + if (debug_threads) + debug_printf ("wait_for_sigstop: pulling events\n"); + + /* Passing NULL_PTID as filter indicates we want all events to be + left pending. Eventually this returns when there are no + unwaited-for children left. */ + ret = linux_wait_for_event_filtered (minus_one_ptid, null_ptid, + &wstat, __WALL); + gdb_assert (ret == -1); + + if (saved_thread == NULL || linux_thread_alive (saved_tid)) + current_thread = saved_thread; + else + { + if (debug_threads) + debug_printf ("Previously current thread died.\n"); + + /* We can't change the current inferior behind GDB's back, + otherwise, a subsequent command may apply to the wrong + process. */ + current_thread = NULL; + } +} + +/* Returns true if THREAD is stopped in a jump pad, and we can't + move it out, because we need to report the stop event to GDB. For + example, if the user puts a breakpoint in the jump pad, it's + because she wants to debug it. */ + +static bool +stuck_in_jump_pad_callback (thread_info *thread) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + if (lwp->suspended != 0) + { + internal_error (__FILE__, __LINE__, + "LWP %ld is suspended, suspended=%d\n", + lwpid_of (thread), lwp->suspended); + } + gdb_assert (lwp->stopped); + + /* Allow debugging the jump pad, gdb_collect, etc.. */ + return (supports_fast_tracepoints () + && agent_loaded_p () + && (gdb_breakpoint_here (lwp->stop_pc) + || lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT + || thread->last_resume_kind == resume_step) + && (linux_fast_tracepoint_collecting (lwp, NULL) + != fast_tpoint_collect_result::not_collecting)); +} + +static void +move_out_of_jump_pad_callback (thread_info *thread) +{ + struct thread_info *saved_thread; + struct lwp_info *lwp = get_thread_lwp (thread); + int *wstat; + + if (lwp->suspended != 0) + { + internal_error (__FILE__, __LINE__, + "LWP %ld is suspended, suspended=%d\n", + lwpid_of (thread), lwp->suspended); + } + gdb_assert (lwp->stopped); + + /* For gdb_breakpoint_here. */ + saved_thread = current_thread; + current_thread = thread; + + wstat = lwp->status_pending_p ? &lwp->status_pending : NULL; + + /* Allow debugging the jump pad, gdb_collect, etc. */ + if (!gdb_breakpoint_here (lwp->stop_pc) + && lwp->stop_reason != TARGET_STOPPED_BY_WATCHPOINT + && thread->last_resume_kind != resume_step + && maybe_move_out_of_jump_pad (lwp, wstat)) + { + if (debug_threads) + debug_printf ("LWP %ld needs stabilizing (in jump pad)\n", + lwpid_of (thread)); + + if (wstat) + { + lwp->status_pending_p = 0; + enqueue_one_deferred_signal (lwp, wstat); + + if (debug_threads) + debug_printf ("Signal %d for LWP %ld deferred " + "(in jump pad)\n", + WSTOPSIG (*wstat), lwpid_of (thread)); + } + + linux_resume_one_lwp (lwp, 0, 0, NULL); + } + else + lwp_suspended_inc (lwp); + + current_thread = saved_thread; +} + +static bool +lwp_running (thread_info *thread) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + if (lwp_is_marked_dead (lwp)) + return false; + + return !lwp->stopped; +} + +/* Stop all lwps that aren't stopped yet, except EXCEPT, if not NULL. + If SUSPEND, then also increase the suspend count of every LWP, + except EXCEPT. */ + +static void +stop_all_lwps (int suspend, struct lwp_info *except) +{ + /* Should not be called recursively. */ + gdb_assert (stopping_threads == NOT_STOPPING_THREADS); + + if (debug_threads) + { + debug_enter (); + debug_printf ("stop_all_lwps (%s, except=%s)\n", + suspend ? "stop-and-suspend" : "stop", + except != NULL + ? target_pid_to_str (ptid_of (get_lwp_thread (except))) + : "none"); + } + + stopping_threads = (suspend + ? STOPPING_AND_SUSPENDING_THREADS + : STOPPING_THREADS); + + if (suspend) + for_each_thread ([&] (thread_info *thread) + { + suspend_and_send_sigstop (thread, except); + }); + else + for_each_thread ([&] (thread_info *thread) + { + send_sigstop (thread, except); + }); + + wait_for_sigstop (); + stopping_threads = NOT_STOPPING_THREADS; + + if (debug_threads) + { + debug_printf ("stop_all_lwps done, setting stopping_threads " + "back to !stopping\n"); + debug_exit (); + } +} + +/* Enqueue one signal in the chain of signals which need to be + delivered to this process on next resume. */ + +static void +enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info) +{ + struct pending_signals *p_sig = XNEW (struct pending_signals); + + p_sig->prev = lwp->pending_signals; + p_sig->signal = signal; + if (info == NULL) + memset (&p_sig->info, 0, sizeof (siginfo_t)); + else + memcpy (&p_sig->info, info, sizeof (siginfo_t)); + lwp->pending_signals = p_sig; +} + +/* Install breakpoints for software single stepping. */ + +static void +install_software_single_step_breakpoints (struct lwp_info *lwp) +{ + struct thread_info *thread = get_lwp_thread (lwp); + struct regcache *regcache = get_thread_regcache (thread, 1); + + scoped_restore save_current_thread = make_scoped_restore (¤t_thread); + + current_thread = thread; + std::vector next_pcs = the_low_target.get_next_pcs (regcache); + + for (CORE_ADDR pc : next_pcs) + set_single_step_breakpoint (pc, current_ptid); +} + +/* Single step via hardware or software single step. + Return 1 if hardware single stepping, 0 if software single stepping + or can't single step. */ + +static int +single_step (struct lwp_info* lwp) +{ + int step = 0; + + if (can_hardware_single_step ()) + { + step = 1; + } + else if (can_software_single_step ()) + { + install_software_single_step_breakpoints (lwp); + step = 0; + } + else + { + if (debug_threads) + debug_printf ("stepping is not implemented on this target"); + } + + return step; +} + +/* The signal can be delivered to the inferior if we are not trying to + finish a fast tracepoint collect. Since signal can be delivered in + the step-over, the program may go to signal handler and trap again + after return from the signal handler. We can live with the spurious + double traps. */ + +static int +lwp_signal_can_be_delivered (struct lwp_info *lwp) +{ + return (lwp->collecting_fast_tracepoint + == fast_tpoint_collect_result::not_collecting); +} + +/* Resume execution of LWP. If STEP is nonzero, single-step it. If + SIGNAL is nonzero, give it that signal. */ + +static void +linux_resume_one_lwp_throw (struct lwp_info *lwp, + int step, int signal, siginfo_t *info) +{ + struct thread_info *thread = get_lwp_thread (lwp); + struct thread_info *saved_thread; + int ptrace_request; + struct process_info *proc = get_thread_process (thread); + + /* Note that target description may not be initialised + (proc->tdesc == NULL) at this point because the program hasn't + stopped at the first instruction yet. It means GDBserver skips + the extra traps from the wrapper program (see option --wrapper). + Code in this function that requires register access should be + guarded by proc->tdesc == NULL or something else. */ + + if (lwp->stopped == 0) + return; + + gdb_assert (lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + + fast_tpoint_collect_result fast_tp_collecting + = lwp->collecting_fast_tracepoint; + + gdb_assert (!stabilizing_threads + || (fast_tp_collecting + != fast_tpoint_collect_result::not_collecting)); + + /* Cancel actions that rely on GDB not changing the PC (e.g., the + user used the "jump" command, or "set $pc = foo"). */ + if (thread->while_stepping != NULL && lwp->stop_pc != get_pc (lwp)) + { + /* Collecting 'while-stepping' actions doesn't make sense + anymore. */ + release_while_stepping_state_list (thread); + } + + /* If we have pending signals or status, and a new signal, enqueue the + signal. Also enqueue the signal if it can't be delivered to the + inferior right now. */ + if (signal != 0 + && (lwp->status_pending_p + || lwp->pending_signals != NULL + || !lwp_signal_can_be_delivered (lwp))) + { + enqueue_pending_signal (lwp, signal, info); + + /* Postpone any pending signal. It was enqueued above. */ + signal = 0; + } + + if (lwp->status_pending_p) + { + if (debug_threads) + debug_printf ("Not resuming lwp %ld (%s, stop %s);" + " has pending status\n", + lwpid_of (thread), step ? "step" : "continue", + lwp->stop_expected ? "expected" : "not expected"); + return; + } + + saved_thread = current_thread; + current_thread = thread; + + /* This bit needs some thinking about. If we get a signal that + we must report while a single-step reinsert is still pending, + we often end up resuming the thread. It might be better to + (ew) allow a stack of pending events; then we could be sure that + the reinsert happened right away and not lose any signals. + + Making this stack would also shrink the window in which breakpoints are + uninserted (see comment in linux_wait_for_lwp) but not enough for + complete correctness, so it won't solve that problem. It may be + worthwhile just to solve this one, however. */ + if (lwp->bp_reinsert != 0) + { + if (debug_threads) + debug_printf (" pending reinsert at 0x%s\n", + paddress (lwp->bp_reinsert)); + + if (can_hardware_single_step ()) + { + if (fast_tp_collecting == fast_tpoint_collect_result::not_collecting) + { + if (step == 0) + warning ("BAD - reinserting but not stepping."); + if (lwp->suspended) + warning ("BAD - reinserting and suspended(%d).", + lwp->suspended); + } + } + + step = maybe_hw_step (thread); + } + + if (fast_tp_collecting == fast_tpoint_collect_result::before_insn) + { + if (debug_threads) + debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad" + " (exit-jump-pad-bkpt)\n", + lwpid_of (thread)); + } + else if (fast_tp_collecting == fast_tpoint_collect_result::at_insn) + { + if (debug_threads) + debug_printf ("lwp %ld wants to get out of fast tracepoint jump pad" + " single-stepping\n", + lwpid_of (thread)); + + if (can_hardware_single_step ()) + step = 1; + else + { + internal_error (__FILE__, __LINE__, + "moving out of jump pad single-stepping" + " not implemented on this target"); + } + } + + /* If we have while-stepping actions in this thread set it stepping. + If we have a signal to deliver, it may or may not be set to + SIG_IGN, we don't know. Assume so, and allow collecting + while-stepping into a signal handler. A possible smart thing to + do would be to set an internal breakpoint at the signal return + address, continue, and carry on catching this while-stepping + action only when that breakpoint is hit. A future + enhancement. */ + if (thread->while_stepping != NULL) + { + if (debug_threads) + debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n", + lwpid_of (thread)); + + step = single_step (lwp); + } + + if (proc->tdesc != NULL && the_low_target.get_pc != NULL) + { + struct regcache *regcache = get_thread_regcache (current_thread, 1); + + lwp->stop_pc = (*the_low_target.get_pc) (regcache); + + if (debug_threads) + { + debug_printf (" %s from pc 0x%lx\n", step ? "step" : "continue", + (long) lwp->stop_pc); + } + } + + /* If we have pending signals, consume one if it can be delivered to + the inferior. */ + if (lwp->pending_signals != NULL && lwp_signal_can_be_delivered (lwp)) + { + struct pending_signals **p_sig; + + p_sig = &lwp->pending_signals; + while ((*p_sig)->prev != NULL) + p_sig = &(*p_sig)->prev; + + signal = (*p_sig)->signal; + if ((*p_sig)->info.si_signo != 0) + ptrace (PTRACE_SETSIGINFO, lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, + &(*p_sig)->info); + + free (*p_sig); + *p_sig = NULL; + } + + if (debug_threads) + debug_printf ("Resuming lwp %ld (%s, signal %d, stop %s)\n", + lwpid_of (thread), step ? "step" : "continue", signal, + lwp->stop_expected ? "expected" : "not expected"); + + if (the_low_target.prepare_to_resume != NULL) + the_low_target.prepare_to_resume (lwp); + + regcache_invalidate_thread (thread); + errno = 0; + lwp->stepping = step; + if (step) + ptrace_request = PTRACE_SINGLESTEP; + else if (gdb_catching_syscalls_p (lwp)) + ptrace_request = PTRACE_SYSCALL; + else + ptrace_request = PTRACE_CONT; + ptrace (ptrace_request, + lwpid_of (thread), + (PTRACE_TYPE_ARG3) 0, + /* Coerce to a uintptr_t first to avoid potential gcc warning + of coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_TYPE_ARG4) (uintptr_t) signal); + + current_thread = saved_thread; + if (errno) + perror_with_name ("resuming thread"); + + /* Successfully resumed. Clear state that no longer makes sense, + and mark the LWP as running. Must not do this before resuming + otherwise if that fails other code will be confused. E.g., we'd + later try to stop the LWP and hang forever waiting for a stop + status. Note that we must not throw after this is cleared, + otherwise handle_zombie_lwp_error would get confused. */ + lwp->stopped = 0; + lwp->stop_reason = TARGET_STOPPED_BY_NO_REASON; +} + +/* Called when we try to resume a stopped LWP and that errors out. If + the LWP is no longer in ptrace-stopped state (meaning it's zombie, + or about to become), discard the error, clear any pending status + the LWP may have, and return true (we'll collect the exit status + soon enough). Otherwise, return false. */ + +static int +check_ptrace_stopped_lwp_gone (struct lwp_info *lp) +{ + struct thread_info *thread = get_lwp_thread (lp); + + /* If we get an error after resuming the LWP successfully, we'd + confuse !T state for the LWP being gone. */ + gdb_assert (lp->stopped); + + /* We can't just check whether the LWP is in 'Z (Zombie)' state, + because even if ptrace failed with ESRCH, the tracee may be "not + yet fully dead", but already refusing ptrace requests. In that + case the tracee has 'R (Running)' state for a little bit + (observed in Linux 3.18). See also the note on ESRCH in the + ptrace(2) man page. Instead, check whether the LWP has any state + other than ptrace-stopped. */ + + /* Don't assume anything if /proc/PID/status can't be read. */ + if (linux_proc_pid_is_trace_stopped_nowarn (lwpid_of (thread)) == 0) + { + lp->stop_reason = TARGET_STOPPED_BY_NO_REASON; + lp->status_pending_p = 0; + return 1; + } + return 0; +} + +/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP + disappears while we try to resume it. */ + +static void +linux_resume_one_lwp (struct lwp_info *lwp, + int step, int signal, siginfo_t *info) +{ + try + { + linux_resume_one_lwp_throw (lwp, step, signal, info); + } + catch (const gdb_exception_error &ex) + { + if (!check_ptrace_stopped_lwp_gone (lwp)) + throw; + } +} + +/* This function is called once per thread via for_each_thread. + We look up which resume request applies to THREAD and mark it with a + pointer to the appropriate resume request. + + This algorithm is O(threads * resume elements), but resume elements + is small (and will remain small at least until GDB supports thread + suspension). */ + +static void +linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + for (int ndx = 0; ndx < n; ndx++) + { + ptid_t ptid = resume[ndx].thread; + if (ptid == minus_one_ptid + || ptid == thread->id + /* Handle both 'pPID' and 'pPID.-1' as meaning 'all threads + of PID'. */ + || (ptid.pid () == pid_of (thread) + && (ptid.is_pid () + || ptid.lwp () == -1))) + { + if (resume[ndx].kind == resume_stop + && thread->last_resume_kind == resume_stop) + { + if (debug_threads) + debug_printf ("already %s LWP %ld at GDB's request\n", + (thread->last_status.kind + == TARGET_WAITKIND_STOPPED) + ? "stopped" + : "stopping", + lwpid_of (thread)); + + continue; + } + + /* Ignore (wildcard) resume requests for already-resumed + threads. */ + if (resume[ndx].kind != resume_stop + && thread->last_resume_kind != resume_stop) + { + if (debug_threads) + debug_printf ("already %s LWP %ld at GDB's request\n", + (thread->last_resume_kind + == resume_step) + ? "stepping" + : "continuing", + lwpid_of (thread)); + continue; + } + + /* Don't let wildcard resumes resume fork children that GDB + does not yet know are new fork children. */ + if (lwp->fork_relative != NULL) + { + struct lwp_info *rel = lwp->fork_relative; + + if (rel->status_pending_p + && (rel->waitstatus.kind == TARGET_WAITKIND_FORKED + || rel->waitstatus.kind == TARGET_WAITKIND_VFORKED)) + { + if (debug_threads) + debug_printf ("not resuming LWP %ld: has queued stop reply\n", + lwpid_of (thread)); + continue; + } + } + + /* If the thread has a pending event that has already been + reported to GDBserver core, but GDB has not pulled the + event out of the vStopped queue yet, likewise, ignore the + (wildcard) resume request. */ + if (in_queued_stop_replies (thread->id)) + { + if (debug_threads) + debug_printf ("not resuming LWP %ld: has queued stop reply\n", + lwpid_of (thread)); + continue; + } + + lwp->resume = &resume[ndx]; + thread->last_resume_kind = lwp->resume->kind; + + lwp->step_range_start = lwp->resume->step_range_start; + lwp->step_range_end = lwp->resume->step_range_end; + + /* If we had a deferred signal to report, dequeue one now. + This can happen if LWP gets more than one signal while + trying to get out of a jump pad. */ + if (lwp->stopped + && !lwp->status_pending_p + && dequeue_one_deferred_signal (lwp, &lwp->status_pending)) + { + lwp->status_pending_p = 1; + + if (debug_threads) + debug_printf ("Dequeueing deferred signal %d for LWP %ld, " + "leaving status pending.\n", + WSTOPSIG (lwp->status_pending), + lwpid_of (thread)); + } + + return; + } + } + + /* No resume action for this thread. */ + lwp->resume = NULL; +} + +/* find_thread callback for linux_resume. Return true if this lwp has an + interesting status pending. */ + +static bool +resume_status_pending_p (thread_info *thread) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + /* LWPs which will not be resumed are not interesting, because + we might not wait for them next time through linux_wait. */ + if (lwp->resume == NULL) + return false; + + return thread_still_has_status_pending_p (thread); +} + +/* Return 1 if this lwp that GDB wants running is stopped at an + internal breakpoint that we need to step over. It assumes that any + required STOP_PC adjustment has already been propagated to the + inferior's regcache. */ + +static bool +need_step_over_p (thread_info *thread) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + struct thread_info *saved_thread; + CORE_ADDR pc; + struct process_info *proc = get_thread_process (thread); + + /* GDBserver is skipping the extra traps from the wrapper program, + don't have to do step over. */ + if (proc->tdesc == NULL) + return false; + + /* LWPs which will not be resumed are not interesting, because we + might not wait for them next time through linux_wait. */ + + if (!lwp->stopped) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? Ignoring, not stopped\n", + lwpid_of (thread)); + return false; + } + + if (thread->last_resume_kind == resume_stop) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? Ignoring, should remain" + " stopped\n", + lwpid_of (thread)); + return false; + } + + gdb_assert (lwp->suspended >= 0); + + if (lwp->suspended) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? Ignoring, suspended\n", + lwpid_of (thread)); + return false; + } + + if (lwp->status_pending_p) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? Ignoring, has pending" + " status.\n", + lwpid_of (thread)); + return false; + } + + /* Note: PC, not STOP_PC. Either GDB has adjusted the PC already, + or we have. */ + pc = get_pc (lwp); + + /* If the PC has changed since we stopped, then don't do anything, + and let the breakpoint/tracepoint be hit. This happens if, for + instance, GDB handled the decr_pc_after_break subtraction itself, + GDB is OOL stepping this thread, or the user has issued a "jump" + command, or poked thread's registers herself. */ + if (pc != lwp->stop_pc) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? Cancelling, PC was changed. " + "Old stop_pc was 0x%s, PC is now 0x%s\n", + lwpid_of (thread), + paddress (lwp->stop_pc), paddress (pc)); + return false; + } + + /* On software single step target, resume the inferior with signal + rather than stepping over. */ + if (can_software_single_step () + && lwp->pending_signals != NULL + && lwp_signal_can_be_delivered (lwp)) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? Ignoring, has pending" + " signals.\n", + lwpid_of (thread)); + + return false; + } + + saved_thread = current_thread; + current_thread = thread; + + /* We can only step over breakpoints we know about. */ + if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc)) + { + /* Don't step over a breakpoint that GDB expects to hit + though. If the condition is being evaluated on the target's side + and it evaluate to false, step over this breakpoint as well. */ + if (gdb_breakpoint_here (pc) + && gdb_condition_true_at_breakpoint (pc) + && gdb_no_commands_at_breakpoint (pc)) + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? yes, but found" + " GDB breakpoint at 0x%s; skipping step over\n", + lwpid_of (thread), paddress (pc)); + + current_thread = saved_thread; + return false; + } + else + { + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? yes, " + "found breakpoint at 0x%s\n", + lwpid_of (thread), paddress (pc)); + + /* We've found an lwp that needs stepping over --- return 1 so + that find_thread stops looking. */ + current_thread = saved_thread; + + return true; + } + } + + current_thread = saved_thread; + + if (debug_threads) + debug_printf ("Need step over [LWP %ld]? No, no breakpoint found" + " at 0x%s\n", + lwpid_of (thread), paddress (pc)); + + return false; +} + +/* Start a step-over operation on LWP. When LWP stopped at a + breakpoint, to make progress, we need to remove the breakpoint out + of the way. If we let other threads run while we do that, they may + pass by the breakpoint location and miss hitting it. To avoid + that, a step-over momentarily stops all threads while LWP is + single-stepped by either hardware or software while the breakpoint + is temporarily uninserted from the inferior. When the single-step + finishes, we reinsert the breakpoint, and let all threads that are + supposed to be running, run again. */ + +static int +start_step_over (struct lwp_info *lwp) +{ + struct thread_info *thread = get_lwp_thread (lwp); + struct thread_info *saved_thread; + CORE_ADDR pc; + int step; + + if (debug_threads) + debug_printf ("Starting step-over on LWP %ld. Stopping all threads\n", + lwpid_of (thread)); + + stop_all_lwps (1, lwp); + + if (lwp->suspended != 0) + { + internal_error (__FILE__, __LINE__, + "LWP %ld suspended=%d\n", lwpid_of (thread), + lwp->suspended); + } + + if (debug_threads) + debug_printf ("Done stopping all threads for step-over.\n"); + + /* Note, we should always reach here with an already adjusted PC, + either by GDB (if we're resuming due to GDB's request), or by our + caller, if we just finished handling an internal breakpoint GDB + shouldn't care about. */ + pc = get_pc (lwp); + + saved_thread = current_thread; + current_thread = thread; + + lwp->bp_reinsert = pc; + uninsert_breakpoints_at (pc); + uninsert_fast_tracepoint_jumps_at (pc); + + step = single_step (lwp); + + current_thread = saved_thread; + + linux_resume_one_lwp (lwp, step, 0, NULL); + + /* Require next event from this LWP. */ + step_over_bkpt = thread->id; + return 1; +} + +/* Finish a step-over. Reinsert the breakpoint we had uninserted in + start_step_over, if still there, and delete any single-step + breakpoints we've set, on non hardware single-step targets. */ + +static int +finish_step_over (struct lwp_info *lwp) +{ + if (lwp->bp_reinsert != 0) + { + struct thread_info *saved_thread = current_thread; + + if (debug_threads) + debug_printf ("Finished step over.\n"); + + current_thread = get_lwp_thread (lwp); + + /* Reinsert any breakpoint at LWP->BP_REINSERT. Note that there + may be no breakpoint to reinsert there by now. */ + reinsert_breakpoints_at (lwp->bp_reinsert); + reinsert_fast_tracepoint_jumps_at (lwp->bp_reinsert); + + lwp->bp_reinsert = 0; + + /* Delete any single-step breakpoints. No longer needed. We + don't have to worry about other threads hitting this trap, + and later not being able to explain it, because we were + stepping over a breakpoint, and we hold all threads but + LWP stopped while doing that. */ + if (!can_hardware_single_step ()) + { + gdb_assert (has_single_step_breakpoints (current_thread)); + delete_single_step_breakpoints (current_thread); + } + + step_over_bkpt = null_ptid; + current_thread = saved_thread; + return 1; + } + else + return 0; +} + +/* If there's a step over in progress, wait until all threads stop + (that is, until the stepping thread finishes its step), and + unsuspend all lwps. The stepping thread ends with its status + pending, which is processed later when we get back to processing + events. */ + +static void +complete_ongoing_step_over (void) +{ + if (step_over_bkpt != null_ptid) + { + struct lwp_info *lwp; + int wstat; + int ret; + + if (debug_threads) + debug_printf ("detach: step over in progress, finish it first\n"); + + /* Passing NULL_PTID as filter indicates we want all events to + be left pending. Eventually this returns when there are no + unwaited-for children left. */ + ret = linux_wait_for_event_filtered (minus_one_ptid, null_ptid, + &wstat, __WALL); + gdb_assert (ret == -1); + + lwp = find_lwp_pid (step_over_bkpt); + if (lwp != NULL) + finish_step_over (lwp); + step_over_bkpt = null_ptid; + unsuspend_all_lwps (lwp); + } +} + +/* This function is called once per thread. We check the thread's resume + request, which will tell us whether to resume, step, or leave the thread + stopped; and what signal, if any, it should be sent. + + For threads which we aren't explicitly told otherwise, we preserve + the stepping flag; this is used for stepping over gdbserver-placed + breakpoints. + + If pending_flags was set in any thread, we queue any needed + signals, since we won't actually resume. We already have a pending + event to report, so we don't need to preserve any step requests; + they should be re-issued if necessary. */ + +static void +linux_resume_one_thread (thread_info *thread, bool leave_all_stopped) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + int leave_pending; + + if (lwp->resume == NULL) + return; + + if (lwp->resume->kind == resume_stop) + { + if (debug_threads) + debug_printf ("resume_stop request for LWP %ld\n", lwpid_of (thread)); + + if (!lwp->stopped) + { + if (debug_threads) + debug_printf ("stopping LWP %ld\n", lwpid_of (thread)); + + /* Stop the thread, and wait for the event asynchronously, + through the event loop. */ + send_sigstop (lwp); + } + else + { + if (debug_threads) + debug_printf ("already stopped LWP %ld\n", + lwpid_of (thread)); + + /* The LWP may have been stopped in an internal event that + was not meant to be notified back to GDB (e.g., gdbserver + breakpoint), so we should be reporting a stop event in + this case too. */ + + /* If the thread already has a pending SIGSTOP, this is a + no-op. Otherwise, something later will presumably resume + the thread and this will cause it to cancel any pending + operation, due to last_resume_kind == resume_stop. If + the thread already has a pending status to report, we + will still report it the next time we wait - see + status_pending_p_callback. */ + + /* If we already have a pending signal to report, then + there's no need to queue a SIGSTOP, as this means we're + midway through moving the LWP out of the jumppad, and we + will report the pending signal as soon as that is + finished. */ + if (lwp->pending_signals_to_report == NULL) + send_sigstop (lwp); + } + + /* For stop requests, we're done. */ + lwp->resume = NULL; + thread->last_status.kind = TARGET_WAITKIND_IGNORE; + return; + } + + /* If this thread which is about to be resumed has a pending status, + then don't resume it - we can just report the pending status. + Likewise if it is suspended, because e.g., another thread is + stepping past a breakpoint. Make sure to queue any signals that + would otherwise be sent. In all-stop mode, we do this decision + based on if *any* thread has a pending status. If there's a + thread that needs the step-over-breakpoint dance, then don't + resume any other thread but that particular one. */ + leave_pending = (lwp->suspended + || lwp->status_pending_p + || leave_all_stopped); + + /* If we have a new signal, enqueue the signal. */ + if (lwp->resume->sig != 0) + { + siginfo_t info, *info_p; + + /* If this is the same signal we were previously stopped by, + make sure to queue its siginfo. */ + if (WIFSTOPPED (lwp->last_status) + && WSTOPSIG (lwp->last_status) == lwp->resume->sig + && ptrace (PTRACE_GETSIGINFO, lwpid_of (thread), + (PTRACE_TYPE_ARG3) 0, &info) == 0) + info_p = &info; + else + info_p = NULL; + + enqueue_pending_signal (lwp, lwp->resume->sig, info_p); + } + + if (!leave_pending) + { + if (debug_threads) + debug_printf ("resuming LWP %ld\n", lwpid_of (thread)); + + proceed_one_lwp (thread, NULL); + } + else + { + if (debug_threads) + debug_printf ("leaving LWP %ld stopped\n", lwpid_of (thread)); + } + + thread->last_status.kind = TARGET_WAITKIND_IGNORE; + lwp->resume = NULL; +} + +static void +linux_resume (struct thread_resume *resume_info, size_t n) +{ + struct thread_info *need_step_over = NULL; + + if (debug_threads) + { + debug_enter (); + debug_printf ("linux_resume:\n"); + } + + for_each_thread ([&] (thread_info *thread) + { + linux_set_resume_request (thread, resume_info, n); + }); + + /* If there is a thread which would otherwise be resumed, which has + a pending status, then don't resume any threads - we can just + report the pending status. Make sure to queue any signals that + would otherwise be sent. In non-stop mode, we'll apply this + logic to each thread individually. We consume all pending events + before considering to start a step-over (in all-stop). */ + bool any_pending = false; + if (!non_stop) + any_pending = find_thread (resume_status_pending_p) != NULL; + + /* If there is a thread which would otherwise be resumed, which is + stopped at a breakpoint that needs stepping over, then don't + resume any threads - have it step over the breakpoint with all + other threads stopped, then resume all threads again. Make sure + to queue any signals that would otherwise be delivered or + queued. */ + if (!any_pending && supports_breakpoints ()) + need_step_over = find_thread (need_step_over_p); + + bool leave_all_stopped = (need_step_over != NULL || any_pending); + + if (debug_threads) + { + if (need_step_over != NULL) + debug_printf ("Not resuming all, need step over\n"); + else if (any_pending) + debug_printf ("Not resuming, all-stop and found " + "an LWP with pending status\n"); + else + debug_printf ("Resuming, no pending status or step over needed\n"); + } + + /* Even if we're leaving threads stopped, queue all signals we'd + otherwise deliver. */ + for_each_thread ([&] (thread_info *thread) + { + linux_resume_one_thread (thread, leave_all_stopped); + }); + + if (need_step_over) + start_step_over (get_thread_lwp (need_step_over)); + + if (debug_threads) + { + debug_printf ("linux_resume done\n"); + debug_exit (); + } + + /* We may have events that were pending that can/should be sent to + the client now. Trigger a linux_wait call. */ + if (target_is_async_p ()) + async_file_mark (); +} + +/* This function is called once per thread. We check the thread's + last resume request, which will tell us whether to resume, step, or + leave the thread stopped. Any signal the client requested to be + delivered has already been enqueued at this point. + + If any thread that GDB wants running is stopped at an internal + breakpoint that needs stepping over, we start a step-over operation + on that particular thread, and leave all others stopped. */ + +static void +proceed_one_lwp (thread_info *thread, lwp_info *except) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + int step; + + if (lwp == except) + return; + + if (debug_threads) + debug_printf ("proceed_one_lwp: lwp %ld\n", lwpid_of (thread)); + + if (!lwp->stopped) + { + if (debug_threads) + debug_printf (" LWP %ld already running\n", lwpid_of (thread)); + return; + } + + if (thread->last_resume_kind == resume_stop + && thread->last_status.kind != TARGET_WAITKIND_IGNORE) + { + if (debug_threads) + debug_printf (" client wants LWP to remain %ld stopped\n", + lwpid_of (thread)); + return; + } + + if (lwp->status_pending_p) + { + if (debug_threads) + debug_printf (" LWP %ld has pending status, leaving stopped\n", + lwpid_of (thread)); + return; + } + + gdb_assert (lwp->suspended >= 0); + + if (lwp->suspended) + { + if (debug_threads) + debug_printf (" LWP %ld is suspended\n", lwpid_of (thread)); + return; + } + + if (thread->last_resume_kind == resume_stop + && lwp->pending_signals_to_report == NULL + && (lwp->collecting_fast_tracepoint + == fast_tpoint_collect_result::not_collecting)) + { + /* We haven't reported this LWP as stopped yet (otherwise, the + last_status.kind check above would catch it, and we wouldn't + reach here. This LWP may have been momentarily paused by a + stop_all_lwps call while handling for example, another LWP's + step-over. In that case, the pending expected SIGSTOP signal + that was queued at vCont;t handling time will have already + been consumed by wait_for_sigstop, and so we need to requeue + another one here. Note that if the LWP already has a SIGSTOP + pending, this is a no-op. */ + + if (debug_threads) + debug_printf ("Client wants LWP %ld to stop. " + "Making sure it has a SIGSTOP pending\n", + lwpid_of (thread)); + + send_sigstop (lwp); + } + + if (thread->last_resume_kind == resume_step) + { + if (debug_threads) + debug_printf (" stepping LWP %ld, client wants it stepping\n", + lwpid_of (thread)); + + /* If resume_step is requested by GDB, install single-step + breakpoints when the thread is about to be actually resumed if + the single-step breakpoints weren't removed. */ + if (can_software_single_step () + && !has_single_step_breakpoints (thread)) + install_software_single_step_breakpoints (lwp); + + step = maybe_hw_step (thread); + } + else if (lwp->bp_reinsert != 0) + { + if (debug_threads) + debug_printf (" stepping LWP %ld, reinsert set\n", + lwpid_of (thread)); + + step = maybe_hw_step (thread); + } + else + step = 0; + + linux_resume_one_lwp (lwp, step, 0, NULL); +} + +static void +unsuspend_and_proceed_one_lwp (thread_info *thread, lwp_info *except) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + if (lwp == except) + return; + + lwp_suspended_decr (lwp); + + proceed_one_lwp (thread, except); +} + +/* When we finish a step-over, set threads running again. If there's + another thread that may need a step-over, now's the time to start + it. Eventually, we'll move all threads past their breakpoints. */ + +static void +proceed_all_lwps (void) +{ + struct thread_info *need_step_over; + + /* If there is a thread which would otherwise be resumed, which is + stopped at a breakpoint that needs stepping over, then don't + resume any threads - have it step over the breakpoint with all + other threads stopped, then resume all threads again. */ + + if (supports_breakpoints ()) + { + need_step_over = find_thread (need_step_over_p); + + if (need_step_over != NULL) + { + if (debug_threads) + debug_printf ("proceed_all_lwps: found " + "thread %ld needing a step-over\n", + lwpid_of (need_step_over)); + + start_step_over (get_thread_lwp (need_step_over)); + return; + } + } + + if (debug_threads) + debug_printf ("Proceeding, no step-over needed\n"); + + for_each_thread ([] (thread_info *thread) + { + proceed_one_lwp (thread, NULL); + }); +} + +/* Stopped LWPs that the client wanted to be running, that don't have + pending statuses, are set to run again, except for EXCEPT, if not + NULL. This undoes a stop_all_lwps call. */ + +static void +unstop_all_lwps (int unsuspend, struct lwp_info *except) +{ + if (debug_threads) + { + debug_enter (); + if (except) + debug_printf ("unstopping all lwps, except=(LWP %ld)\n", + lwpid_of (get_lwp_thread (except))); + else + debug_printf ("unstopping all lwps\n"); + } + + if (unsuspend) + for_each_thread ([&] (thread_info *thread) + { + unsuspend_and_proceed_one_lwp (thread, except); + }); + else + for_each_thread ([&] (thread_info *thread) + { + proceed_one_lwp (thread, except); + }); + + if (debug_threads) + { + debug_printf ("unstop_all_lwps done\n"); + debug_exit (); + } +} + + +#ifdef HAVE_LINUX_REGSETS + +#define use_linux_regsets 1 + +/* Returns true if REGSET has been disabled. */ + +static int +regset_disabled (struct regsets_info *info, struct regset_info *regset) +{ + return (info->disabled_regsets != NULL + && info->disabled_regsets[regset - info->regsets]); +} + +/* Disable REGSET. */ + +static void +disable_regset (struct regsets_info *info, struct regset_info *regset) +{ + int dr_offset; + + dr_offset = regset - info->regsets; + if (info->disabled_regsets == NULL) + info->disabled_regsets = (char *) xcalloc (1, info->num_regsets); + info->disabled_regsets[dr_offset] = 1; +} + +static int +regsets_fetch_inferior_registers (struct regsets_info *regsets_info, + struct regcache *regcache) +{ + struct regset_info *regset; + int saw_general_regs = 0; + int pid; + struct iovec iov; + + pid = lwpid_of (current_thread); + for (regset = regsets_info->regsets; regset->size >= 0; regset++) + { + void *buf, *data; + int nt_type, res; + + if (regset->size == 0 || regset_disabled (regsets_info, regset)) + continue; + + buf = xmalloc (regset->size); + + nt_type = regset->nt_type; + if (nt_type) + { + iov.iov_base = buf; + iov.iov_len = regset->size; + data = (void *) &iov; + } + else + data = buf; + +#ifndef __sparc__ + res = ptrace (regset->get_request, pid, + (PTRACE_TYPE_ARG3) (long) nt_type, data); +#else + res = ptrace (regset->get_request, pid, data, nt_type); +#endif + if (res < 0) + { + if (errno == EIO + || (errno == EINVAL && regset->type == OPTIONAL_REGS)) + { + /* If we get EIO on a regset, or an EINVAL and the regset is + optional, do not try it again for this process mode. */ + disable_regset (regsets_info, regset); + } + else if (errno == ENODATA) + { + /* ENODATA may be returned if the regset is currently + not "active". This can happen in normal operation, + so suppress the warning in this case. */ + } + else if (errno == ESRCH) + { + /* At this point, ESRCH should mean the process is + already gone, in which case we simply ignore attempts + to read its registers. */ + } + else + { + char s[256]; + sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d", + pid); + perror (s); + } + } + else + { + if (regset->type == GENERAL_REGS) + saw_general_regs = 1; + regset->store_function (regcache, buf); + } + free (buf); + } + if (saw_general_regs) + return 0; + else + return 1; +} + +static int +regsets_store_inferior_registers (struct regsets_info *regsets_info, + struct regcache *regcache) +{ + struct regset_info *regset; + int saw_general_regs = 0; + int pid; + struct iovec iov; + + pid = lwpid_of (current_thread); + for (regset = regsets_info->regsets; regset->size >= 0; regset++) + { + void *buf, *data; + int nt_type, res; + + if (regset->size == 0 || regset_disabled (regsets_info, regset) + || regset->fill_function == NULL) + continue; + + buf = xmalloc (regset->size); + + /* First fill the buffer with the current register set contents, + in case there are any items in the kernel's regset that are + not in gdbserver's regcache. */ + + nt_type = regset->nt_type; + if (nt_type) + { + iov.iov_base = buf; + iov.iov_len = regset->size; + data = (void *) &iov; + } + else + data = buf; + +#ifndef __sparc__ + res = ptrace (regset->get_request, pid, + (PTRACE_TYPE_ARG3) (long) nt_type, data); +#else + res = ptrace (regset->get_request, pid, data, nt_type); +#endif + + if (res == 0) + { + /* Then overlay our cached registers on that. */ + regset->fill_function (regcache, buf); + + /* Only now do we write the register set. */ +#ifndef __sparc__ + res = ptrace (regset->set_request, pid, + (PTRACE_TYPE_ARG3) (long) nt_type, data); +#else + res = ptrace (regset->set_request, pid, data, nt_type); +#endif + } + + if (res < 0) + { + if (errno == EIO + || (errno == EINVAL && regset->type == OPTIONAL_REGS)) + { + /* If we get EIO on a regset, or an EINVAL and the regset is + optional, do not try it again for this process mode. */ + disable_regset (regsets_info, regset); + } + else if (errno == ESRCH) + { + /* At this point, ESRCH should mean the process is + already gone, in which case we simply ignore attempts + to change its registers. See also the related + comment in linux_resume_one_lwp. */ + free (buf); + return 0; + } + else + { + perror ("Warning: ptrace(regsets_store_inferior_registers)"); + } + } + else if (regset->type == GENERAL_REGS) + saw_general_regs = 1; + free (buf); + } + if (saw_general_regs) + return 0; + else + return 1; +} + +#else /* !HAVE_LINUX_REGSETS */ + +#define use_linux_regsets 0 +#define regsets_fetch_inferior_registers(regsets_info, regcache) 1 +#define regsets_store_inferior_registers(regsets_info, regcache) 1 + +#endif + +/* Return 1 if register REGNO is supported by one of the regset ptrace + calls or 0 if it has to be transferred individually. */ + +static int +linux_register_in_regsets (const struct regs_info *regs_info, int regno) +{ + unsigned char mask = 1 << (regno % 8); + size_t index = regno / 8; + + return (use_linux_regsets + && (regs_info->regset_bitmap == NULL + || (regs_info->regset_bitmap[index] & mask) != 0)); +} + +#ifdef HAVE_LINUX_USRREGS + +static int +register_addr (const struct usrregs_info *usrregs, int regnum) +{ + int addr; + + if (regnum < 0 || regnum >= usrregs->num_regs) + error ("Invalid register number %d.", regnum); + + addr = usrregs->regmap[regnum]; + + return addr; +} + +/* Fetch one register. */ +static void +fetch_register (const struct usrregs_info *usrregs, + struct regcache *regcache, int regno) +{ + CORE_ADDR regaddr; + int i, size; + char *buf; + int pid; + + if (regno >= usrregs->num_regs) + return; + if ((*the_low_target.cannot_fetch_register) (regno)) + return; + + regaddr = register_addr (usrregs, regno); + if (regaddr == -1) + return; + + size = ((register_size (regcache->tdesc, regno) + + sizeof (PTRACE_XFER_TYPE) - 1) + & -sizeof (PTRACE_XFER_TYPE)); + buf = (char *) alloca (size); + + pid = lwpid_of (current_thread); + for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) (buf + i) = + ptrace (PTRACE_PEEKUSER, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + of coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_TYPE_ARG3) (uintptr_t) regaddr, (PTRACE_TYPE_ARG4) 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + /* Mark register REGNO unavailable. */ + supply_register (regcache, regno, NULL); + return; + } + } + + if (the_low_target.supply_ptrace_register) + the_low_target.supply_ptrace_register (regcache, regno, buf); + else + supply_register (regcache, regno, buf); +} + +/* Store one register. */ +static void +store_register (const struct usrregs_info *usrregs, + struct regcache *regcache, int regno) +{ + CORE_ADDR regaddr; + int i, size; + char *buf; + int pid; + + if (regno >= usrregs->num_regs) + return; + if ((*the_low_target.cannot_store_register) (regno)) + return; + + regaddr = register_addr (usrregs, regno); + if (regaddr == -1) + return; + + size = ((register_size (regcache->tdesc, regno) + + sizeof (PTRACE_XFER_TYPE) - 1) + & -sizeof (PTRACE_XFER_TYPE)); + buf = (char *) alloca (size); + memset (buf, 0, size); + + if (the_low_target.collect_ptrace_register) + the_low_target.collect_ptrace_register (regcache, regno, buf); + else + collect_register (regcache, regno, buf); + + pid = lwpid_of (current_thread); + for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PTRACE_POKEUSER, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_TYPE_ARG3) (uintptr_t) regaddr, + (PTRACE_TYPE_ARG4) *(PTRACE_XFER_TYPE *) (buf + i)); + if (errno != 0) + { + /* At this point, ESRCH should mean the process is + already gone, in which case we simply ignore attempts + to change its registers. See also the related + comment in linux_resume_one_lwp. */ + if (errno == ESRCH) + return; + + if ((*the_low_target.cannot_store_register) (regno) == 0) + error ("writing register %d: %s", regno, safe_strerror (errno)); + } + regaddr += sizeof (PTRACE_XFER_TYPE); + } +} + +/* Fetch all registers, or just one, from the child process. + If REGNO is -1, do this for all registers, skipping any that are + assumed to have been retrieved by regsets_fetch_inferior_registers, + unless ALL is non-zero. + Otherwise, REGNO specifies which register (so we can save time). */ +static void +usr_fetch_inferior_registers (const struct regs_info *regs_info, + struct regcache *regcache, int regno, int all) +{ + struct usrregs_info *usr = regs_info->usrregs; + + if (regno == -1) + { + for (regno = 0; regno < usr->num_regs; regno++) + if (all || !linux_register_in_regsets (regs_info, regno)) + fetch_register (usr, regcache, regno); + } + else + fetch_register (usr, regcache, regno); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers, skipping any that are + assumed to have been saved by regsets_store_inferior_registers, + unless ALL is non-zero. + Otherwise, REGNO specifies which register (so we can save time). */ +static void +usr_store_inferior_registers (const struct regs_info *regs_info, + struct regcache *regcache, int regno, int all) +{ + struct usrregs_info *usr = regs_info->usrregs; + + if (regno == -1) + { + for (regno = 0; regno < usr->num_regs; regno++) + if (all || !linux_register_in_regsets (regs_info, regno)) + store_register (usr, regcache, regno); + } + else + store_register (usr, regcache, regno); +} + +#else /* !HAVE_LINUX_USRREGS */ + +#define usr_fetch_inferior_registers(regs_info, regcache, regno, all) do {} while (0) +#define usr_store_inferior_registers(regs_info, regcache, regno, all) do {} while (0) + +#endif + + +static void +linux_fetch_registers (struct regcache *regcache, int regno) +{ + int use_regsets; + int all = 0; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + + if (regno == -1) + { + if (the_low_target.fetch_register != NULL + && regs_info->usrregs != NULL) + for (regno = 0; regno < regs_info->usrregs->num_regs; regno++) + (*the_low_target.fetch_register) (regcache, regno); + + all = regsets_fetch_inferior_registers (regs_info->regsets_info, regcache); + if (regs_info->usrregs != NULL) + usr_fetch_inferior_registers (regs_info, regcache, -1, all); + } + else + { + if (the_low_target.fetch_register != NULL + && (*the_low_target.fetch_register) (regcache, regno)) + return; + + use_regsets = linux_register_in_regsets (regs_info, regno); + if (use_regsets) + all = regsets_fetch_inferior_registers (regs_info->regsets_info, + regcache); + if ((!use_regsets || all) && regs_info->usrregs != NULL) + usr_fetch_inferior_registers (regs_info, regcache, regno, 1); + } +} + +static void +linux_store_registers (struct regcache *regcache, int regno) +{ + int use_regsets; + int all = 0; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + + if (regno == -1) + { + all = regsets_store_inferior_registers (regs_info->regsets_info, + regcache); + if (regs_info->usrregs != NULL) + usr_store_inferior_registers (regs_info, regcache, regno, all); + } + else + { + use_regsets = linux_register_in_regsets (regs_info, regno); + if (use_regsets) + all = regsets_store_inferior_registers (regs_info->regsets_info, + regcache); + if ((!use_regsets || all) && regs_info->usrregs != NULL) + usr_store_inferior_registers (regs_info, regcache, regno, 1); + } +} + + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +static int +linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + int pid = lwpid_of (current_thread); + PTRACE_XFER_TYPE *buffer; + CORE_ADDR addr; + int count; + char filename[64]; + int i; + int ret; + int fd; + + /* Try using /proc. Don't bother for one word. */ + if (len >= 3 * sizeof (long)) + { + int bytes; + + /* We could keep this file open and cache it - possibly one per + thread. That requires some juggling, but is even faster. */ + sprintf (filename, "/proc/%d/mem", pid); + fd = open (filename, O_RDONLY | O_LARGEFILE); + if (fd == -1) + goto no_proc; + + /* If pread64 is available, use it. It's faster if the kernel + supports it (only one syscall), and it's 64-bit safe even on + 32-bit platforms (for instance, SPARC debugging a SPARC64 + application). */ +#ifdef HAVE_PREAD64 + bytes = pread64 (fd, myaddr, len, memaddr); +#else + bytes = -1; + if (lseek (fd, memaddr, SEEK_SET) != -1) + bytes = read (fd, myaddr, len); +#endif + + close (fd); + if (bytes == len) + return 0; + + /* Some data was read, we'll try to get the rest with ptrace. */ + if (bytes > 0) + { + memaddr += bytes; + myaddr += bytes; + len -= bytes; + } + } + + no_proc: + /* Round starting address down to longword boundary. */ + addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); + /* Round ending address up; get number of longwords that makes. */ + count = ((((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE)); + /* Allocate buffer of that many longwords. */ + buffer = XALLOCAVEC (PTRACE_XFER_TYPE, count); + + /* Read all the longwords */ + errno = 0; + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + buffer[i] = ptrace (PTRACE_PEEKTEXT, pid, + (PTRACE_TYPE_ARG3) (uintptr_t) addr, + (PTRACE_TYPE_ARG4) 0); + if (errno) + break; + } + ret = errno; + + /* Copy appropriate bytes out of the buffer. */ + if (i > 0) + { + i *= sizeof (PTRACE_XFER_TYPE); + i -= memaddr & (sizeof (PTRACE_XFER_TYPE) - 1); + memcpy (myaddr, + (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + i < len ? i : len); + } + + return ret; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's + memory at MEMADDR. On failure (cannot write to the inferior) + returns the value of errno. Always succeeds if LEN is zero. */ + +static int +linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +{ + int i; + /* Round starting address down to longword boundary. */ + CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); + /* Round ending address up; get number of longwords that makes. */ + int count + = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE); + + /* Allocate buffer of that many longwords. */ + PTRACE_XFER_TYPE *buffer = XALLOCAVEC (PTRACE_XFER_TYPE, count); + + int pid = lwpid_of (current_thread); + + if (len == 0) + { + /* Zero length write always succeeds. */ + return 0; + } + + if (debug_threads) + { + /* Dump up to four bytes. */ + char str[4 * 2 + 1]; + char *p = str; + int dump = len < 4 ? len : 4; + + for (i = 0; i < dump; i++) + { + sprintf (p, "%02x", myaddr[i]); + p += 2; + } + *p = '\0'; + + debug_printf ("Writing %s to 0x%08lx in process %d\n", + str, (long) memaddr, pid); + } + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + errno = 0; + /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + buffer[0] = ptrace (PTRACE_PEEKTEXT, pid, + (PTRACE_TYPE_ARG3) (uintptr_t) addr, + (PTRACE_TYPE_ARG4) 0); + if (errno) + return errno; + + if (count > 1) + { + errno = 0; + buffer[count - 1] + = ptrace (PTRACE_PEEKTEXT, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_TYPE_ARG3) (uintptr_t) (addr + (count - 1) + * sizeof (PTRACE_XFER_TYPE)), + (PTRACE_TYPE_ARG4) 0); + if (errno) + return errno; + } + + /* Copy data to be written over corresponding part of buffer. */ + + memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PTRACE_POKETEXT, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_TYPE_ARG3) (uintptr_t) addr, + (PTRACE_TYPE_ARG4) buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +static void +linux_look_up_symbols (void) +{ +#ifdef USE_THREAD_DB + struct process_info *proc = current_process (); + + if (proc->priv->thread_db != NULL) + return; + + thread_db_init (); +#endif +} + +static void +linux_request_interrupt (void) +{ + /* Send a SIGINT to the process group. This acts just like the user + typed a ^C on the controlling terminal. */ + kill (-signal_pid, SIGINT); +} + +/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET + to debugger memory starting at MYADDR. */ + +static int +linux_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len) +{ + char filename[PATH_MAX]; + int fd, n; + int pid = lwpid_of (current_thread); + + xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid); + + fd = open (filename, O_RDONLY); + if (fd < 0) + return -1; + + if (offset != (CORE_ADDR) 0 + && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset) + n = -1; + else + n = read (fd, myaddr, len); + + close (fd); + + return n; +} + +/* These breakpoint and watchpoint related wrapper functions simply + pass on the function call if the target has registered a + corresponding function. */ + +static int +linux_supports_z_point_type (char z_type) +{ + return (the_low_target.supports_z_point_type != NULL + && the_low_target.supports_z_point_type (z_type)); +} + +static int +linux_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + if (type == raw_bkpt_type_sw) + return insert_memory_breakpoint (bp); + else if (the_low_target.insert_point != NULL) + return the_low_target.insert_point (type, addr, size, bp); + else + /* Unsupported (see target.h). */ + return 1; +} + +static int +linux_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + if (type == raw_bkpt_type_sw) + return remove_memory_breakpoint (bp); + else if (the_low_target.remove_point != NULL) + return the_low_target.remove_point (type, addr, size, bp); + else + /* Unsupported (see target.h). */ + return 1; +} + +/* Implement the to_stopped_by_sw_breakpoint target_ops + method. */ + +static int +linux_stopped_by_sw_breakpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT); +} + +/* Implement the to_supports_stopped_by_sw_breakpoint target_ops + method. */ + +static int +linux_supports_stopped_by_sw_breakpoint (void) +{ + return USE_SIGTRAP_SIGINFO; +} + +/* Implement the to_stopped_by_hw_breakpoint target_ops + method. */ + +static int +linux_stopped_by_hw_breakpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT); +} + +/* Implement the to_supports_stopped_by_hw_breakpoint target_ops + method. */ + +static int +linux_supports_stopped_by_hw_breakpoint (void) +{ + return USE_SIGTRAP_SIGINFO; +} + +/* Implement the supports_hardware_single_step target_ops method. */ + +static int +linux_supports_hardware_single_step (void) +{ + return can_hardware_single_step (); +} + +static int +linux_supports_software_single_step (void) +{ + return can_software_single_step (); +} + +static int +linux_stopped_by_watchpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT; +} + +static CORE_ADDR +linux_stopped_data_address (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return lwp->stopped_data_address; +} + +#if defined(__UCLIBC__) && defined(HAS_NOMMU) \ + && defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) \ + && defined(PT_TEXT_END_ADDR) + +/* This is only used for targets that define PT_TEXT_ADDR, + PT_DATA_ADDR and PT_TEXT_END_ADDR. If those are not defined, supposedly + the target has different ways of acquiring this information, like + loadmaps. */ + +/* Under uClinux, programs are loaded at non-zero offsets, which we need + to tell gdb about. */ + +static int +linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p) +{ + unsigned long text, text_end, data; + int pid = lwpid_of (current_thread); + + errno = 0; + + text = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_TEXT_ADDR, + (PTRACE_TYPE_ARG4) 0); + text_end = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_TEXT_END_ADDR, + (PTRACE_TYPE_ARG4) 0); + data = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_DATA_ADDR, + (PTRACE_TYPE_ARG4) 0); + + if (errno == 0) + { + /* Both text and data offsets produced at compile-time (and so + used by gdb) are relative to the beginning of the program, + with the data segment immediately following the text segment. + However, the actual runtime layout in memory may put the data + somewhere else, so when we send gdb a data base-address, we + use the real data base address and subtract the compile-time + data base-address from it (which is just the length of the + text segment). BSS immediately follows data in both + cases. */ + *text_p = text; + *data_p = data - (text_end - text); + + return 1; + } + return 0; +} +#endif + +static int +linux_qxfer_osdata (const char *annex, + unsigned char *readbuf, unsigned const char *writebuf, + CORE_ADDR offset, int len) +{ + return linux_common_xfer_osdata (annex, readbuf, offset, len); +} + +/* Convert a native/host siginfo object, into/from the siginfo in the + layout of the inferiors' architecture. */ + +static void +siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction) +{ + int done = 0; + + if (the_low_target.siginfo_fixup != NULL) + done = the_low_target.siginfo_fixup (siginfo, inf_siginfo, direction); + + /* If there was no callback, or the callback didn't do anything, + then just do a straight memcpy. */ + if (!done) + { + if (direction == 1) + memcpy (siginfo, inf_siginfo, sizeof (siginfo_t)); + else + memcpy (inf_siginfo, siginfo, sizeof (siginfo_t)); + } +} + +static int +linux_xfer_siginfo (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, CORE_ADDR offset, int len) +{ + int pid; + siginfo_t siginfo; + gdb_byte inf_siginfo[sizeof (siginfo_t)]; + + if (current_thread == NULL) + return -1; + + pid = lwpid_of (current_thread); + + if (debug_threads) + debug_printf ("%s siginfo for lwp %d.\n", + readbuf != NULL ? "Reading" : "Writing", + pid); + + if (offset >= sizeof (siginfo)) + return -1; + + if (ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo) != 0) + return -1; + + /* When GDBSERVER is built as a 64-bit application, ptrace writes into + SIGINFO an object with 64-bit layout. Since debugging a 32-bit + inferior with a 64-bit GDBSERVER should look the same as debugging it + with a 32-bit GDBSERVER, we need to convert it. */ + siginfo_fixup (&siginfo, inf_siginfo, 0); + + if (offset + len > sizeof (siginfo)) + len = sizeof (siginfo) - offset; + + if (readbuf != NULL) + memcpy (readbuf, inf_siginfo + offset, len); + else + { + memcpy (inf_siginfo + offset, writebuf, len); + + /* Convert back to ptrace layout before flushing it out. */ + siginfo_fixup (&siginfo, inf_siginfo, 1); + + if (ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo) != 0) + return -1; + } + + return len; +} + +/* SIGCHLD handler that serves two purposes: In non-stop/async mode, + so we notice when children change state; as the handler for the + sigsuspend in my_waitpid. */ + +static void +sigchld_handler (int signo) +{ + int old_errno = errno; + + if (debug_threads) + { + do + { + /* Use the async signal safe debug function. */ + if (debug_write ("sigchld_handler\n", + sizeof ("sigchld_handler\n") - 1) < 0) + break; /* just ignore */ + } while (0); + } + + if (target_is_async_p ()) + async_file_mark (); /* trigger a linux_wait */ + + errno = old_errno; +} + +static int +linux_supports_non_stop (void) +{ + return 1; +} + +static int +linux_async (int enable) +{ + int previous = target_is_async_p (); + + if (debug_threads) + debug_printf ("linux_async (%d), previous=%d\n", + enable, previous); + + if (previous != enable) + { + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + + gdb_sigmask (SIG_BLOCK, &mask, NULL); + + if (enable) + { + if (pipe (linux_event_pipe) == -1) + { + linux_event_pipe[0] = -1; + linux_event_pipe[1] = -1; + gdb_sigmask (SIG_UNBLOCK, &mask, NULL); + + warning ("creating event pipe failed."); + return previous; + } + + fcntl (linux_event_pipe[0], F_SETFL, O_NONBLOCK); + fcntl (linux_event_pipe[1], F_SETFL, O_NONBLOCK); + + /* Register the event loop handler. */ + add_file_handler (linux_event_pipe[0], + handle_target_event, NULL); + + /* Always trigger a linux_wait. */ + async_file_mark (); + } + else + { + delete_file_handler (linux_event_pipe[0]); + + close (linux_event_pipe[0]); + close (linux_event_pipe[1]); + linux_event_pipe[0] = -1; + linux_event_pipe[1] = -1; + } + + gdb_sigmask (SIG_UNBLOCK, &mask, NULL); + } + + return previous; +} + +static int +linux_start_non_stop (int nonstop) +{ + /* Register or unregister from event-loop accordingly. */ + linux_async (nonstop); + + if (target_is_async_p () != (nonstop != 0)) + return -1; + + return 0; +} + +static int +linux_supports_multi_process (void) +{ + return 1; +} + +/* Check if fork events are supported. */ + +static int +linux_supports_fork_events (void) +{ + return linux_supports_tracefork (); +} + +/* Check if vfork events are supported. */ + +static int +linux_supports_vfork_events (void) +{ + return linux_supports_tracefork (); +} + +/* Check if exec events are supported. */ + +static int +linux_supports_exec_events (void) +{ + return linux_supports_traceexec (); +} + +/* Target hook for 'handle_new_gdb_connection'. Causes a reset of the + ptrace flags for all inferiors. This is in case the new GDB connection + doesn't support the same set of events that the previous one did. */ + +static void +linux_handle_new_gdb_connection (void) +{ + /* Request that all the lwps reset their ptrace options. */ + for_each_thread ([] (thread_info *thread) + { + struct lwp_info *lwp = get_thread_lwp (thread); + + if (!lwp->stopped) + { + /* Stop the lwp so we can modify its ptrace options. */ + lwp->must_set_ptrace_flags = 1; + linux_stop_lwp (lwp); + } + else + { + /* Already stopped; go ahead and set the ptrace options. */ + struct process_info *proc = find_process_pid (pid_of (thread)); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid_of (thread), options); + lwp->must_set_ptrace_flags = 0; + } + }); +} + +static int +linux_supports_disable_randomization (void) +{ +#ifdef HAVE_PERSONALITY + return 1; +#else + return 0; +#endif +} + +static int +linux_supports_agent (void) +{ + return 1; +} + +static int +linux_supports_range_stepping (void) +{ + if (can_software_single_step ()) + return 1; + if (*the_low_target.supports_range_stepping == NULL) + return 0; + + return (*the_low_target.supports_range_stepping) (); +} + +#if defined PT_GETDSBT || defined PTRACE_GETFDPIC +struct target_loadseg +{ + /* Core address to which the segment is mapped. */ + Elf32_Addr addr; + /* VMA recorded in the program header. */ + Elf32_Addr p_vaddr; + /* Size of this segment in memory. */ + Elf32_Word p_memsz; +}; + +# if defined PT_GETDSBT +struct target_loadmap +{ + /* Protocol version number, must be zero. */ + Elf32_Word version; + /* Pointer to the DSBT table, its size, and the DSBT index. */ + unsigned *dsbt_table; + unsigned dsbt_size, dsbt_index; + /* Number of segments in this map. */ + Elf32_Word nsegs; + /* The actual memory map. */ + struct target_loadseg segs[/*nsegs*/]; +}; +# define LINUX_LOADMAP PT_GETDSBT +# define LINUX_LOADMAP_EXEC PTRACE_GETDSBT_EXEC +# define LINUX_LOADMAP_INTERP PTRACE_GETDSBT_INTERP +# else +struct target_loadmap +{ + /* Protocol version number, must be zero. */ + Elf32_Half version; + /* Number of segments in this map. */ + Elf32_Half nsegs; + /* The actual memory map. */ + struct target_loadseg segs[/*nsegs*/]; +}; +# define LINUX_LOADMAP PTRACE_GETFDPIC +# define LINUX_LOADMAP_EXEC PTRACE_GETFDPIC_EXEC +# define LINUX_LOADMAP_INTERP PTRACE_GETFDPIC_INTERP +# endif + +static int +linux_read_loadmap (const char *annex, CORE_ADDR offset, + unsigned char *myaddr, unsigned int len) +{ + int pid = lwpid_of (current_thread); + int addr = -1; + struct target_loadmap *data = NULL; + unsigned int actual_length, copy_length; + + if (strcmp (annex, "exec") == 0) + addr = (int) LINUX_LOADMAP_EXEC; + else if (strcmp (annex, "interp") == 0) + addr = (int) LINUX_LOADMAP_INTERP; + else + return -1; + + if (ptrace (LINUX_LOADMAP, pid, addr, &data) != 0) + return -1; + + if (data == NULL) + return -1; + + actual_length = sizeof (struct target_loadmap) + + sizeof (struct target_loadseg) * data->nsegs; + + if (offset < 0 || offset > actual_length) + return -1; + + copy_length = actual_length - offset < len ? actual_length - offset : len; + memcpy (myaddr, (char *) data + offset, copy_length); + return copy_length; +} +#else +# define linux_read_loadmap NULL +#endif /* defined PT_GETDSBT || defined PTRACE_GETFDPIC */ + +static void +linux_process_qsupported (char **features, int count) +{ + if (the_low_target.process_qsupported != NULL) + the_low_target.process_qsupported (features, count); +} + +static int +linux_supports_catch_syscall (void) +{ + return (the_low_target.get_syscall_trapinfo != NULL + && linux_supports_tracesysgood ()); +} + +static int +linux_get_ipa_tdesc_idx (void) +{ + if (the_low_target.get_ipa_tdesc_idx == NULL) + return 0; + + return (*the_low_target.get_ipa_tdesc_idx) (); +} + +static int +linux_supports_tracepoints (void) +{ + if (*the_low_target.supports_tracepoints == NULL) + return 0; + + return (*the_low_target.supports_tracepoints) (); +} + +static CORE_ADDR +linux_read_pc (struct regcache *regcache) +{ + if (the_low_target.get_pc == NULL) + return 0; + + return (*the_low_target.get_pc) (regcache); +} + +static void +linux_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + gdb_assert (the_low_target.set_pc != NULL); + + (*the_low_target.set_pc) (regcache, pc); +} + +static int +linux_thread_stopped (struct thread_info *thread) +{ + return get_thread_lwp (thread)->stopped; +} + +/* This exposes stop-all-threads functionality to other modules. */ + +static void +linux_pause_all (int freeze) +{ + stop_all_lwps (freeze, NULL); +} + +/* This exposes unstop-all-threads functionality to other gdbserver + modules. */ + +static void +linux_unpause_all (int unfreeze) +{ + unstop_all_lwps (unfreeze, NULL); +} + +static int +linux_prepare_to_access_memory (void) +{ + /* Neither ptrace nor /proc/PID/mem allow accessing memory through a + running LWP. */ + if (non_stop) + linux_pause_all (1); + return 0; +} + +static void +linux_done_accessing_memory (void) +{ + /* Neither ptrace nor /proc/PID/mem allow accessing memory through a + running LWP. */ + if (non_stop) + linux_unpause_all (1); +} + +static int +linux_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + return (*the_low_target.install_fast_tracepoint_jump_pad) + (tpoint, tpaddr, collector, lockaddr, orig_size, + jump_entry, trampoline, trampoline_size, + jjump_pad_insn, jjump_pad_insn_size, + adjusted_insn_addr, adjusted_insn_addr_end, + err); +} + +static struct emit_ops * +linux_emit_ops (void) +{ + if (the_low_target.emit_ops != NULL) + return (*the_low_target.emit_ops) (); + else + return NULL; +} + +static int +linux_get_min_fast_tracepoint_insn_len (void) +{ + return (*the_low_target.get_min_fast_tracepoint_insn_len) (); +} + +/* Extract &phdr and num_phdr in the inferior. Return 0 on success. */ + +static int +get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, + CORE_ADDR *phdr_memaddr, int *num_phdr) +{ + char filename[PATH_MAX]; + int fd; + const int auxv_size = is_elf64 + ? sizeof (Elf64_auxv_t) : sizeof (Elf32_auxv_t); + char buf[sizeof (Elf64_auxv_t)]; /* The larger of the two. */ + + xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid); + + fd = open (filename, O_RDONLY); + if (fd < 0) + return 1; + + *phdr_memaddr = 0; + *num_phdr = 0; + while (read (fd, buf, auxv_size) == auxv_size + && (*phdr_memaddr == 0 || *num_phdr == 0)) + { + if (is_elf64) + { + Elf64_auxv_t *const aux = (Elf64_auxv_t *) buf; + + switch (aux->a_type) + { + case AT_PHDR: + *phdr_memaddr = aux->a_un.a_val; + break; + case AT_PHNUM: + *num_phdr = aux->a_un.a_val; + break; + } + } + else + { + Elf32_auxv_t *const aux = (Elf32_auxv_t *) buf; + + switch (aux->a_type) + { + case AT_PHDR: + *phdr_memaddr = aux->a_un.a_val; + break; + case AT_PHNUM: + *num_phdr = aux->a_un.a_val; + break; + } + } + } + + close (fd); + + if (*phdr_memaddr == 0 || *num_phdr == 0) + { + warning ("Unexpected missing AT_PHDR and/or AT_PHNUM: " + "phdr_memaddr = %ld, phdr_num = %d", + (long) *phdr_memaddr, *num_phdr); + return 2; + } + + return 0; +} + +/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ + +static CORE_ADDR +get_dynamic (const int pid, const int is_elf64) +{ + CORE_ADDR phdr_memaddr, relocation; + int num_phdr, i; + unsigned char *phdr_buf; + const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); + + if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) + return 0; + + gdb_assert (num_phdr < 100); /* Basic sanity check. */ + phdr_buf = (unsigned char *) alloca (num_phdr * phdr_size); + + if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size)) + return 0; + + /* Compute relocation: it is expected to be 0 for "regular" executables, + non-zero for PIE ones. */ + relocation = -1; + for (i = 0; relocation == -1 && i < num_phdr; i++) + if (is_elf64) + { + Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_PHDR) + relocation = phdr_memaddr - p->p_vaddr; + } + else + { + Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_PHDR) + relocation = phdr_memaddr - p->p_vaddr; + } + + if (relocation == -1) + { + /* PT_PHDR is optional, but necessary for PIE in general. Fortunately + any real world executables, including PIE executables, have always + PT_PHDR present. PT_PHDR is not present in some shared libraries or + in fpc (Free Pascal 2.4) binaries but neither of those have a need for + or present DT_DEBUG anyway (fpc binaries are statically linked). + + Therefore if there exists DT_DEBUG there is always also PT_PHDR. + + GDB could find RELOCATION also from AT_ENTRY - e_entry. */ + + return 0; + } + + for (i = 0; i < num_phdr; i++) + { + if (is_elf64) + { + Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_DYNAMIC) + return p->p_vaddr + relocation; + } + else + { + Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_DYNAMIC) + return p->p_vaddr + relocation; + } + } + + return 0; +} + +/* Return &_r_debug in the inferior, or -1 if not present. Return value + can be 0 if the inferior does not yet have the library list initialized. + We look for DT_MIPS_RLD_MAP first. MIPS executables use this instead of + DT_DEBUG, although they sometimes contain an unused DT_DEBUG entry too. */ + +static CORE_ADDR +get_r_debug (const int pid, const int is_elf64) +{ + CORE_ADDR dynamic_memaddr; + const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn); + unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */ + CORE_ADDR map = -1; + + dynamic_memaddr = get_dynamic (pid, is_elf64); + if (dynamic_memaddr == 0) + return map; + + while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0) + { + if (is_elf64) + { + Elf64_Dyn *const dyn = (Elf64_Dyn *) buf; +#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL + union + { + Elf64_Xword map; + unsigned char buf[sizeof (Elf64_Xword)]; + } + rld_map; +#endif +#ifdef DT_MIPS_RLD_MAP + if (dyn->d_tag == DT_MIPS_RLD_MAP) + { + if (linux_read_memory (dyn->d_un.d_val, + rld_map.buf, sizeof (rld_map.buf)) == 0) + return rld_map.map; + else + break; + } +#endif /* DT_MIPS_RLD_MAP */ +#ifdef DT_MIPS_RLD_MAP_REL + if (dyn->d_tag == DT_MIPS_RLD_MAP_REL) + { + if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr, + rld_map.buf, sizeof (rld_map.buf)) == 0) + return rld_map.map; + else + break; + } +#endif /* DT_MIPS_RLD_MAP_REL */ + + if (dyn->d_tag == DT_DEBUG && map == -1) + map = dyn->d_un.d_val; + + if (dyn->d_tag == DT_NULL) + break; + } + else + { + Elf32_Dyn *const dyn = (Elf32_Dyn *) buf; +#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL + union + { + Elf32_Word map; + unsigned char buf[sizeof (Elf32_Word)]; + } + rld_map; +#endif +#ifdef DT_MIPS_RLD_MAP + if (dyn->d_tag == DT_MIPS_RLD_MAP) + { + if (linux_read_memory (dyn->d_un.d_val, + rld_map.buf, sizeof (rld_map.buf)) == 0) + return rld_map.map; + else + break; + } +#endif /* DT_MIPS_RLD_MAP */ +#ifdef DT_MIPS_RLD_MAP_REL + if (dyn->d_tag == DT_MIPS_RLD_MAP_REL) + { + if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr, + rld_map.buf, sizeof (rld_map.buf)) == 0) + return rld_map.map; + else + break; + } +#endif /* DT_MIPS_RLD_MAP_REL */ + + if (dyn->d_tag == DT_DEBUG && map == -1) + map = dyn->d_un.d_val; + + if (dyn->d_tag == DT_NULL) + break; + } + + dynamic_memaddr += dyn_size; + } + + return map; +} + +/* Read one pointer from MEMADDR in the inferior. */ + +static int +read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size) +{ + int ret; + + /* Go through a union so this works on either big or little endian + hosts, when the inferior's pointer size is smaller than the size + of CORE_ADDR. It is assumed the inferior's endianness is the + same of the superior's. */ + union + { + CORE_ADDR core_addr; + unsigned int ui; + unsigned char uc; + } addr; + + ret = linux_read_memory (memaddr, &addr.uc, ptr_size); + if (ret == 0) + { + if (ptr_size == sizeof (CORE_ADDR)) + *ptr = addr.core_addr; + else if (ptr_size == sizeof (unsigned int)) + *ptr = addr.ui; + else + gdb_assert_not_reached ("unhandled pointer size"); + } + return ret; +} + +struct link_map_offsets + { + /* Offset and size of r_debug.r_version. */ + int r_version_offset; + + /* Offset and size of r_debug.r_map. */ + int r_map_offset; + + /* Offset to l_addr field in struct link_map. */ + int l_addr_offset; + + /* Offset to l_name field in struct link_map. */ + int l_name_offset; + + /* Offset to l_ld field in struct link_map. */ + int l_ld_offset; + + /* Offset to l_next field in struct link_map. */ + int l_next_offset; + + /* Offset to l_prev field in struct link_map. */ + int l_prev_offset; + }; + +/* Construct qXfer:libraries-svr4:read reply. */ + +static int +linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len) +{ + struct process_info_private *const priv = current_process ()->priv; + char filename[PATH_MAX]; + int pid, is_elf64; + + static const struct link_map_offsets lmo_32bit_offsets = + { + 0, /* r_version offset. */ + 4, /* r_debug.r_map offset. */ + 0, /* l_addr offset in link_map. */ + 4, /* l_name offset in link_map. */ + 8, /* l_ld offset in link_map. */ + 12, /* l_next offset in link_map. */ + 16 /* l_prev offset in link_map. */ + }; + + static const struct link_map_offsets lmo_64bit_offsets = + { + 0, /* r_version offset. */ + 8, /* r_debug.r_map offset. */ + 0, /* l_addr offset in link_map. */ + 8, /* l_name offset in link_map. */ + 16, /* l_ld offset in link_map. */ + 24, /* l_next offset in link_map. */ + 32 /* l_prev offset in link_map. */ + }; + const struct link_map_offsets *lmo; + unsigned int machine; + int ptr_size; + CORE_ADDR lm_addr = 0, lm_prev = 0; + CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev; + int header_done = 0; + + if (writebuf != NULL) + return -2; + if (readbuf == NULL) + return -1; + + pid = lwpid_of (current_thread); + xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid); + is_elf64 = elf_64_file_p (filename, &machine); + lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; + ptr_size = is_elf64 ? 8 : 4; + + while (annex[0] != '\0') + { + const char *sep; + CORE_ADDR *addrp; + int name_len; + + sep = strchr (annex, '='); + if (sep == NULL) + break; + + name_len = sep - annex; + if (name_len == 5 && startswith (annex, "start")) + addrp = &lm_addr; + else if (name_len == 4 && startswith (annex, "prev")) + addrp = &lm_prev; + else + { + annex = strchr (sep, ';'); + if (annex == NULL) + break; + annex++; + continue; + } + + annex = decode_address_to_semicolon (addrp, sep + 1); + } + + if (lm_addr == 0) + { + int r_version = 0; + + if (priv->r_debug == 0) + priv->r_debug = get_r_debug (pid, is_elf64); + + /* We failed to find DT_DEBUG. Such situation will not change + for this inferior - do not retry it. Report it to GDB as + E01, see for the reasons at the GDB solib-svr4.c side. */ + if (priv->r_debug == (CORE_ADDR) -1) + return -1; + + if (priv->r_debug != 0) + { + if (linux_read_memory (priv->r_debug + lmo->r_version_offset, + (unsigned char *) &r_version, + sizeof (r_version)) != 0 + || r_version != 1) + { + warning ("unexpected r_debug version %d", r_version); + } + else if (read_one_ptr (priv->r_debug + lmo->r_map_offset, + &lm_addr, ptr_size) != 0) + { + warning ("unable to read r_map from 0x%lx", + (long) priv->r_debug + lmo->r_map_offset); + } + } + } + + std::string document = "l_name_offset, + &l_name, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_addr_offset, + &l_addr, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_ld_offset, + &l_ld, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_prev_offset, + &l_prev, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_next_offset, + &l_next, ptr_size) == 0) + { + unsigned char libname[PATH_MAX]; + + if (lm_prev != l_prev) + { + warning ("Corrupted shared library list: 0x%lx != 0x%lx", + (long) lm_prev, (long) l_prev); + break; + } + + /* Ignore the first entry even if it has valid name as the first entry + corresponds to the main executable. The first entry should not be + skipped if the dynamic loader was loaded late by a static executable + (see solib-svr4.c parameter ignore_first). But in such case the main + executable does not have PT_DYNAMIC present and this function already + exited above due to failed get_r_debug. */ + if (lm_prev == 0) + string_appendf (document, " main-lm=\"0x%lx\"", (unsigned long) lm_addr); + else + { + /* Not checking for error because reading may stop before + we've got PATH_MAX worth of characters. */ + libname[0] = '\0'; + linux_read_memory (l_name, libname, sizeof (libname) - 1); + libname[sizeof (libname) - 1] = '\0'; + if (libname[0] != '\0') + { + if (!header_done) + { + /* Terminate `", + (unsigned long) lm_addr, (unsigned long) l_addr, + (unsigned long) l_ld); + } + } + + lm_prev = lm_addr; + lm_addr = l_next; + } + + if (!header_done) + { + /* Empty list; terminate ` document_len) + len = document_len; + + memcpy (readbuf, document.data () + offset, len); + + return len; +} + +#ifdef HAVE_LINUX_BTRACE + +/* See to_disable_btrace target method. */ + +static int +linux_low_disable_btrace (struct btrace_target_info *tinfo) +{ + enum btrace_error err; + + err = linux_disable_btrace (tinfo); + return (err == BTRACE_ERR_NONE ? 0 : -1); +} + +/* Encode an Intel Processor Trace configuration. */ + +static void +linux_low_encode_pt_config (struct buffer *buffer, + const struct btrace_data_pt_config *config) +{ + buffer_grow_str (buffer, "\n"); + + switch (config->cpu.vendor) + { + case CV_INTEL: + buffer_xml_printf (buffer, "\n", + config->cpu.family, config->cpu.model, + config->cpu.stepping); + break; + + default: + break; + } + + buffer_grow_str (buffer, "\n"); +} + +/* Encode a raw buffer. */ + +static void +linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data, + unsigned int size) +{ + if (size == 0) + return; + + /* We use hex encoding - see gdbsupport/rsp-low.h. */ + buffer_grow_str (buffer, "\n"); + + while (size-- > 0) + { + char elem[2]; + + elem[0] = tohex ((*data >> 4) & 0xf); + elem[1] = tohex (*data++ & 0xf); + + buffer_grow (buffer, elem, 2); + } + + buffer_grow_str (buffer, "\n"); +} + +/* See to_read_btrace target method. */ + +static int +linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer, + enum btrace_read_type type) +{ + struct btrace_data btrace; + enum btrace_error err; + + err = linux_read_btrace (&btrace, tinfo, type); + if (err != BTRACE_ERR_NONE) + { + if (err == BTRACE_ERR_OVERFLOW) + buffer_grow_str0 (buffer, "E.Overflow."); + else + buffer_grow_str0 (buffer, "E.Generic Error."); + + return -1; + } + + switch (btrace.format) + { + case BTRACE_FORMAT_NONE: + buffer_grow_str0 (buffer, "E.No Trace."); + return -1; + + case BTRACE_FORMAT_BTS: + buffer_grow_str (buffer, "\n"); + buffer_grow_str (buffer, "\n"); + + for (const btrace_block &block : *btrace.variant.bts.blocks) + buffer_xml_printf (buffer, "\n", + paddress (block.begin), paddress (block.end)); + + buffer_grow_str0 (buffer, "\n"); + break; + + case BTRACE_FORMAT_PT: + buffer_grow_str (buffer, "\n"); + buffer_grow_str (buffer, "\n"); + buffer_grow_str (buffer, "\n"); + + linux_low_encode_pt_config (buffer, &btrace.variant.pt.config); + + linux_low_encode_raw (buffer, btrace.variant.pt.data, + btrace.variant.pt.size); + + buffer_grow_str (buffer, "\n"); + buffer_grow_str0 (buffer, "\n"); + break; + + default: + buffer_grow_str0 (buffer, "E.Unsupported Trace Format."); + return -1; + } + + return 0; +} + +/* See to_btrace_conf target method. */ + +static int +linux_low_btrace_conf (const struct btrace_target_info *tinfo, + struct buffer *buffer) +{ + const struct btrace_config *conf; + + buffer_grow_str (buffer, "\n"); + buffer_grow_str (buffer, "\n"); + + conf = linux_btrace_conf (tinfo); + if (conf != NULL) + { + switch (conf->format) + { + case BTRACE_FORMAT_NONE: + break; + + case BTRACE_FORMAT_BTS: + buffer_xml_printf (buffer, "bts.size); + buffer_xml_printf (buffer, " />\n"); + break; + + case BTRACE_FORMAT_PT: + buffer_xml_printf (buffer, "pt.size); + buffer_xml_printf (buffer, "/>\n"); + break; + } + } + + buffer_grow_str0 (buffer, "\n"); + return 0; +} +#endif /* HAVE_LINUX_BTRACE */ + +/* See nat/linux-nat.h. */ + +ptid_t +current_lwp_ptid (void) +{ + return ptid_of (current_thread); +} + +/* Implementation of the target_ops method "breakpoint_kind_from_pc". */ + +static int +linux_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + if (the_low_target.breakpoint_kind_from_pc != NULL) + return (*the_low_target.breakpoint_kind_from_pc) (pcptr); + else + return default_breakpoint_kind_from_pc (pcptr); +} + +/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +linux_sw_breakpoint_from_kind (int kind, int *size) +{ + gdb_assert (the_low_target.sw_breakpoint_from_kind != NULL); + + return (*the_low_target.sw_breakpoint_from_kind) (kind, size); +} + +/* Implementation of the target_ops method + "breakpoint_kind_from_current_state". */ + +static int +linux_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) +{ + if (the_low_target.breakpoint_kind_from_current_state != NULL) + return (*the_low_target.breakpoint_kind_from_current_state) (pcptr); + else + return linux_breakpoint_kind_from_pc (pcptr); +} + +/* Default implementation of linux_target_ops method "set_pc" for + 32-bit pc register which is literally named "pc". */ + +void +linux_set_pc_32bit (struct regcache *regcache, CORE_ADDR pc) +{ + uint32_t newpc = pc; + + supply_register_by_name (regcache, "pc", &newpc); +} + +/* Default implementation of linux_target_ops method "get_pc" for + 32-bit pc register which is literally named "pc". */ + +CORE_ADDR +linux_get_pc_32bit (struct regcache *regcache) +{ + uint32_t pc; + + collect_register_by_name (regcache, "pc", &pc); + if (debug_threads) + debug_printf ("stop pc is 0x%" PRIx32 "\n", pc); + return pc; +} + +/* Default implementation of linux_target_ops method "set_pc" for + 64-bit pc register which is literally named "pc". */ + +void +linux_set_pc_64bit (struct regcache *regcache, CORE_ADDR pc) +{ + uint64_t newpc = pc; + + supply_register_by_name (regcache, "pc", &newpc); +} + +/* Default implementation of linux_target_ops method "get_pc" for + 64-bit pc register which is literally named "pc". */ + +CORE_ADDR +linux_get_pc_64bit (struct regcache *regcache) +{ + uint64_t pc; + + collect_register_by_name (regcache, "pc", &pc); + if (debug_threads) + debug_printf ("stop pc is 0x%" PRIx64 "\n", pc); + return pc; +} + +/* See linux-low.h. */ + +int +linux_get_auxv (int wordsize, CORE_ADDR match, CORE_ADDR *valp) +{ + gdb_byte *data = (gdb_byte *) alloca (2 * wordsize); + int offset = 0; + + gdb_assert (wordsize == 4 || wordsize == 8); + + while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize) + { + if (wordsize == 4) + { + uint32_t *data_p = (uint32_t *) data; + if (data_p[0] == match) + { + *valp = data_p[1]; + return 1; + } + } + else + { + uint64_t *data_p = (uint64_t *) data; + if (data_p[0] == match) + { + *valp = data_p[1]; + return 1; + } + } + + offset += 2 * wordsize; + } + + return 0; +} + +/* See linux-low.h. */ + +CORE_ADDR +linux_get_hwcap (int wordsize) +{ + CORE_ADDR hwcap = 0; + linux_get_auxv (wordsize, AT_HWCAP, &hwcap); + return hwcap; +} + +/* See linux-low.h. */ + +CORE_ADDR +linux_get_hwcap2 (int wordsize) +{ + CORE_ADDR hwcap2 = 0; + linux_get_auxv (wordsize, AT_HWCAP2, &hwcap2); + return hwcap2; +} + +static process_stratum_target linux_target_ops = { + linux_create_inferior, + linux_post_create_inferior, + linux_attach, + linux_kill, + linux_detach, + linux_mourn, + linux_join, + linux_thread_alive, + linux_resume, + linux_wait, + linux_fetch_registers, + linux_store_registers, + linux_prepare_to_access_memory, + linux_done_accessing_memory, + linux_read_memory, + linux_write_memory, + linux_look_up_symbols, + linux_request_interrupt, + linux_read_auxv, + linux_supports_z_point_type, + linux_insert_point, + linux_remove_point, + linux_stopped_by_sw_breakpoint, + linux_supports_stopped_by_sw_breakpoint, + linux_stopped_by_hw_breakpoint, + linux_supports_stopped_by_hw_breakpoint, + linux_supports_hardware_single_step, + linux_stopped_by_watchpoint, + linux_stopped_data_address, +#if defined(__UCLIBC__) && defined(HAS_NOMMU) \ + && defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) \ + && defined(PT_TEXT_END_ADDR) + linux_read_offsets, +#else + NULL, +#endif +#ifdef USE_THREAD_DB + thread_db_get_tls_address, +#else + NULL, +#endif + hostio_last_error_from_errno, + linux_qxfer_osdata, + linux_xfer_siginfo, + linux_supports_non_stop, + linux_async, + linux_start_non_stop, + linux_supports_multi_process, + linux_supports_fork_events, + linux_supports_vfork_events, + linux_supports_exec_events, + linux_handle_new_gdb_connection, +#ifdef USE_THREAD_DB + thread_db_handle_monitor_command, +#else + NULL, +#endif + linux_common_core_of_thread, + linux_read_loadmap, + linux_process_qsupported, + linux_supports_tracepoints, + linux_read_pc, + linux_write_pc, + linux_thread_stopped, + NULL, + linux_pause_all, + linux_unpause_all, + linux_stabilize_threads, + linux_install_fast_tracepoint_jump_pad, + linux_emit_ops, + linux_supports_disable_randomization, + linux_get_min_fast_tracepoint_insn_len, + linux_qxfer_libraries_svr4, + linux_supports_agent, +#ifdef HAVE_LINUX_BTRACE + linux_enable_btrace, + linux_low_disable_btrace, + linux_low_read_btrace, + linux_low_btrace_conf, +#else + NULL, + NULL, + NULL, + NULL, +#endif + linux_supports_range_stepping, + linux_proc_pid_to_exec_file, + linux_mntns_open_cloexec, + linux_mntns_unlink, + linux_mntns_readlink, + linux_breakpoint_kind_from_pc, + linux_sw_breakpoint_from_kind, + linux_proc_tid_get_name, + linux_breakpoint_kind_from_current_state, + linux_supports_software_single_step, + linux_supports_catch_syscall, + linux_get_ipa_tdesc_idx, +#if USE_THREAD_DB + thread_db_thread_handle, +#else + NULL, +#endif +}; + +#ifdef HAVE_LINUX_REGSETS +void +initialize_regsets_info (struct regsets_info *info) +{ + for (info->num_regsets = 0; + info->regsets[info->num_regsets].size >= 0; + info->num_regsets++) + ; +} +#endif + +void +initialize_low (void) +{ + struct sigaction sigchld_action; + + memset (&sigchld_action, 0, sizeof (sigchld_action)); + set_target_ops (&linux_target_ops); + + linux_ptrace_init_warnings (); + linux_proc_init_warnings (); + + sigchld_action.sa_handler = sigchld_handler; + sigemptyset (&sigchld_action.sa_mask); + sigchld_action.sa_flags = SA_RESTART; + sigaction (SIGCHLD, &sigchld_action, NULL); + + initialize_low_arch (); + + linux_check_ptrace_features (); +} diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h new file mode 100644 index 00000000000..e25ddd024dd --- /dev/null +++ b/gdbserver/linux-low.h @@ -0,0 +1,456 @@ +/* Internal interfaces for the GNU/Linux specific target code for gdbserver. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_LOW_H +#define GDBSERVER_LINUX_LOW_H + +#include "nat/linux-nat.h" +#include "nat/gdb_thread_db.h" +#include + +#include "gdbthread.h" +#include "gdb_proc_service.h" + +/* Included for ptrace type definitions. */ +#include "nat/linux-ptrace.h" +#include "target/waitstatus.h" /* For enum target_stop_reason. */ +#include "tracepoint.h" + +#define PTRACE_XFER_TYPE long + +#ifdef HAVE_LINUX_REGSETS +typedef void (*regset_fill_func) (struct regcache *, void *); +typedef void (*regset_store_func) (struct regcache *, const void *); +enum regset_type { + GENERAL_REGS, + FP_REGS, + EXTENDED_REGS, + OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */ +}; + +/* The arch's regsets array initializer must be terminated with a NULL + regset. */ +#define NULL_REGSET \ + { 0, 0, 0, -1, (enum regset_type) -1, NULL, NULL } + +struct regset_info +{ + int get_request, set_request; + /* If NT_TYPE isn't 0, it will be passed to ptrace as the 3rd + argument and the 4th argument should be "const struct iovec *". */ + int nt_type; + int size; + enum regset_type type; + regset_fill_func fill_function; + regset_store_func store_function; +}; + +/* Aggregation of all the supported regsets of a given + architecture/mode. */ + +struct regsets_info +{ + /* The regsets array. */ + struct regset_info *regsets; + + /* The number of regsets in the REGSETS array. */ + int num_regsets; + + /* If we get EIO on a regset, do not try it again. Note the set of + supported regsets may depend on processor mode on biarch + machines. This is a (lazily allocated) array holding one boolean + byte (0/1) per regset, with each element corresponding to the + regset in the REGSETS array above at the same offset. */ + char *disabled_regsets; +}; + +#endif + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register array layout. */ + +struct usrregs_info +{ + /* The number of registers accessible. */ + int num_regs; + + /* The registers map. */ + int *regmap; +}; + +/* All info needed to access an architecture/mode's registers. */ + +struct regs_info +{ + /* Regset support bitmap: 1 for registers that are transferred as a part + of a regset, 0 for ones that need to be handled individually. This + can be NULL if all registers are transferred with regsets or regsets + are not supported. */ + unsigned char *regset_bitmap; + + /* Info used when accessing registers with PTRACE_PEEKUSER / + PTRACE_POKEUSER. This can be NULL if all registers are + transferred with regsets .*/ + struct usrregs_info *usrregs; + +#ifdef HAVE_LINUX_REGSETS + /* Info used when accessing registers with regsets. */ + struct regsets_info *regsets_info; +#endif +}; + +struct process_info_private +{ + /* Arch-specific additions. */ + struct arch_process_info *arch_private; + + /* libthread_db-specific additions. Not NULL if this process has loaded + thread_db, and it is active. */ + struct thread_db *thread_db; + + /* &_r_debug. 0 if not yet determined. -1 if no PT_DYNAMIC in Phdrs. */ + CORE_ADDR r_debug; +}; + +struct lwp_info; + +struct linux_target_ops +{ + /* Architecture-specific setup. */ + void (*arch_setup) (void); + + const struct regs_info *(*regs_info) (void); + int (*cannot_fetch_register) (int); + + /* Returns 0 if we can store the register, 1 if we can not + store the register, and 2 if failure to store the register + is acceptable. */ + int (*cannot_store_register) (int); + + /* Hook to fetch a register in some non-standard way. Used for + example by backends that have read-only registers with hardcoded + values (e.g., IA64's gr0/fr0/fr1). Returns true if register + REGNO was supplied, false if not, and we should fallback to the + standard ptrace methods. */ + int (*fetch_register) (struct regcache *regcache, int regno); + + CORE_ADDR (*get_pc) (struct regcache *regcache); + void (*set_pc) (struct regcache *regcache, CORE_ADDR newpc); + + /* See target.h for details. */ + int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr); + + /* See target.h for details. */ + const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size); + + /* Find the next possible PCs after the current instruction executes. */ + std::vector (*get_next_pcs) (struct regcache *regcache); + + int decr_pc_after_break; + int (*breakpoint_at) (CORE_ADDR pc); + + /* Breakpoint and watchpoint related functions. See target.h for + comments. */ + int (*supports_z_point_type) (char z_type); + int (*insert_point) (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp); + int (*remove_point) (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp); + + int (*stopped_by_watchpoint) (void); + CORE_ADDR (*stopped_data_address) (void); + + /* Hooks to reformat register data for PEEKUSR/POKEUSR (in particular + for registers smaller than an xfer unit). */ + void (*collect_ptrace_register) (struct regcache *regcache, + int regno, char *buf); + void (*supply_ptrace_register) (struct regcache *regcache, + int regno, const char *buf); + + /* Hook to convert from target format to ptrace format and back. + Returns true if any conversion was done; false otherwise. + If DIRECTION is 1, then copy from INF to NATIVE. + If DIRECTION is 0, copy from NATIVE to INF. */ + int (*siginfo_fixup) (siginfo_t *native, gdb_byte *inf, int direction); + + /* Hook to call when a new process is created or attached to. + If extra per-process architecture-specific data is needed, + allocate it here. */ + struct arch_process_info * (*new_process) (void); + + /* Hook to call when a process is being deleted. If extra per-process + architecture-specific data is needed, delete it here. */ + void (*delete_process) (struct arch_process_info *info); + + /* Hook to call when a new thread is detected. + If extra per-thread architecture-specific data is needed, + allocate it here. */ + void (*new_thread) (struct lwp_info *); + + /* Hook to call when a thread is being deleted. If extra per-thread + architecture-specific data is needed, delete it here. */ + void (*delete_thread) (struct arch_lwp_info *); + + /* Hook to call, if any, when a new fork is attached. */ + void (*new_fork) (struct process_info *parent, struct process_info *child); + + /* Hook to call prior to resuming a thread. */ + void (*prepare_to_resume) (struct lwp_info *); + + /* Hook to support target specific qSupported. */ + void (*process_qsupported) (char **, int count); + + /* Returns true if the low target supports tracepoints. */ + int (*supports_tracepoints) (void); + + /* Fill ADDRP with the thread area address of LWPID. Returns 0 on + success, -1 on failure. */ + int (*get_thread_area) (int lwpid, CORE_ADDR *addrp); + + /* Install a fast tracepoint jump pad. See target.h for + comments. */ + int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err); + + /* Return the bytecode operations vector for the current inferior. + Returns NULL if bytecode compilation is not supported. */ + struct emit_ops *(*emit_ops) (void); + + /* Return the minimum length of an instruction that can be safely overwritten + for use as a fast tracepoint. */ + int (*get_min_fast_tracepoint_insn_len) (void); + + /* Returns true if the low target supports range stepping. */ + int (*supports_range_stepping) (void); + + /* See target.h. */ + int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr); + + /* See target.h. */ + int (*supports_hardware_single_step) (void); + + /* Fill *SYSNO with the syscall nr trapped. Only to be called when + inferior is stopped due to SYSCALL_SIGTRAP. */ + void (*get_syscall_trapinfo) (struct regcache *regcache, int *sysno); + + /* See target.h. */ + int (*get_ipa_tdesc_idx) (void); +}; + +extern struct linux_target_ops the_low_target; + +#define get_thread_lwp(thr) ((struct lwp_info *) (thread_target_data (thr))) +#define get_lwp_thread(lwp) ((lwp)->thread) + +/* This struct is recorded in the target_data field of struct thread_info. + + On linux ``all_threads'' is keyed by the LWP ID, which we use as the + GDB protocol representation of the thread ID. Threads also have + a "process ID" (poorly named) which is (presently) the same as the + LWP ID. + + There is also ``all_processes'' is keyed by the "overall process ID", + which GNU/Linux calls tgid, "thread group ID". */ + +struct lwp_info +{ + /* Backlink to the parent object. */ + struct thread_info *thread; + + /* If this flag is set, the next SIGSTOP will be ignored (the + process will be immediately resumed). This means that either we + sent the SIGSTOP to it ourselves and got some other pending event + (so the SIGSTOP is still pending), or that we stopped the + inferior implicitly via PTRACE_ATTACH and have not waited for it + yet. */ + int stop_expected; + + /* When this is true, we shall not try to resume this thread, even + if last_resume_kind isn't resume_stop. */ + int suspended; + + /* If this flag is set, the lwp is known to be stopped right now (stop + event already received in a wait()). */ + int stopped; + + /* Signal whether we are in a SYSCALL_ENTRY or + in a SYSCALL_RETURN event. + Values: + - TARGET_WAITKIND_SYSCALL_ENTRY + - TARGET_WAITKIND_SYSCALL_RETURN */ + enum target_waitkind syscall_state; + + /* When stopped is set, the last wait status recorded for this lwp. */ + int last_status; + + /* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for + this LWP's last event, to pass to GDB without any further + processing. This is used to store extended ptrace event + information or exit status until it can be reported to GDB. */ + struct target_waitstatus waitstatus; + + /* A pointer to the fork child/parent relative. Valid only while + the parent fork event is not reported to higher layers. Used to + avoid wildcard vCont actions resuming a fork child before GDB is + notified about the parent's fork event. */ + struct lwp_info *fork_relative; + + /* When stopped is set, this is where the lwp last stopped, with + decr_pc_after_break already accounted for. If the LWP is + running, this is the address at which the lwp was resumed. */ + CORE_ADDR stop_pc; + + /* If this flag is set, STATUS_PENDING is a waitstatus that has not yet + been reported. */ + int status_pending_p; + int status_pending; + + /* The reason the LWP last stopped, if we need to track it + (breakpoint, watchpoint, etc.) */ + enum target_stop_reason stop_reason; + + /* On architectures where it is possible to know the data address of + a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and + contains such data address. Only valid if STOPPED_BY_WATCHPOINT + is true. */ + CORE_ADDR stopped_data_address; + + /* If this is non-zero, it is a breakpoint to be reinserted at our next + stop (SIGTRAP stops only). */ + CORE_ADDR bp_reinsert; + + /* If this flag is set, the last continue operation at the ptrace + level on this process was a single-step. */ + int stepping; + + /* Range to single step within. This is a copy of the step range + passed along the last resume request. See 'struct + thread_resume'. */ + CORE_ADDR step_range_start; /* Inclusive */ + CORE_ADDR step_range_end; /* Exclusive */ + + /* If this flag is set, we need to set the event request flags the + next time we see this LWP stop. */ + int must_set_ptrace_flags; + + /* If this is non-zero, it points to a chain of signals which need to + be delivered to this process. */ + struct pending_signals *pending_signals; + + /* A link used when resuming. It is initialized from the resume request, + and then processed and cleared in linux_resume_one_lwp. */ + struct thread_resume *resume; + + /* Information bout this lwp's fast tracepoint collection status (is it + currently stopped in the jump pad, and if so, before or at/after the + relocated instruction). Normally, we won't care about this, but we will + if a signal arrives to this lwp while it is collecting. */ + fast_tpoint_collect_result collecting_fast_tracepoint; + + /* If this is non-zero, it points to a chain of signals which need + to be reported to GDB. These were deferred because the thread + was doing a fast tracepoint collect when they arrived. */ + struct pending_signals *pending_signals_to_report; + + /* When collecting_fast_tracepoint is first found to be 1, we insert + a exit-jump-pad-quickly breakpoint. This is it. */ + struct breakpoint *exit_jump_pad_bkpt; + +#ifdef USE_THREAD_DB + int thread_known; + /* The thread handle, used for e.g. TLS access. Only valid if + THREAD_KNOWN is set. */ + td_thrhandle_t th; + + /* The pthread_t handle. */ + thread_t thread_handle; +#endif + + /* Arch-specific additions. */ + struct arch_lwp_info *arch_private; +}; + +int linux_pid_exe_is_elf_64_file (int pid, unsigned int *machine); + +/* Attach to PTID. Returns 0 on success, non-zero otherwise (an + errno). */ +int linux_attach_lwp (ptid_t ptid); + +struct lwp_info *find_lwp_pid (ptid_t ptid); +/* For linux_stop_lwp see nat/linux-nat.h. */ + +#ifdef HAVE_LINUX_REGSETS +void initialize_regsets_info (struct regsets_info *regsets_info); +#endif + +void initialize_low_arch (void); + +void linux_set_pc_32bit (struct regcache *regcache, CORE_ADDR pc); +CORE_ADDR linux_get_pc_32bit (struct regcache *regcache); + +void linux_set_pc_64bit (struct regcache *regcache, CORE_ADDR pc); +CORE_ADDR linux_get_pc_64bit (struct regcache *regcache); + +/* From thread-db.c */ +int thread_db_init (void); +void thread_db_detach (struct process_info *); +void thread_db_mourn (struct process_info *); +int thread_db_handle_monitor_command (char *); +int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, + CORE_ADDR load_module, CORE_ADDR *address); +int thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp); + +/* Called from linux-low.c when a clone event is detected. Upon entry, + both the clone and the parent should be stopped. This function does + whatever is required have the clone under thread_db's control. */ + +void thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid); + +bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len); + +extern int have_ptrace_getregset; + +/* Search for the value with type MATCH in the auxv vector with + entries of length WORDSIZE bytes. If found, store the value in + *VALP and return 1. If not found or if there is an error, return + 0. */ + +int linux_get_auxv (int wordsize, CORE_ADDR match, + CORE_ADDR *valp); + +/* Fetch the AT_HWCAP entry from the auxv vector, where entries are length + WORDSIZE. If no entry was found, return zero. */ + +CORE_ADDR linux_get_hwcap (int wordsize); + +/* Fetch the AT_HWCAP2 entry from the auxv vector, where entries are length + WORDSIZE. If no entry was found, return zero. */ + +CORE_ADDR linux_get_hwcap2 (int wordsize); + +#endif /* GDBSERVER_LINUX_LOW_H */ diff --git a/gdbserver/linux-m32r-low.c b/gdbserver/linux-m32r-low.c new file mode 100644 index 00000000000..c52e816e341 --- /dev/null +++ b/gdbserver/linux-m32r-low.c @@ -0,0 +1,157 @@ +/* GNU/Linux/m32r specific low level interface, for the remote server for GDB. + Copyright (C) 2005-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +#ifdef HAVE_SYS_REG_H +#include +#endif + +/* Defined in auto-generated file reg-m32r.c. */ +void init_registers_m32r (void); +extern const struct target_desc *tdesc_m32r; + +#define m32r_num_regs 25 + +static int m32r_regmap[] = { +#ifdef PT_R0 + PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, + PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU, + PT_PSW, PT_CBR, PT_SPI, PT_SPU, PT_BPC, PT_PC, PT_ACCL, PT_ACCH, PT_EVB +#else + 4 * 4, 4 * 5, 4 * 6, 4 * 7, 4 * 0, 4 * 1, 4 * 2, 4 * 8, + 4 * 9, 4 * 10, 4 * 11, 4 * 12, 4 * 13, 4 * 24, 4 * 25, 4 * 23, + 4 * 19, 4 * 31, 4 * 26, 4 * 23, 4 * 20, 4 * 30, 4 * 16, 4 * 15, 4 * 32 +#endif +}; + +static int +m32r_cannot_store_register (int regno) +{ + return (regno >= m32r_num_regs); +} + +static int +m32r_cannot_fetch_register (int regno) +{ + return (regno >= m32r_num_regs); +} + +static const unsigned short m32r_breakpoint = 0x10f1; +#define m32r_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +m32r_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = m32r_breakpoint_len; + return (const gdb_byte *) &m32r_breakpoint; +} + +static int +m32r_breakpoint_at (CORE_ADDR where) +{ + unsigned short insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, + m32r_breakpoint_len); + if (insn == m32r_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +static void +m32r_arch_setup (void) +{ + current_process ()->tdesc = tdesc_m32r; +} + +/* Support for hardware single step. */ + +static int +m32r_supports_hardware_single_step (void) +{ + return 1; +} + +static struct usrregs_info m32r_usrregs_info = + { + m32r_num_regs, + m32r_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &m32r_usrregs_info, + }; + +static const struct regs_info * +m32r_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + m32r_arch_setup, + m32r_regs_info, + m32r_cannot_fetch_register, + m32r_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_from_pc */ + m32r_sw_breakpoint_from_kind, + NULL, + 0, + m32r_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + m32r_supports_hardware_single_step, +}; + +void +initialize_low_arch (void) +{ + init_registers_m32r (); +} diff --git a/gdbserver/linux-m68k-low.c b/gdbserver/linux-m68k-low.c new file mode 100644 index 00000000000..246b295a875 --- /dev/null +++ b/gdbserver/linux-m68k-low.c @@ -0,0 +1,255 @@ +/* GNU/Linux/m68k specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +/* Defined in auto-generated file reg-m68k.c. */ +void init_registers_m68k (void); +extern const struct target_desc *tdesc_m68k; + +#ifdef HAVE_SYS_REG_H +#include +#endif + +#define m68k_num_regs 29 +#define m68k_num_gregs 18 + +/* This table must line up with REGISTER_NAMES in tm-m68k.h */ +static int m68k_regmap[] = +{ +#ifdef PT_D0 + PT_D0 * 4, PT_D1 * 4, PT_D2 * 4, PT_D3 * 4, + PT_D4 * 4, PT_D5 * 4, PT_D6 * 4, PT_D7 * 4, + PT_A0 * 4, PT_A1 * 4, PT_A2 * 4, PT_A3 * 4, + PT_A4 * 4, PT_A5 * 4, PT_A6 * 4, PT_USP * 4, + PT_SR * 4, PT_PC * 4, +#else + 14 * 4, 0 * 4, 1 * 4, 2 * 4, 3 * 4, 4 * 4, 5 * 4, 6 * 4, + 7 * 4, 8 * 4, 9 * 4, 10 * 4, 11 * 4, 12 * 4, 13 * 4, 15 * 4, + 17 * 4, 18 * 4, +#endif +#ifdef PT_FP0 + PT_FP0 * 4, PT_FP1 * 4, PT_FP2 * 4, PT_FP3 * 4, + PT_FP4 * 4, PT_FP5 * 4, PT_FP6 * 4, PT_FP7 * 4, + PT_FPCR * 4, PT_FPSR * 4, PT_FPIAR * 4 +#else + 21 * 4, 24 * 4, 27 * 4, 30 * 4, 33 * 4, 36 * 4, + 39 * 4, 42 * 4, 45 * 4, 46 * 4, 47 * 4 +#endif +}; + +static int +m68k_cannot_store_register (int regno) +{ + return (regno >= m68k_num_regs); +} + +static int +m68k_cannot_fetch_register (int regno) +{ + return (regno >= m68k_num_regs); +} + +#ifdef HAVE_PTRACE_GETREGS +#include +#include "nat/gdb_ptrace.h" + +static void +m68k_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + + for (i = 0; i < m68k_num_gregs; i++) + collect_register (regcache, i, (char *) buf + m68k_regmap[i]); +} + +static void +m68k_store_gregset (struct regcache *regcache, const void *buf) +{ + int i; + + for (i = 0; i < m68k_num_gregs; i++) + supply_register (regcache, i, (const char *) buf + m68k_regmap[i]); +} + +static void +m68k_fill_fpregset (struct regcache *regcache, void *buf) +{ + int i; + + for (i = m68k_num_gregs; i < m68k_num_regs; i++) + collect_register (regcache, i, ((char *) buf + + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs]))); +} + +static void +m68k_store_fpregset (struct regcache *regcache, const void *buf) +{ + int i; + + for (i = m68k_num_gregs; i < m68k_num_regs; i++) + supply_register (regcache, i, ((const char *) buf + + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs]))); +} + +#endif /* HAVE_PTRACE_GETREGS */ + +static struct regset_info m68k_regsets[] = { +#ifdef HAVE_PTRACE_GETREGS + { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), + GENERAL_REGS, + m68k_fill_gregset, m68k_store_gregset }, + { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t), + FP_REGS, + m68k_fill_fpregset, m68k_store_fpregset }, +#endif /* HAVE_PTRACE_GETREGS */ + NULL_REGSET +}; + +static const gdb_byte m68k_breakpoint[] = { 0x4E, 0x4F }; +#define m68k_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +m68k_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = m68k_breakpoint_len; + return m68k_breakpoint; +} + +static int +m68k_breakpoint_at (CORE_ADDR pc) +{ + unsigned char c[2]; + + read_inferior_memory (pc, c, 2); + if (c[0] == 0x4E && c[1] == 0x4F) + return 1; + + return 0; +} + +#include + +#ifdef PTRACE_GET_THREAD_AREA +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *)*base - idx); + + return PS_OK; +} +#endif /* PTRACE_GET_THREAD_AREA */ + +static struct regsets_info m68k_regsets_info = + { + m68k_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info m68k_usrregs_info = + { + m68k_num_regs, + m68k_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &m68k_usrregs_info, + &m68k_regsets_info + }; + +static const struct regs_info * +m68k_regs_info (void) +{ + return ®s_info; +} + +static void +m68k_arch_setup (void) +{ + current_process ()->tdesc = tdesc_m68k; +} + +/* Support for hardware single step. */ + +static int +m68k_supports_hardware_single_step (void) +{ + return 1; +} + +struct linux_target_ops the_low_target = { + m68k_arch_setup, + m68k_regs_info, + m68k_cannot_fetch_register, + m68k_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + m68k_sw_breakpoint_from_kind, + NULL, + 2, + m68k_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + m68k_supports_hardware_single_step, +}; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_m68k (); + + initialize_regsets_info (&m68k_regsets_info); +} diff --git a/gdbserver/linux-mips-low.c b/gdbserver/linux-mips-low.c new file mode 100644 index 00000000000..f94e141be79 --- /dev/null +++ b/gdbserver/linux-mips-low.c @@ -0,0 +1,978 @@ +/* GNU/Linux/MIPS specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +#include "nat/gdb_ptrace.h" +#include + +#include "nat/mips-linux-watch.h" +#include "gdb_proc_service.h" + +/* Defined in auto-generated file mips-linux.c. */ +void init_registers_mips_linux (void); +extern const struct target_desc *tdesc_mips_linux; + +/* Defined in auto-generated file mips-dsp-linux.c. */ +void init_registers_mips_dsp_linux (void); +extern const struct target_desc *tdesc_mips_dsp_linux; + +/* Defined in auto-generated file mips64-linux.c. */ +void init_registers_mips64_linux (void); +extern const struct target_desc *tdesc_mips64_linux; + +/* Defined in auto-generated file mips64-dsp-linux.c. */ +void init_registers_mips64_dsp_linux (void); +extern const struct target_desc *tdesc_mips64_dsp_linux; + +#ifdef __mips64 +#define tdesc_mips_linux tdesc_mips64_linux +#define tdesc_mips_dsp_linux tdesc_mips64_dsp_linux +#endif + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +#ifdef HAVE_SYS_REG_H +#include +#endif + +#define mips_num_regs 73 +#define mips_dsp_num_regs 80 + +#include + +#ifndef DSP_BASE +#define DSP_BASE 71 +#define DSP_CONTROL 77 +#endif + +union mips_register +{ + unsigned char buf[8]; + + /* Deliberately signed, for proper sign extension. */ + int reg32; + long long reg64; +}; + +/* Return the ptrace ``address'' of register REGNO. */ + +#define mips_base_regs \ + -1, 1, 2, 3, 4, 5, 6, 7, \ + 8, 9, 10, 11, 12, 13, 14, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26, 27, 28, 29, 30, 31, \ + \ + -1, MMLO, MMHI, BADVADDR, CAUSE, PC, \ + \ + FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3, \ + FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7, \ + FPR_BASE + 8, FPR_BASE + 9, FPR_BASE + 10, FPR_BASE + 11, \ + FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15, \ + FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19, \ + FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23, \ + FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27, \ + FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31, \ + FPC_CSR, FPC_EIR + +#define mips_dsp_regs \ + DSP_BASE, DSP_BASE + 1, DSP_BASE + 2, DSP_BASE + 3, \ + DSP_BASE + 4, DSP_BASE + 5, \ + DSP_CONTROL + +static int mips_regmap[mips_num_regs] = { + mips_base_regs, + 0 +}; + +static int mips_dsp_regmap[mips_dsp_num_regs] = { + mips_base_regs, + mips_dsp_regs, + 0 +}; + +/* DSP registers are not in any regset and can only be accessed + individually. */ + +static unsigned char mips_dsp_regset_bitmap[(mips_dsp_num_regs + 7) / 8] = { + 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x80 +}; + +static int have_dsp = -1; + +/* Try peeking at an arbitrarily chosen DSP register and pick the available + user register set accordingly. */ + +static const struct target_desc * +mips_read_description (void) +{ + if (have_dsp < 0) + { + int pid = lwpid_of (current_thread); + + errno = 0; + ptrace (PTRACE_PEEKUSER, pid, DSP_CONTROL, 0); + switch (errno) + { + case 0: + have_dsp = 1; + break; + case EIO: + have_dsp = 0; + break; + default: + perror_with_name ("ptrace"); + break; + } + } + + return have_dsp ? tdesc_mips_dsp_linux : tdesc_mips_linux; +} + +static void +mips_arch_setup (void) +{ + current_process ()->tdesc = mips_read_description (); +} + +static struct usrregs_info * +get_usrregs_info (void) +{ + const struct regs_info *regs_info = the_low_target.regs_info (); + + return regs_info->usrregs; +} + +/* Per-process arch-specific data we want to keep. */ + +struct arch_process_info +{ + /* -1 if the kernel and/or CPU do not support watch registers. + 1 if watch_readback is valid and we can read style, num_valid + and the masks. + 0 if we need to read the watch_readback. */ + + int watch_readback_valid; + + /* Cached watch register read values. */ + + struct pt_watch_regs watch_readback; + + /* Current watchpoint requests for this process. */ + + struct mips_watchpoint *current_watches; + + /* The current set of watch register values for writing the + registers. */ + + struct pt_watch_regs watch_mirror; +}; + +/* Per-thread arch-specific data we want to keep. */ + +struct arch_lwp_info +{ + /* Non-zero if our copy differs from what's recorded in the thread. */ + int watch_registers_changed; +}; + +/* From mips-linux-nat.c. */ + +/* Pseudo registers can not be read. ptrace does not provide a way to + read (or set) PS_REGNUM, and there's no point in reading or setting + ZERO_REGNUM, it's always 0. We also can not set BADVADDR, CAUSE, + or FCRIR via ptrace(). */ + +static int +mips_cannot_fetch_register (int regno) +{ + const struct target_desc *tdesc; + + if (get_usrregs_info ()->regmap[regno] == -1) + return 1; + + tdesc = current_process ()->tdesc; + + /* On n32 we can't access 64-bit registers via PTRACE_PEEKUSR. */ + if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE)) + return 1; + + if (find_regno (tdesc, "r0") == regno) + return 1; + + return 0; +} + +static int +mips_cannot_store_register (int regno) +{ + const struct target_desc *tdesc; + + if (get_usrregs_info ()->regmap[regno] == -1) + return 1; + + tdesc = current_process ()->tdesc; + + /* On n32 we can't access 64-bit registers via PTRACE_POKEUSR. */ + if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE)) + return 1; + + if (find_regno (tdesc, "r0") == regno) + return 1; + + if (find_regno (tdesc, "cause") == regno) + return 1; + + if (find_regno (tdesc, "badvaddr") == regno) + return 1; + + if (find_regno (tdesc, "fir") == regno) + return 1; + + return 0; +} + +static int +mips_fetch_register (struct regcache *regcache, int regno) +{ + const struct target_desc *tdesc = current_process ()->tdesc; + + if (find_regno (tdesc, "r0") == regno) + { + supply_register_zeroed (regcache, regno); + return 1; + } + + return 0; +} + +static CORE_ADDR +mips_get_pc (struct regcache *regcache) +{ + union mips_register pc; + collect_register_by_name (regcache, "pc", pc.buf); + return register_size (regcache->tdesc, 0) == 4 ? pc.reg32 : pc.reg64; +} + +static void +mips_set_pc (struct regcache *regcache, CORE_ADDR pc) +{ + union mips_register newpc; + if (register_size (regcache->tdesc, 0) == 4) + newpc.reg32 = pc; + else + newpc.reg64 = pc; + + supply_register_by_name (regcache, "pc", newpc.buf); +} + +/* Correct in either endianness. */ +static const unsigned int mips_breakpoint = 0x0005000d; +#define mips_breakpoint_len 4 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +mips_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = mips_breakpoint_len; + return (const gdb_byte *) &mips_breakpoint; +} + +static int +mips_breakpoint_at (CORE_ADDR where) +{ + unsigned int insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 4); + if (insn == mips_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +/* Mark the watch registers of lwp, represented by ENTRY, as changed. */ + +static void +update_watch_registers_callback (thread_info *thread) +{ + struct lwp_info *lwp = get_thread_lwp (thread); + + /* The actual update is done later just before resuming the lwp, + we just mark that the registers need updating. */ + lwp->arch_private->watch_registers_changed = 1; + + /* If the lwp isn't stopped, force it to momentarily pause, so + we can update its watch registers. */ + if (!lwp->stopped) + linux_stop_lwp (lwp); +} + +/* This is the implementation of linux_target_ops method + new_process. */ + +static struct arch_process_info * +mips_linux_new_process (void) +{ + struct arch_process_info *info = XCNEW (struct arch_process_info); + + return info; +} + +/* This is the implementation of linux_target_ops method + delete_process. */ + +static void +mips_linux_delete_process (struct arch_process_info *info) +{ + xfree (info); +} + +/* This is the implementation of linux_target_ops method new_thread. + Mark the watch registers as changed, so the threads' copies will + be updated. */ + +static void +mips_linux_new_thread (struct lwp_info *lwp) +{ + struct arch_lwp_info *info = XCNEW (struct arch_lwp_info); + + info->watch_registers_changed = 1; + + lwp->arch_private = info; +} + +/* Function to call when a thread is being deleted. */ + +static void +mips_linux_delete_thread (struct arch_lwp_info *arch_lwp) +{ + xfree (arch_lwp); +} + +/* Create a new mips_watchpoint and add it to the list. */ + +static void +mips_add_watchpoint (struct arch_process_info *priv, CORE_ADDR addr, int len, + enum target_hw_bp_type watch_type) +{ + struct mips_watchpoint *new_watch; + struct mips_watchpoint **pw; + + new_watch = XNEW (struct mips_watchpoint); + new_watch->addr = addr; + new_watch->len = len; + new_watch->type = watch_type; + new_watch->next = NULL; + + pw = &priv->current_watches; + while (*pw != NULL) + pw = &(*pw)->next; + *pw = new_watch; +} + +/* Hook to call when a new fork is attached. */ + +static void +mips_linux_new_fork (struct process_info *parent, + struct process_info *child) +{ + struct arch_process_info *parent_private; + struct arch_process_info *child_private; + struct mips_watchpoint *wp; + + /* These are allocated by linux_add_process. */ + gdb_assert (parent->priv != NULL + && parent->priv->arch_private != NULL); + gdb_assert (child->priv != NULL + && child->priv->arch_private != NULL); + + /* Linux kernel before 2.6.33 commit + 72f674d203cd230426437cdcf7dd6f681dad8b0d + will inherit hardware debug registers from parent + on fork/vfork/clone. Newer Linux kernels create such tasks with + zeroed debug registers. + + GDB core assumes the child inherits the watchpoints/hw + breakpoints of the parent, and will remove them all from the + forked off process. Copy the debug registers mirrors into the + new process so that all breakpoints and watchpoints can be + removed together. The debug registers mirror will become zeroed + in the end before detaching the forked off process, thus making + this compatible with older Linux kernels too. */ + + parent_private = parent->priv->arch_private; + child_private = child->priv->arch_private; + + child_private->watch_readback_valid = parent_private->watch_readback_valid; + child_private->watch_readback = parent_private->watch_readback; + + for (wp = parent_private->current_watches; wp != NULL; wp = wp->next) + mips_add_watchpoint (child_private, wp->addr, wp->len, wp->type); + + child_private->watch_mirror = parent_private->watch_mirror; +} +/* This is the implementation of linux_target_ops method + prepare_to_resume. If the watch regs have changed, update the + thread's copies. */ + +static void +mips_linux_prepare_to_resume (struct lwp_info *lwp) +{ + ptid_t ptid = ptid_of (get_lwp_thread (lwp)); + struct process_info *proc = find_process_pid (ptid.pid ()); + struct arch_process_info *priv = proc->priv->arch_private; + + if (lwp->arch_private->watch_registers_changed) + { + /* Only update the watch registers if we have set or unset a + watchpoint already. */ + if (mips_linux_watch_get_num_valid (&priv->watch_mirror) > 0) + { + /* Write the mirrored watch register values. */ + int tid = ptid.lwp (); + + if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid, + &priv->watch_mirror, NULL)) + perror_with_name ("Couldn't write watch register"); + } + + lwp->arch_private->watch_registers_changed = 0; + } +} + +static int +mips_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_WRITE_WP: + case Z_PACKET_READ_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + return 0; + } +} + +/* This is the implementation of linux_target_ops method + insert_point. */ + +static int +mips_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + struct process_info *proc = current_process (); + struct arch_process_info *priv = proc->priv->arch_private; + struct pt_watch_regs regs; + long lwpid; + enum target_hw_bp_type watch_type; + uint32_t irw; + + lwpid = lwpid_of (current_thread); + if (!mips_linux_read_watch_registers (lwpid, + &priv->watch_readback, + &priv->watch_readback_valid, + 0)) + return -1; + + if (len <= 0) + return -1; + + regs = priv->watch_readback; + /* Add the current watches. */ + mips_linux_watch_populate_regs (priv->current_watches, ®s); + + /* Now try to add the new watch. */ + watch_type = raw_bkpt_type_to_target_hw_bp_type (type); + irw = mips_linux_watch_type_to_irw (watch_type); + if (!mips_linux_watch_try_one_watch (®s, addr, len, irw)) + return -1; + + /* It fit. Stick it on the end of the list. */ + mips_add_watchpoint (priv, addr, len, watch_type); + + priv->watch_mirror = regs; + + /* Only update the threads of this process. */ + for_each_thread (proc->pid, update_watch_registers_callback); + + return 0; +} + +/* This is the implementation of linux_target_ops method + remove_point. */ + +static int +mips_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int len, struct raw_breakpoint *bp) +{ + struct process_info *proc = current_process (); + struct arch_process_info *priv = proc->priv->arch_private; + + int deleted_one; + enum target_hw_bp_type watch_type; + + struct mips_watchpoint **pw; + struct mips_watchpoint *w; + + /* Search for a known watch that matches. Then unlink and free it. */ + watch_type = raw_bkpt_type_to_target_hw_bp_type (type); + deleted_one = 0; + pw = &priv->current_watches; + while ((w = *pw)) + { + if (w->addr == addr && w->len == len && w->type == watch_type) + { + *pw = w->next; + free (w); + deleted_one = 1; + break; + } + pw = &(w->next); + } + + if (!deleted_one) + return -1; /* We don't know about it, fail doing nothing. */ + + /* At this point watch_readback is known to be valid because we + could not have added the watch without reading it. */ + gdb_assert (priv->watch_readback_valid == 1); + + priv->watch_mirror = priv->watch_readback; + mips_linux_watch_populate_regs (priv->current_watches, + &priv->watch_mirror); + + /* Only update the threads of this process. */ + for_each_thread (proc->pid, update_watch_registers_callback); + + return 0; +} + +/* This is the implementation of linux_target_ops method + stopped_by_watchpoint. The watchhi R and W bits indicate + the watch register triggered. */ + +static int +mips_stopped_by_watchpoint (void) +{ + struct process_info *proc = current_process (); + struct arch_process_info *priv = proc->priv->arch_private; + int n; + int num_valid; + long lwpid = lwpid_of (current_thread); + + if (!mips_linux_read_watch_registers (lwpid, + &priv->watch_readback, + &priv->watch_readback_valid, + 1)) + return 0; + + num_valid = mips_linux_watch_get_num_valid (&priv->watch_readback); + + for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++) + if (mips_linux_watch_get_watchhi (&priv->watch_readback, n) + & (R_MASK | W_MASK)) + return 1; + + return 0; +} + +/* This is the implementation of linux_target_ops method + stopped_data_address. */ + +static CORE_ADDR +mips_stopped_data_address (void) +{ + struct process_info *proc = current_process (); + struct arch_process_info *priv = proc->priv->arch_private; + int n; + int num_valid; + long lwpid = lwpid_of (current_thread); + + /* On MIPS we don't know the low order 3 bits of the data address. + GDB does not support remote targets that can't report the + watchpoint address. So, make our best guess; return the starting + address of a watchpoint request which overlaps the one that + triggered. */ + + if (!mips_linux_read_watch_registers (lwpid, + &priv->watch_readback, + &priv->watch_readback_valid, + 0)) + return 0; + + num_valid = mips_linux_watch_get_num_valid (&priv->watch_readback); + + for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++) + if (mips_linux_watch_get_watchhi (&priv->watch_readback, n) + & (R_MASK | W_MASK)) + { + CORE_ADDR t_low, t_hi; + int t_irw; + struct mips_watchpoint *watch; + + t_low = mips_linux_watch_get_watchlo (&priv->watch_readback, n); + t_irw = t_low & IRW_MASK; + t_hi = (mips_linux_watch_get_watchhi (&priv->watch_readback, n) + | IRW_MASK); + t_low &= ~(CORE_ADDR)t_hi; + + for (watch = priv->current_watches; + watch != NULL; + watch = watch->next) + { + CORE_ADDR addr = watch->addr; + CORE_ADDR last_byte = addr + watch->len - 1; + + if ((t_irw & mips_linux_watch_type_to_irw (watch->type)) == 0) + { + /* Different type. */ + continue; + } + /* Check for overlap of even a single byte. */ + if (last_byte >= t_low && addr <= t_low + t_hi) + return addr; + } + } + + /* Shouldn't happen. */ + return 0; +} + +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *)*base - idx); + + return PS_OK; +} + +static void +mips_collect_register (struct regcache *regcache, + int use_64bit, int regno, union mips_register *reg) +{ + union mips_register tmp_reg; + + if (use_64bit) + { + collect_register (regcache, regno, &tmp_reg.reg64); + *reg = tmp_reg; + } + else + { + collect_register (regcache, regno, &tmp_reg.reg32); + reg->reg64 = tmp_reg.reg32; + } +} + +static void +mips_supply_register (struct regcache *regcache, + int use_64bit, int regno, const union mips_register *reg) +{ + int offset = 0; + + /* For big-endian 32-bit targets, ignore the high four bytes of each + eight-byte slot. */ + if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit) + offset = 4; + + supply_register (regcache, regno, reg->buf + offset); +} + +#ifdef HAVE_PTRACE_GETREGS + +static void +mips_collect_register_32bit (struct regcache *regcache, + int use_64bit, int regno, unsigned char *buf) +{ + union mips_register tmp_reg; + int reg32; + + mips_collect_register (regcache, use_64bit, regno, &tmp_reg); + reg32 = tmp_reg.reg64; + memcpy (buf, ®32, 4); +} + +static void +mips_supply_register_32bit (struct regcache *regcache, + int use_64bit, int regno, const unsigned char *buf) +{ + union mips_register tmp_reg; + int reg32; + + memcpy (®32, buf, 4); + tmp_reg.reg64 = reg32; + mips_supply_register (regcache, use_64bit, regno, &tmp_reg); +} + +static void +mips_fill_gregset (struct regcache *regcache, void *buf) +{ + union mips_register *regset = (union mips_register *) buf; + int i, use_64bit; + const struct target_desc *tdesc = regcache->tdesc; + + use_64bit = (register_size (tdesc, 0) == 8); + + for (i = 1; i < 32; i++) + mips_collect_register (regcache, use_64bit, i, regset + i); + + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "lo"), regset + 32); + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "hi"), regset + 33); + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "pc"), regset + 34); + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "badvaddr"), regset + 35); + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "status"), regset + 36); + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "cause"), regset + 37); + + mips_collect_register (regcache, use_64bit, + find_regno (tdesc, "restart"), regset + 0); +} + +static void +mips_store_gregset (struct regcache *regcache, const void *buf) +{ + const union mips_register *regset = (const union mips_register *) buf; + int i, use_64bit; + + use_64bit = (register_size (regcache->tdesc, 0) == 8); + + supply_register_by_name_zeroed (regcache, "r0"); + + for (i = 1; i < 32; i++) + mips_supply_register (regcache, use_64bit, i, regset + i); + + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "lo"), regset + 32); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "hi"), regset + 33); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "pc"), regset + 34); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "badvaddr"), regset + 35); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "status"), regset + 36); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "cause"), regset + 37); + + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "restart"), regset + 0); +} + +static void +mips_fill_fpregset (struct regcache *regcache, void *buf) +{ + union mips_register *regset = (union mips_register *) buf; + int i, use_64bit, first_fp, big_endian; + + use_64bit = (register_size (regcache->tdesc, 0) == 8); + first_fp = find_regno (regcache->tdesc, "f0"); + big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + + /* See GDB for a discussion of this peculiar layout. */ + for (i = 0; i < 32; i++) + if (use_64bit) + collect_register (regcache, first_fp + i, regset[i].buf); + else + collect_register (regcache, first_fp + i, + regset[i & ~1].buf + 4 * (big_endian != (i & 1))); + + mips_collect_register_32bit (regcache, use_64bit, + find_regno (regcache->tdesc, "fcsr"), regset[32].buf); + mips_collect_register_32bit (regcache, use_64bit, + find_regno (regcache->tdesc, "fir"), + regset[32].buf + 4); +} + +static void +mips_store_fpregset (struct regcache *regcache, const void *buf) +{ + const union mips_register *regset = (const union mips_register *) buf; + int i, use_64bit, first_fp, big_endian; + + use_64bit = (register_size (regcache->tdesc, 0) == 8); + first_fp = find_regno (regcache->tdesc, "f0"); + big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + + /* See GDB for a discussion of this peculiar layout. */ + for (i = 0; i < 32; i++) + if (use_64bit) + supply_register (regcache, first_fp + i, regset[i].buf); + else + supply_register (regcache, first_fp + i, + regset[i & ~1].buf + 4 * (big_endian != (i & 1))); + + mips_supply_register_32bit (regcache, use_64bit, + find_regno (regcache->tdesc, "fcsr"), + regset[32].buf); + mips_supply_register_32bit (regcache, use_64bit, + find_regno (regcache->tdesc, "fir"), + regset[32].buf + 4); +} +#endif /* HAVE_PTRACE_GETREGS */ + +/* Take care of 32-bit registers with 64-bit ptrace, POKEUSER side. */ + +static void +mips_collect_ptrace_register (struct regcache *regcache, + int regno, char *buf) +{ + int use_64bit = sizeof (PTRACE_XFER_TYPE) == 8; + + if (use_64bit && register_size (regcache->tdesc, regno) == 4) + { + union mips_register reg; + + mips_collect_register (regcache, 0, regno, ®); + memcpy (buf, ®, sizeof (reg)); + } + else + collect_register (regcache, regno, buf); +} + +/* Take care of 32-bit registers with 64-bit ptrace, PEEKUSER side. */ + +static void +mips_supply_ptrace_register (struct regcache *regcache, + int regno, const char *buf) +{ + int use_64bit = sizeof (PTRACE_XFER_TYPE) == 8; + + if (use_64bit && register_size (regcache->tdesc, regno) == 4) + { + union mips_register reg; + + memcpy (®, buf, sizeof (reg)); + mips_supply_register (regcache, 0, regno, ®); + } + else + supply_register (regcache, regno, buf); +} + +static struct regset_info mips_regsets[] = { +#ifdef HAVE_PTRACE_GETREGS + { PTRACE_GETREGS, PTRACE_SETREGS, 0, 38 * 8, GENERAL_REGS, + mips_fill_gregset, mips_store_gregset }, + { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, 33 * 8, FP_REGS, + mips_fill_fpregset, mips_store_fpregset }, +#endif /* HAVE_PTRACE_GETREGS */ + NULL_REGSET +}; + +static struct regsets_info mips_regsets_info = + { + mips_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info mips_dsp_usrregs_info = + { + mips_dsp_num_regs, + mips_dsp_regmap, + }; + +static struct usrregs_info mips_usrregs_info = + { + mips_num_regs, + mips_regmap, + }; + +static struct regs_info dsp_regs_info = + { + mips_dsp_regset_bitmap, + &mips_dsp_usrregs_info, + &mips_regsets_info + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &mips_usrregs_info, + &mips_regsets_info + }; + +static const struct regs_info * +mips_regs_info (void) +{ + if (have_dsp) + return &dsp_regs_info; + else + return ®s_info; +} + +struct linux_target_ops the_low_target = { + mips_arch_setup, + mips_regs_info, + mips_cannot_fetch_register, + mips_cannot_store_register, + mips_fetch_register, + mips_get_pc, + mips_set_pc, + NULL, /* breakpoint_kind_from_pc */ + mips_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 0, + mips_breakpoint_at, + mips_supports_z_point_type, + mips_insert_point, + mips_remove_point, + mips_stopped_by_watchpoint, + mips_stopped_data_address, + mips_collect_ptrace_register, + mips_supply_ptrace_register, + NULL, /* siginfo_fixup */ + mips_linux_new_process, + mips_linux_delete_process, + mips_linux_new_thread, + mips_linux_delete_thread, + mips_linux_new_fork, + mips_linux_prepare_to_resume +}; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_mips_linux (); + init_registers_mips_dsp_linux (); + init_registers_mips64_linux (); + init_registers_mips64_dsp_linux (); + + initialize_regsets_info (&mips_regsets_info); +} diff --git a/gdbserver/linux-nios2-low.c b/gdbserver/linux-nios2-low.c new file mode 100644 index 00000000000..bfc5aee165d --- /dev/null +++ b/gdbserver/linux-nios2-low.c @@ -0,0 +1,259 @@ +/* GNU/Linux/Nios II specific low level interface, for the remote server for + GDB. + Copyright (C) 2008-2020 Free Software Foundation, Inc. + + Contributed by Mentor Graphics, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "elf/common.h" +#include "nat/gdb_ptrace.h" +#include +#include "gdb_proc_service.h" +#include + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +/* The following definition must agree with the number of registers + defined in "struct user_regs" in GLIBC + (sysdeps/unix/sysv/linux/nios2/sys/user.h), and also with + NIOS2_NUM_REGS in GDB proper. */ + +#define nios2_num_regs 49 + +/* Defined in auto-generated file nios2-linux.c. */ + +void init_registers_nios2_linux (void); +extern const struct target_desc *tdesc_nios2_linux; + +/* This union is used to convert between int and byte buffer + representations of register contents. */ + +union nios2_register +{ + unsigned char buf[4]; + int reg32; +}; + +/* Return the ptrace ``address'' of register REGNO. */ + +static int nios2_regmap[] = { + -1, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, + 0 +}; + +/* Implement the arch_setup linux_target_ops method. */ + +static void +nios2_arch_setup (void) +{ + current_process ()->tdesc = tdesc_nios2_linux; +} + +/* Implement the cannot_fetch_register linux_target_ops method. */ + +static int +nios2_cannot_fetch_register (int regno) +{ + if (nios2_regmap[regno] == -1) + return 1; + + return 0; +} + +/* Implement the cannot_store_register linux_target_ops method. */ + +static int +nios2_cannot_store_register (int regno) +{ + if (nios2_regmap[regno] == -1) + return 1; + + return 0; +} + +/* Breakpoint support. Also see comments on nios2_breakpoint_from_pc + in nios2-tdep.c. */ + +#if defined(__nios2_arch__) && __nios2_arch__ == 2 +#define NIOS2_BREAKPOINT 0xb7fd0020 +#define CDX_BREAKPOINT 0xd7c9 +#else +#define NIOS2_BREAKPOINT 0x003b6ffa +#endif + +/* We only register the 4-byte breakpoint, even on R2 targets which also + support 2-byte breakpoints. Since there is no supports_z_point_type + function provided, gdbserver never inserts software breakpoints itself + and instead relies on GDB to insert the breakpoint of the correct length + via a memory write. */ +static const unsigned int nios2_breakpoint = NIOS2_BREAKPOINT; +#define nios2_breakpoint_len 4 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +nios2_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = nios2_breakpoint_len; + return (const gdb_byte *) &nios2_breakpoint; +} + +/* Implement the breakpoint_at linux_target_ops method. */ + +static int +nios2_breakpoint_at (CORE_ADDR where) +{ + unsigned int insn; + + /* For R2, first check for the 2-byte CDX trap.n breakpoint encoding. */ +#if defined(__nios2_arch__) && __nios2_arch__ == 2 + (*the_target->read_memory) (where, (unsigned char *) &insn, 2); + if (insn == CDX_BREAKPOINT) + return 1; +#endif + + (*the_target->read_memory) (where, (unsigned char *) &insn, 4); + if (insn == nios2_breakpoint) + return 1; + return 0; +} + +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *) *base - idx); + + return PS_OK; +} + +/* Helper functions to collect/supply a single register REGNO. */ + +static void +nios2_collect_register (struct regcache *regcache, int regno, + union nios2_register *reg) +{ + union nios2_register tmp_reg; + + collect_register (regcache, regno, &tmp_reg.reg32); + reg->reg32 = tmp_reg.reg32; +} + +static void +nios2_supply_register (struct regcache *regcache, int regno, + const union nios2_register *reg) +{ + supply_register (regcache, regno, reg->buf); +} + +/* We have only a single register set on Nios II. */ + +static void +nios2_fill_gregset (struct regcache *regcache, void *buf) +{ + union nios2_register *regset = (union nios2_register *) buf; + int i; + + for (i = 1; i < nios2_num_regs; i++) + nios2_collect_register (regcache, i, regset + i); +} + +static void +nios2_store_gregset (struct regcache *regcache, const void *buf) +{ + const union nios2_register *regset = (union nios2_register *) buf; + int i; + + for (i = 0; i < nios2_num_regs; i++) + nios2_supply_register (regcache, i, regset + i); +} + +static struct regset_info nios2_regsets[] = +{ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, + nios2_num_regs * 4, GENERAL_REGS, + nios2_fill_gregset, nios2_store_gregset }, + NULL_REGSET +}; + +static struct regsets_info nios2_regsets_info = + { + nios2_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info nios2_usrregs_info = + { + nios2_num_regs, + nios2_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &nios2_usrregs_info, + &nios2_regsets_info + }; + +static const struct regs_info * +nios2_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = +{ + nios2_arch_setup, + nios2_regs_info, + nios2_cannot_fetch_register, + nios2_cannot_store_register, + NULL, + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + nios2_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 0, + nios2_breakpoint_at, +}; + +void +initialize_low_arch (void) +{ + init_registers_nios2_linux (); + + initialize_regsets_info (&nios2_regsets_info); +} diff --git a/gdbserver/linux-ppc-ipa.c b/gdbserver/linux-ppc-ipa.c new file mode 100644 index 00000000000..42d668f7d37 --- /dev/null +++ b/gdbserver/linux-ppc-ipa.c @@ -0,0 +1,259 @@ +/* GNU/Linux/PowerPC specific low level interface, for the in-process + agent library for GDB. + + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include +#include "tracepoint.h" +#include "arch/ppc-linux-tdesc.h" +#include "linux-ppc-tdesc-init.h" +#include +#ifdef HAVE_GETAUXVAL +#include +#endif + +/* These macros define the position of registers in the buffer collected + by the fast tracepoint jump pad. */ +#define FT_CR_R0 0 +#define FT_CR_CR 32 +#define FT_CR_XER 33 +#define FT_CR_LR 34 +#define FT_CR_CTR 35 +#define FT_CR_PC 36 +#define FT_CR_GPR(n) (FT_CR_R0 + (n)) + +static const int ppc_ft_collect_regmap[] = { + /* GPRs */ + FT_CR_GPR (0), FT_CR_GPR (1), FT_CR_GPR (2), + FT_CR_GPR (3), FT_CR_GPR (4), FT_CR_GPR (5), + FT_CR_GPR (6), FT_CR_GPR (7), FT_CR_GPR (8), + FT_CR_GPR (9), FT_CR_GPR (10), FT_CR_GPR (11), + FT_CR_GPR (12), FT_CR_GPR (13), FT_CR_GPR (14), + FT_CR_GPR (15), FT_CR_GPR (16), FT_CR_GPR (17), + FT_CR_GPR (18), FT_CR_GPR (19), FT_CR_GPR (20), + FT_CR_GPR (21), FT_CR_GPR (22), FT_CR_GPR (23), + FT_CR_GPR (24), FT_CR_GPR (25), FT_CR_GPR (26), + FT_CR_GPR (27), FT_CR_GPR (28), FT_CR_GPR (29), + FT_CR_GPR (30), FT_CR_GPR (31), + /* FPRs - not collected. */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + FT_CR_PC, /* PC */ + -1, /* MSR */ + FT_CR_CR, /* CR */ + FT_CR_LR, /* LR */ + FT_CR_CTR, /* CTR */ + FT_CR_XER, /* XER */ + -1, /* FPSCR */ +}; + +#define PPC_NUM_FT_COLLECT_GREGS \ + (sizeof (ppc_ft_collect_regmap) / sizeof(ppc_ft_collect_regmap[0])) + +/* Supply registers collected by the fast tracepoint jump pad. + BUF is the second argument we pass to gdb_collect in jump pad. */ + +void +supply_fast_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf) +{ + int i; + + for (i = 0; i < PPC_NUM_FT_COLLECT_GREGS; i++) + { + if (ppc_ft_collect_regmap[i] == -1) + continue; + supply_register (regcache, i, + ((char *) buf) + + ppc_ft_collect_regmap[i] * sizeof (long)); + } +} + +/* Return the value of register REGNUM. RAW_REGS is collected buffer + by jump pad. This function is called by emit_reg. */ + +ULONGEST +get_raw_reg (const unsigned char *raw_regs, int regnum) +{ + if (regnum >= PPC_NUM_FT_COLLECT_GREGS) + return 0; + if (ppc_ft_collect_regmap[regnum] == -1) + return 0; + + return *(unsigned long *) (raw_regs + + ppc_ft_collect_regmap[regnum] * sizeof (long)); +} + +/* Allocate buffer for the jump pads. The branch instruction has a reach + of +/- 32MiB, and the executable is loaded at 0x10000000 (256MiB). + + 64-bit: To maximize the area of executable that can use tracepoints, + try allocating at 0x10000000 - size initially, decreasing until we hit + a free area. + + 32-bit: ld.so loads dynamic libraries right below the executable, so + we cannot depend on that area (dynamic libraries can be quite large). + Instead, aim right after the executable - at sbrk(0). This will + cause future brk to fail, and malloc will fallback to mmap. */ + +void * +alloc_jump_pad_buffer (size_t size) +{ +#ifdef __powerpc64__ + uintptr_t addr; + uintptr_t exec_base = getauxval (AT_PHDR); + int pagesize; + void *res; + + if (exec_base == 0) + exec_base = 0x10000000; + + pagesize = sysconf (_SC_PAGE_SIZE); + if (pagesize == -1) + perror_with_name ("sysconf"); + + addr = exec_base - size; + + /* size should already be page-aligned, but this can't hurt. */ + addr &= ~(pagesize - 1); + + /* Search for a free area. If we hit 0, we're out of luck. */ + for (; addr; addr -= pagesize) + { + /* No MAP_FIXED - we don't want to zap someone's mapping. */ + res = mmap ((void *) addr, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* If we got what we wanted, return. */ + if ((uintptr_t) res == addr) + return res; + + /* If we got a mapping, but at a wrong address, undo it. */ + if (res != MAP_FAILED) + munmap (res, size); + } + + return NULL; +#else + void *target = sbrk (0); + void *res = mmap (target, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (res == target) + return res; + + if (res != MAP_FAILED) + munmap (res, size); + + return NULL; +#endif +} + +/* Return target_desc to use for IPA, given the tdesc index passed by + gdbserver. */ + +const struct target_desc * +get_ipa_tdesc (int idx) +{ + switch (idx) + { +#ifdef __powerpc64__ + case PPC_TDESC_BASE: + return tdesc_powerpc_64l; + case PPC_TDESC_ALTIVEC: + return tdesc_powerpc_altivec64l; + case PPC_TDESC_VSX: + return tdesc_powerpc_vsx64l; + case PPC_TDESC_ISA205: + return tdesc_powerpc_isa205_64l; + case PPC_TDESC_ISA205_ALTIVEC: + return tdesc_powerpc_isa205_altivec64l; + case PPC_TDESC_ISA205_VSX: + return tdesc_powerpc_isa205_vsx64l; + case PPC_TDESC_ISA205_PPR_DSCR_VSX: + return tdesc_powerpc_isa205_ppr_dscr_vsx64l; + case PPC_TDESC_ISA207_VSX: + return tdesc_powerpc_isa207_vsx64l; + case PPC_TDESC_ISA207_HTM_VSX: + return tdesc_powerpc_isa207_htm_vsx64l; +#else + case PPC_TDESC_BASE: + return tdesc_powerpc_32l; + case PPC_TDESC_ALTIVEC: + return tdesc_powerpc_altivec32l; + case PPC_TDESC_VSX: + return tdesc_powerpc_vsx32l; + case PPC_TDESC_ISA205: + return tdesc_powerpc_isa205_32l; + case PPC_TDESC_ISA205_ALTIVEC: + return tdesc_powerpc_isa205_altivec32l; + case PPC_TDESC_ISA205_VSX: + return tdesc_powerpc_isa205_vsx32l; + case PPC_TDESC_ISA205_PPR_DSCR_VSX: + return tdesc_powerpc_isa205_ppr_dscr_vsx32l; + case PPC_TDESC_ISA207_VSX: + return tdesc_powerpc_isa207_vsx32l; + case PPC_TDESC_ISA207_HTM_VSX: + return tdesc_powerpc_isa207_htm_vsx32l; + case PPC_TDESC_E500: + return tdesc_powerpc_e500l; +#endif + default: + internal_error (__FILE__, __LINE__, + "unknown ipa tdesc index: %d", idx); +#ifdef __powerpc64__ + return tdesc_powerpc_64l; +#else + return tdesc_powerpc_32l; +#endif + } +} + + +/* Initialize ipa_tdesc and others. */ + +void +initialize_low_tracepoint (void) +{ +#ifdef __powerpc64__ + init_registers_powerpc_64l (); + init_registers_powerpc_altivec64l (); + init_registers_powerpc_vsx64l (); + init_registers_powerpc_isa205_64l (); + init_registers_powerpc_isa205_altivec64l (); + init_registers_powerpc_isa205_vsx64l (); + init_registers_powerpc_isa205_ppr_dscr_vsx64l (); + init_registers_powerpc_isa207_vsx64l (); + init_registers_powerpc_isa207_htm_vsx64l (); +#else + init_registers_powerpc_32l (); + init_registers_powerpc_altivec32l (); + init_registers_powerpc_vsx32l (); + init_registers_powerpc_isa205_32l (); + init_registers_powerpc_isa205_altivec32l (); + init_registers_powerpc_isa205_vsx32l (); + init_registers_powerpc_isa205_ppr_dscr_vsx32l (); + init_registers_powerpc_isa207_vsx32l (); + init_registers_powerpc_isa207_htm_vsx32l (); + init_registers_powerpc_e500l (); +#endif +} diff --git a/gdbserver/linux-ppc-low.c b/gdbserver/linux-ppc-low.c new file mode 100644 index 00000000000..5d8d67bec2f --- /dev/null +++ b/gdbserver/linux-ppc-low.c @@ -0,0 +1,3441 @@ +/* GNU/Linux/PowerPC specific low level interface, for the remote server for + GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +#include "elf/common.h" +#include +#include +#include + +#include "arch/ppc-linux-common.h" +#include "arch/ppc-linux-tdesc.h" +#include "nat/ppc-linux.h" +#include "nat/linux-ptrace.h" +#include "linux-ppc-tdesc-init.h" +#include "ax.h" +#include "tracepoint.h" + +#define PPC_FIELD(value, from, len) \ + (((value) >> (32 - (from) - (len))) & ((1 << (len)) - 1)) +#define PPC_SEXT(v, bs) \ + ((((CORE_ADDR) (v) & (((CORE_ADDR) 1 << (bs)) - 1)) \ + ^ ((CORE_ADDR) 1 << ((bs) - 1))) \ + - ((CORE_ADDR) 1 << ((bs) - 1))) +#define PPC_OP6(insn) PPC_FIELD (insn, 0, 6) +#define PPC_BO(insn) PPC_FIELD (insn, 6, 5) +#define PPC_LI(insn) (PPC_SEXT (PPC_FIELD (insn, 6, 24), 24) << 2) +#define PPC_BD(insn) (PPC_SEXT (PPC_FIELD (insn, 16, 14), 14) << 2) + +/* Holds the AT_HWCAP auxv entry. */ + +static unsigned long ppc_hwcap; + +/* Holds the AT_HWCAP2 auxv entry. */ + +static unsigned long ppc_hwcap2; + + +#define ppc_num_regs 73 + +#ifdef __powerpc64__ +/* We use a constant for FPSCR instead of PT_FPSCR, because + many shipped PPC64 kernels had the wrong value in ptrace.h. */ +static int ppc_regmap[] = + {PT_R0 * 8, PT_R1 * 8, PT_R2 * 8, PT_R3 * 8, + PT_R4 * 8, PT_R5 * 8, PT_R6 * 8, PT_R7 * 8, + PT_R8 * 8, PT_R9 * 8, PT_R10 * 8, PT_R11 * 8, + PT_R12 * 8, PT_R13 * 8, PT_R14 * 8, PT_R15 * 8, + PT_R16 * 8, PT_R17 * 8, PT_R18 * 8, PT_R19 * 8, + PT_R20 * 8, PT_R21 * 8, PT_R22 * 8, PT_R23 * 8, + PT_R24 * 8, PT_R25 * 8, PT_R26 * 8, PT_R27 * 8, + PT_R28 * 8, PT_R29 * 8, PT_R30 * 8, PT_R31 * 8, + PT_FPR0*8, PT_FPR0*8 + 8, PT_FPR0*8+16, PT_FPR0*8+24, + PT_FPR0*8+32, PT_FPR0*8+40, PT_FPR0*8+48, PT_FPR0*8+56, + PT_FPR0*8+64, PT_FPR0*8+72, PT_FPR0*8+80, PT_FPR0*8+88, + PT_FPR0*8+96, PT_FPR0*8+104, PT_FPR0*8+112, PT_FPR0*8+120, + PT_FPR0*8+128, PT_FPR0*8+136, PT_FPR0*8+144, PT_FPR0*8+152, + PT_FPR0*8+160, PT_FPR0*8+168, PT_FPR0*8+176, PT_FPR0*8+184, + PT_FPR0*8+192, PT_FPR0*8+200, PT_FPR0*8+208, PT_FPR0*8+216, + PT_FPR0*8+224, PT_FPR0*8+232, PT_FPR0*8+240, PT_FPR0*8+248, + PT_NIP * 8, PT_MSR * 8, PT_CCR * 8, PT_LNK * 8, + PT_CTR * 8, PT_XER * 8, PT_FPR0*8 + 256, + PT_ORIG_R3 * 8, PT_TRAP * 8 }; +#else +/* Currently, don't check/send MQ. */ +static int ppc_regmap[] = + {PT_R0 * 4, PT_R1 * 4, PT_R2 * 4, PT_R3 * 4, + PT_R4 * 4, PT_R5 * 4, PT_R6 * 4, PT_R7 * 4, + PT_R8 * 4, PT_R9 * 4, PT_R10 * 4, PT_R11 * 4, + PT_R12 * 4, PT_R13 * 4, PT_R14 * 4, PT_R15 * 4, + PT_R16 * 4, PT_R17 * 4, PT_R18 * 4, PT_R19 * 4, + PT_R20 * 4, PT_R21 * 4, PT_R22 * 4, PT_R23 * 4, + PT_R24 * 4, PT_R25 * 4, PT_R26 * 4, PT_R27 * 4, + PT_R28 * 4, PT_R29 * 4, PT_R30 * 4, PT_R31 * 4, + PT_FPR0*4, PT_FPR0*4 + 8, PT_FPR0*4+16, PT_FPR0*4+24, + PT_FPR0*4+32, PT_FPR0*4+40, PT_FPR0*4+48, PT_FPR0*4+56, + PT_FPR0*4+64, PT_FPR0*4+72, PT_FPR0*4+80, PT_FPR0*4+88, + PT_FPR0*4+96, PT_FPR0*4+104, PT_FPR0*4+112, PT_FPR0*4+120, + PT_FPR0*4+128, PT_FPR0*4+136, PT_FPR0*4+144, PT_FPR0*4+152, + PT_FPR0*4+160, PT_FPR0*4+168, PT_FPR0*4+176, PT_FPR0*4+184, + PT_FPR0*4+192, PT_FPR0*4+200, PT_FPR0*4+208, PT_FPR0*4+216, + PT_FPR0*4+224, PT_FPR0*4+232, PT_FPR0*4+240, PT_FPR0*4+248, + PT_NIP * 4, PT_MSR * 4, PT_CCR * 4, PT_LNK * 4, + PT_CTR * 4, PT_XER * 4, PT_FPSCR * 4, + PT_ORIG_R3 * 4, PT_TRAP * 4 + }; + +static int ppc_regmap_e500[] = + {PT_R0 * 4, PT_R1 * 4, PT_R2 * 4, PT_R3 * 4, + PT_R4 * 4, PT_R5 * 4, PT_R6 * 4, PT_R7 * 4, + PT_R8 * 4, PT_R9 * 4, PT_R10 * 4, PT_R11 * 4, + PT_R12 * 4, PT_R13 * 4, PT_R14 * 4, PT_R15 * 4, + PT_R16 * 4, PT_R17 * 4, PT_R18 * 4, PT_R19 * 4, + PT_R20 * 4, PT_R21 * 4, PT_R22 * 4, PT_R23 * 4, + PT_R24 * 4, PT_R25 * 4, PT_R26 * 4, PT_R27 * 4, + PT_R28 * 4, PT_R29 * 4, PT_R30 * 4, PT_R31 * 4, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + PT_NIP * 4, PT_MSR * 4, PT_CCR * 4, PT_LNK * 4, + PT_CTR * 4, PT_XER * 4, -1, + PT_ORIG_R3 * 4, PT_TRAP * 4 + }; +#endif + +/* Check whether the kernel provides a register set with number + REGSET_ID of size REGSETSIZE for process/thread TID. */ + +static int +ppc_check_regset (int tid, int regset_id, int regsetsize) +{ + void *buf = alloca (regsetsize); + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = regsetsize; + + if (ptrace (PTRACE_GETREGSET, tid, regset_id, &iov) >= 0 + || errno == ENODATA) + return 1; + return 0; +} + +static int +ppc_cannot_store_register (int regno) +{ + const struct target_desc *tdesc = current_process ()->tdesc; + +#ifndef __powerpc64__ + /* Some kernels do not allow us to store fpscr. */ + if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE) + && regno == find_regno (tdesc, "fpscr")) + return 2; +#endif + + /* Some kernels do not allow us to store orig_r3 or trap. */ + if (regno == find_regno (tdesc, "orig_r3") + || regno == find_regno (tdesc, "trap")) + return 2; + + return 0; +} + +static int +ppc_cannot_fetch_register (int regno) +{ + return 0; +} + +static void +ppc_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) +{ + memset (buf, 0, sizeof (long)); + + if (__BYTE_ORDER == __LITTLE_ENDIAN) + { + /* Little-endian values always sit at the left end of the buffer. */ + collect_register (regcache, regno, buf); + } + else if (__BYTE_ORDER == __BIG_ENDIAN) + { + /* Big-endian values sit at the right end of the buffer. In case of + registers whose sizes are smaller than sizeof (long), we must use a + padding to access them correctly. */ + int size = register_size (regcache->tdesc, regno); + + if (size < sizeof (long)) + collect_register (regcache, regno, buf + sizeof (long) - size); + else + collect_register (regcache, regno, buf); + } + else + perror_with_name ("Unexpected byte order"); +} + +static void +ppc_supply_ptrace_register (struct regcache *regcache, + int regno, const char *buf) +{ + if (__BYTE_ORDER == __LITTLE_ENDIAN) + { + /* Little-endian values always sit at the left end of the buffer. */ + supply_register (regcache, regno, buf); + } + else if (__BYTE_ORDER == __BIG_ENDIAN) + { + /* Big-endian values sit at the right end of the buffer. In case of + registers whose sizes are smaller than sizeof (long), we must use a + padding to access them correctly. */ + int size = register_size (regcache->tdesc, regno); + + if (size < sizeof (long)) + supply_register (regcache, regno, buf + sizeof (long) - size); + else + supply_register (regcache, regno, buf); + } + else + perror_with_name ("Unexpected byte order"); +} + +static CORE_ADDR +ppc_get_pc (struct regcache *regcache) +{ + if (register_size (regcache->tdesc, 0) == 4) + { + unsigned int pc; + collect_register_by_name (regcache, "pc", &pc); + return (CORE_ADDR) pc; + } + else + { + unsigned long pc; + collect_register_by_name (regcache, "pc", &pc); + return (CORE_ADDR) pc; + } +} + +static void +ppc_set_pc (struct regcache *regcache, CORE_ADDR pc) +{ + if (register_size (regcache->tdesc, 0) == 4) + { + unsigned int newpc = pc; + supply_register_by_name (regcache, "pc", &newpc); + } + else + { + unsigned long newpc = pc; + supply_register_by_name (regcache, "pc", &newpc); + } +} + +#ifndef __powerpc64__ +static int ppc_regmap_adjusted; +#endif + + +/* Correct in either endianness. + This instruction is "twge r2, r2", which GDB uses as a software + breakpoint. */ +static const unsigned int ppc_breakpoint = 0x7d821008; +#define ppc_breakpoint_len 4 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +ppc_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = ppc_breakpoint_len; + return (const gdb_byte *) &ppc_breakpoint; +} + +static int +ppc_breakpoint_at (CORE_ADDR where) +{ + unsigned int insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 4); + if (insn == ppc_breakpoint) + return 1; + /* If necessary, recognize more trap instructions here. GDB only uses + the one. */ + + return 0; +} + +/* Implement supports_z_point_type target-ops. + Returns true if type Z_TYPE breakpoint is supported. + + Handling software breakpoint at server side, so tracepoints + and breakpoints can be inserted at the same location. */ + +static int +ppc_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + return 1; + case Z_PACKET_HW_BP: + case Z_PACKET_WRITE_WP: + case Z_PACKET_ACCESS_WP: + default: + return 0; + } +} + +/* Implement insert_point target-ops. + Returns 0 on success, -1 on failure and 1 on unsupported. */ + +static int +ppc_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + switch (type) + { + case raw_bkpt_type_sw: + return insert_memory_breakpoint (bp); + + case raw_bkpt_type_hw: + case raw_bkpt_type_write_wp: + case raw_bkpt_type_access_wp: + default: + /* Unsupported. */ + return 1; + } +} + +/* Implement remove_point target-ops. + Returns 0 on success, -1 on failure and 1 on unsupported. */ + +static int +ppc_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + switch (type) + { + case raw_bkpt_type_sw: + return remove_memory_breakpoint (bp); + + case raw_bkpt_type_hw: + case raw_bkpt_type_write_wp: + case raw_bkpt_type_access_wp: + default: + /* Unsupported. */ + return 1; + } +} + +/* Provide only a fill function for the general register set. ps_lgetregs + will use this for NPTL support. */ + +static void ppc_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + + for (i = 0; i < 32; i++) + ppc_collect_ptrace_register (regcache, i, (char *) buf + ppc_regmap[i]); + + for (i = 64; i < 70; i++) + ppc_collect_ptrace_register (regcache, i, (char *) buf + ppc_regmap[i]); + + for (i = 71; i < 73; i++) + ppc_collect_ptrace_register (regcache, i, (char *) buf + ppc_regmap[i]); +} + +/* Program Priority Register regset fill function. */ + +static void +ppc_fill_pprregset (struct regcache *regcache, void *buf) +{ + char *ppr = (char *) buf; + + collect_register_by_name (regcache, "ppr", ppr); +} + +/* Program Priority Register regset store function. */ + +static void +ppc_store_pprregset (struct regcache *regcache, const void *buf) +{ + const char *ppr = (const char *) buf; + + supply_register_by_name (regcache, "ppr", ppr); +} + +/* Data Stream Control Register regset fill function. */ + +static void +ppc_fill_dscrregset (struct regcache *regcache, void *buf) +{ + char *dscr = (char *) buf; + + collect_register_by_name (regcache, "dscr", dscr); +} + +/* Data Stream Control Register regset store function. */ + +static void +ppc_store_dscrregset (struct regcache *regcache, const void *buf) +{ + const char *dscr = (const char *) buf; + + supply_register_by_name (regcache, "dscr", dscr); +} + +/* Target Address Register regset fill function. */ + +static void +ppc_fill_tarregset (struct regcache *regcache, void *buf) +{ + char *tar = (char *) buf; + + collect_register_by_name (regcache, "tar", tar); +} + +/* Target Address Register regset store function. */ + +static void +ppc_store_tarregset (struct regcache *regcache, const void *buf) +{ + const char *tar = (const char *) buf; + + supply_register_by_name (regcache, "tar", tar); +} + +/* Event-Based Branching regset store function. Unless the inferior + has a perf event open, ptrace can return in error when reading and + writing to the regset, with ENODATA. For reading, the registers + will correctly show as unavailable. For writing, gdbserver + currently only caches any register writes from P and G packets and + the stub always tries to write all the regsets when resuming the + inferior, which would result in frequent warnings. For this + reason, we don't define a fill function. This also means that the + client-side regcache will be dirty if the user tries to write to + the EBB registers. G packets that the client sends to write to + unrelated registers will also include data for EBB registers, even + if they are unavailable. */ + +static void +ppc_store_ebbregset (struct regcache *regcache, const void *buf) +{ + const char *regset = (const char *) buf; + + /* The order in the kernel regset is: EBBRR, EBBHR, BESCR. In the + .dat file is BESCR, EBBHR, EBBRR. */ + supply_register_by_name (regcache, "ebbrr", ®set[0]); + supply_register_by_name (regcache, "ebbhr", ®set[8]); + supply_register_by_name (regcache, "bescr", ®set[16]); +} + +/* Performance Monitoring Unit regset fill function. */ + +static void +ppc_fill_pmuregset (struct regcache *regcache, void *buf) +{ + char *regset = (char *) buf; + + /* The order in the kernel regset is SIAR, SDAR, SIER, MMCR2, MMCR0. + In the .dat file is MMCR0, MMCR2, SIAR, SDAR, SIER. */ + collect_register_by_name (regcache, "siar", ®set[0]); + collect_register_by_name (regcache, "sdar", ®set[8]); + collect_register_by_name (regcache, "sier", ®set[16]); + collect_register_by_name (regcache, "mmcr2", ®set[24]); + collect_register_by_name (regcache, "mmcr0", ®set[32]); +} + +/* Performance Monitoring Unit regset store function. */ + +static void +ppc_store_pmuregset (struct regcache *regcache, const void *buf) +{ + const char *regset = (const char *) buf; + + supply_register_by_name (regcache, "siar", ®set[0]); + supply_register_by_name (regcache, "sdar", ®set[8]); + supply_register_by_name (regcache, "sier", ®set[16]); + supply_register_by_name (regcache, "mmcr2", ®set[24]); + supply_register_by_name (regcache, "mmcr0", ®set[32]); +} + +/* Hardware Transactional Memory special-purpose register regset fill + function. */ + +static void +ppc_fill_tm_sprregset (struct regcache *regcache, void *buf) +{ + int i, base; + char *regset = (char *) buf; + + base = find_regno (regcache->tdesc, "tfhar"); + for (i = 0; i < 3; i++) + collect_register (regcache, base + i, ®set[i * 8]); +} + +/* Hardware Transactional Memory special-purpose register regset store + function. */ + +static void +ppc_store_tm_sprregset (struct regcache *regcache, const void *buf) +{ + int i, base; + const char *regset = (const char *) buf; + + base = find_regno (regcache->tdesc, "tfhar"); + for (i = 0; i < 3; i++) + supply_register (regcache, base + i, ®set[i * 8]); +} + +/* For the same reasons as the EBB regset, none of the HTM + checkpointed regsets have a fill function. These registers are + only available if the inferior is in a transaction. */ + +/* Hardware Transactional Memory checkpointed general-purpose regset + store function. */ + +static void +ppc_store_tm_cgprregset (struct regcache *regcache, const void *buf) +{ + int i, base, size, endian_offset; + const char *regset = (const char *) buf; + + base = find_regno (regcache->tdesc, "cr0"); + size = register_size (regcache->tdesc, base); + + gdb_assert (size == 4 || size == 8); + + for (i = 0; i < 32; i++) + supply_register (regcache, base + i, ®set[i * size]); + + endian_offset = 0; + + if ((size == 8) && (__BYTE_ORDER == __BIG_ENDIAN)) + endian_offset = 4; + + supply_register_by_name (regcache, "ccr", + ®set[PT_CCR * size + endian_offset]); + + supply_register_by_name (regcache, "cxer", + ®set[PT_XER * size + endian_offset]); + + supply_register_by_name (regcache, "clr", ®set[PT_LNK * size]); + supply_register_by_name (regcache, "cctr", ®set[PT_CTR * size]); +} + +/* Hardware Transactional Memory checkpointed floating-point regset + store function. */ + +static void +ppc_store_tm_cfprregset (struct regcache *regcache, const void *buf) +{ + int i, base; + const char *regset = (const char *) buf; + + base = find_regno (regcache->tdesc, "cf0"); + + for (i = 0; i < 32; i++) + supply_register (regcache, base + i, ®set[i * 8]); + + supply_register_by_name (regcache, "cfpscr", ®set[32 * 8]); +} + +/* Hardware Transactional Memory checkpointed vector regset store + function. */ + +static void +ppc_store_tm_cvrregset (struct regcache *regcache, const void *buf) +{ + int i, base; + const char *regset = (const char *) buf; + int vscr_offset = 0; + + base = find_regno (regcache->tdesc, "cvr0"); + + for (i = 0; i < 32; i++) + supply_register (regcache, base + i, ®set[i * 16]); + + if (__BYTE_ORDER == __BIG_ENDIAN) + vscr_offset = 12; + + supply_register_by_name (regcache, "cvscr", + ®set[32 * 16 + vscr_offset]); + + supply_register_by_name (regcache, "cvrsave", ®set[33 * 16]); +} + +/* Hardware Transactional Memory checkpointed vector-scalar regset + store function. */ + +static void +ppc_store_tm_cvsxregset (struct regcache *regcache, const void *buf) +{ + int i, base; + const char *regset = (const char *) buf; + + base = find_regno (regcache->tdesc, "cvs0h"); + for (i = 0; i < 32; i++) + supply_register (regcache, base + i, ®set[i * 8]); +} + +/* Hardware Transactional Memory checkpointed Program Priority + Register regset store function. */ + +static void +ppc_store_tm_cpprregset (struct regcache *regcache, const void *buf) +{ + const char *cppr = (const char *) buf; + + supply_register_by_name (regcache, "cppr", cppr); +} + +/* Hardware Transactional Memory checkpointed Data Stream Control + Register regset store function. */ + +static void +ppc_store_tm_cdscrregset (struct regcache *regcache, const void *buf) +{ + const char *cdscr = (const char *) buf; + + supply_register_by_name (regcache, "cdscr", cdscr); +} + +/* Hardware Transactional Memory checkpointed Target Address Register + regset store function. */ + +static void +ppc_store_tm_ctarregset (struct regcache *regcache, const void *buf) +{ + const char *ctar = (const char *) buf; + + supply_register_by_name (regcache, "ctar", ctar); +} + +static void +ppc_fill_vsxregset (struct regcache *regcache, void *buf) +{ + int i, base; + char *regset = (char *) buf; + + base = find_regno (regcache->tdesc, "vs0h"); + for (i = 0; i < 32; i++) + collect_register (regcache, base + i, ®set[i * 8]); +} + +static void +ppc_store_vsxregset (struct regcache *regcache, const void *buf) +{ + int i, base; + const char *regset = (const char *) buf; + + base = find_regno (regcache->tdesc, "vs0h"); + for (i = 0; i < 32; i++) + supply_register (regcache, base + i, ®set[i * 8]); +} + +static void +ppc_fill_vrregset (struct regcache *regcache, void *buf) +{ + int i, base; + char *regset = (char *) buf; + int vscr_offset = 0; + + base = find_regno (regcache->tdesc, "vr0"); + for (i = 0; i < 32; i++) + collect_register (regcache, base + i, ®set[i * 16]); + + if (__BYTE_ORDER == __BIG_ENDIAN) + vscr_offset = 12; + + collect_register_by_name (regcache, "vscr", + ®set[32 * 16 + vscr_offset]); + + collect_register_by_name (regcache, "vrsave", ®set[33 * 16]); +} + +static void +ppc_store_vrregset (struct regcache *regcache, const void *buf) +{ + int i, base; + const char *regset = (const char *) buf; + int vscr_offset = 0; + + base = find_regno (regcache->tdesc, "vr0"); + for (i = 0; i < 32; i++) + supply_register (regcache, base + i, ®set[i * 16]); + + if (__BYTE_ORDER == __BIG_ENDIAN) + vscr_offset = 12; + + supply_register_by_name (regcache, "vscr", + ®set[32 * 16 + vscr_offset]); + supply_register_by_name (regcache, "vrsave", ®set[33 * 16]); +} + +struct gdb_evrregset_t +{ + unsigned long evr[32]; + unsigned long long acc; + unsigned long spefscr; +}; + +static void +ppc_fill_evrregset (struct regcache *regcache, void *buf) +{ + int i, ev0; + struct gdb_evrregset_t *regset = (struct gdb_evrregset_t *) buf; + + ev0 = find_regno (regcache->tdesc, "ev0h"); + for (i = 0; i < 32; i++) + collect_register (regcache, ev0 + i, ®set->evr[i]); + + collect_register_by_name (regcache, "acc", ®set->acc); + collect_register_by_name (regcache, "spefscr", ®set->spefscr); +} + +static void +ppc_store_evrregset (struct regcache *regcache, const void *buf) +{ + int i, ev0; + const struct gdb_evrregset_t *regset = (const struct gdb_evrregset_t *) buf; + + ev0 = find_regno (regcache->tdesc, "ev0h"); + for (i = 0; i < 32; i++) + supply_register (regcache, ev0 + i, ®set->evr[i]); + + supply_register_by_name (regcache, "acc", ®set->acc); + supply_register_by_name (regcache, "spefscr", ®set->spefscr); +} + +/* Support for hardware single step. */ + +static int +ppc_supports_hardware_single_step (void) +{ + return 1; +} + +static struct regset_info ppc_regsets[] = { + /* List the extra register sets before GENERAL_REGS. That way we will + fetch them every time, but still fall back to PTRACE_PEEKUSER for the + general registers. Some kernels support these, but not the newer + PPC_PTRACE_GETREGS. */ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CTAR, 0, EXTENDED_REGS, + NULL, ppc_store_tm_ctarregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CDSCR, 0, EXTENDED_REGS, + NULL, ppc_store_tm_cdscrregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CPPR, 0, EXTENDED_REGS, + NULL, ppc_store_tm_cpprregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CVSX, 0, EXTENDED_REGS, + NULL, ppc_store_tm_cvsxregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CVMX, 0, EXTENDED_REGS, + NULL, ppc_store_tm_cvrregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CFPR, 0, EXTENDED_REGS, + NULL, ppc_store_tm_cfprregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_CGPR, 0, EXTENDED_REGS, + NULL, ppc_store_tm_cgprregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TM_SPR, 0, EXTENDED_REGS, + ppc_fill_tm_sprregset, ppc_store_tm_sprregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_EBB, 0, EXTENDED_REGS, + NULL, ppc_store_ebbregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_PMU, 0, EXTENDED_REGS, + ppc_fill_pmuregset, ppc_store_pmuregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TAR, 0, EXTENDED_REGS, + ppc_fill_tarregset, ppc_store_tarregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_PPR, 0, EXTENDED_REGS, + ppc_fill_pprregset, ppc_store_pprregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_DSCR, 0, EXTENDED_REGS, + ppc_fill_dscrregset, ppc_store_dscrregset }, + { PTRACE_GETVSXREGS, PTRACE_SETVSXREGS, 0, 0, EXTENDED_REGS, + ppc_fill_vsxregset, ppc_store_vsxregset }, + { PTRACE_GETVRREGS, PTRACE_SETVRREGS, 0, 0, EXTENDED_REGS, + ppc_fill_vrregset, ppc_store_vrregset }, + { PTRACE_GETEVRREGS, PTRACE_SETEVRREGS, 0, 0, EXTENDED_REGS, + ppc_fill_evrregset, ppc_store_evrregset }, + { 0, 0, 0, 0, GENERAL_REGS, ppc_fill_gregset, NULL }, + NULL_REGSET +}; + +static struct usrregs_info ppc_usrregs_info = + { + ppc_num_regs, + ppc_regmap, + }; + +static struct regsets_info ppc_regsets_info = + { + ppc_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &ppc_usrregs_info, + &ppc_regsets_info + }; + +static const struct regs_info * +ppc_regs_info (void) +{ + return ®s_info; +} + +static void +ppc_arch_setup (void) +{ + const struct target_desc *tdesc; + struct regset_info *regset; + struct ppc_linux_features features = ppc_linux_no_features; + + int tid = lwpid_of (current_thread); + + features.wordsize = ppc_linux_target_wordsize (tid); + + if (features.wordsize == 4) + tdesc = tdesc_powerpc_32l; + else + tdesc = tdesc_powerpc_64l; + + current_process ()->tdesc = tdesc; + + /* The value of current_process ()->tdesc needs to be set for this + call. */ + ppc_hwcap = linux_get_hwcap (features.wordsize); + ppc_hwcap2 = linux_get_hwcap2 (features.wordsize); + + features.isa205 = ppc_linux_has_isa205 (ppc_hwcap); + + if (ppc_hwcap & PPC_FEATURE_HAS_VSX) + features.vsx = true; + + if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC) + features.altivec = true; + + if ((ppc_hwcap2 & PPC_FEATURE2_DSCR) + && ppc_check_regset (tid, NT_PPC_DSCR, PPC_LINUX_SIZEOF_DSCRREGSET) + && ppc_check_regset (tid, NT_PPC_PPR, PPC_LINUX_SIZEOF_PPRREGSET)) + { + features.ppr_dscr = true; + if ((ppc_hwcap2 & PPC_FEATURE2_ARCH_2_07) + && (ppc_hwcap2 & PPC_FEATURE2_TAR) + && (ppc_hwcap2 & PPC_FEATURE2_EBB) + && ppc_check_regset (tid, NT_PPC_TAR, + PPC_LINUX_SIZEOF_TARREGSET) + && ppc_check_regset (tid, NT_PPC_EBB, + PPC_LINUX_SIZEOF_EBBREGSET) + && ppc_check_regset (tid, NT_PPC_PMU, + PPC_LINUX_SIZEOF_PMUREGSET)) + { + features.isa207 = true; + if ((ppc_hwcap2 & PPC_FEATURE2_HTM) + && ppc_check_regset (tid, NT_PPC_TM_SPR, + PPC_LINUX_SIZEOF_TM_SPRREGSET)) + features.htm = true; + } + } + + tdesc = ppc_linux_match_description (features); + + /* On 32-bit machines, check for SPE registers. + Set the low target's regmap field as appropriately. */ +#ifndef __powerpc64__ + if (ppc_hwcap & PPC_FEATURE_HAS_SPE) + tdesc = tdesc_powerpc_e500l; + + if (!ppc_regmap_adjusted) + { + if (ppc_hwcap & PPC_FEATURE_HAS_SPE) + ppc_usrregs_info.regmap = ppc_regmap_e500; + + /* If the FPSCR is 64-bit wide, we need to fetch the whole + 64-bit slot and not just its second word. The PT_FPSCR + supplied in a 32-bit GDB compilation doesn't reflect + this. */ + if (register_size (tdesc, 70) == 8) + ppc_regmap[70] = (48 + 2*32) * sizeof (long); + + ppc_regmap_adjusted = 1; + } +#endif + + current_process ()->tdesc = tdesc; + + for (regset = ppc_regsets; regset->size >= 0; regset++) + switch (regset->get_request) + { + case PTRACE_GETVRREGS: + regset->size = features.altivec ? PPC_LINUX_SIZEOF_VRREGSET : 0; + break; + case PTRACE_GETVSXREGS: + regset->size = features.vsx ? PPC_LINUX_SIZEOF_VSXREGSET : 0; + break; + case PTRACE_GETEVRREGS: + if (ppc_hwcap & PPC_FEATURE_HAS_SPE) + regset->size = 32 * 4 + 8 + 4; + else + regset->size = 0; + break; + case PTRACE_GETREGSET: + switch (regset->nt_type) + { + case NT_PPC_PPR: + regset->size = (features.ppr_dscr ? + PPC_LINUX_SIZEOF_PPRREGSET : 0); + break; + case NT_PPC_DSCR: + regset->size = (features.ppr_dscr ? + PPC_LINUX_SIZEOF_DSCRREGSET : 0); + break; + case NT_PPC_TAR: + regset->size = (features.isa207 ? + PPC_LINUX_SIZEOF_TARREGSET : 0); + break; + case NT_PPC_EBB: + regset->size = (features.isa207 ? + PPC_LINUX_SIZEOF_EBBREGSET : 0); + break; + case NT_PPC_PMU: + regset->size = (features.isa207 ? + PPC_LINUX_SIZEOF_PMUREGSET : 0); + break; + case NT_PPC_TM_SPR: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_TM_SPRREGSET : 0); + break; + case NT_PPC_TM_CGPR: + if (features.wordsize == 4) + regset->size = (features.htm ? + PPC32_LINUX_SIZEOF_CGPRREGSET : 0); + else + regset->size = (features.htm ? + PPC64_LINUX_SIZEOF_CGPRREGSET : 0); + break; + case NT_PPC_TM_CFPR: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_CFPRREGSET : 0); + break; + case NT_PPC_TM_CVMX: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_CVMXREGSET : 0); + break; + case NT_PPC_TM_CVSX: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_CVSXREGSET : 0); + break; + case NT_PPC_TM_CPPR: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_CPPRREGSET : 0); + break; + case NT_PPC_TM_CDSCR: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_CDSCRREGSET : 0); + break; + case NT_PPC_TM_CTAR: + regset->size = (features.htm ? + PPC_LINUX_SIZEOF_CTARREGSET : 0); + break; + default: + break; + } + break; + default: + break; + } +} + +/* Implementation of linux_target_ops method "supports_tracepoints". */ + +static int +ppc_supports_tracepoints (void) +{ + return 1; +} + +/* Get the thread area address. This is used to recognize which + thread is which when tracing with the in-process agent library. We + don't read anything from the address, and treat it as opaque; it's + the address itself that we assume is unique per-thread. */ + +static int +ppc_get_thread_area (int lwpid, CORE_ADDR *addr) +{ + struct lwp_info *lwp = find_lwp_pid (ptid_t (lwpid)); + struct thread_info *thr = get_lwp_thread (lwp); + struct regcache *regcache = get_thread_regcache (thr, 1); + ULONGEST tp = 0; + +#ifdef __powerpc64__ + if (register_size (regcache->tdesc, 0) == 8) + collect_register_by_name (regcache, "r13", &tp); + else +#endif + collect_register_by_name (regcache, "r2", &tp); + + *addr = tp; + + return 0; +} + +#ifdef __powerpc64__ + +/* Older glibc doesn't provide this. */ + +#ifndef EF_PPC64_ABI +#define EF_PPC64_ABI 3 +#endif + +/* Returns 1 if inferior is using ELFv2 ABI. Undefined for 32-bit + inferiors. */ + +static int +is_elfv2_inferior (void) +{ + /* To be used as fallback if we're unable to determine the right result - + assume inferior uses the same ABI as gdbserver. */ +#if _CALL_ELF == 2 + const int def_res = 1; +#else + const int def_res = 0; +#endif + CORE_ADDR phdr; + Elf64_Ehdr ehdr; + + const struct target_desc *tdesc = current_process ()->tdesc; + int wordsize = register_size (tdesc, 0); + + if (!linux_get_auxv (wordsize, AT_PHDR, &phdr)) + return def_res; + + /* Assume ELF header is at the beginning of the page where program headers + are located. If it doesn't look like one, bail. */ + + read_inferior_memory (phdr & ~0xfff, (unsigned char *) &ehdr, sizeof ehdr); + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG)) + return def_res; + + return (ehdr.e_flags & EF_PPC64_ABI) == 2; +} + +#endif + +/* Generate a ds-form instruction in BUF and return the number of bytes written + + 0 6 11 16 30 32 + | OPCD | RST | RA | DS |XO| */ + +__attribute__((unused)) /* Maybe unused due to conditional compilation. */ +static int +gen_ds_form (uint32_t *buf, int opcd, int rst, int ra, int ds, int xo) +{ + uint32_t insn; + + gdb_assert ((opcd & ~0x3f) == 0); + gdb_assert ((rst & ~0x1f) == 0); + gdb_assert ((ra & ~0x1f) == 0); + gdb_assert ((xo & ~0x3) == 0); + + insn = (rst << 21) | (ra << 16) | (ds & 0xfffc) | (xo & 0x3); + *buf = (opcd << 26) | insn; + return 1; +} + +/* Followings are frequently used ds-form instructions. */ + +#define GEN_STD(buf, rs, ra, offset) gen_ds_form (buf, 62, rs, ra, offset, 0) +#define GEN_STDU(buf, rs, ra, offset) gen_ds_form (buf, 62, rs, ra, offset, 1) +#define GEN_LD(buf, rt, ra, offset) gen_ds_form (buf, 58, rt, ra, offset, 0) +#define GEN_LDU(buf, rt, ra, offset) gen_ds_form (buf, 58, rt, ra, offset, 1) + +/* Generate a d-form instruction in BUF. + + 0 6 11 16 32 + | OPCD | RST | RA | D | */ + +static int +gen_d_form (uint32_t *buf, int opcd, int rst, int ra, int si) +{ + uint32_t insn; + + gdb_assert ((opcd & ~0x3f) == 0); + gdb_assert ((rst & ~0x1f) == 0); + gdb_assert ((ra & ~0x1f) == 0); + + insn = (rst << 21) | (ra << 16) | (si & 0xffff); + *buf = (opcd << 26) | insn; + return 1; +} + +/* Followings are frequently used d-form instructions. */ + +#define GEN_ADDI(buf, rt, ra, si) gen_d_form (buf, 14, rt, ra, si) +#define GEN_ADDIS(buf, rt, ra, si) gen_d_form (buf, 15, rt, ra, si) +#define GEN_LI(buf, rt, si) GEN_ADDI (buf, rt, 0, si) +#define GEN_LIS(buf, rt, si) GEN_ADDIS (buf, rt, 0, si) +#define GEN_ORI(buf, rt, ra, si) gen_d_form (buf, 24, rt, ra, si) +#define GEN_ORIS(buf, rt, ra, si) gen_d_form (buf, 25, rt, ra, si) +#define GEN_LWZ(buf, rt, ra, si) gen_d_form (buf, 32, rt, ra, si) +#define GEN_STW(buf, rt, ra, si) gen_d_form (buf, 36, rt, ra, si) +#define GEN_STWU(buf, rt, ra, si) gen_d_form (buf, 37, rt, ra, si) + +/* Generate a xfx-form instruction in BUF and return the number of bytes + written. + + 0 6 11 21 31 32 + | OPCD | RST | RI | XO |/| */ + +static int +gen_xfx_form (uint32_t *buf, int opcd, int rst, int ri, int xo) +{ + uint32_t insn; + unsigned int n = ((ri & 0x1f) << 5) | ((ri >> 5) & 0x1f); + + gdb_assert ((opcd & ~0x3f) == 0); + gdb_assert ((rst & ~0x1f) == 0); + gdb_assert ((xo & ~0x3ff) == 0); + + insn = (rst << 21) | (n << 11) | (xo << 1); + *buf = (opcd << 26) | insn; + return 1; +} + +/* Followings are frequently used xfx-form instructions. */ + +#define GEN_MFSPR(buf, rt, spr) gen_xfx_form (buf, 31, rt, spr, 339) +#define GEN_MTSPR(buf, rt, spr) gen_xfx_form (buf, 31, rt, spr, 467) +#define GEN_MFCR(buf, rt) gen_xfx_form (buf, 31, rt, 0, 19) +#define GEN_MTCR(buf, rt) gen_xfx_form (buf, 31, rt, 0x3cf, 144) +#define GEN_SYNC(buf, L, E) gen_xfx_form (buf, 31, L & 0x3, \ + E & 0xf, 598) +#define GEN_LWSYNC(buf) GEN_SYNC (buf, 1, 0) + + +/* Generate a x-form instruction in BUF and return the number of bytes written. + + 0 6 11 16 21 31 32 + | OPCD | RST | RA | RB | XO |RC| */ + +static int +gen_x_form (uint32_t *buf, int opcd, int rst, int ra, int rb, int xo, int rc) +{ + uint32_t insn; + + gdb_assert ((opcd & ~0x3f) == 0); + gdb_assert ((rst & ~0x1f) == 0); + gdb_assert ((ra & ~0x1f) == 0); + gdb_assert ((rb & ~0x1f) == 0); + gdb_assert ((xo & ~0x3ff) == 0); + gdb_assert ((rc & ~1) == 0); + + insn = (rst << 21) | (ra << 16) | (rb << 11) | (xo << 1) | rc; + *buf = (opcd << 26) | insn; + return 1; +} + +/* Followings are frequently used x-form instructions. */ + +#define GEN_OR(buf, ra, rs, rb) gen_x_form (buf, 31, rs, ra, rb, 444, 0) +#define GEN_MR(buf, ra, rs) GEN_OR (buf, ra, rs, rs) +#define GEN_LWARX(buf, rt, ra, rb) gen_x_form (buf, 31, rt, ra, rb, 20, 0) +#define GEN_STWCX(buf, rs, ra, rb) gen_x_form (buf, 31, rs, ra, rb, 150, 1) +/* Assume bf = cr7. */ +#define GEN_CMPW(buf, ra, rb) gen_x_form (buf, 31, 28, ra, rb, 0, 0) + + +/* Generate a md-form instruction in BUF and return the number of bytes written. + + 0 6 11 16 21 27 30 31 32 + | OPCD | RS | RA | sh | mb | XO |sh|Rc| */ + +static int +gen_md_form (uint32_t *buf, int opcd, int rs, int ra, int sh, int mb, + int xo, int rc) +{ + uint32_t insn; + unsigned int n = ((mb & 0x1f) << 1) | ((mb >> 5) & 0x1); + unsigned int sh0_4 = sh & 0x1f; + unsigned int sh5 = (sh >> 5) & 1; + + gdb_assert ((opcd & ~0x3f) == 0); + gdb_assert ((rs & ~0x1f) == 0); + gdb_assert ((ra & ~0x1f) == 0); + gdb_assert ((sh & ~0x3f) == 0); + gdb_assert ((mb & ~0x3f) == 0); + gdb_assert ((xo & ~0x7) == 0); + gdb_assert ((rc & ~0x1) == 0); + + insn = (rs << 21) | (ra << 16) | (sh0_4 << 11) | (n << 5) + | (sh5 << 1) | (xo << 2) | (rc & 1); + *buf = (opcd << 26) | insn; + return 1; +} + +/* The following are frequently used md-form instructions. */ + +#define GEN_RLDICL(buf, ra, rs ,sh, mb) \ + gen_md_form (buf, 30, rs, ra, sh, mb, 0, 0) +#define GEN_RLDICR(buf, ra, rs ,sh, mb) \ + gen_md_form (buf, 30, rs, ra, sh, mb, 1, 0) + +/* Generate a i-form instruction in BUF and return the number of bytes written. + + 0 6 30 31 32 + | OPCD | LI |AA|LK| */ + +static int +gen_i_form (uint32_t *buf, int opcd, int li, int aa, int lk) +{ + uint32_t insn; + + gdb_assert ((opcd & ~0x3f) == 0); + + insn = (li & 0x3fffffc) | (aa & 1) | (lk & 1); + *buf = (opcd << 26) | insn; + return 1; +} + +/* The following are frequently used i-form instructions. */ + +#define GEN_B(buf, li) gen_i_form (buf, 18, li, 0, 0) +#define GEN_BL(buf, li) gen_i_form (buf, 18, li, 0, 1) + +/* Generate a b-form instruction in BUF and return the number of bytes written. + + 0 6 11 16 30 31 32 + | OPCD | BO | BI | BD |AA|LK| */ + +static int +gen_b_form (uint32_t *buf, int opcd, int bo, int bi, int bd, + int aa, int lk) +{ + uint32_t insn; + + gdb_assert ((opcd & ~0x3f) == 0); + gdb_assert ((bo & ~0x1f) == 0); + gdb_assert ((bi & ~0x1f) == 0); + + insn = (bo << 21) | (bi << 16) | (bd & 0xfffc) | (aa & 1) | (lk & 1); + *buf = (opcd << 26) | insn; + return 1; +} + +/* The following are frequently used b-form instructions. */ +/* Assume bi = cr7. */ +#define GEN_BNE(buf, bd) gen_b_form (buf, 16, 0x4, (7 << 2) | 2, bd, 0 ,0) + +/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32 + respectively. They are primary used for save/restore GPRs in jump-pad, + not used for bytecode compiling. */ + +#ifdef __powerpc64__ +#define GEN_LOAD(buf, rt, ra, si, is_64) (is_64 ? \ + GEN_LD (buf, rt, ra, si) : \ + GEN_LWZ (buf, rt, ra, si)) +#define GEN_STORE(buf, rt, ra, si, is_64) (is_64 ? \ + GEN_STD (buf, rt, ra, si) : \ + GEN_STW (buf, rt, ra, si)) +#else +#define GEN_LOAD(buf, rt, ra, si, is_64) GEN_LWZ (buf, rt, ra, si) +#define GEN_STORE(buf, rt, ra, si, is_64) GEN_STW (buf, rt, ra, si) +#endif + +/* Generate a sequence of instructions to load IMM in the register REG. + Write the instructions in BUF and return the number of bytes written. */ + +static int +gen_limm (uint32_t *buf, int reg, uint64_t imm, int is_64) +{ + uint32_t *p = buf; + + if ((imm + 32768) < 65536) + { + /* li reg, imm[15:0] */ + p += GEN_LI (p, reg, imm); + } + else if ((imm >> 32) == 0) + { + /* lis reg, imm[31:16] + ori reg, reg, imm[15:0] + rldicl reg, reg, 0, 32 */ + p += GEN_LIS (p, reg, (imm >> 16) & 0xffff); + if ((imm & 0xffff) != 0) + p += GEN_ORI (p, reg, reg, imm & 0xffff); + /* Clear upper 32-bit if sign-bit is set. */ + if (imm & (1u << 31) && is_64) + p += GEN_RLDICL (p, reg, reg, 0, 32); + } + else + { + gdb_assert (is_64); + /* lis reg, + ori reg, reg, + rldicr reg, reg, 32, 31 + oris reg, reg, + ori reg, reg, */ + p += GEN_LIS (p, reg, ((imm >> 48) & 0xffff)); + if (((imm >> 32) & 0xffff) != 0) + p += GEN_ORI (p, reg, reg, ((imm >> 32) & 0xffff)); + p += GEN_RLDICR (p, reg, reg, 32, 31); + if (((imm >> 16) & 0xffff) != 0) + p += GEN_ORIS (p, reg, reg, ((imm >> 16) & 0xffff)); + if ((imm & 0xffff) != 0) + p += GEN_ORI (p, reg, reg, (imm & 0xffff)); + } + + return p - buf; +} + +/* Generate a sequence for atomically exchange at location LOCK. + This code sequence clobbers r6, r7, r8. LOCK is the location for + the atomic-xchg, OLD_VALUE is expected old value stored in the + location, and R_NEW is a register for the new value. */ + +static int +gen_atomic_xchg (uint32_t *buf, CORE_ADDR lock, int old_value, int r_new, + int is_64) +{ + const int r_lock = 6; + const int r_old = 7; + const int r_tmp = 8; + uint32_t *p = buf; + + /* + 1: lwarx TMP, 0, LOCK + cmpwi TMP, OLD + bne 1b + stwcx. NEW, 0, LOCK + bne 1b */ + + p += gen_limm (p, r_lock, lock, is_64); + p += gen_limm (p, r_old, old_value, is_64); + + p += GEN_LWARX (p, r_tmp, 0, r_lock); + p += GEN_CMPW (p, r_tmp, r_old); + p += GEN_BNE (p, -8); + p += GEN_STWCX (p, r_new, 0, r_lock); + p += GEN_BNE (p, -16); + + return p - buf; +} + +/* Generate a sequence of instructions for calling a function + at address of FN. Return the number of bytes are written in BUF. */ + +static int +gen_call (uint32_t *buf, CORE_ADDR fn, int is_64, int is_opd) +{ + uint32_t *p = buf; + + /* Must be called by r12 for caller to calculate TOC address. */ + p += gen_limm (p, 12, fn, is_64); + if (is_opd) + { + p += GEN_LOAD (p, 11, 12, 16, is_64); + p += GEN_LOAD (p, 2, 12, 8, is_64); + p += GEN_LOAD (p, 12, 12, 0, is_64); + } + p += GEN_MTSPR (p, 12, 9); /* mtctr r12 */ + *p++ = 0x4e800421; /* bctrl */ + + return p - buf; +} + +/* Copy the instruction from OLDLOC to *TO, and update *TO to *TO + size + of instruction. This function is used to adjust pc-relative instructions + when copying. */ + +static void +ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc) +{ + uint32_t insn, op6; + long rel, newrel; + + read_inferior_memory (oldloc, (unsigned char *) &insn, 4); + op6 = PPC_OP6 (insn); + + if (op6 == 18 && (insn & 2) == 0) + { + /* branch && AA = 0 */ + rel = PPC_LI (insn); + newrel = (oldloc - *to) + rel; + + /* Out of range. Cannot relocate instruction. */ + if (newrel >= (1 << 25) || newrel < -(1 << 25)) + return; + + insn = (insn & ~0x3fffffc) | (newrel & 0x3fffffc); + } + else if (op6 == 16 && (insn & 2) == 0) + { + /* conditional branch && AA = 0 */ + + /* If the new relocation is too big for even a 26-bit unconditional + branch, there is nothing we can do. Just abort. + + Otherwise, if it can be fit in 16-bit conditional branch, just + copy the instruction and relocate the address. + + If the it's big for conditional-branch (16-bit), try to invert the + condition and jump with 26-bit branch. For example, + + beq .Lgoto + INSN1 + + => + + bne 1f (+8) + b .Lgoto + 1:INSN1 + + After this transform, we are actually jump from *TO+4 instead of *TO, + so check the relocation again because it will be 1-insn farther then + before if *TO is after OLDLOC. + + + For BDNZT (or so) is transformed from + + bdnzt eq, .Lgoto + INSN1 + + => + + bdz 1f (+12) + bf eq, 1f (+8) + b .Lgoto + 1:INSN1 + + See also "BO field encodings". */ + + rel = PPC_BD (insn); + newrel = (oldloc - *to) + rel; + + if (newrel < (1 << 15) && newrel >= -(1 << 15)) + insn = (insn & ~0xfffc) | (newrel & 0xfffc); + else if ((PPC_BO (insn) & 0x14) == 0x4 || (PPC_BO (insn) & 0x14) == 0x10) + { + newrel -= 4; + + /* Out of range. Cannot relocate instruction. */ + if (newrel >= (1 << 25) || newrel < -(1 << 25)) + return; + + if ((PPC_BO (insn) & 0x14) == 0x4) + insn ^= (1 << 24); + else if ((PPC_BO (insn) & 0x14) == 0x10) + insn ^= (1 << 22); + + /* Jump over the unconditional branch. */ + insn = (insn & ~0xfffc) | 0x8; + target_write_memory (*to, (unsigned char *) &insn, 4); + *to += 4; + + /* Build a unconditional branch and copy LK bit. */ + insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3); + target_write_memory (*to, (unsigned char *) &insn, 4); + *to += 4; + + return; + } + else if ((PPC_BO (insn) & 0x14) == 0) + { + uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12; + uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8; + + newrel -= 8; + + /* Out of range. Cannot relocate instruction. */ + if (newrel >= (1 << 25) || newrel < -(1 << 25)) + return; + + /* Copy BI field. */ + bf_insn |= (insn & 0x1f0000); + + /* Invert condition. */ + bdnz_insn |= (insn ^ (1 << 22)) & (1 << 22); + bf_insn |= (insn ^ (1 << 24)) & (1 << 24); + + target_write_memory (*to, (unsigned char *) &bdnz_insn, 4); + *to += 4; + target_write_memory (*to, (unsigned char *) &bf_insn, 4); + *to += 4; + + /* Build a unconditional branch and copy LK bit. */ + insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3); + target_write_memory (*to, (unsigned char *) &insn, 4); + *to += 4; + + return; + } + else /* (BO & 0x14) == 0x14, branch always. */ + { + /* Out of range. Cannot relocate instruction. */ + if (newrel >= (1 << 25) || newrel < -(1 << 25)) + return; + + /* Build a unconditional branch and copy LK bit. */ + insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3); + target_write_memory (*to, (unsigned char *) &insn, 4); + *to += 4; + + return; + } + } + + target_write_memory (*to, (unsigned char *) &insn, 4); + *to += 4; +} + +/* Implement install_fast_tracepoint_jump_pad of target_ops. + See target.h for details. */ + +static int +ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + uint32_t buf[256]; + uint32_t *p = buf; + int j, offset; + CORE_ADDR buildaddr = *jump_entry; + const CORE_ADDR entryaddr = *jump_entry; + int rsz, min_frame, frame_size, tp_reg; +#ifdef __powerpc64__ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + int is_64 = register_size (regcache->tdesc, 0) == 8; + int is_opd = is_64 && !is_elfv2_inferior (); +#else + int is_64 = 0, is_opd = 0; +#endif + +#ifdef __powerpc64__ + if (is_64) + { + /* Minimum frame size is 32 bytes for ELFv2, and 112 bytes for ELFv1. */ + rsz = 8; + min_frame = 112; + frame_size = (40 * rsz) + min_frame; + tp_reg = 13; + } + else + { +#endif + rsz = 4; + min_frame = 16; + frame_size = (40 * rsz) + min_frame; + tp_reg = 2; +#ifdef __powerpc64__ + } +#endif + + /* Stack frame layout for this jump pad, + + High thread_area (r13/r2) | + tpoint - collecting_t obj + PC/ | +36 + CTR | +35 + LR | +34 + XER | +33 + CR | +32 + R31 | + R29 | + ... | + R1 | +1 + R0 - collected registers + ... | + ... | + Low Back-chain - + + + The code flow of this jump pad, + + 1. Adjust SP + 2. Save GPR and SPR + 3. Prepare argument + 4. Call gdb_collector + 5. Restore GPR and SPR + 6. Restore SP + 7. Build a jump for back to the program + 8. Copy/relocate original instruction + 9. Build a jump for replacing original instruction. */ + + /* Adjust stack pointer. */ + if (is_64) + p += GEN_STDU (p, 1, 1, -frame_size); /* stdu r1,-frame_size(r1) */ + else + p += GEN_STWU (p, 1, 1, -frame_size); /* stwu r1,-frame_size(r1) */ + + /* Store GPRs. Save R1 later, because it had just been modified, but + we want the original value. */ + for (j = 2; j < 32; j++) + p += GEN_STORE (p, j, 1, min_frame + j * rsz, is_64); + p += GEN_STORE (p, 0, 1, min_frame + 0 * rsz, is_64); + /* Set r0 to the original value of r1 before adjusting stack frame, + and then save it. */ + p += GEN_ADDI (p, 0, 1, frame_size); + p += GEN_STORE (p, 0, 1, min_frame + 1 * rsz, is_64); + + /* Save CR, XER, LR, and CTR. */ + p += GEN_MFCR (p, 3); /* mfcr r3 */ + p += GEN_MFSPR (p, 4, 1); /* mfxer r4 */ + p += GEN_MFSPR (p, 5, 8); /* mflr r5 */ + p += GEN_MFSPR (p, 6, 9); /* mfctr r6 */ + p += GEN_STORE (p, 3, 1, min_frame + 32 * rsz, is_64);/* std r3, 32(r1) */ + p += GEN_STORE (p, 4, 1, min_frame + 33 * rsz, is_64);/* std r4, 33(r1) */ + p += GEN_STORE (p, 5, 1, min_frame + 34 * rsz, is_64);/* std r5, 34(r1) */ + p += GEN_STORE (p, 6, 1, min_frame + 35 * rsz, is_64);/* std r6, 35(r1) */ + + /* Save PC */ + p += gen_limm (p, 3, tpaddr, is_64); + p += GEN_STORE (p, 3, 1, min_frame + 36 * rsz, is_64); + + + /* Setup arguments to collector. */ + /* Set r4 to collected registers. */ + p += GEN_ADDI (p, 4, 1, min_frame); + /* Set r3 to TPOINT. */ + p += gen_limm (p, 3, tpoint, is_64); + + /* Prepare collecting_t object for lock. */ + p += GEN_STORE (p, 3, 1, min_frame + 37 * rsz, is_64); + p += GEN_STORE (p, tp_reg, 1, min_frame + 38 * rsz, is_64); + /* Set R5 to collecting object. */ + p += GEN_ADDI (p, 5, 1, 37 * rsz); + + p += GEN_LWSYNC (p); + p += gen_atomic_xchg (p, lockaddr, 0, 5, is_64); + p += GEN_LWSYNC (p); + + /* Call to collector. */ + p += gen_call (p, collector, is_64, is_opd); + + /* Simply write 0 to release the lock. */ + p += gen_limm (p, 3, lockaddr, is_64); + p += gen_limm (p, 4, 0, is_64); + p += GEN_LWSYNC (p); + p += GEN_STORE (p, 4, 3, 0, is_64); + + /* Restore stack and registers. */ + p += GEN_LOAD (p, 3, 1, min_frame + 32 * rsz, is_64); /* ld r3, 32(r1) */ + p += GEN_LOAD (p, 4, 1, min_frame + 33 * rsz, is_64); /* ld r4, 33(r1) */ + p += GEN_LOAD (p, 5, 1, min_frame + 34 * rsz, is_64); /* ld r5, 34(r1) */ + p += GEN_LOAD (p, 6, 1, min_frame + 35 * rsz, is_64); /* ld r6, 35(r1) */ + p += GEN_MTCR (p, 3); /* mtcr r3 */ + p += GEN_MTSPR (p, 4, 1); /* mtxer r4 */ + p += GEN_MTSPR (p, 5, 8); /* mtlr r5 */ + p += GEN_MTSPR (p, 6, 9); /* mtctr r6 */ + + /* Restore GPRs. */ + for (j = 2; j < 32; j++) + p += GEN_LOAD (p, j, 1, min_frame + j * rsz, is_64); + p += GEN_LOAD (p, 0, 1, min_frame + 0 * rsz, is_64); + /* Restore SP. */ + p += GEN_ADDI (p, 1, 1, frame_size); + + /* Flush instructions to inferior memory. */ + target_write_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4); + + /* Now, insert the original instruction to execute in the jump pad. */ + *adjusted_insn_addr = buildaddr + (p - buf) * 4; + *adjusted_insn_addr_end = *adjusted_insn_addr; + ppc_relocate_instruction (adjusted_insn_addr_end, tpaddr); + + /* Verify the relocation size. If should be 4 for normal copy, + 8 or 12 for some conditional branch. */ + if ((*adjusted_insn_addr_end - *adjusted_insn_addr == 0) + || (*adjusted_insn_addr_end - *adjusted_insn_addr > 12)) + { + sprintf (err, "E.Unexpected instruction length = %d" + "when relocate instruction.", + (int) (*adjusted_insn_addr_end - *adjusted_insn_addr)); + return 1; + } + + buildaddr = *adjusted_insn_addr_end; + p = buf; + /* Finally, write a jump back to the program. */ + offset = (tpaddr + 4) - buildaddr; + if (offset >= (1 << 25) || offset < -(1 << 25)) + { + sprintf (err, "E.Jump back from jump pad too far from tracepoint " + "(offset 0x%x > 26-bit).", offset); + return 1; + } + /* b */ + p += GEN_B (p, offset); + target_write_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4); + *jump_entry = buildaddr + (p - buf) * 4; + + /* The jump pad is now built. Wire in a jump to our jump pad. This + is always done last (by our caller actually), so that we can + install fast tracepoints with threads running. This relies on + the agent's atomic write support. */ + offset = entryaddr - tpaddr; + if (offset >= (1 << 25) || offset < -(1 << 25)) + { + sprintf (err, "E.Jump back from jump pad too far from tracepoint " + "(offset 0x%x > 26-bit).", offset); + return 1; + } + /* b */ + GEN_B ((uint32_t *) jjump_pad_insn, offset); + *jjump_pad_insn_size = 4; + + return 0; +} + +/* Returns the minimum instruction length for installing a tracepoint. */ + +static int +ppc_get_min_fast_tracepoint_insn_len (void) +{ + return 4; +} + +/* Emits a given buffer into the target at current_insn_ptr. Length + is in units of 32-bit words. */ + +static void +emit_insns (uint32_t *buf, int n) +{ + n = n * sizeof (uint32_t); + target_write_memory (current_insn_ptr, (unsigned char *) buf, n); + current_insn_ptr += n; +} + +#define __EMIT_ASM(NAME, INSNS) \ + do \ + { \ + extern uint32_t start_bcax_ ## NAME []; \ + extern uint32_t end_bcax_ ## NAME []; \ + emit_insns (start_bcax_ ## NAME, \ + end_bcax_ ## NAME - start_bcax_ ## NAME); \ + __asm__ (".section .text.__ppcbcax\n\t" \ + "start_bcax_" #NAME ":\n\t" \ + INSNS "\n\t" \ + "end_bcax_" #NAME ":\n\t" \ + ".previous\n\t"); \ + } while (0) + +#define _EMIT_ASM(NAME, INSNS) __EMIT_ASM (NAME, INSNS) +#define EMIT_ASM(INSNS) _EMIT_ASM (__LINE__, INSNS) + +/* + + Bytecode execution stack frame - 32-bit + + | LR save area (SP + 4) + SP' -> +- Back chain (SP + 0) + | Save r31 for access saved arguments + | Save r30 for bytecode stack pointer + | Save r4 for incoming argument *value + | Save r3 for incoming argument regs + r30 -> +- Bytecode execution stack + | + | 64-byte (8 doublewords) at initial. + | Expand stack as needed. + | + +- + | Some padding for minimum stack frame and 16-byte alignment. + | 16 bytes. + SP +- Back-chain (SP') + + initial frame size + = 16 + (4 * 4) + 64 + = 96 + + r30 is the stack-pointer for bytecode machine. + It should point to next-empty, so we can use LDU for pop. + r3 is used for cache of the high part of TOP value. + It was the first argument, pointer to regs. + r4 is used for cache of the low part of TOP value. + It was the second argument, pointer to the result. + We should set *result = TOP after leaving this function. + + Note: + * To restore stack at epilogue + => sp = r31 + * To check stack is big enough for bytecode execution. + => r30 - 8 > SP + 8 + * To return execution result. + => 0(r4) = TOP + + */ + +/* Regardless of endian, register 3 is always high part, 4 is low part. + These defines are used when the register pair is stored/loaded. + Likewise, to simplify code, have a similiar define for 5:6. */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define TOP_FIRST "4" +#define TOP_SECOND "3" +#define TMP_FIRST "6" +#define TMP_SECOND "5" +#else +#define TOP_FIRST "3" +#define TOP_SECOND "4" +#define TMP_FIRST "5" +#define TMP_SECOND "6" +#endif + +/* Emit prologue in inferior memory. See above comments. */ + +static void +ppc_emit_prologue (void) +{ + EMIT_ASM (/* Save return address. */ + "mflr 0 \n" + "stw 0, 4(1) \n" + /* Adjust SP. 96 is the initial frame size. */ + "stwu 1, -96(1) \n" + /* Save r30 and incoming arguments. */ + "stw 31, 96-4(1) \n" + "stw 30, 96-8(1) \n" + "stw 4, 96-12(1) \n" + "stw 3, 96-16(1) \n" + /* Point r31 to original r1 for access arguments. */ + "addi 31, 1, 96 \n" + /* Set r30 to pointing stack-top. */ + "addi 30, 1, 64 \n" + /* Initial r3/TOP to 0. */ + "li 3, 0 \n" + "li 4, 0 \n"); +} + +/* Emit epilogue in inferior memory. See above comments. */ + +static void +ppc_emit_epilogue (void) +{ + EMIT_ASM (/* *result = TOP */ + "lwz 5, -12(31) \n" + "stw " TOP_FIRST ", 0(5) \n" + "stw " TOP_SECOND ", 4(5) \n" + /* Restore registers. */ + "lwz 31, -4(31) \n" + "lwz 30, -8(31) \n" + /* Restore SP. */ + "lwz 1, 0(1) \n" + /* Restore LR. */ + "lwz 0, 4(1) \n" + /* Return 0 for no-error. */ + "li 3, 0 \n" + "mtlr 0 \n" + "blr \n"); +} + +/* TOP = stack[--sp] + TOP */ + +static void +ppc_emit_add (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30)\n" + "addc 4, 6, 4 \n" + "adde 3, 5, 3 \n"); +} + +/* TOP = stack[--sp] - TOP */ + +static void +ppc_emit_sub (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "subfc 4, 4, 6 \n" + "subfe 3, 3, 5 \n"); +} + +/* TOP = stack[--sp] * TOP */ + +static void +ppc_emit_mul (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "mulhwu 7, 6, 4 \n" + "mullw 3, 6, 3 \n" + "mullw 5, 4, 5 \n" + "mullw 4, 6, 4 \n" + "add 3, 5, 3 \n" + "add 3, 7, 3 \n"); +} + +/* TOP = stack[--sp] << TOP */ + +static void +ppc_emit_lsh (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "subfic 3, 4, 32\n" /* r3 = 32 - TOP */ + "addi 7, 4, -32\n" /* r7 = TOP - 32 */ + "slw 5, 5, 4\n" /* Shift high part left */ + "slw 4, 6, 4\n" /* Shift low part left */ + "srw 3, 6, 3\n" /* Shift low to high if shift < 32 */ + "slw 7, 6, 7\n" /* Shift low to high if shift >= 32 */ + "or 3, 5, 3\n" + "or 3, 7, 3\n"); /* Assemble high part */ +} + +/* Top = stack[--sp] >> TOP + (Arithmetic shift right) */ + +static void +ppc_emit_rsh_signed (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "addi 7, 4, -32\n" /* r7 = TOP - 32 */ + "sraw 3, 5, 4\n" /* Shift high part right */ + "cmpwi 7, 1\n" + "blt 0, 1f\n" /* If shift <= 32, goto 1: */ + "sraw 4, 5, 7\n" /* Shift high to low */ + "b 2f\n" + "1:\n" + "subfic 7, 4, 32\n" /* r7 = 32 - TOP */ + "srw 4, 6, 4\n" /* Shift low part right */ + "slw 5, 5, 7\n" /* Shift high to low */ + "or 4, 4, 5\n" /* Assemble low part */ + "2:\n"); +} + +/* Top = stack[--sp] >> TOP + (Logical shift right) */ + +static void +ppc_emit_rsh_unsigned (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "subfic 3, 4, 32\n" /* r3 = 32 - TOP */ + "addi 7, 4, -32\n" /* r7 = TOP - 32 */ + "srw 6, 6, 4\n" /* Shift low part right */ + "slw 3, 5, 3\n" /* Shift high to low if shift < 32 */ + "srw 7, 5, 7\n" /* Shift high to low if shift >= 32 */ + "or 6, 6, 3\n" + "srw 3, 5, 4\n" /* Shift high part right */ + "or 4, 6, 7\n"); /* Assemble low part */ +} + +/* Emit code for signed-extension specified by ARG. */ + +static void +ppc_emit_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM ("extsb 4, 4\n" + "srawi 3, 4, 31"); + break; + case 16: + EMIT_ASM ("extsh 4, 4\n" + "srawi 3, 4, 31"); + break; + case 32: + EMIT_ASM ("srawi 3, 4, 31"); + break; + default: + emit_error = 1; + } +} + +/* Emit code for zero-extension specified by ARG. */ + +static void +ppc_emit_zero_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM ("clrlwi 4,4,24\n" + "li 3, 0\n"); + break; + case 16: + EMIT_ASM ("clrlwi 4,4,16\n" + "li 3, 0\n"); + break; + case 32: + EMIT_ASM ("li 3, 0"); + break; + default: + emit_error = 1; + } +} + +/* TOP = !TOP + i.e., TOP = (TOP == 0) ? 1 : 0; */ + +static void +ppc_emit_log_not (void) +{ + EMIT_ASM ("or 4, 3, 4 \n" + "cntlzw 4, 4 \n" + "srwi 4, 4, 5 \n" + "li 3, 0 \n"); +} + +/* TOP = stack[--sp] & TOP */ + +static void +ppc_emit_bit_and (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "and 4, 6, 4 \n" + "and 3, 5, 3 \n"); +} + +/* TOP = stack[--sp] | TOP */ + +static void +ppc_emit_bit_or (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "or 4, 6, 4 \n" + "or 3, 5, 3 \n"); +} + +/* TOP = stack[--sp] ^ TOP */ + +static void +ppc_emit_bit_xor (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "xor 4, 6, 4 \n" + "xor 3, 5, 3 \n"); +} + +/* TOP = ~TOP + i.e., TOP = ~(TOP | TOP) */ + +static void +ppc_emit_bit_not (void) +{ + EMIT_ASM ("nor 3, 3, 3 \n" + "nor 4, 4, 4 \n"); +} + +/* TOP = stack[--sp] == TOP */ + +static void +ppc_emit_equal (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "xor 4, 6, 4 \n" + "xor 3, 5, 3 \n" + "or 4, 3, 4 \n" + "cntlzw 4, 4 \n" + "srwi 4, 4, 5 \n" + "li 3, 0 \n"); +} + +/* TOP = stack[--sp] < TOP + (Signed comparison) */ + +static void +ppc_emit_less_signed (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "cmplw 6, 6, 4 \n" + "cmpw 7, 5, 3 \n" + /* CR6 bit 0 = low less and high equal */ + "crand 6*4+0, 6*4+0, 7*4+2\n" + /* CR7 bit 0 = (low less and high equal) or high less */ + "cror 7*4+0, 7*4+0, 6*4+0\n" + "mfcr 4 \n" + "rlwinm 4, 4, 29, 31, 31 \n" + "li 3, 0 \n"); +} + +/* TOP = stack[--sp] < TOP + (Unsigned comparison) */ + +static void +ppc_emit_less_unsigned (void) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "cmplw 6, 6, 4 \n" + "cmplw 7, 5, 3 \n" + /* CR6 bit 0 = low less and high equal */ + "crand 6*4+0, 6*4+0, 7*4+2\n" + /* CR7 bit 0 = (low less and high equal) or high less */ + "cror 7*4+0, 7*4+0, 6*4+0\n" + "mfcr 4 \n" + "rlwinm 4, 4, 29, 31, 31 \n" + "li 3, 0 \n"); +} + +/* Access the memory address in TOP in size of SIZE. + Zero-extend the read value. */ + +static void +ppc_emit_ref (int size) +{ + switch (size) + { + case 1: + EMIT_ASM ("lbz 4, 0(4)\n" + "li 3, 0"); + break; + case 2: + EMIT_ASM ("lhz 4, 0(4)\n" + "li 3, 0"); + break; + case 4: + EMIT_ASM ("lwz 4, 0(4)\n" + "li 3, 0"); + break; + case 8: + if (__BYTE_ORDER == __LITTLE_ENDIAN) + EMIT_ASM ("lwz 3, 4(4)\n" + "lwz 4, 0(4)"); + else + EMIT_ASM ("lwz 3, 0(4)\n" + "lwz 4, 4(4)"); + break; + } +} + +/* TOP = NUM */ + +static void +ppc_emit_const (LONGEST num) +{ + uint32_t buf[10]; + uint32_t *p = buf; + + p += gen_limm (p, 3, num >> 32 & 0xffffffff, 0); + p += gen_limm (p, 4, num & 0xffffffff, 0); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Set TOP to the value of register REG by calling get_raw_reg function + with two argument, collected buffer and register number. */ + +static void +ppc_emit_reg (int reg) +{ + uint32_t buf[13]; + uint32_t *p = buf; + + /* fctx->regs is passed in r3 and then saved in -16(31). */ + p += GEN_LWZ (p, 3, 31, -16); + p += GEN_LI (p, 4, reg); /* li r4, reg */ + p += gen_call (p, get_raw_reg_func_addr (), 0, 0); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); + + if (__BYTE_ORDER == __LITTLE_ENDIAN) + { + EMIT_ASM ("mr 5, 4\n" + "mr 4, 3\n" + "mr 3, 5\n"); + } +} + +/* TOP = stack[--sp] */ + +static void +ppc_emit_pop (void) +{ + EMIT_ASM ("lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30) \n"); +} + +/* stack[sp++] = TOP + + Because we may use up bytecode stack, expand 8 doublewords more + if needed. */ + +static void +ppc_emit_stack_flush (void) +{ + /* Make sure bytecode stack is big enough before push. + Otherwise, expand 64-byte more. */ + + EMIT_ASM (" stw " TOP_FIRST ", 0(30) \n" + " stw " TOP_SECOND ", 4(30)\n" + " addi 5, 30, -(8 + 8) \n" + " cmpw 7, 5, 1 \n" + " bgt 7, 1f \n" + " stwu 31, -64(1) \n" + "1:addi 30, 30, -8 \n"); +} + +/* Swap TOP and stack[sp-1] */ + +static void +ppc_emit_swap (void) +{ + EMIT_ASM ("lwz " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 12(30) \n" + "stw " TOP_FIRST ", 8(30) \n" + "stw " TOP_SECOND ", 12(30) \n" + "mr 3, 5 \n" + "mr 4, 6 \n"); +} + +/* Discard N elements in the stack. Also used for ppc64. */ + +static void +ppc_emit_stack_adjust (int n) +{ + uint32_t buf[6]; + uint32_t *p = buf; + + n = n << 3; + if ((n >> 15) != 0) + { + emit_error = 1; + return; + } + + p += GEN_ADDI (p, 30, 30, n); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Call function FN. */ + +static void +ppc_emit_call (CORE_ADDR fn) +{ + uint32_t buf[11]; + uint32_t *p = buf; + + p += gen_call (p, fn, 0, 0); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* FN's prototype is `LONGEST(*fn)(int)'. + TOP = fn (arg1) + */ + +static void +ppc_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[15]; + uint32_t *p = buf; + + /* Setup argument. arg1 is a 16-bit value. */ + p += gen_limm (p, 3, (uint32_t) arg1, 0); + p += gen_call (p, fn, 0, 0); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); + + if (__BYTE_ORDER == __LITTLE_ENDIAN) + { + EMIT_ASM ("mr 5, 4\n" + "mr 4, 3\n" + "mr 3, 5\n"); + } +} + +/* FN's prototype is `void(*fn)(int,LONGEST)'. + fn (arg1, TOP) + + TOP should be preserved/restored before/after the call. */ + +static void +ppc_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[21]; + uint32_t *p = buf; + + /* Save TOP. 0(30) is next-empty. */ + p += GEN_STW (p, 3, 30, 0); + p += GEN_STW (p, 4, 30, 4); + + /* Setup argument. arg1 is a 16-bit value. */ + if (__BYTE_ORDER == __LITTLE_ENDIAN) + { + p += GEN_MR (p, 5, 4); + p += GEN_MR (p, 6, 3); + } + else + { + p += GEN_MR (p, 5, 3); + p += GEN_MR (p, 6, 4); + } + p += gen_limm (p, 3, (uint32_t) arg1, 0); + p += gen_call (p, fn, 0, 0); + + /* Restore TOP */ + p += GEN_LWZ (p, 3, 30, 0); + p += GEN_LWZ (p, 4, 30, 4); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Note in the following goto ops: + + When emitting goto, the target address is later relocated by + write_goto_address. OFFSET_P is the offset of the branch instruction + in the code sequence, and SIZE_P is how to relocate the instruction, + recognized by ppc_write_goto_address. In current implementation, + SIZE can be either 24 or 14 for branch of conditional-branch instruction. + */ + +/* If TOP is true, goto somewhere. Otherwise, just fall-through. */ + +static void +ppc_emit_if_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("or. 3, 3, 4 \n" + "lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30) \n" + "1:bne 0, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Unconditional goto. Also used for ppc64. */ + +static void +ppc_emit_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("1:b 1b"); + + if (offset_p) + *offset_p = 0; + if (size_p) + *size_p = 24; +} + +/* Goto if stack[--sp] == TOP */ + +static void +ppc_emit_eq_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "xor 4, 6, 4 \n" + "xor 3, 5, 3 \n" + "or. 3, 3, 4 \n" + "lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30) \n" + "1:beq 0, 1b \n"); + + if (offset_p) + *offset_p = 28; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] != TOP */ + +static void +ppc_emit_ne_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "xor 4, 6, 4 \n" + "xor 3, 5, 3 \n" + "or. 3, 3, 4 \n" + "lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30) \n" + "1:bne 0, 1b \n"); + + if (offset_p) + *offset_p = 28; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] < TOP */ + +static void +ppc_emit_lt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "cmplw 6, 6, 4 \n" + "cmpw 7, 5, 3 \n" + /* CR6 bit 0 = low less and high equal */ + "crand 6*4+0, 6*4+0, 7*4+2\n" + /* CR7 bit 0 = (low less and high equal) or high less */ + "cror 7*4+0, 7*4+0, 6*4+0\n" + "lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30)\n" + "1:blt 7, 1b \n"); + + if (offset_p) + *offset_p = 32; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] <= TOP */ + +static void +ppc_emit_le_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "cmplw 6, 6, 4 \n" + "cmpw 7, 5, 3 \n" + /* CR6 bit 0 = low less/equal and high equal */ + "crandc 6*4+0, 7*4+2, 6*4+1\n" + /* CR7 bit 0 = (low less/eq and high equal) or high less */ + "cror 7*4+0, 7*4+0, 6*4+0\n" + "lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30)\n" + "1:blt 7, 1b \n"); + + if (offset_p) + *offset_p = 32; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] > TOP */ + +static void +ppc_emit_gt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "cmplw 6, 6, 4 \n" + "cmpw 7, 5, 3 \n" + /* CR6 bit 0 = low greater and high equal */ + "crand 6*4+0, 6*4+1, 7*4+2\n" + /* CR7 bit 0 = (low greater and high equal) or high greater */ + "cror 7*4+0, 7*4+1, 6*4+0\n" + "lwzu " TOP_FIRST ", 8(30) \n" + "lwz " TOP_SECOND ", 4(30)\n" + "1:blt 7, 1b \n"); + + if (offset_p) + *offset_p = 32; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] >= TOP */ + +static void +ppc_emit_ge_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("lwzu " TMP_FIRST ", 8(30) \n" + "lwz " TMP_SECOND ", 4(30) \n" + "cmplw 6, 6, 4 \n" + "cmpw 7, 5, 3 \n" + /* CR6 bit 0 = low ge and high equal */ + "crandc 6*4+0, 7*4+2, 6*4+0\n" + /* CR7 bit 0 = (low ge and high equal) or high greater */ + "cror 7*4+0, 7*4+1, 6*4+0\n" + "lwzu " TOP_FIRST ", 8(30)\n" + "lwz " TOP_SECOND ", 4(30)\n" + "1:blt 7, 1b \n"); + + if (offset_p) + *offset_p = 32; + if (size_p) + *size_p = 14; +} + +/* Relocate previous emitted branch instruction. FROM is the address + of the branch instruction, TO is the goto target address, and SIZE + if the value we set by *SIZE_P before. Currently, it is either + 24 or 14 of branch and conditional-branch instruction. + Also used for ppc64. */ + +static void +ppc_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) +{ + long rel = to - from; + uint32_t insn; + int opcd; + + read_inferior_memory (from, (unsigned char *) &insn, 4); + opcd = (insn >> 26) & 0x3f; + + switch (size) + { + case 14: + if (opcd != 16 + || (rel >= (1 << 15) || rel < -(1 << 15))) + emit_error = 1; + insn = (insn & ~0xfffc) | (rel & 0xfffc); + break; + case 24: + if (opcd != 18 + || (rel >= (1 << 25) || rel < -(1 << 25))) + emit_error = 1; + insn = (insn & ~0x3fffffc) | (rel & 0x3fffffc); + break; + default: + emit_error = 1; + } + + if (!emit_error) + target_write_memory (from, (unsigned char *) &insn, 4); +} + +/* Table of emit ops for 32-bit. */ + +static struct emit_ops ppc_emit_ops_impl = +{ + ppc_emit_prologue, + ppc_emit_epilogue, + ppc_emit_add, + ppc_emit_sub, + ppc_emit_mul, + ppc_emit_lsh, + ppc_emit_rsh_signed, + ppc_emit_rsh_unsigned, + ppc_emit_ext, + ppc_emit_log_not, + ppc_emit_bit_and, + ppc_emit_bit_or, + ppc_emit_bit_xor, + ppc_emit_bit_not, + ppc_emit_equal, + ppc_emit_less_signed, + ppc_emit_less_unsigned, + ppc_emit_ref, + ppc_emit_if_goto, + ppc_emit_goto, + ppc_write_goto_address, + ppc_emit_const, + ppc_emit_call, + ppc_emit_reg, + ppc_emit_pop, + ppc_emit_stack_flush, + ppc_emit_zero_ext, + ppc_emit_swap, + ppc_emit_stack_adjust, + ppc_emit_int_call_1, + ppc_emit_void_call_2, + ppc_emit_eq_goto, + ppc_emit_ne_goto, + ppc_emit_lt_goto, + ppc_emit_le_goto, + ppc_emit_gt_goto, + ppc_emit_ge_goto +}; + +#ifdef __powerpc64__ + +/* + + Bytecode execution stack frame - 64-bit + + | LR save area (SP + 16) + | CR save area (SP + 8) + SP' -> +- Back chain (SP + 0) + | Save r31 for access saved arguments + | Save r30 for bytecode stack pointer + | Save r4 for incoming argument *value + | Save r3 for incoming argument regs + r30 -> +- Bytecode execution stack + | + | 64-byte (8 doublewords) at initial. + | Expand stack as needed. + | + +- + | Some padding for minimum stack frame. + | 112 for ELFv1. + SP +- Back-chain (SP') + + initial frame size + = 112 + (4 * 8) + 64 + = 208 + + r30 is the stack-pointer for bytecode machine. + It should point to next-empty, so we can use LDU for pop. + r3 is used for cache of TOP value. + It was the first argument, pointer to regs. + r4 is the second argument, pointer to the result. + We should set *result = TOP after leaving this function. + + Note: + * To restore stack at epilogue + => sp = r31 + * To check stack is big enough for bytecode execution. + => r30 - 8 > SP + 112 + * To return execution result. + => 0(r4) = TOP + + */ + +/* Emit prologue in inferior memory. See above comments. */ + +static void +ppc64v1_emit_prologue (void) +{ + /* On ELFv1, function pointers really point to function descriptor, + so emit one here. We don't care about contents of words 1 and 2, + so let them just overlap out code. */ + uint64_t opd = current_insn_ptr + 8; + uint32_t buf[2]; + + /* Mind the strict aliasing rules. */ + memcpy (buf, &opd, sizeof buf); + emit_insns(buf, 2); + EMIT_ASM (/* Save return address. */ + "mflr 0 \n" + "std 0, 16(1) \n" + /* Save r30 and incoming arguments. */ + "std 31, -8(1) \n" + "std 30, -16(1) \n" + "std 4, -24(1) \n" + "std 3, -32(1) \n" + /* Point r31 to current r1 for access arguments. */ + "mr 31, 1 \n" + /* Adjust SP. 208 is the initial frame size. */ + "stdu 1, -208(1) \n" + /* Set r30 to pointing stack-top. */ + "addi 30, 1, 168 \n" + /* Initial r3/TOP to 0. */ + "li 3, 0 \n"); +} + +/* Emit prologue in inferior memory. See above comments. */ + +static void +ppc64v2_emit_prologue (void) +{ + EMIT_ASM (/* Save return address. */ + "mflr 0 \n" + "std 0, 16(1) \n" + /* Save r30 and incoming arguments. */ + "std 31, -8(1) \n" + "std 30, -16(1) \n" + "std 4, -24(1) \n" + "std 3, -32(1) \n" + /* Point r31 to current r1 for access arguments. */ + "mr 31, 1 \n" + /* Adjust SP. 208 is the initial frame size. */ + "stdu 1, -208(1) \n" + /* Set r30 to pointing stack-top. */ + "addi 30, 1, 168 \n" + /* Initial r3/TOP to 0. */ + "li 3, 0 \n"); +} + +/* Emit epilogue in inferior memory. See above comments. */ + +static void +ppc64_emit_epilogue (void) +{ + EMIT_ASM (/* Restore SP. */ + "ld 1, 0(1) \n" + /* *result = TOP */ + "ld 4, -24(1) \n" + "std 3, 0(4) \n" + /* Restore registers. */ + "ld 31, -8(1) \n" + "ld 30, -16(1) \n" + /* Restore LR. */ + "ld 0, 16(1) \n" + /* Return 0 for no-error. */ + "li 3, 0 \n" + "mtlr 0 \n" + "blr \n"); +} + +/* TOP = stack[--sp] + TOP */ + +static void +ppc64_emit_add (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "add 3, 4, 3 \n"); +} + +/* TOP = stack[--sp] - TOP */ + +static void +ppc64_emit_sub (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "sub 3, 4, 3 \n"); +} + +/* TOP = stack[--sp] * TOP */ + +static void +ppc64_emit_mul (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "mulld 3, 4, 3 \n"); +} + +/* TOP = stack[--sp] << TOP */ + +static void +ppc64_emit_lsh (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "sld 3, 4, 3 \n"); +} + +/* Top = stack[--sp] >> TOP + (Arithmetic shift right) */ + +static void +ppc64_emit_rsh_signed (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "srad 3, 4, 3 \n"); +} + +/* Top = stack[--sp] >> TOP + (Logical shift right) */ + +static void +ppc64_emit_rsh_unsigned (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "srd 3, 4, 3 \n"); +} + +/* Emit code for signed-extension specified by ARG. */ + +static void +ppc64_emit_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM ("extsb 3, 3"); + break; + case 16: + EMIT_ASM ("extsh 3, 3"); + break; + case 32: + EMIT_ASM ("extsw 3, 3"); + break; + default: + emit_error = 1; + } +} + +/* Emit code for zero-extension specified by ARG. */ + +static void +ppc64_emit_zero_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM ("rldicl 3,3,0,56"); + break; + case 16: + EMIT_ASM ("rldicl 3,3,0,48"); + break; + case 32: + EMIT_ASM ("rldicl 3,3,0,32"); + break; + default: + emit_error = 1; + } +} + +/* TOP = !TOP + i.e., TOP = (TOP == 0) ? 1 : 0; */ + +static void +ppc64_emit_log_not (void) +{ + EMIT_ASM ("cntlzd 3, 3 \n" + "srdi 3, 3, 6 \n"); +} + +/* TOP = stack[--sp] & TOP */ + +static void +ppc64_emit_bit_and (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "and 3, 4, 3 \n"); +} + +/* TOP = stack[--sp] | TOP */ + +static void +ppc64_emit_bit_or (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "or 3, 4, 3 \n"); +} + +/* TOP = stack[--sp] ^ TOP */ + +static void +ppc64_emit_bit_xor (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "xor 3, 4, 3 \n"); +} + +/* TOP = ~TOP + i.e., TOP = ~(TOP | TOP) */ + +static void +ppc64_emit_bit_not (void) +{ + EMIT_ASM ("nor 3, 3, 3 \n"); +} + +/* TOP = stack[--sp] == TOP */ + +static void +ppc64_emit_equal (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "xor 3, 3, 4 \n" + "cntlzd 3, 3 \n" + "srdi 3, 3, 6 \n"); +} + +/* TOP = stack[--sp] < TOP + (Signed comparison) */ + +static void +ppc64_emit_less_signed (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "mfcr 3 \n" + "rlwinm 3, 3, 29, 31, 31 \n"); +} + +/* TOP = stack[--sp] < TOP + (Unsigned comparison) */ + +static void +ppc64_emit_less_unsigned (void) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpld 7, 4, 3 \n" + "mfcr 3 \n" + "rlwinm 3, 3, 29, 31, 31 \n"); +} + +/* Access the memory address in TOP in size of SIZE. + Zero-extend the read value. */ + +static void +ppc64_emit_ref (int size) +{ + switch (size) + { + case 1: + EMIT_ASM ("lbz 3, 0(3)"); + break; + case 2: + EMIT_ASM ("lhz 3, 0(3)"); + break; + case 4: + EMIT_ASM ("lwz 3, 0(3)"); + break; + case 8: + EMIT_ASM ("ld 3, 0(3)"); + break; + } +} + +/* TOP = NUM */ + +static void +ppc64_emit_const (LONGEST num) +{ + uint32_t buf[5]; + uint32_t *p = buf; + + p += gen_limm (p, 3, num, 1); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Set TOP to the value of register REG by calling get_raw_reg function + with two argument, collected buffer and register number. */ + +static void +ppc64v1_emit_reg (int reg) +{ + uint32_t buf[15]; + uint32_t *p = buf; + + /* fctx->regs is passed in r3 and then saved in 176(1). */ + p += GEN_LD (p, 3, 31, -32); + p += GEN_LI (p, 4, reg); + p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ + p += gen_call (p, get_raw_reg_func_addr (), 1, 1); + p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Likewise, for ELFv2. */ + +static void +ppc64v2_emit_reg (int reg) +{ + uint32_t buf[12]; + uint32_t *p = buf; + + /* fctx->regs is passed in r3 and then saved in 176(1). */ + p += GEN_LD (p, 3, 31, -32); + p += GEN_LI (p, 4, reg); + p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ + p += gen_call (p, get_raw_reg_func_addr (), 1, 0); + p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* TOP = stack[--sp] */ + +static void +ppc64_emit_pop (void) +{ + EMIT_ASM ("ldu 3, 8(30)"); +} + +/* stack[sp++] = TOP + + Because we may use up bytecode stack, expand 8 doublewords more + if needed. */ + +static void +ppc64_emit_stack_flush (void) +{ + /* Make sure bytecode stack is big enough before push. + Otherwise, expand 64-byte more. */ + + EMIT_ASM (" std 3, 0(30) \n" + " addi 4, 30, -(112 + 8) \n" + " cmpd 7, 4, 1 \n" + " bgt 7, 1f \n" + " stdu 31, -64(1) \n" + "1:addi 30, 30, -8 \n"); +} + +/* Swap TOP and stack[sp-1] */ + +static void +ppc64_emit_swap (void) +{ + EMIT_ASM ("ld 4, 8(30) \n" + "std 3, 8(30) \n" + "mr 3, 4 \n"); +} + +/* Call function FN - ELFv1. */ + +static void +ppc64v1_emit_call (CORE_ADDR fn) +{ + uint32_t buf[13]; + uint32_t *p = buf; + + p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ + p += gen_call (p, fn, 1, 1); + p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Call function FN - ELFv2. */ + +static void +ppc64v2_emit_call (CORE_ADDR fn) +{ + uint32_t buf[10]; + uint32_t *p = buf; + + p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ + p += gen_call (p, fn, 1, 0); + p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* FN's prototype is `LONGEST(*fn)(int)'. + TOP = fn (arg1) + */ + +static void +ppc64v1_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[13]; + uint32_t *p = buf; + + /* Setup argument. arg1 is a 16-bit value. */ + p += gen_limm (p, 3, arg1, 1); + p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ + p += gen_call (p, fn, 1, 1); + p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Likewise for ELFv2. */ + +static void +ppc64v2_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[10]; + uint32_t *p = buf; + + /* Setup argument. arg1 is a 16-bit value. */ + p += gen_limm (p, 3, arg1, 1); + p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ + p += gen_call (p, fn, 1, 0); + p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* FN's prototype is `void(*fn)(int,LONGEST)'. + fn (arg1, TOP) + + TOP should be preserved/restored before/after the call. */ + +static void +ppc64v1_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[17]; + uint32_t *p = buf; + + /* Save TOP. 0(30) is next-empty. */ + p += GEN_STD (p, 3, 30, 0); + + /* Setup argument. arg1 is a 16-bit value. */ + p += GEN_MR (p, 4, 3); /* mr r4, r3 */ + p += gen_limm (p, 3, arg1, 1); + p += GEN_STD (p, 2, 1, 40); /* Save TOC. */ + p += gen_call (p, fn, 1, 1); + p += GEN_LD (p, 2, 1, 40); /* Restore TOC. */ + + /* Restore TOP */ + p += GEN_LD (p, 3, 30, 0); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* Likewise for ELFv2. */ + +static void +ppc64v2_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + uint32_t buf[14]; + uint32_t *p = buf; + + /* Save TOP. 0(30) is next-empty. */ + p += GEN_STD (p, 3, 30, 0); + + /* Setup argument. arg1 is a 16-bit value. */ + p += GEN_MR (p, 4, 3); /* mr r4, r3 */ + p += gen_limm (p, 3, arg1, 1); + p += GEN_STD (p, 2, 1, 24); /* Save TOC. */ + p += gen_call (p, fn, 1, 0); + p += GEN_LD (p, 2, 1, 24); /* Restore TOC. */ + + /* Restore TOP */ + p += GEN_LD (p, 3, 30, 0); + + emit_insns (buf, p - buf); + gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf))); +} + +/* If TOP is true, goto somewhere. Otherwise, just fall-through. */ + +static void +ppc64_emit_if_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("cmpdi 7, 3, 0 \n" + "ldu 3, 8(30) \n" + "1:bne 7, 1b \n"); + + if (offset_p) + *offset_p = 8; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] == TOP */ + +static void +ppc64_emit_eq_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "ldu 3, 8(30) \n" + "1:beq 7, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] != TOP */ + +static void +ppc64_emit_ne_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "ldu 3, 8(30) \n" + "1:bne 7, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] < TOP */ + +static void +ppc64_emit_lt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "ldu 3, 8(30) \n" + "1:blt 7, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] <= TOP */ + +static void +ppc64_emit_le_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "ldu 3, 8(30) \n" + "1:ble 7, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] > TOP */ + +static void +ppc64_emit_gt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "ldu 3, 8(30) \n" + "1:bgt 7, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Goto if stack[--sp] >= TOP */ + +static void +ppc64_emit_ge_goto (int *offset_p, int *size_p) +{ + EMIT_ASM ("ldu 4, 8(30) \n" + "cmpd 7, 4, 3 \n" + "ldu 3, 8(30) \n" + "1:bge 7, 1b \n"); + + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 14; +} + +/* Table of emit ops for 64-bit ELFv1. */ + +static struct emit_ops ppc64v1_emit_ops_impl = +{ + ppc64v1_emit_prologue, + ppc64_emit_epilogue, + ppc64_emit_add, + ppc64_emit_sub, + ppc64_emit_mul, + ppc64_emit_lsh, + ppc64_emit_rsh_signed, + ppc64_emit_rsh_unsigned, + ppc64_emit_ext, + ppc64_emit_log_not, + ppc64_emit_bit_and, + ppc64_emit_bit_or, + ppc64_emit_bit_xor, + ppc64_emit_bit_not, + ppc64_emit_equal, + ppc64_emit_less_signed, + ppc64_emit_less_unsigned, + ppc64_emit_ref, + ppc64_emit_if_goto, + ppc_emit_goto, + ppc_write_goto_address, + ppc64_emit_const, + ppc64v1_emit_call, + ppc64v1_emit_reg, + ppc64_emit_pop, + ppc64_emit_stack_flush, + ppc64_emit_zero_ext, + ppc64_emit_swap, + ppc_emit_stack_adjust, + ppc64v1_emit_int_call_1, + ppc64v1_emit_void_call_2, + ppc64_emit_eq_goto, + ppc64_emit_ne_goto, + ppc64_emit_lt_goto, + ppc64_emit_le_goto, + ppc64_emit_gt_goto, + ppc64_emit_ge_goto +}; + +/* Table of emit ops for 64-bit ELFv2. */ + +static struct emit_ops ppc64v2_emit_ops_impl = +{ + ppc64v2_emit_prologue, + ppc64_emit_epilogue, + ppc64_emit_add, + ppc64_emit_sub, + ppc64_emit_mul, + ppc64_emit_lsh, + ppc64_emit_rsh_signed, + ppc64_emit_rsh_unsigned, + ppc64_emit_ext, + ppc64_emit_log_not, + ppc64_emit_bit_and, + ppc64_emit_bit_or, + ppc64_emit_bit_xor, + ppc64_emit_bit_not, + ppc64_emit_equal, + ppc64_emit_less_signed, + ppc64_emit_less_unsigned, + ppc64_emit_ref, + ppc64_emit_if_goto, + ppc_emit_goto, + ppc_write_goto_address, + ppc64_emit_const, + ppc64v2_emit_call, + ppc64v2_emit_reg, + ppc64_emit_pop, + ppc64_emit_stack_flush, + ppc64_emit_zero_ext, + ppc64_emit_swap, + ppc_emit_stack_adjust, + ppc64v2_emit_int_call_1, + ppc64v2_emit_void_call_2, + ppc64_emit_eq_goto, + ppc64_emit_ne_goto, + ppc64_emit_lt_goto, + ppc64_emit_le_goto, + ppc64_emit_gt_goto, + ppc64_emit_ge_goto +}; + +#endif + +/* Implementation of linux_target_ops method "emit_ops". */ + +static struct emit_ops * +ppc_emit_ops (void) +{ +#ifdef __powerpc64__ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + + if (register_size (regcache->tdesc, 0) == 8) + { + if (is_elfv2_inferior ()) + return &ppc64v2_emit_ops_impl; + else + return &ppc64v1_emit_ops_impl; + } +#endif + return &ppc_emit_ops_impl; +} + +/* Implementation of linux_target_ops method "get_ipa_tdesc_idx". */ + +static int +ppc_get_ipa_tdesc_idx (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + const struct target_desc *tdesc = regcache->tdesc; + +#ifdef __powerpc64__ + if (tdesc == tdesc_powerpc_64l) + return PPC_TDESC_BASE; + if (tdesc == tdesc_powerpc_altivec64l) + return PPC_TDESC_ALTIVEC; + if (tdesc == tdesc_powerpc_vsx64l) + return PPC_TDESC_VSX; + if (tdesc == tdesc_powerpc_isa205_64l) + return PPC_TDESC_ISA205; + if (tdesc == tdesc_powerpc_isa205_altivec64l) + return PPC_TDESC_ISA205_ALTIVEC; + if (tdesc == tdesc_powerpc_isa205_vsx64l) + return PPC_TDESC_ISA205_VSX; + if (tdesc == tdesc_powerpc_isa205_ppr_dscr_vsx64l) + return PPC_TDESC_ISA205_PPR_DSCR_VSX; + if (tdesc == tdesc_powerpc_isa207_vsx64l) + return PPC_TDESC_ISA207_VSX; + if (tdesc == tdesc_powerpc_isa207_htm_vsx64l) + return PPC_TDESC_ISA207_HTM_VSX; +#endif + + if (tdesc == tdesc_powerpc_32l) + return PPC_TDESC_BASE; + if (tdesc == tdesc_powerpc_altivec32l) + return PPC_TDESC_ALTIVEC; + if (tdesc == tdesc_powerpc_vsx32l) + return PPC_TDESC_VSX; + if (tdesc == tdesc_powerpc_isa205_32l) + return PPC_TDESC_ISA205; + if (tdesc == tdesc_powerpc_isa205_altivec32l) + return PPC_TDESC_ISA205_ALTIVEC; + if (tdesc == tdesc_powerpc_isa205_vsx32l) + return PPC_TDESC_ISA205_VSX; + if (tdesc == tdesc_powerpc_isa205_ppr_dscr_vsx32l) + return PPC_TDESC_ISA205_PPR_DSCR_VSX; + if (tdesc == tdesc_powerpc_isa207_vsx32l) + return PPC_TDESC_ISA207_VSX; + if (tdesc == tdesc_powerpc_isa207_htm_vsx32l) + return PPC_TDESC_ISA207_HTM_VSX; + if (tdesc == tdesc_powerpc_e500l) + return PPC_TDESC_E500; + + return 0; +} + +struct linux_target_ops the_low_target = { + ppc_arch_setup, + ppc_regs_info, + ppc_cannot_fetch_register, + ppc_cannot_store_register, + NULL, /* fetch_register */ + ppc_get_pc, + ppc_set_pc, + NULL, /* breakpoint_kind_from_pc */ + ppc_sw_breakpoint_from_kind, + NULL, + 0, + ppc_breakpoint_at, + ppc_supports_z_point_type, + ppc_insert_point, + ppc_remove_point, + NULL, + NULL, + ppc_collect_ptrace_register, + ppc_supply_ptrace_register, + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + ppc_supports_tracepoints, + ppc_get_thread_area, + ppc_install_fast_tracepoint_jump_pad, + ppc_emit_ops, + ppc_get_min_fast_tracepoint_insn_len, + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + ppc_supports_hardware_single_step, + NULL, /* get_syscall_trapinfo */ + ppc_get_ipa_tdesc_idx, +}; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + + init_registers_powerpc_32l (); + init_registers_powerpc_altivec32l (); + init_registers_powerpc_vsx32l (); + init_registers_powerpc_isa205_32l (); + init_registers_powerpc_isa205_altivec32l (); + init_registers_powerpc_isa205_vsx32l (); + init_registers_powerpc_isa205_ppr_dscr_vsx32l (); + init_registers_powerpc_isa207_vsx32l (); + init_registers_powerpc_isa207_htm_vsx32l (); + init_registers_powerpc_e500l (); +#if __powerpc64__ + init_registers_powerpc_64l (); + init_registers_powerpc_altivec64l (); + init_registers_powerpc_vsx64l (); + init_registers_powerpc_isa205_64l (); + init_registers_powerpc_isa205_altivec64l (); + init_registers_powerpc_isa205_vsx64l (); + init_registers_powerpc_isa205_ppr_dscr_vsx64l (); + init_registers_powerpc_isa207_vsx64l (); + init_registers_powerpc_isa207_htm_vsx64l (); +#endif + + initialize_regsets_info (&ppc_regsets_info); +} diff --git a/gdbserver/linux-ppc-tdesc-init.h b/gdbserver/linux-ppc-tdesc-init.h new file mode 100644 index 00000000000..3afd78baee3 --- /dev/null +++ b/gdbserver/linux-ppc-tdesc-init.h @@ -0,0 +1,106 @@ +/* Low level support for ppc, shared between gdbserver and IPA. + + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_PPC_TDESC_INIT_H +#define GDBSERVER_LINUX_PPC_TDESC_INIT_H + +/* Note: since IPA obviously knows what ABI it's running on (32 vs 64), + it's sufficient to pass only the register set here. This, together with + the ABI known at IPA compile time, maps to a tdesc. */ + +enum ppc_linux_tdesc { + PPC_TDESC_BASE, + PPC_TDESC_ALTIVEC, + PPC_TDESC_CELL, /* No longer used, but kept to avoid ABI changes. */ + PPC_TDESC_VSX, + PPC_TDESC_ISA205, + PPC_TDESC_ISA205_ALTIVEC, + PPC_TDESC_ISA205_VSX, + PPC_TDESC_ISA205_PPR_DSCR_VSX, + PPC_TDESC_ISA207_VSX, + PPC_TDESC_ISA207_HTM_VSX, + PPC_TDESC_E500, +}; + +#if !defined __powerpc64__ || !defined IN_PROCESS_AGENT + +/* Defined in auto-generated file powerpc-32l.c. */ +void init_registers_powerpc_32l (void); + +/* Defined in auto-generated file powerpc-altivec32l.c. */ +void init_registers_powerpc_altivec32l (void); + +/* Defined in auto-generated file powerpc-vsx32l.c. */ +void init_registers_powerpc_vsx32l (void); + +/* Defined in auto-generated file powerpc-isa205-32l.c. */ +void init_registers_powerpc_isa205_32l (void); + +/* Defined in auto-generated file powerpc-isa205-altivec32l.c. */ +void init_registers_powerpc_isa205_altivec32l (void); + +/* Defined in auto-generated file powerpc-isa205-vsx32l.c. */ +void init_registers_powerpc_isa205_vsx32l (void); + +/* Defined in auto-generated file powerpc-isa205-ppr-dscr-vsx32l.c. */ +void init_registers_powerpc_isa205_ppr_dscr_vsx32l (void); + +/* Defined in auto-generated file powerpc-isa207-vsx32l.c. */ +void init_registers_powerpc_isa207_vsx32l (void); + +/* Defined in auto-generated file powerpc-isa207-htm-vsx32l.c. */ +void init_registers_powerpc_isa207_htm_vsx32l (void); + +/* Defined in auto-generated file powerpc-e500l.c. */ +void init_registers_powerpc_e500l (void); + +#endif + +#if defined __powerpc64__ + +/* Defined in auto-generated file powerpc-64l.c. */ +void init_registers_powerpc_64l (void); + +/* Defined in auto-generated file powerpc-altivec64l.c. */ +void init_registers_powerpc_altivec64l (void); + +/* Defined in auto-generated file powerpc-vsx64l.c. */ +void init_registers_powerpc_vsx64l (void); + +/* Defined in auto-generated file powerpc-isa205-64l.c. */ +void init_registers_powerpc_isa205_64l (void); + +/* Defined in auto-generated file powerpc-isa205-altivec64l.c. */ +void init_registers_powerpc_isa205_altivec64l (void); + +/* Defined in auto-generated file powerpc-isa205-vsx64l.c. */ +void init_registers_powerpc_isa205_vsx64l (void); + +/* Defined in auto-generated file powerpc-isa205-ppr-dscr-vsx64l.c. */ +void init_registers_powerpc_isa205_ppr_dscr_vsx64l (void); + +/* Defined in auto-generated file powerpc-isa207-vsx64l.c. */ +void init_registers_powerpc_isa207_vsx64l (void); + +/* Defined in auto-generated file powerpc-isa207-htm-vsx64l.c. */ +void init_registers_powerpc_isa207_htm_vsx64l (void); + +#endif + +#endif /* GDBSERVER_LINUX_PPC_TDESC_INIT_H */ diff --git a/gdbserver/linux-s390-ipa.c b/gdbserver/linux-s390-ipa.c new file mode 100644 index 00000000000..5b90302b1eb --- /dev/null +++ b/gdbserver/linux-s390-ipa.c @@ -0,0 +1,463 @@ +/* GNU/Linux S/390 specific low level interface, for the in-process + agent library for GDB. + + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include +#include "tracepoint.h" +#include "linux-s390-tdesc.h" +#include +#ifdef HAVE_GETAUXVAL +#include +#endif + +#define FT_FPR(x) (0x000 + (x) * 0x10) +#define FT_VR(x) (0x000 + (x) * 0x10) +#define FT_VR_L(x) (0x008 + (x) * 0x10) +#define FT_GPR(x) (0x200 + (x) * 8) +#define FT_GPR_U(x) (0x200 + (x) * 8) +#define FT_GPR_L(x) (0x204 + (x) * 8) +#define FT_GPR(x) (0x200 + (x) * 8) +#define FT_ACR(x) (0x280 + (x) * 4) +#define FT_PSWM 0x2c0 +#define FT_PSWM_U 0x2c0 +#define FT_PSWA 0x2c8 +#define FT_PSWA_L 0x2cc +#define FT_FPC 0x2d0 + +/* Mappings between registers collected by the jump pad and GDB's register + array layout used by regcache. + + See linux-s390-low.c (s390_install_fast_tracepoint_jump_pad) for more + details. */ + +#ifndef __s390x__ + +/* Used for s390-linux32, s390-linux32v1, s390-linux32v2. */ + +static const int s390_linux32_ft_collect_regmap[] = { + /* 32-bit PSWA and PSWM. */ + FT_PSWM_U, FT_PSWA_L, + /* 32-bit GPRs (mapped to lower halves of 64-bit slots). */ + FT_GPR_L (0), FT_GPR_L (1), FT_GPR_L (2), FT_GPR_L (3), + FT_GPR_L (4), FT_GPR_L (5), FT_GPR_L (6), FT_GPR_L (7), + FT_GPR_L (8), FT_GPR_L (9), FT_GPR_L (10), FT_GPR_L (11), + FT_GPR_L (12), FT_GPR_L (13), FT_GPR_L (14), FT_GPR_L (15), + /* ACRs */ + FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), + FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), + FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), + FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), + /* FPRs (mapped to upper halves of 128-bit VR slots). */ + FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), + FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), + FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), + FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), + /* orig_r2, last_break, system_call */ + -1, -1, -1, +}; + +/* Used for s390-linux64, s390-linux64v1, s390-linux64v2, s390-vx-linux64. */ + +static const int s390_linux64_ft_collect_regmap[] = { + /* 32-bit PSWA and PSWM. */ + FT_PSWM_U, FT_PSWA_L, + /* 32-bit halves of 64-bit GPRs. */ + FT_GPR_U (0), FT_GPR_L (0), + FT_GPR_U (1), FT_GPR_L (1), + FT_GPR_U (2), FT_GPR_L (2), + FT_GPR_U (3), FT_GPR_L (3), + FT_GPR_U (4), FT_GPR_L (4), + FT_GPR_U (5), FT_GPR_L (5), + FT_GPR_U (6), FT_GPR_L (6), + FT_GPR_U (7), FT_GPR_L (7), + FT_GPR_U (8), FT_GPR_L (8), + FT_GPR_U (9), FT_GPR_L (9), + FT_GPR_U (10), FT_GPR_L (10), + FT_GPR_U (11), FT_GPR_L (11), + FT_GPR_U (12), FT_GPR_L (12), + FT_GPR_U (13), FT_GPR_L (13), + FT_GPR_U (14), FT_GPR_L (14), + FT_GPR_U (15), FT_GPR_L (15), + /* ACRs */ + FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), + FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), + FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), + FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), + /* FPRs (mapped to upper halves of 128-bit VR slots). */ + FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), + FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), + FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), + FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), + /* orig_r2, last_break, system_call */ + -1, -1, -1, + /* Lower halves of 128-bit VRs. */ + FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), + FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), + FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), + FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), + /* And the next 16 VRs. */ + FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), + FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), + FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), + FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), +}; + +/* Used for s390-te-linux64, s390-tevx-linux64, and s390-gs-linux64. */ + +static const int s390_te_linux64_ft_collect_regmap[] = { + /* 32-bit PSWA and PSWM. */ + FT_PSWM_U, FT_PSWA_L, + /* 32-bit halves of 64-bit GPRs. */ + FT_GPR_U (0), FT_GPR_L (0), + FT_GPR_U (1), FT_GPR_L (1), + FT_GPR_U (2), FT_GPR_L (2), + FT_GPR_U (3), FT_GPR_L (3), + FT_GPR_U (4), FT_GPR_L (4), + FT_GPR_U (5), FT_GPR_L (5), + FT_GPR_U (6), FT_GPR_L (6), + FT_GPR_U (7), FT_GPR_L (7), + FT_GPR_U (8), FT_GPR_L (8), + FT_GPR_U (9), FT_GPR_L (9), + FT_GPR_U (10), FT_GPR_L (10), + FT_GPR_U (11), FT_GPR_L (11), + FT_GPR_U (12), FT_GPR_L (12), + FT_GPR_U (13), FT_GPR_L (13), + FT_GPR_U (14), FT_GPR_L (14), + FT_GPR_U (15), FT_GPR_L (15), + /* ACRs */ + FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), + FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), + FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), + FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), + /* FPRs (mapped to upper halves of 128-bit VR slots). */ + FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), + FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), + FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), + FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), + /* orig_r2, last_break, system_call */ + -1, -1, -1, + /* TDB */ + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + /* Lower halves of 128-bit VRs. */ + FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), + FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), + FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), + FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), + /* And the next 16 VRs. */ + FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), + FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), + FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), + FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), +}; + +#else /* __s390x__ */ + +/* Used for s390x-linux64, s390x-linux64v1, s390x-linux64v2, s390x-vx-linux64. */ + +static const int s390x_ft_collect_regmap[] = { + /* 64-bit PSWA and PSWM. */ + FT_PSWM, FT_PSWA, + /* 64-bit GPRs. */ + FT_GPR (0), FT_GPR (1), FT_GPR (2), FT_GPR (3), + FT_GPR (4), FT_GPR (5), FT_GPR (6), FT_GPR (7), + FT_GPR (8), FT_GPR (9), FT_GPR (10), FT_GPR (11), + FT_GPR (12), FT_GPR (13), FT_GPR (14), FT_GPR (15), + /* ACRs */ + FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), + FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), + FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), + FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), + /* FPRs (mapped to upper halves of 128-bit VR slots). */ + FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), + FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), + FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), + FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), + /* orig_r2, last_break, system_call */ + -1, -1, -1, + /* Lower halves of 128-bit VRs. */ + FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), + FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), + FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), + FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), + /* And the next 16 VRs. */ + FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), + FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), + FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), + FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), +}; + +/* Used for s390x-te-linux64, s390x-tevx-linux64, and + s390x-gs-linux64. */ + +static const int s390x_te_ft_collect_regmap[] = { + /* 64-bit PSWA and PSWM. */ + FT_PSWM, FT_PSWA, + /* 64-bit GPRs. */ + FT_GPR (0), FT_GPR (1), FT_GPR (2), FT_GPR (3), + FT_GPR (4), FT_GPR (5), FT_GPR (6), FT_GPR (7), + FT_GPR (8), FT_GPR (9), FT_GPR (10), FT_GPR (11), + FT_GPR (12), FT_GPR (13), FT_GPR (14), FT_GPR (15), + /* ACRs */ + FT_ACR (0), FT_ACR (1), FT_ACR (2), FT_ACR (3), + FT_ACR (4), FT_ACR (5), FT_ACR (6), FT_ACR (7), + FT_ACR (8), FT_ACR (9), FT_ACR (10), FT_ACR (11), + FT_ACR (12), FT_ACR (13), FT_ACR (14), FT_ACR (15), + /* FPRs (mapped to upper halves of 128-bit VR slots). */ + FT_FPR (0), FT_FPR (1), FT_FPR (2), FT_FPR (3), + FT_FPR (4), FT_FPR (5), FT_FPR (6), FT_FPR (7), + FT_FPR (8), FT_FPR (9), FT_FPR (10), FT_FPR (11), + FT_FPR (12), FT_FPR (13), FT_FPR (14), FT_FPR (15), + /* orig_r2, last_break, system_call */ + -1, -1, -1, + /* TDB */ + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + /* Lower halves of 128-bit VRs. */ + FT_VR_L (0), FT_VR_L (1), FT_VR_L (2), FT_VR_L (3), + FT_VR_L (4), FT_VR_L (5), FT_VR_L (6), FT_VR_L (7), + FT_VR_L (8), FT_VR_L (9), FT_VR_L (10), FT_VR_L (11), + FT_VR_L (12), FT_VR_L (13), FT_VR_L (14), FT_VR_L (15), + /* And the next 16 VRs. */ + FT_VR (16), FT_VR (17), FT_VR (18), FT_VR (19), + FT_VR (20), FT_VR (21), FT_VR (22), FT_VR (23), + FT_VR (24), FT_VR (25), FT_VR (26), FT_VR (27), + FT_VR (28), FT_VR (29), FT_VR (30), FT_VR (31), +}; + +#endif + +/* Initialized by get_ipa_tdesc according to the tdesc in use. */ + +static const int *s390_regmap; +static int s390_regnum; + +/* Fill in REGCACHE with registers saved by the jump pad in BUF. */ + +void +supply_fast_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf) +{ + int i; + for (i = 0; i < s390_regnum; i++) + if (s390_regmap[i] != -1) + supply_register (regcache, i, ((char *) buf) + s390_regmap[i]); +} + +ULONGEST +get_raw_reg (const unsigned char *raw_regs, int regnum) +{ + int offset; + if (regnum >= s390_regnum) + return 0; + offset = s390_regmap[regnum]; + if (offset == -1) + return 0; + + /* The regnums are variable, better to figure out size by FT offset. */ + + /* 64-bit ones. */ + if (offset < FT_VR(16) +#ifdef __s390x__ + || (offset >= FT_GPR(0) && offset < FT_ACR(0)) + || offset == FT_PSWM + || offset == FT_PSWA +#endif + ) + return *(uint64_t *) (raw_regs + offset); + + if (offset >= FT_ACR(0 && offset < FT_PSWM) + || offset == FT_FPC +#ifndef __s390x__ + || (offset >= FT_GPR(0) && offset < FT_ACR(0)) + || offset == FT_PSWM_U + || offset == FT_PSWA_L +#endif + ) + return *(uint32_t *) (raw_regs + offset); + + /* This leaves 128-bit VX. No way to return them. */ + return 0; +} + +/* Return target_desc to use for IPA, given the tdesc index passed by + gdbserver. For s390, it also sets s390_regmap and s390_regnum. */ + +const struct target_desc * +get_ipa_tdesc (int idx) +{ +#define SET_REGMAP(regmap, skip_last) \ + do { \ + s390_regmap = regmap; \ + s390_regnum = (sizeof regmap / sizeof regmap[0]) - skip_last; \ + } while(0) + switch (idx) + { +#ifdef __s390x__ + case S390_TDESC_64: + /* Subtract number of VX regs. */ + SET_REGMAP(s390x_ft_collect_regmap, 32); + return tdesc_s390x_linux64; + case S390_TDESC_64V1: + SET_REGMAP(s390x_ft_collect_regmap, 32); + return tdesc_s390x_linux64v1; + case S390_TDESC_64V2: + SET_REGMAP(s390x_ft_collect_regmap, 32); + return tdesc_s390x_linux64v2; + case S390_TDESC_TE: + SET_REGMAP(s390x_te_ft_collect_regmap, 32); + return tdesc_s390x_te_linux64; + case S390_TDESC_VX: + SET_REGMAP(s390x_ft_collect_regmap, 0); + return tdesc_s390x_vx_linux64; + case S390_TDESC_TEVX: + SET_REGMAP(s390x_te_ft_collect_regmap, 0); + return tdesc_s390x_tevx_linux64; + case S390_TDESC_GS: + SET_REGMAP(s390x_te_ft_collect_regmap, 0); + return tdesc_s390x_gs_linux64; +#else + case S390_TDESC_32: + SET_REGMAP(s390_linux32_ft_collect_regmap, 0); + return tdesc_s390_linux32; + case S390_TDESC_32V1: + SET_REGMAP(s390_linux32_ft_collect_regmap, 0); + return tdesc_s390_linux32v1; + case S390_TDESC_32V2: + SET_REGMAP(s390_linux32_ft_collect_regmap, 0); + return tdesc_s390_linux32v2; + case S390_TDESC_64: + SET_REGMAP(s390_linux64_ft_collect_regmap, 32); + return tdesc_s390_linux64; + case S390_TDESC_64V1: + SET_REGMAP(s390_linux64_ft_collect_regmap, 32); + return tdesc_s390_linux64v1; + case S390_TDESC_64V2: + SET_REGMAP(s390_linux64_ft_collect_regmap, 32); + return tdesc_s390_linux64v2; + case S390_TDESC_TE: + SET_REGMAP(s390_te_linux64_ft_collect_regmap, 32); + return tdesc_s390_te_linux64; + case S390_TDESC_VX: + SET_REGMAP(s390_linux64_ft_collect_regmap, 0); + return tdesc_s390_vx_linux64; + case S390_TDESC_TEVX: + SET_REGMAP(s390_te_linux64_ft_collect_regmap, 0); + return tdesc_s390_tevx_linux64; + case S390_TDESC_GS: + SET_REGMAP(s390_te_linux64_ft_collect_regmap, 0); + return tdesc_s390_gs_linux64; +#endif + default: + internal_error (__FILE__, __LINE__, + "unknown ipa tdesc index: %d", idx); +#ifdef __s390x__ + return tdesc_s390x_linux64; +#else + return tdesc_s390_linux32; +#endif + } +} + +/* Allocate buffer for the jump pads. On 31-bit, JG reaches everywhere, + so just allocate normally. On 64-bit, we have +/-4GiB of reach, and + the executable is usually mapped at 0x80000000 - aim for somewhere + below it. */ + +void * +alloc_jump_pad_buffer (size_t size) +{ +#ifdef __s390x__ + uintptr_t addr; + uintptr_t exec_base = getauxval (AT_PHDR); + int pagesize; + void *res; + + if (exec_base == 0) + exec_base = 0x80000000; + + pagesize = sysconf (_SC_PAGE_SIZE); + if (pagesize == -1) + perror_with_name ("sysconf"); + + addr = exec_base - size; + + /* size should already be page-aligned, but this can't hurt. */ + addr &= ~(pagesize - 1); + + /* Search for a free area. If we hit 0, we're out of luck. */ + for (; addr; addr -= pagesize) + { + /* No MAP_FIXED - we don't want to zap someone's mapping. */ + res = mmap ((void *) addr, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* If we got what we wanted, return. */ + if ((uintptr_t) res == addr) + return res; + + /* If we got a mapping, but at a wrong address, undo it. */ + if (res != MAP_FAILED) + munmap (res, size); + } + + return NULL; +#else + void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (res == MAP_FAILED) + return NULL; + + return res; +#endif +} + +void +initialize_low_tracepoint (void) +{ +#ifdef __s390x__ + init_registers_s390x_linux64 (); + init_registers_s390x_linux64v1 (); + init_registers_s390x_linux64v2 (); + init_registers_s390x_te_linux64 (); + init_registers_s390x_vx_linux64 (); + init_registers_s390x_tevx_linux64 (); + init_registers_s390x_gs_linux64 (); +#else + init_registers_s390_linux32 (); + init_registers_s390_linux32v1 (); + init_registers_s390_linux32v2 (); + init_registers_s390_linux64 (); + init_registers_s390_linux64v1 (); + init_registers_s390_linux64v2 (); + init_registers_s390_te_linux64 (); + init_registers_s390_vx_linux64 (); + init_registers_s390_tevx_linux64 (); + init_registers_s390_gs_linux64 (); +#endif +} diff --git a/gdbserver/linux-s390-low.c b/gdbserver/linux-s390-low.c new file mode 100644 index 00000000000..f3d6f093099 --- /dev/null +++ b/gdbserver/linux-s390-low.c @@ -0,0 +1,2860 @@ +/* GNU/Linux S/390 specific low level interface, for the remote server + for GDB. + Copyright (C) 2001-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +/* This file is used for both 31-bit and 64-bit S/390 systems. */ + +#include "server.h" +#include "linux-low.h" +#include "elf/common.h" +#include "ax.h" +#include "tracepoint.h" + +#include +#include "nat/gdb_ptrace.h" +#include +#include +#include + +#include "linux-s390-tdesc.h" + +#ifndef HWCAP_S390_HIGH_GPRS +#define HWCAP_S390_HIGH_GPRS 512 +#endif + +#ifndef HWCAP_S390_TE +#define HWCAP_S390_TE 1024 +#endif + +#ifndef HWCAP_S390_VX +#define HWCAP_S390_VX 2048 +#endif + +#ifndef HWCAP_S390_GS +#define HWCAP_S390_GS 16384 +#endif + +#define s390_num_regs 52 + +static int s390_regmap[] = { + PT_PSWMASK, PT_PSWADDR, + + PT_GPR0, PT_GPR1, PT_GPR2, PT_GPR3, + PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7, + PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11, + PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15, + + PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3, + PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7, + PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11, + PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15, + + PT_FPC, + +#ifndef __s390x__ + PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI, + PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI, + PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI, + PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI, +#else + PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3, + PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7, + PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11, + PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15, +#endif + + PT_ORIGGPR2, +}; + +#define s390_num_regs_3264 68 + +#ifdef __s390x__ +static int s390_regmap_3264[] = { + PT_PSWMASK, PT_PSWADDR, + + PT_GPR0, PT_GPR0, PT_GPR1, PT_GPR1, + PT_GPR2, PT_GPR2, PT_GPR3, PT_GPR3, + PT_GPR4, PT_GPR4, PT_GPR5, PT_GPR5, + PT_GPR6, PT_GPR6, PT_GPR7, PT_GPR7, + PT_GPR8, PT_GPR8, PT_GPR9, PT_GPR9, + PT_GPR10, PT_GPR10, PT_GPR11, PT_GPR11, + PT_GPR12, PT_GPR12, PT_GPR13, PT_GPR13, + PT_GPR14, PT_GPR14, PT_GPR15, PT_GPR15, + + PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3, + PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7, + PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11, + PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15, + + PT_FPC, + + PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3, + PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7, + PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11, + PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15, + + PT_ORIGGPR2, +}; +#else +static int s390_regmap_3264[] = { + PT_PSWMASK, PT_PSWADDR, + + -1, PT_GPR0, -1, PT_GPR1, + -1, PT_GPR2, -1, PT_GPR3, + -1, PT_GPR4, -1, PT_GPR5, + -1, PT_GPR6, -1, PT_GPR7, + -1, PT_GPR8, -1, PT_GPR9, + -1, PT_GPR10, -1, PT_GPR11, + -1, PT_GPR12, -1, PT_GPR13, + -1, PT_GPR14, -1, PT_GPR15, + + PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3, + PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7, + PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11, + PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15, + + PT_FPC, + + PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI, + PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI, + PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI, + PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI, + + PT_ORIGGPR2, +}; +#endif + + +static int +s390_cannot_fetch_register (int regno) +{ + return 0; +} + +static int +s390_cannot_store_register (int regno) +{ + return 0; +} + +static void +s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) +{ + int size = register_size (regcache->tdesc, regno); + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct usrregs_info *usr = regs_info->usrregs; + int regaddr = usr->regmap[regno]; + + if (size < sizeof (long)) + { + memset (buf, 0, sizeof (long)); + + if ((regno ^ 1) < usr->num_regs + && usr->regmap[regno ^ 1] == regaddr) + { + collect_register (regcache, regno & ~1, buf); + collect_register (regcache, (regno & ~1) + 1, + buf + sizeof (long) - size); + } + else if (regaddr == PT_PSWMASK) + { + /* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying + the basic addressing mode bit from the PSW address. */ + gdb_byte *addr = (gdb_byte *) alloca (register_size (regcache->tdesc, regno ^ 1)); + collect_register (regcache, regno, buf); + collect_register (regcache, regno ^ 1, addr); + buf[1] &= ~0x8; + buf[size] |= (addr[0] & 0x80); + } + else if (regaddr == PT_PSWADDR) + { + /* Convert 4-byte PSW address to 8 bytes by clearing the addressing + mode bit (which gets copied to the PSW mask instead). */ + collect_register (regcache, regno, buf + sizeof (long) - size); + buf[sizeof (long) - size] &= ~0x80; + } + else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15) + || regaddr == PT_ORIGGPR2) + collect_register (regcache, regno, buf + sizeof (long) - size); + else + collect_register (regcache, regno, buf); + } + else if (regaddr != -1) + collect_register (regcache, regno, buf); +} + +static void +s390_supply_ptrace_register (struct regcache *regcache, + int regno, const char *buf) +{ + int size = register_size (regcache->tdesc, regno); + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct usrregs_info *usr = regs_info->usrregs; + int regaddr = usr->regmap[regno]; + + if (size < sizeof (long)) + { + if ((regno ^ 1) < usr->num_regs + && usr->regmap[regno ^ 1] == regaddr) + { + supply_register (regcache, regno & ~1, buf); + supply_register (regcache, (regno & ~1) + 1, + buf + sizeof (long) - size); + } + else if (regaddr == PT_PSWMASK) + { + /* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying + the basic addressing mode into the PSW address. */ + gdb_byte *mask = (gdb_byte *) alloca (size); + gdb_byte *addr = (gdb_byte *) alloca (register_size (regcache->tdesc, regno ^ 1)); + memcpy (mask, buf, size); + mask[1] |= 0x8; + supply_register (regcache, regno, mask); + + collect_register (regcache, regno ^ 1, addr); + addr[0] &= ~0x80; + addr[0] |= (buf[size] & 0x80); + supply_register (regcache, regno ^ 1, addr); + } + else if (regaddr == PT_PSWADDR) + { + /* Convert 8-byte PSW address to 4 bytes by truncating, but + keeping the addressing mode bit (which was set from the mask). */ + gdb_byte *addr = (gdb_byte *) alloca (size); + char amode; + collect_register (regcache, regno, addr); + amode = addr[0] & 0x80; + memcpy (addr, buf + sizeof (long) - size, size); + addr[0] &= ~0x80; + addr[0] |= amode; + supply_register (regcache, regno, addr); + } + else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15) + || regaddr == PT_ORIGGPR2) + supply_register (regcache, regno, buf + sizeof (long) - size); + else + supply_register (regcache, regno, buf); + } + else if (regaddr != -1) + supply_register (regcache, regno, buf); +} + +/* Provide only a fill function for the general register set. ps_lgetregs + will use this for NPTL support. */ + +static void +s390_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct usrregs_info *usr = regs_info->usrregs; + + for (i = 0; i < usr->num_regs; i++) + { + if (usr->regmap[i] < PT_PSWMASK + || usr->regmap[i] > PT_ACR15) + continue; + + s390_collect_ptrace_register (regcache, i, + (char *) buf + usr->regmap[i]); + } +} + +/* Fill and store functions for extended register sets. */ + +#ifndef __s390x__ +static void +s390_fill_gprs_high (struct regcache *regcache, void *buf) +{ + int r0h = find_regno (regcache->tdesc, "r0h"); + int i; + + for (i = 0; i < 16; i++) + collect_register (regcache, r0h + 2 * i, (char *) buf + 4 * i); +} + +static void +s390_store_gprs_high (struct regcache *regcache, const void *buf) +{ + int r0h = find_regno (regcache->tdesc, "r0h"); + int i; + + for (i = 0; i < 16; i++) + supply_register (regcache, r0h + 2 * i, (const char *) buf + 4 * i); +} +#endif + +static void +s390_store_last_break (struct regcache *regcache, const void *buf) +{ + const char *p; + + p = (const char *) buf + 8 - register_size (regcache->tdesc, 0); + supply_register_by_name (regcache, "last_break", p); +} + +static void +s390_fill_system_call (struct regcache *regcache, void *buf) +{ + collect_register_by_name (regcache, "system_call", buf); +} + +static void +s390_store_system_call (struct regcache *regcache, const void *buf) +{ + supply_register_by_name (regcache, "system_call", buf); +} + +static void +s390_store_tdb (struct regcache *regcache, const void *buf) +{ + int tdb0 = find_regno (regcache->tdesc, "tdb0"); + int tr0 = find_regno (regcache->tdesc, "tr0"); + int i; + + for (i = 0; i < 4; i++) + supply_register (regcache, tdb0 + i, (const char *) buf + 8 * i); + + for (i = 0; i < 16; i++) + supply_register (regcache, tr0 + i, (const char *) buf + 8 * (16 + i)); +} + +static void +s390_fill_vxrs_low (struct regcache *regcache, void *buf) +{ + int v0 = find_regno (regcache->tdesc, "v0l"); + int i; + + for (i = 0; i < 16; i++) + collect_register (regcache, v0 + i, (char *) buf + 8 * i); +} + +static void +s390_store_vxrs_low (struct regcache *regcache, const void *buf) +{ + int v0 = find_regno (regcache->tdesc, "v0l"); + int i; + + for (i = 0; i < 16; i++) + supply_register (regcache, v0 + i, (const char *) buf + 8 * i); +} + +static void +s390_fill_vxrs_high (struct regcache *regcache, void *buf) +{ + int v16 = find_regno (regcache->tdesc, "v16"); + int i; + + for (i = 0; i < 16; i++) + collect_register (regcache, v16 + i, (char *) buf + 16 * i); +} + +static void +s390_store_vxrs_high (struct regcache *regcache, const void *buf) +{ + int v16 = find_regno (regcache->tdesc, "v16"); + int i; + + for (i = 0; i < 16; i++) + supply_register (regcache, v16 + i, (const char *) buf + 16 * i); +} + +static void +s390_store_gs (struct regcache *regcache, const void *buf) +{ + int gsd = find_regno (regcache->tdesc, "gsd"); + int i; + + for (i = 0; i < 3; i++) + supply_register (regcache, gsd + i, (const char *) buf + 8 * (i + 1)); +} + +static void +s390_store_gsbc (struct regcache *regcache, const void *buf) +{ + int bc_gsd = find_regno (regcache->tdesc, "bc_gsd"); + int i; + + for (i = 0; i < 3; i++) + supply_register (regcache, bc_gsd + i, (const char *) buf + 8 * (i + 1)); +} + +static struct regset_info s390_regsets[] = { + { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL }, +#ifndef __s390x__ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_HIGH_GPRS, 0, + EXTENDED_REGS, s390_fill_gprs_high, s390_store_gprs_high }, +#endif + /* Last break address is read-only; no fill function. */ + { PTRACE_GETREGSET, -1, NT_S390_LAST_BREAK, 0, EXTENDED_REGS, + NULL, s390_store_last_break }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_SYSTEM_CALL, 0, + EXTENDED_REGS, s390_fill_system_call, s390_store_system_call }, + /* TDB is read-only. */ + { PTRACE_GETREGSET, -1, NT_S390_TDB, 0, EXTENDED_REGS, + NULL, s390_store_tdb }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_VXRS_LOW, 0, + EXTENDED_REGS, s390_fill_vxrs_low, s390_store_vxrs_low }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_VXRS_HIGH, 0, + EXTENDED_REGS, s390_fill_vxrs_high, s390_store_vxrs_high }, + /* Guarded storage registers are read-only. */ + { PTRACE_GETREGSET, -1, NT_S390_GS_CB, 0, EXTENDED_REGS, + NULL, s390_store_gs }, + { PTRACE_GETREGSET, -1, NT_S390_GS_BC, 0, EXTENDED_REGS, + NULL, s390_store_gsbc }, + NULL_REGSET +}; + + +static const gdb_byte s390_breakpoint[] = { 0, 1 }; +#define s390_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +s390_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = s390_breakpoint_len; + return s390_breakpoint; +} + +static CORE_ADDR +s390_get_pc (struct regcache *regcache) +{ + if (register_size (regcache->tdesc, 0) == 4) + { + unsigned int pswa; + collect_register_by_name (regcache, "pswa", &pswa); + return pswa & 0x7fffffff; + } + else + { + unsigned long pc; + collect_register_by_name (regcache, "pswa", &pc); + return pc; + } +} + +static void +s390_set_pc (struct regcache *regcache, CORE_ADDR newpc) +{ + if (register_size (regcache->tdesc, 0) == 4) + { + unsigned int pswa; + collect_register_by_name (regcache, "pswa", &pswa); + pswa = (pswa & 0x80000000) | (newpc & 0x7fffffff); + supply_register_by_name (regcache, "pswa", &pswa); + } + else + { + unsigned long pc = newpc; + supply_register_by_name (regcache, "pswa", &pc); + } +} + +/* Determine the word size for the given PID, in bytes. */ + +#ifdef __s390x__ +static int +s390_get_wordsize (int pid) +{ + errno = 0; + PTRACE_XFER_TYPE pswm = ptrace (PTRACE_PEEKUSER, pid, + (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) 0); + if (errno != 0) + { + warning (_("Couldn't determine word size, assuming 64-bit.")); + return 8; + } + /* Derive word size from extended addressing mode (PSW bit 31). */ + return pswm & (1L << 32) ? 8 : 4; +} +#else +#define s390_get_wordsize(pid) 4 +#endif + +static int +s390_check_regset (int pid, int regset, int regsize) +{ + void *buf = alloca (regsize); + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = regsize; + + if (ptrace (PTRACE_GETREGSET, pid, (long) regset, (long) &iov) >= 0 + || errno == ENODATA) + return 1; + return 0; +} + +/* For a 31-bit inferior, whether the kernel supports using the full + 64-bit GPRs. */ +static int have_hwcap_s390_high_gprs = 0; +static int have_hwcap_s390_vx = 0; + +static void +s390_arch_setup (void) +{ + const struct target_desc *tdesc; + struct regset_info *regset; + + /* Determine word size and HWCAP. */ + int pid = pid_of (current_thread); + int wordsize = s390_get_wordsize (pid); + unsigned long hwcap = linux_get_hwcap (wordsize); + + /* Check whether the kernel supports extra register sets. */ + int have_regset_last_break + = s390_check_regset (pid, NT_S390_LAST_BREAK, 8); + int have_regset_system_call + = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4); + int have_regset_tdb + = (s390_check_regset (pid, NT_S390_TDB, 256) + && (hwcap & HWCAP_S390_TE) != 0); + int have_regset_vxrs + = (s390_check_regset (pid, NT_S390_VXRS_LOW, 128) + && s390_check_regset (pid, NT_S390_VXRS_HIGH, 256) + && (hwcap & HWCAP_S390_VX) != 0); + int have_regset_gs + = (s390_check_regset (pid, NT_S390_GS_CB, 32) + && s390_check_regset (pid, NT_S390_GS_BC, 32) + && (hwcap & HWCAP_S390_GS) != 0); + + { +#ifdef __s390x__ + if (wordsize == 8) + { + if (have_regset_gs) + tdesc = tdesc_s390x_gs_linux64; + else if (have_regset_vxrs) + tdesc = (have_regset_tdb ? tdesc_s390x_tevx_linux64 : + tdesc_s390x_vx_linux64); + else if (have_regset_tdb) + tdesc = tdesc_s390x_te_linux64; + else if (have_regset_system_call) + tdesc = tdesc_s390x_linux64v2; + else if (have_regset_last_break) + tdesc = tdesc_s390x_linux64v1; + else + tdesc = tdesc_s390x_linux64; + } + + /* For a 31-bit inferior, check whether the kernel supports + using the full 64-bit GPRs. */ + else +#endif + if (hwcap & HWCAP_S390_HIGH_GPRS) + { + have_hwcap_s390_high_gprs = 1; + if (have_regset_gs) + tdesc = tdesc_s390_gs_linux64; + else if (have_regset_vxrs) + tdesc = (have_regset_tdb ? tdesc_s390_tevx_linux64 : + tdesc_s390_vx_linux64); + else if (have_regset_tdb) + tdesc = tdesc_s390_te_linux64; + else if (have_regset_system_call) + tdesc = tdesc_s390_linux64v2; + else if (have_regset_last_break) + tdesc = tdesc_s390_linux64v1; + else + tdesc = tdesc_s390_linux64; + } + else + { + /* Assume 31-bit inferior process. */ + if (have_regset_system_call) + tdesc = tdesc_s390_linux32v2; + else if (have_regset_last_break) + tdesc = tdesc_s390_linux32v1; + else + tdesc = tdesc_s390_linux32; + } + + have_hwcap_s390_vx = have_regset_vxrs; + } + + /* Update target_regsets according to available register sets. */ + for (regset = s390_regsets; regset->size >= 0; regset++) + if (regset->get_request == PTRACE_GETREGSET) + switch (regset->nt_type) + { +#ifndef __s390x__ + case NT_S390_HIGH_GPRS: + regset->size = have_hwcap_s390_high_gprs ? 64 : 0; + break; +#endif + case NT_S390_LAST_BREAK: + regset->size = have_regset_last_break ? 8 : 0; + break; + case NT_S390_SYSTEM_CALL: + regset->size = have_regset_system_call ? 4 : 0; + break; + case NT_S390_TDB: + regset->size = have_regset_tdb ? 256 : 0; + break; + case NT_S390_VXRS_LOW: + regset->size = have_regset_vxrs ? 128 : 0; + break; + case NT_S390_VXRS_HIGH: + regset->size = have_regset_vxrs ? 256 : 0; + break; + case NT_S390_GS_CB: + case NT_S390_GS_BC: + regset->size = have_regset_gs ? 32 : 0; + default: + break; + } + + current_process ()->tdesc = tdesc; +} + + +static int +s390_breakpoint_at (CORE_ADDR pc) +{ + unsigned char c[s390_breakpoint_len]; + read_inferior_memory (pc, c, s390_breakpoint_len); + return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0; +} + +/* Breakpoint/Watchpoint support. */ + +/* The "supports_z_point_type" linux_target_ops method. */ + +static int +s390_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + return 1; + default: + return 0; + } +} + +/* Support for hardware single step. */ + +static int +s390_supports_hardware_single_step (void) +{ + return 1; +} + +static struct usrregs_info s390_usrregs_info = + { + s390_num_regs, + s390_regmap, + }; + +static struct regsets_info s390_regsets_info = + { + s390_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &s390_usrregs_info, + &s390_regsets_info + }; + +static struct usrregs_info s390_usrregs_info_3264 = + { + s390_num_regs_3264, + s390_regmap_3264 + }; + +static struct regsets_info s390_regsets_info_3264 = + { + s390_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info_3264 = + { + NULL, /* regset_bitmap */ + &s390_usrregs_info_3264, + &s390_regsets_info_3264 + }; + +static const struct regs_info * +s390_regs_info (void) +{ + if (have_hwcap_s390_high_gprs) + { +#ifdef __s390x__ + const struct target_desc *tdesc = current_process ()->tdesc; + + if (register_size (tdesc, 0) == 4) + return ®s_info_3264; +#else + return ®s_info_3264; +#endif + } + return ®s_info; +} + +/* The "supports_tracepoints" linux_target_ops method. */ + +static int +s390_supports_tracepoints (void) +{ + return 1; +} + +/* Implementation of linux_target_ops method "get_thread_area". */ + +static int +s390_get_thread_area (int lwpid, CORE_ADDR *addrp) +{ + CORE_ADDR res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_ACR0, (long) 0); +#ifdef __s390x__ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + + if (register_size (regcache->tdesc, 0) == 4) + res &= 0xffffffffull; +#endif + *addrp = res; + return 0; +} + + +/* Fast tracepoint support. + + The register save area on stack is identical for all targets: + + 0x000+i*0x10: VR0-VR31 + 0x200+i*8: GR0-GR15 + 0x280+i*4: AR0-AR15 + 0x2c0: PSWM [64-bit] + 0x2c8: PSWA [64-bit] + 0x2d0: FPC + + If we're on 31-bit linux, we just don't store the high parts of the GPRs. + Likewise, if there's no VX support, we just store the FRs into the slots + of low VR halves. The agent code is responsible for rearranging that + into regcache. */ + +/* Code sequence saving GPRs for 31-bit target with no high GPRs. There's + one trick used at the very beginning: since there's no way to allocate + stack space without destroying CC (lay instruction can do it, but it's + only supported on later CPUs), we take 4 different execution paths for + every possible value of CC, allocate stack space, save %r0, stuff the + CC value in %r0 (shifted to match its position in PSWM high word), + then branch to common path. */ + +static const unsigned char s390_ft_entry_gpr_esa[] = { + 0xa7, 0x14, 0x00, 0x1e, /* jo .Lcc3 */ + 0xa7, 0x24, 0x00, 0x14, /* jh .Lcc2 */ + 0xa7, 0x44, 0x00, 0x0a, /* jl .Lcc1 */ + /* CC = 0 */ + 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ + 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ + 0xa7, 0x08, 0x00, 0x00, /* lhi %r0, 0 */ + 0xa7, 0xf4, 0x00, 0x18, /* j .Lccdone */ + /* .Lcc1: */ + 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ + 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ + 0xa7, 0x08, 0x10, 0x00, /* lhi %r0, 0x1000 */ + 0xa7, 0xf4, 0x00, 0x10, /* j .Lccdone */ + /* .Lcc2: */ + 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ + 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ + 0xa7, 0x08, 0x20, 0x00, /* lhi %r0, 0x2000 */ + 0xa7, 0xf4, 0x00, 0x08, /* j .Lccdone */ + /* .Lcc3: */ + 0xa7, 0xfa, 0xfd, 0x00, /* ahi %r15, -0x300 */ + 0x50, 0x00, 0xf2, 0x04, /* st %r0, 0x204(%r15) */ + 0xa7, 0x08, 0x30, 0x00, /* lhi %r0, 0x3000 */ + /* .Lccdone: */ + 0x50, 0x10, 0xf2, 0x0c, /* st %r1, 0x20c(%r15) */ + 0x50, 0x20, 0xf2, 0x14, /* st %r2, 0x214(%r15) */ + 0x50, 0x30, 0xf2, 0x1c, /* st %r3, 0x21c(%r15) */ + 0x50, 0x40, 0xf2, 0x24, /* st %r4, 0x224(%r15) */ + 0x50, 0x50, 0xf2, 0x2c, /* st %r5, 0x22c(%r15) */ + 0x50, 0x60, 0xf2, 0x34, /* st %r6, 0x234(%r15) */ + 0x50, 0x70, 0xf2, 0x3c, /* st %r7, 0x23c(%r15) */ + 0x50, 0x80, 0xf2, 0x44, /* st %r8, 0x244(%r15) */ + 0x50, 0x90, 0xf2, 0x4c, /* st %r9, 0x24c(%r15) */ + 0x50, 0xa0, 0xf2, 0x54, /* st %r10, 0x254(%r15) */ + 0x50, 0xb0, 0xf2, 0x5c, /* st %r11, 0x25c(%r15) */ + 0x50, 0xc0, 0xf2, 0x64, /* st %r12, 0x264(%r15) */ + 0x50, 0xd0, 0xf2, 0x6c, /* st %r13, 0x26c(%r15) */ + 0x50, 0xe0, 0xf2, 0x74, /* st %r14, 0x274(%r15) */ + /* Compute original value of %r15 and store it. We use ahi instead + of la to preserve the whole value, and not just the low 31 bits. + This is not particularly important here, but essential in the + zarch case where someone might be using the high word of %r15 + as an extra register. */ + 0x18, 0x1f, /* lr %r1, %r15 */ + 0xa7, 0x1a, 0x03, 0x00, /* ahi %r1, 0x300 */ + 0x50, 0x10, 0xf2, 0x7c, /* st %r1, 0x27c(%r15) */ +}; + +/* Code sequence saving GPRs for 31-bit target with high GPRs and for 64-bit + target. Same as above, except this time we can use load/store multiple, + since the 64-bit regs are tightly packed. */ + +static const unsigned char s390_ft_entry_gpr_zarch[] = { + 0xa7, 0x14, 0x00, 0x21, /* jo .Lcc3 */ + 0xa7, 0x24, 0x00, 0x16, /* jh .Lcc2 */ + 0xa7, 0x44, 0x00, 0x0b, /* jl .Lcc1 */ + /* CC = 0 */ + 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ + 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ + 0xa7, 0x08, 0x00, 0x00, /* lhi %r0, 0 */ + 0xa7, 0xf4, 0x00, 0x1b, /* j .Lccdone */ + /* .Lcc1: */ + 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ + 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ + 0xa7, 0x08, 0x10, 0x00, /* lhi %r0, 0x1000 */ + 0xa7, 0xf4, 0x00, 0x12, /* j .Lccdone */ + /* .Lcc2: */ + 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ + 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ + 0xa7, 0x08, 0x20, 0x00, /* lhi %r0, 0x2000 */ + 0xa7, 0xf4, 0x00, 0x09, /* j .Lccdone */ + /* .Lcc3: */ + 0xa7, 0xfb, 0xfd, 0x00, /* aghi %r15, -0x300 */ + 0xeb, 0x0e, 0xf2, 0x00, 0x00, 0x24, /* stmg %r0, %r14, 0x200(%r15) */ + 0xa7, 0x08, 0x30, 0x00, /* lhi %r0, 0x3000 */ + /* .Lccdone: */ + 0xb9, 0x04, 0x00, 0x1f, /* lgr %r1, %r15 */ + 0xa7, 0x1b, 0x03, 0x00, /* aghi %r1, 0x300 */ + 0xe3, 0x10, 0xf2, 0x78, 0x00, 0x24, /* stg %r1, 0x278(%r15) */ +}; + +/* Code sequence saving ARs, PSWM and FPC. PSWM has to be assembled from + current PSWM (read by epsw) and CC from entry (in %r0). */ + +static const unsigned char s390_ft_entry_misc[] = { + 0x9b, 0x0f, 0xf2, 0x80, /* stam %a0, %a15, 0x20(%%r15) */ + 0xb9, 0x8d, 0x00, 0x23, /* epsw %r2, %r3 */ + 0xa7, 0x18, 0xcf, 0xff, /* lhi %r1, ~0x3000 */ + 0x14, 0x21, /* nr %r2, %r1 */ + 0x16, 0x20, /* or %r2, %r0 */ + 0x50, 0x20, 0xf2, 0xc0, /* st %r2, 0x2c0(%r15) */ + 0x50, 0x30, 0xf2, 0xc4, /* st %r3, 0x2c4(%r15) */ + 0xb2, 0x9c, 0xf2, 0xd0, /* stfpc 0x2d0(%r15) */ +}; + +/* Code sequence saving FRs, used if VX not supported. */ + +static const unsigned char s390_ft_entry_fr[] = { + 0x60, 0x00, 0xf0, 0x00, /* std %f0, 0x000(%r15) */ + 0x60, 0x10, 0xf0, 0x10, /* std %f1, 0x010(%r15) */ + 0x60, 0x20, 0xf0, 0x20, /* std %f2, 0x020(%r15) */ + 0x60, 0x30, 0xf0, 0x30, /* std %f3, 0x030(%r15) */ + 0x60, 0x40, 0xf0, 0x40, /* std %f4, 0x040(%r15) */ + 0x60, 0x50, 0xf0, 0x50, /* std %f5, 0x050(%r15) */ + 0x60, 0x60, 0xf0, 0x60, /* std %f6, 0x060(%r15) */ + 0x60, 0x70, 0xf0, 0x70, /* std %f7, 0x070(%r15) */ + 0x60, 0x80, 0xf0, 0x80, /* std %f8, 0x080(%r15) */ + 0x60, 0x90, 0xf0, 0x90, /* std %f9, 0x090(%r15) */ + 0x60, 0xa0, 0xf0, 0xa0, /* std %f10, 0x0a0(%r15) */ + 0x60, 0xb0, 0xf0, 0xb0, /* std %f11, 0x0b0(%r15) */ + 0x60, 0xc0, 0xf0, 0xc0, /* std %f12, 0x0c0(%r15) */ + 0x60, 0xd0, 0xf0, 0xd0, /* std %f13, 0x0d0(%r15) */ + 0x60, 0xe0, 0xf0, 0xe0, /* std %f14, 0x0e0(%r15) */ + 0x60, 0xf0, 0xf0, 0xf0, /* std %f15, 0x0f0(%r15) */ +}; + +/* Code sequence saving VRs, used if VX not supported. */ + +static const unsigned char s390_ft_entry_vr[] = { + 0xe7, 0x0f, 0xf0, 0x00, 0x00, 0x3e, /* vstm %v0, %v15, 0x000(%r15) */ + 0xe7, 0x0f, 0xf1, 0x00, 0x0c, 0x3e, /* vstm %v16, %v31, 0x100(%r15) */ +}; + +/* Code sequence doing the collection call for 31-bit target. %r1 contains + the address of the literal pool. */ + +static const unsigned char s390_ft_main_31[] = { + /* Load the literals into registers. */ + 0x58, 0x50, 0x10, 0x00, /* l %r5, 0x0(%r1) */ + 0x58, 0x20, 0x10, 0x04, /* l %r2, 0x4(%r1) */ + 0x58, 0x40, 0x10, 0x08, /* l %r4, 0x8(%r1) */ + 0x58, 0x60, 0x10, 0x0c, /* l %r6, 0xc(%r1) */ + /* Save original PSWA (tracepoint address | 0x80000000). */ + 0x50, 0x50, 0xf2, 0xcc, /* st %r5, 0x2cc(%r15) */ + /* Construct a collecting_t object at %r15+0x2e0. */ + 0x50, 0x20, 0xf2, 0xe0, /* st %r2, 0x2e0(%r15) */ + 0x9b, 0x00, 0xf2, 0xe4, /* stam %a0, %a0, 0x2e4(%r15) */ + /* Move its address to %r0. */ + 0x41, 0x00, 0xf2, 0xe0, /* la %r0, 0x2e0(%r15) */ + /* Take the lock. */ + /* .Lloop: */ + 0xa7, 0x18, 0x00, 0x00, /* lhi %r1, 0 */ + 0xba, 0x10, 0x60, 0x00, /* cs %r1, %r0, 0(%r6) */ + 0xa7, 0x74, 0xff, 0xfc, /* jne .Lloop */ + /* Address of the register save block to %r3. */ + 0x18, 0x3f, /* lr %r3, %r15 */ + /* Make a stack frame, so that we can call the collector. */ + 0xa7, 0xfa, 0xff, 0xa0, /* ahi %r15, -0x60 */ + /* Call it. */ + 0x0d, 0xe4, /* basr %r14, %r4 */ + /* And get rid of the stack frame again. */ + 0x41, 0xf0, 0xf0, 0x60, /* la %r15, 0x60(%r15) */ + /* Leave the lock. */ + 0x07, 0xf0, /* br %r0 */ + 0xa7, 0x18, 0x00, 0x00, /* lhi %r1, 0 */ + 0x50, 0x10, 0x60, 0x00, /* st %t1, 0(%r6) */ +}; + +/* Code sequence doing the collection call for 64-bit target. %r1 contains + the address of the literal pool. */ + +static const unsigned char s390_ft_main_64[] = { + /* Load the literals into registers. */ + 0xe3, 0x50, 0x10, 0x00, 0x00, 0x04, /* lg %r5, 0x00(%r1) */ + 0xe3, 0x20, 0x10, 0x08, 0x00, 0x04, /* lg %r2, 0x08(%r1) */ + 0xe3, 0x40, 0x10, 0x10, 0x00, 0x04, /* lg %r4, 0x10(%r1) */ + 0xe3, 0x60, 0x10, 0x18, 0x00, 0x04, /* lg %r6, 0x18(%r1) */ + /* Save original PSWA (tracepoint address). */ + 0xe3, 0x50, 0xf2, 0xc8, 0x00, 0x24, /* stg %r5, 0x2c8(%r15) */ + /* Construct a collecting_t object at %r15+0x2e0. */ + 0xe3, 0x20, 0xf2, 0xe0, 0x00, 0x24, /* stg %r2, 0x2e0(%r15) */ + 0x9b, 0x01, 0xf2, 0xe8, /* stam %a0, %a1, 0x2e8(%r15) */ + /* Move its address to %r0. */ + 0x41, 0x00, 0xf2, 0xe0, /* la %r0, 0x2e0(%r15) */ + /* Take the lock. */ + /* .Lloop: */ + 0xa7, 0x19, 0x00, 0x00, /* lghi %r1, 0 */ + 0xeb, 0x10, 0x60, 0x00, 0x00, 0x30, /* csg %r1, %r0, 0(%r6) */ + 0xa7, 0x74, 0xff, 0xfb, /* jne .Lloop */ + /* Address of the register save block to %r3. */ + 0xb9, 0x04, 0x00, 0x3f, /* lgr %r3, %r15 */ + /* Make a stack frame, so that we can call the collector. */ + 0xa7, 0xfb, 0xff, 0x60, /* aghi %r15, -0xa0 */ + /* Call it. */ + 0x0d, 0xe4, /* basr %r14, %r4 */ + /* And get rid of the stack frame again. */ + 0x41, 0xf0, 0xf0, 0xa0, /* la %r15, 0xa0(%r15) */ + /* Leave the lock. */ + 0x07, 0xf0, /* br %r0 */ + 0xa7, 0x19, 0x00, 0x00, /* lghi %r1, 0 */ + 0xe3, 0x10, 0x60, 0x00, 0x00, 0x24, /* stg %t1, 0(%r6) */ +}; + +/* Code sequence restoring FRs, for targets with no VX support. */ + +static const unsigned char s390_ft_exit_fr[] = { + 0x68, 0x00, 0xf0, 0x00, /* ld %f0, 0x000(%r15) */ + 0x68, 0x10, 0xf0, 0x10, /* ld %f1, 0x010(%r15) */ + 0x68, 0x20, 0xf0, 0x20, /* ld %f2, 0x020(%r15) */ + 0x68, 0x30, 0xf0, 0x30, /* ld %f3, 0x030(%r15) */ + 0x68, 0x40, 0xf0, 0x40, /* ld %f4, 0x040(%r15) */ + 0x68, 0x50, 0xf0, 0x50, /* ld %f5, 0x050(%r15) */ + 0x68, 0x60, 0xf0, 0x60, /* ld %f6, 0x060(%r15) */ + 0x68, 0x70, 0xf0, 0x70, /* ld %f7, 0x070(%r15) */ + 0x68, 0x80, 0xf0, 0x80, /* ld %f8, 0x080(%r15) */ + 0x68, 0x90, 0xf0, 0x90, /* ld %f9, 0x090(%r15) */ + 0x68, 0xa0, 0xf0, 0xa0, /* ld %f10, 0x0a0(%r15) */ + 0x68, 0xb0, 0xf0, 0xb0, /* ld %f11, 0x0b0(%r15) */ + 0x68, 0xc0, 0xf0, 0xc0, /* ld %f12, 0x0c0(%r15) */ + 0x68, 0xd0, 0xf0, 0xd0, /* ld %f13, 0x0d0(%r15) */ + 0x68, 0xe0, 0xf0, 0xe0, /* ld %f14, 0x0e0(%r15) */ + 0x68, 0xf0, 0xf0, 0xf0, /* ld %f15, 0x0f0(%r15) */ +}; + +/* Code sequence restoring VRs. */ + +static const unsigned char s390_ft_exit_vr[] = { + 0xe7, 0x0f, 0xf0, 0x00, 0x00, 0x36, /* vlm %v0, %v15, 0x000(%r15) */ + 0xe7, 0x0f, 0xf1, 0x00, 0x0c, 0x36, /* vlm %v16, %v31, 0x100(%r15) */ +}; + +/* Code sequence restoring misc registers. As for PSWM, only CC should be + modified by C code, so we use the alr instruction to restore it by + manufacturing an operand that'll result in the original flags. */ + +static const unsigned char s390_ft_exit_misc[] = { + 0xb2, 0x9d, 0xf2, 0xd0, /* lfpc 0x2d0(%r15) */ + 0x58, 0x00, 0xf2, 0xc0, /* l %r0, 0x2c0(%r15) */ + /* Extract CC to high 2 bits of %r0. */ + 0x88, 0x00, 0x00, 0x0c, /* srl %r0, 12 */ + 0x89, 0x00, 0x00, 0x1e, /* sll %r0, 30 */ + /* Add %r0 to itself. Result will be nonzero iff CC bit 0 is set, and + will have carry iff CC bit 1 is set - resulting in the same flags + as the original. */ + 0x1e, 0x00, /* alr %r0, %r0 */ + 0x9a, 0x0f, 0xf2, 0x80, /* lam %a0, %a15, 0x280(%r15) */ +}; + +/* Code sequence restoring GPRs, for 31-bit targets with no high GPRs. */ + +static const unsigned char s390_ft_exit_gpr_esa[] = { + 0x58, 0x00, 0xf2, 0x04, /* l %r0, 0x204(%r15) */ + 0x58, 0x10, 0xf2, 0x0c, /* l %r1, 0x20c(%r15) */ + 0x58, 0x20, 0xf2, 0x14, /* l %r2, 0x214(%r15) */ + 0x58, 0x30, 0xf2, 0x1c, /* l %r3, 0x21c(%r15) */ + 0x58, 0x40, 0xf2, 0x24, /* l %r4, 0x224(%r15) */ + 0x58, 0x50, 0xf2, 0x2c, /* l %r5, 0x22c(%r15) */ + 0x58, 0x60, 0xf2, 0x34, /* l %r6, 0x234(%r15) */ + 0x58, 0x70, 0xf2, 0x3c, /* l %r7, 0x23c(%r15) */ + 0x58, 0x80, 0xf2, 0x44, /* l %r8, 0x244(%r15) */ + 0x58, 0x90, 0xf2, 0x4c, /* l %r9, 0x24c(%r15) */ + 0x58, 0xa0, 0xf2, 0x54, /* l %r10, 0x254(%r15) */ + 0x58, 0xb0, 0xf2, 0x5c, /* l %r11, 0x25c(%r15) */ + 0x58, 0xc0, 0xf2, 0x64, /* l %r12, 0x264(%r15) */ + 0x58, 0xd0, 0xf2, 0x6c, /* l %r13, 0x26c(%r15) */ + 0x58, 0xe0, 0xf2, 0x74, /* l %r14, 0x274(%r15) */ + 0x58, 0xf0, 0xf2, 0x7c, /* l %r15, 0x27c(%r15) */ +}; + +/* Code sequence restoring GPRs, for 64-bit targets and 31-bit targets + with high GPRs. */ + +static const unsigned char s390_ft_exit_gpr_zarch[] = { + 0xeb, 0x0f, 0xf2, 0x00, 0x00, 0x04, /* lmg %r0, %r15, 0x200(%r15) */ +}; + +/* Writes instructions to target, updating the to pointer. */ + +static void +append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf) +{ + target_write_memory (*to, buf, len); + *to += len; +} + +/* Relocates an instruction from oldloc to *to, updating to. */ + +static int +s390_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc, int is_64) +{ + gdb_byte buf[6]; + int ilen; + int op2; + /* 0: no fixup, 1: PC16DBL fixup, 2: PC32DBL fixup. */ + int mode = 0; + int is_bras = 0; + read_inferior_memory (oldloc, buf, sizeof buf); + if (buf[0] < 0x40) + ilen = 2; + else if (buf[0] < 0xc0) + ilen = 4; + else + ilen = 6; + switch (buf[0]) + { + case 0x05: /* BALR */ + case 0x0c: /* BASSM */ + case 0x0d: /* BASR */ + case 0x45: /* BAL */ + case 0x4d: /* BAS */ + /* These save a return address and mess around with registers. + We can't relocate them. */ + return 1; + case 0x84: /* BRXH */ + case 0x85: /* BRXLE */ + mode = 1; + break; + case 0xa7: + op2 = buf[1] & 0xf; + /* BRC, BRAS, BRCT, BRCTG */ + if (op2 >= 4 && op2 <= 7) + mode = 1; + /* BRAS */ + if (op2 == 5) + is_bras = 1; + break; + case 0xc0: + op2 = buf[1] & 0xf; + /* LARL, BRCL, BRASL */ + if (op2 == 0 || op2 == 4 || op2 == 5) + mode = 2; + /* BRASL */ + if (op2 == 5) + is_bras = 1; + break; + case 0xc4: + case 0xc6: + /* PC-relative addressing instructions. */ + mode = 2; + break; + case 0xc5: /* BPRP */ + case 0xc7: /* BPP */ + /* Branch prediction - just skip it. */ + return 0; + case 0xcc: + op2 = buf[1] & 0xf; + /* BRCTH */ + if (op2 == 6) + mode = 2; + break; + case 0xec: + op2 = buf[5]; + switch (op2) + { + case 0x44: /* BRXHG */ + case 0x45: /* BRXLG */ + case 0x64: /* CGRJ */ + case 0x65: /* CLGRJ */ + case 0x76: /* CRJ */ + case 0x77: /* CLRJ */ + mode = 1; + break; + } + break; + } + + if (mode != 0) + { + /* We'll have to relocate an instruction with a PC-relative field. + First, compute the target. */ + int64_t loffset = 0; + CORE_ADDR target; + if (mode == 1) + { + int16_t soffset = 0; + memcpy (&soffset, buf + 2, 2); + loffset = soffset; + } + else if (mode == 2) + { + int32_t soffset = 0; + memcpy (&soffset, buf + 2, 4); + loffset = soffset; + } + target = oldloc + loffset * 2; + if (!is_64) + target &= 0x7fffffff; + + if (is_bras) + { + /* BRAS or BRASL was used. We cannot just relocate those, since + they save the return address in a register. We can, however, + replace them with a LARL+JG sequence. */ + + /* Make the LARL. */ + int32_t soffset; + buf[0] = 0xc0; + buf[1] &= 0xf0; + loffset = oldloc + ilen - *to; + loffset >>= 1; + soffset = loffset; + if (soffset != loffset && is_64) + return 1; + memcpy (buf + 2, &soffset, 4); + append_insns (to, 6, buf); + + /* Note: this is not fully correct. In 31-bit mode, LARL will write + an address with the top bit 0, while BRAS/BRASL will write it + with top bit 1. It should not matter much, since linux compilers + use BR and not BSM to return from functions, but it could confuse + some poor stack unwinder. */ + + /* We'll now be writing a JG. */ + mode = 2; + buf[0] = 0xc0; + buf[1] = 0xf4; + ilen = 6; + } + + /* Compute the new offset and write it to the buffer. */ + loffset = target - *to; + loffset >>= 1; + + if (mode == 1) + { + int16_t soffset = loffset; + if (soffset != loffset) + return 1; + memcpy (buf + 2, &soffset, 2); + } + else if (mode == 2) + { + int32_t soffset = loffset; + if (soffset != loffset && is_64) + return 1; + memcpy (buf + 2, &soffset, 4); + } + } + append_insns (to, ilen, buf); + return 0; +} + +/* Implementation of linux_target_ops method + "install_fast_tracepoint_jump_pad". */ + +static int +s390_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, + CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + int i; + int64_t loffset; + int32_t offset; + unsigned char jbuf[6] = { 0xc0, 0xf4, 0, 0, 0, 0 }; /* jg ... */ + CORE_ADDR buildaddr = *jump_entry; +#ifdef __s390x__ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + int is_64 = register_size (regcache->tdesc, 0) == 8; + int is_zarch = is_64 || have_hwcap_s390_high_gprs; + int has_vx = have_hwcap_s390_vx; +#else + int is_64 = 0, is_zarch = 0, has_vx = 0; +#endif + CORE_ADDR literals[4] = { + tpaddr, + tpoint, + collector, + lockaddr, + }; + + /* First, store the GPRs. */ + if (is_zarch) + append_insns (&buildaddr, sizeof s390_ft_entry_gpr_zarch, + s390_ft_entry_gpr_zarch); + else + append_insns (&buildaddr, sizeof s390_ft_entry_gpr_esa, + s390_ft_entry_gpr_esa); + + /* Second, misc registers (ARs, PSWM, FPC). PSWA will be stored below. */ + append_insns (&buildaddr, sizeof s390_ft_entry_misc, s390_ft_entry_misc); + + /* Third, FRs or VRs. */ + if (has_vx) + append_insns (&buildaddr, sizeof s390_ft_entry_vr, s390_ft_entry_vr); + else + append_insns (&buildaddr, sizeof s390_ft_entry_fr, s390_ft_entry_fr); + + /* Now, the main part of code - store PSWA, take lock, call collector, + leave lock. First, we'll need to fetch 4 literals. */ + if (is_64) { + unsigned char buf[] = { + 0x07, 0x07, /* nopr %r7 */ + 0x07, 0x07, /* nopr %r7 */ + 0x07, 0x07, /* nopr %r7 */ + 0xa7, 0x15, 0x00, 0x12, /* bras %r1, .Lend */ + 0, 0, 0, 0, 0, 0, 0, 0, /* tpaddr */ + 0, 0, 0, 0, 0, 0, 0, 0, /* tpoint */ + 0, 0, 0, 0, 0, 0, 0, 0, /* collector */ + 0, 0, 0, 0, 0, 0, 0, 0, /* lockaddr */ + /* .Lend: */ + }; + /* Find the proper start place in buf, so that literals will be + aligned. */ + int bufpos = (buildaddr + 2) & 7; + /* Stuff the literals into the buffer. */ + for (i = 0; i < 4; i++) { + uint64_t lit = literals[i]; + memcpy (&buf[sizeof buf - 32 + i * 8], &lit, 8); + } + append_insns (&buildaddr, sizeof buf - bufpos, buf + bufpos); + append_insns (&buildaddr, sizeof s390_ft_main_64, s390_ft_main_64); + } else { + unsigned char buf[] = { + 0x07, 0x07, /* nopr %r7 */ + 0xa7, 0x15, 0x00, 0x0a, /* bras %r1, .Lend */ + 0, 0, 0, 0, /* tpaddr */ + 0, 0, 0, 0, /* tpoint */ + 0, 0, 0, 0, /* collector */ + 0, 0, 0, 0, /* lockaddr */ + /* .Lend: */ + }; + /* Find the proper start place in buf, so that literals will be + aligned. */ + int bufpos = (buildaddr + 2) & 3; + /* First literal will be saved as the PSWA, make sure it has the high bit + set. */ + literals[0] |= 0x80000000; + /* Stuff the literals into the buffer. */ + for (i = 0; i < 4; i++) { + uint32_t lit = literals[i]; + memcpy (&buf[sizeof buf - 16 + i * 4], &lit, 4); + } + append_insns (&buildaddr, sizeof buf - bufpos, buf + bufpos); + append_insns (&buildaddr, sizeof s390_ft_main_31, s390_ft_main_31); + } + + /* Restore FRs or VRs. */ + if (has_vx) + append_insns (&buildaddr, sizeof s390_ft_exit_vr, s390_ft_exit_vr); + else + append_insns (&buildaddr, sizeof s390_ft_exit_fr, s390_ft_exit_fr); + + /* Restore misc registers. */ + append_insns (&buildaddr, sizeof s390_ft_exit_misc, s390_ft_exit_misc); + + /* Restore the GPRs. */ + if (is_zarch) + append_insns (&buildaddr, sizeof s390_ft_exit_gpr_zarch, + s390_ft_exit_gpr_zarch); + else + append_insns (&buildaddr, sizeof s390_ft_exit_gpr_esa, + s390_ft_exit_gpr_esa); + + /* Now, adjust the original instruction to execute in the jump + pad. */ + *adjusted_insn_addr = buildaddr; + if (s390_relocate_instruction (&buildaddr, tpaddr, is_64)) + { + sprintf (err, "E.Could not relocate instruction for tracepoint."); + return 1; + } + *adjusted_insn_addr_end = buildaddr; + + /* Finally, write a jump back to the program. */ + + loffset = (tpaddr + orig_size) - buildaddr; + loffset >>= 1; + offset = loffset; + if (is_64 && offset != loffset) + { + sprintf (err, + "E.Jump back from jump pad too far from tracepoint " + "(offset 0x%" PRIx64 " > int33).", loffset); + return 1; + } + memcpy (jbuf + 2, &offset, 4); + append_insns (&buildaddr, sizeof jbuf, jbuf); + + /* The jump pad is now built. Wire in a jump to our jump pad. This + is always done last (by our caller actually), so that we can + install fast tracepoints with threads running. This relies on + the agent's atomic write support. */ + loffset = *jump_entry - tpaddr; + loffset >>= 1; + offset = loffset; + if (is_64 && offset != loffset) + { + sprintf (err, + "E.Jump back from jump pad too far from tracepoint " + "(offset 0x%" PRIx64 " > int33).", loffset); + return 1; + } + memcpy (jbuf + 2, &offset, 4); + memcpy (jjump_pad_insn, jbuf, sizeof jbuf); + *jjump_pad_insn_size = sizeof jbuf; + + /* Return the end address of our pad. */ + *jump_entry = buildaddr; + + return 0; +} + +/* Implementation of linux_target_ops method + "get_min_fast_tracepoint_insn_len". */ + +static int +s390_get_min_fast_tracepoint_insn_len (void) +{ + /* We only support using 6-byte jumps to reach the tracepoint code. + If the tracepoint buffer were allocated sufficiently close (64kiB) + to the executable code, and the traced instruction itself was close + enough to the beginning, we could use 4-byte jumps, but this doesn't + seem to be worth the effort. */ + return 6; +} + +/* Implementation of linux_target_ops method "get_ipa_tdesc_idx". */ + +static int +s390_get_ipa_tdesc_idx (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + const struct target_desc *tdesc = regcache->tdesc; + +#ifdef __s390x__ + if (tdesc == tdesc_s390x_linux64) + return S390_TDESC_64; + if (tdesc == tdesc_s390x_linux64v1) + return S390_TDESC_64V1; + if (tdesc == tdesc_s390x_linux64v2) + return S390_TDESC_64V2; + if (tdesc == tdesc_s390x_te_linux64) + return S390_TDESC_TE; + if (tdesc == tdesc_s390x_vx_linux64) + return S390_TDESC_VX; + if (tdesc == tdesc_s390x_tevx_linux64) + return S390_TDESC_TEVX; + if (tdesc == tdesc_s390x_gs_linux64) + return S390_TDESC_GS; +#endif + + if (tdesc == tdesc_s390_linux32) + return S390_TDESC_32; + if (tdesc == tdesc_s390_linux32v1) + return S390_TDESC_32V1; + if (tdesc == tdesc_s390_linux32v2) + return S390_TDESC_32V2; + if (tdesc == tdesc_s390_linux64) + return S390_TDESC_64; + if (tdesc == tdesc_s390_linux64v1) + return S390_TDESC_64V1; + if (tdesc == tdesc_s390_linux64v2) + return S390_TDESC_64V2; + if (tdesc == tdesc_s390_te_linux64) + return S390_TDESC_TE; + if (tdesc == tdesc_s390_vx_linux64) + return S390_TDESC_VX; + if (tdesc == tdesc_s390_tevx_linux64) + return S390_TDESC_TEVX; + if (tdesc == tdesc_s390_gs_linux64) + return S390_TDESC_GS; + + return 0; +} + +/* Appends given buffer to current_insn_ptr in the target. */ + +static void +add_insns (const unsigned char *start, int len) +{ + CORE_ADDR buildaddr = current_insn_ptr; + + if (debug_threads) + debug_printf ("Adding %d bytes of insn at %s\n", + len, paddress (buildaddr)); + + append_insns (&buildaddr, len, start); + current_insn_ptr = buildaddr; +} + +/* Register usage in emit: + + - %r0, %r1: temp + - %r2: top of stack (high word for 31-bit) + - %r3: low word of top of stack (for 31-bit) + - %r4, %r5: temp + - %r6, %r7, %r8: don't use + - %r9: saved arg1 + - %r10: saved arg2 + - %r11: frame pointer + - %r12: saved top of stack for void_call_2 (high word for 31-bit) + - %r13: low word of saved top of stack (for 31-bit) + - %r14: return address for calls + - %r15: stack pointer + + */ + +/* The "emit_prologue" emit_ops method for s390. */ + +static void +s390_emit_prologue (void) +{ + static const unsigned char buf[] = { + 0x90, 0x9f, 0xf0, 0x24, /* stm %r9, %r15, 0x24(%r15) */ + 0x18, 0x92, /* lr %r9, %r2 */ + 0x18, 0xa3, /* lr %r10, %r3 */ + 0x18, 0xbf, /* lr %r11, %r15 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_epilogue" emit_ops method for s390. */ + +static void +s390_emit_epilogue (void) +{ + static const unsigned char buf[] = { + 0x90, 0x23, 0xa0, 0x00, /* stm %r2, %r3, 0(%r10) */ + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0x98, 0x9f, 0xb0, 0x24, /* lm %r9, %r15, 0x24(%r11) */ + 0x07, 0xfe, /* br %r14 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_add" emit_ops method for s390. */ + +static void +s390_emit_add (void) +{ + static const unsigned char buf[] = { + 0x5e, 0x30, 0xf0, 0x04, /* al %r3, 4(%r15) */ + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x98, /* al %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_sub" emit_ops method for s390. */ + +static void +s390_emit_sub (void) +{ + static const unsigned char buf[] = { + 0x98, 0x45, 0xf0, 0x00, /* lm %r4, %r5, 0(%r15) */ + 0x1f, 0x53, /* slr %r5, %r3 */ + 0xb9, 0x99, 0x00, 0x42, /* slbr %r4, %r2 */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + 0x18, 0x35, /* lr %r3, %r5 */ + 0x18, 0x24, /* lr %r2, %r4 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_mul" emit_ops method for s390. */ + +static void +s390_emit_mul (void) +{ + emit_error = 1; +} + +/* The "emit_lsh" emit_ops method for s390. */ + +static void +s390_emit_lsh (void) +{ + static const unsigned char buf[] = { + 0x18, 0x43, /* lr %r4, %r3 */ + 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ + 0x8d, 0x20, 0x40, 0x00, /* sldl %r2, 0(%r4) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_rsh_signed" emit_ops method for s390. */ + +static void +s390_emit_rsh_signed (void) +{ + static const unsigned char buf[] = { + 0x18, 0x43, /* lr %r4, %r3 */ + 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ + 0x8e, 0x20, 0x40, 0x00, /* srda %r2, 0(%r4) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_rsh_unsigned" emit_ops method for s390. */ + +static void +s390_emit_rsh_unsigned (void) +{ + static const unsigned char buf[] = { + 0x18, 0x43, /* lr %r4, %r3 */ + 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ + 0x8c, 0x20, 0x40, 0x00, /* srdl %r2, 0(%r4) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_ext" emit_ops method for s390. */ + +static void +s390_emit_ext (int arg) +{ + unsigned char buf[] = { + 0x8d, 0x20, 0x00, (unsigned char) (64 - arg), /* sldl %r2, <64-arg> */ + 0x8e, 0x20, 0x00, (unsigned char) (64 - arg), /* srda %r2, <64-arg> */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_log_not" emit_ops method for s390. */ + +static void +s390_emit_log_not (void) +{ + static const unsigned char buf[] = { + 0x16, 0x23, /* or %r2, %r3 */ + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */ + 0xa7, 0x74, 0x00, 0x04, /* jne .Lskip */ + 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */ + /* .Lskip: */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_and" emit_ops method for s390. */ + +static void +s390_emit_bit_and (void) +{ + static const unsigned char buf[] = { + 0x54, 0x20, 0xf0, 0x00, /* n %r2, 0(%r15) */ + 0x54, 0x30, 0xf0, 0x04, /* n %r3, 4(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_or" emit_ops method for s390. */ + +static void +s390_emit_bit_or (void) +{ + static const unsigned char buf[] = { + 0x56, 0x20, 0xf0, 0x00, /* o %r2, 0(%r15) */ + 0x56, 0x30, 0xf0, 0x04, /* o %r3, 4(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_xor" emit_ops method for s390. */ + +static void +s390_emit_bit_xor (void) +{ + static const unsigned char buf[] = { + 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */ + 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_not" emit_ops method for s390. */ + +static void +s390_emit_bit_not (void) +{ + static const unsigned char buf[] = { + 0xa7, 0x48, 0xff, 0xff, /* lhi %r4, -1 */ + 0x17, 0x24, /* xr %r2, %r4 */ + 0x17, 0x34, /* xr %r3, %r4 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_equal" emit_ops method for s390. */ + +static void +s390_emit_equal (void) +{ + s390_emit_bit_xor (); + s390_emit_log_not (); +} + +/* The "emit_less_signed" emit_ops method for s390. */ + +static void +s390_emit_less_signed (void) +{ + static const unsigned char buf[] = { + 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ + 0xa7, 0x24, 0x00, 0x0c, /* jh .Lless */ + 0xa7, 0x44, 0x00, 0x06, /* jl .Lhigh */ + 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ + 0xa7, 0x24, 0x00, 0x06, /* jh .Lless */ + /* .Lhigh: */ + 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */ + 0xa7, 0xf4, 0x00, 0x04, /* j .Lend */ + /* .Lless: */ + 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */ + /* .Lend: */ + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_less_unsigned" emit_ops method for s390. */ + +static void +s390_emit_less_unsigned (void) +{ + static const unsigned char buf[] = { + 0x55, 0x20, 0xf0, 0x00, /* cl %r2, 0(%r15) */ + 0xa7, 0x24, 0x00, 0x0c, /* jh .Lless */ + 0xa7, 0x44, 0x00, 0x06, /* jl .Lhigh */ + 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ + 0xa7, 0x24, 0x00, 0x06, /* jh .Lless */ + /* .Lhigh: */ + 0xa7, 0x38, 0x00, 0x00, /* lhi %r3, 0 */ + 0xa7, 0xf4, 0x00, 0x04, /* j .Lend */ + /* .Lless: */ + 0xa7, 0x38, 0x00, 0x01, /* lhi %r3, 1 */ + /* .Lend: */ + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_ref" emit_ops method for s390. */ + +static void +s390_emit_ref (int size) +{ + static const unsigned char buf1[] = { + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0x43, 0x30, 0x30, 0x00, /* ic %r3, 0(%r3) */ + }; + static const unsigned char buf2[] = { + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0x48, 0x30, 0x30, 0x00, /* lh %r3, 0(%r3) */ + }; + static const unsigned char buf4[] = { + 0xa7, 0x28, 0x00, 0x00, /* lhi %r2, 0 */ + 0x58, 0x30, 0x30, 0x00, /* l %r3, 0(%r3) */ + }; + static const unsigned char buf8[] = { + 0x98, 0x23, 0x30, 0x00, /* lm %r2, %r3, 0(%r3) */ + }; + switch (size) + { + case 1: + add_insns (buf1, sizeof buf1); + break; + case 2: + add_insns (buf2, sizeof buf2); + break; + case 4: + add_insns (buf4, sizeof buf4); + break; + case 8: + add_insns (buf8, sizeof buf8); + break; + default: + emit_error = 1; + } +} + +/* The "emit_if_goto" emit_ops method for s390. */ + +static void +s390_emit_if_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x16, 0x23, /* or %r2, %r3 */ + 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00 /* jgne */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 12; + if (size_p) + *size_p = 4; +} + +/* The "emit_goto" emit_ops method for s390 and s390x. */ + +static void +s390_emit_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 2; + if (size_p) + *size_p = 4; +} + +/* The "write_goto_address" emit_ops method for s390 and s390x. */ + +static void +s390_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) +{ + long diff = ((long) (to - (from - 2))) / 2; + int sdiff = diff; + unsigned char buf[sizeof sdiff]; + + /* We're only doing 4-byte sizes at the moment. */ + if (size != sizeof sdiff || sdiff != diff) + { + emit_error = 1; + return; + } + + memcpy (buf, &sdiff, sizeof sdiff); + target_write_memory (from, buf, sizeof sdiff); +} + +/* Preparation for emitting a literal pool of given size. Loads the address + of the pool into %r1, and jumps over it. Called should emit the pool data + immediately afterwards. Used for both s390 and s390x. */ + +static void +s390_emit_litpool (int size) +{ + static const unsigned char nop[] = { + 0x07, 0x07, + }; + unsigned char buf[] = { + 0xa7, 0x15, 0x00, + (unsigned char) ((size + 4) / 2), /* bras %r1, .Lend+size */ + /* .Lend: */ + }; + if (size == 4) + { + /* buf needs to start at even halfword for litpool to be aligned */ + if (current_insn_ptr & 2) + add_insns (nop, sizeof nop); + } + else + { + while ((current_insn_ptr & 6) != 4) + add_insns (nop, sizeof nop); + } + add_insns (buf, sizeof buf); +} + +/* The "emit_const" emit_ops method for s390. */ + +static void +s390_emit_const (LONGEST num) +{ + unsigned long long n = num; + unsigned char buf_s[] = { + /* lhi %r3, */ + 0xa7, 0x38, + (unsigned char) (num >> 8), (unsigned char) num, + /* xr %r2, %r2 */ + 0x17, 0x22, + }; + static const unsigned char buf_l[] = { + 0x98, 0x23, 0x10, 0x00, /* lm %r2, %r3, 0(%r1) */ + }; + if (num < 0x8000 && num >= 0) + { + add_insns (buf_s, sizeof buf_s); + } + else + { + s390_emit_litpool (8); + add_insns ((unsigned char *) &n, sizeof n); + add_insns (buf_l, sizeof buf_l); + } +} + +/* The "emit_call" emit_ops method for s390. */ + +static void +s390_emit_call (CORE_ADDR fn) +{ + unsigned int n = fn; + static const unsigned char buf[] = { + 0x58, 0x10, 0x10, 0x00, /* l %r1, 0(%r1) */ + 0xa7, 0xfa, 0xff, 0xa0, /* ahi %r15, -0x60 */ + 0x0d, 0xe1, /* basr %r14, %r1 */ + 0xa7, 0xfa, 0x00, 0x60, /* ahi %r15, 0x60 */ + }; + s390_emit_litpool (4); + add_insns ((unsigned char *) &n, sizeof n); + add_insns (buf, sizeof buf); +} + +/* The "emit_reg" emit_ops method for s390. */ + +static void +s390_emit_reg (int reg) +{ + unsigned char bufpre[] = { + /* lr %r2, %r9 */ + 0x18, 0x29, + /* lhi %r3, */ + 0xa7, 0x38, (unsigned char) (reg >> 8), (unsigned char) reg, + }; + add_insns (bufpre, sizeof bufpre); + s390_emit_call (get_raw_reg_func_addr ()); +} + +/* The "emit_pop" emit_ops method for s390. */ + +static void +s390_emit_pop (void) +{ + static const unsigned char buf[] = { + 0x98, 0x23, 0xf0, 0x00, /* lm %r2, %r3, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_stack_flush" emit_ops method for s390. */ + +static void +s390_emit_stack_flush (void) +{ + static const unsigned char buf[] = { + 0xa7, 0xfa, 0xff, 0xf8, /* ahi %r15, -8 */ + 0x90, 0x23, 0xf0, 0x00, /* stm %r2, %r3, 0(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_zero_ext" emit_ops method for s390. */ + +static void +s390_emit_zero_ext (int arg) +{ + unsigned char buf[] = { + 0x8d, 0x20, 0x00, (unsigned char) (64 - arg), /* sldl %r2, <64-arg> */ + 0x8c, 0x20, 0x00, (unsigned char) (64 - arg), /* srdl %r2, <64-arg> */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_swap" emit_ops method for s390. */ + +static void +s390_emit_swap (void) +{ + static const unsigned char buf[] = { + 0x98, 0x45, 0xf0, 0x00, /* lm %r4, %r5, 0(%r15) */ + 0x90, 0x23, 0xf0, 0x00, /* stm %r2, %r3, 0(%r15) */ + 0x18, 0x24, /* lr %r2, %r4 */ + 0x18, 0x35, /* lr %r3, %r5 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_stack_adjust" emit_ops method for s390. */ + +static void +s390_emit_stack_adjust (int n) +{ + unsigned char buf[] = { + /* ahi %r15, 8*n */ + 0xa7, 0xfa, + (unsigned char ) (n * 8 >> 8), (unsigned char) (n * 8), + }; + add_insns (buf, sizeof buf); +} + +/* Sets %r2 to a 32-bit constant. */ + +static void +s390_emit_set_r2 (int arg1) +{ + unsigned char buf_s[] = { + /* lhi %r2, */ + 0xa7, 0x28, (unsigned char) (arg1 >> 8), (unsigned char) arg1, + }; + static const unsigned char buf_l[] = { + 0x58, 0x20, 0x10, 0x00, /* l %r2, 0(%r1) */ + }; + if (arg1 < 0x8000 && arg1 >= -0x8000) + { + add_insns (buf_s, sizeof buf_s); + } + else + { + s390_emit_litpool (4); + add_insns ((unsigned char *) &arg1, sizeof arg1); + add_insns (buf_l, sizeof buf_l); + } +} + +/* The "emit_int_call_1" emit_ops method for s390. */ + +static void +s390_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + /* FN's prototype is `LONGEST(*fn)(int)'. */ + s390_emit_set_r2 (arg1); + s390_emit_call (fn); +} + +/* The "emit_void_call_2" emit_ops method for s390. */ + +static void +s390_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + /* FN's prototype is `void(*fn)(int,LONGEST)'. */ + static const unsigned char buf[] = { + 0x18, 0xc2, /* lr %r12, %r2 */ + 0x18, 0xd3, /* lr %r13, %r3 */ + 0x18, 0x43, /* lr %r4, %r3 */ + 0x18, 0x32, /* lr %r3, %r2 */ + }; + static const unsigned char buf2[] = { + 0x18, 0x2c, /* lr %r2, %r12 */ + 0x18, 0x3d, /* lr %r3, %r13 */ + }; + add_insns (buf, sizeof buf); + s390_emit_set_r2 (arg1); + s390_emit_call (fn); + add_insns (buf2, sizeof buf2); +} + +/* The "emit_eq_goto" emit_ops method for s390. */ + +static void +s390_emit_eq_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */ + 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */ + 0x16, 0x23, /* or %r2, %r3 */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0x84, 0x00, 0x00, 0x00, 0x00, /* jge */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 20; + if (size_p) + *size_p = 4; +} + +/* The "emit_ne_goto" emit_ops method for s390. */ + +static void +s390_emit_ne_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x57, 0x20, 0xf0, 0x00, /* x %r2, 0(%r15) */ + 0x57, 0x30, 0xf0, 0x04, /* x %r3, 4(%r15) */ + 0x16, 0x23, /* or %r2, %r3 */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 20; + if (size_p) + *size_p = 4; +} + +/* The "emit_lt_goto" emit_ops method for s390. */ + +static void +s390_emit_lt_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ + 0xa7, 0x24, 0x00, 0x0e, /* jh .Ltrue */ + 0xa7, 0x44, 0x00, 0x06, /* jl .Lfalse */ + 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ + 0xa7, 0x24, 0x00, 0x08, /* jh .Ltrue */ + /* .Lfalse: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ + /* .Ltrue: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ + /* .Lend: */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 42; + if (size_p) + *size_p = 4; +} + +/* The "emit_le_goto" emit_ops method for s390. */ + +static void +s390_emit_le_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ + 0xa7, 0x24, 0x00, 0x0e, /* jh .Ltrue */ + 0xa7, 0x44, 0x00, 0x06, /* jl .Lfalse */ + 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ + 0xa7, 0xa4, 0x00, 0x08, /* jhe .Ltrue */ + /* .Lfalse: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ + /* .Ltrue: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ + /* .Lend: */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 42; + if (size_p) + *size_p = 4; +} + +/* The "emit_gt_goto" emit_ops method for s390. */ + +static void +s390_emit_gt_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ + 0xa7, 0x44, 0x00, 0x0e, /* jl .Ltrue */ + 0xa7, 0x24, 0x00, 0x06, /* jh .Lfalse */ + 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ + 0xa7, 0x44, 0x00, 0x08, /* jl .Ltrue */ + /* .Lfalse: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ + /* .Ltrue: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ + /* .Lend: */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 42; + if (size_p) + *size_p = 4; +} + +/* The "emit_ge_goto" emit_ops method for s390. */ + +static void +s390_emit_ge_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0x59, 0x20, 0xf0, 0x00, /* c %r2, 0(%r15) */ + 0xa7, 0x44, 0x00, 0x0e, /* jl .Ltrue */ + 0xa7, 0x24, 0x00, 0x06, /* jh .Lfalse */ + 0x55, 0x30, 0xf0, 0x04, /* cl %r3, 4(%r15) */ + 0xa7, 0xc4, 0x00, 0x08, /* jle .Ltrue */ + /* .Lfalse: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xa7, 0xf4, 0x00, 0x09, /* j .Lend */ + /* .Ltrue: */ + 0x98, 0x23, 0xf0, 0x08, /* lm %r2, %r3, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg */ + /* .Lend: */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 42; + if (size_p) + *size_p = 4; +} + +/* The "emit_ops" structure for s390. Named _impl to avoid name + collision with s390_emit_ops function. */ + +static struct emit_ops s390_emit_ops_impl = + { + s390_emit_prologue, + s390_emit_epilogue, + s390_emit_add, + s390_emit_sub, + s390_emit_mul, + s390_emit_lsh, + s390_emit_rsh_signed, + s390_emit_rsh_unsigned, + s390_emit_ext, + s390_emit_log_not, + s390_emit_bit_and, + s390_emit_bit_or, + s390_emit_bit_xor, + s390_emit_bit_not, + s390_emit_equal, + s390_emit_less_signed, + s390_emit_less_unsigned, + s390_emit_ref, + s390_emit_if_goto, + s390_emit_goto, + s390_write_goto_address, + s390_emit_const, + s390_emit_call, + s390_emit_reg, + s390_emit_pop, + s390_emit_stack_flush, + s390_emit_zero_ext, + s390_emit_swap, + s390_emit_stack_adjust, + s390_emit_int_call_1, + s390_emit_void_call_2, + s390_emit_eq_goto, + s390_emit_ne_goto, + s390_emit_lt_goto, + s390_emit_le_goto, + s390_emit_gt_goto, + s390_emit_ge_goto + }; + +#ifdef __s390x__ + +/* The "emit_prologue" emit_ops method for s390x. */ + +static void +s390x_emit_prologue (void) +{ + static const unsigned char buf[] = { + 0xeb, 0x9f, 0xf0, 0x48, 0x00, 0x24, /* stmg %r9, %r15, 0x48(%r15) */ + 0xb9, 0x04, 0x00, 0x92, /* lgr %r9, %r2 */ + 0xb9, 0x04, 0x00, 0xa3, /* lgr %r10, %r3 */ + 0xb9, 0x04, 0x00, 0xbf, /* lgr %r11, %r15 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_epilogue" emit_ops method for s390x. */ + +static void +s390x_emit_epilogue (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xa0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r10) */ + 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */ + 0xeb, 0x9f, 0xf0, 0x48, 0x00, 0x04, /* lmg %r9, %r15, 0x48(%r15) */ + 0x07, 0xfe, /* br %r14 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_add" emit_ops method for s390x. */ + +static void +s390x_emit_add (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x0a, /* alg %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_sub" emit_ops method for s390x. */ + +static void +s390x_emit_sub (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ + 0xb9, 0x0b, 0x00, 0x32, /* slgr %r3, %r2 */ + 0xb9, 0x04, 0x00, 0x23, /* lgr %r2, %r3 */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_mul" emit_ops method for s390x. */ + +static void +s390x_emit_mul (void) +{ + emit_error = 1; +} + +/* The "emit_lsh" emit_ops method for s390x. */ + +static void +s390x_emit_lsh (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ + 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0d, /* sllg %r2, %r3, 0(%r2) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_rsh_signed" emit_ops method for s390x. */ + +static void +s390x_emit_rsh_signed (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ + 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0a, /* srag %r2, %r3, 0(%r2) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_rsh_unsigned" emit_ops method for s390x. */ + +static void +s390x_emit_rsh_unsigned (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ + 0xeb, 0x23, 0x20, 0x00, 0x00, 0x0c, /* srlg %r2, %r3, 0(%r2) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_ext" emit_ops method for s390x. */ + +static void +s390x_emit_ext (int arg) +{ + unsigned char buf[] = { + /* sllg %r2, %r2, <64-arg> */ + 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0d, + /* srag %r2, %r2, <64-arg> */ + 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0a, + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_log_not" emit_ops method for s390x. */ + +static void +s390x_emit_log_not (void) +{ + static const unsigned char buf[] = { + 0xb9, 0x00, 0x00, 0x22, /* lpgr %r2, %r2 */ + 0xa7, 0x2b, 0xff, 0xff, /* aghi %r2, -1 */ + 0xeb, 0x22, 0x00, 0x3f, 0x00, 0x0c, /* srlg %r2, %r2, 63 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_and" emit_ops method for s390x. */ + +static void +s390x_emit_bit_and (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x80, /* ng %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_or" emit_ops method for s390x. */ + +static void +s390x_emit_bit_or (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x81, /* og %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_xor" emit_ops method for s390x. */ + +static void +s390x_emit_bit_xor (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x82, /* xg %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_bit_not" emit_ops method for s390x. */ + +static void +s390x_emit_bit_not (void) +{ + static const unsigned char buf[] = { + 0xa7, 0x39, 0xff, 0xff, /* lghi %r3, -1 */ + 0xb9, 0x82, 0x00, 0x23, /* xgr %r2, %r3 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_equal" emit_ops method for s390x. */ + +static void +s390x_emit_equal (void) +{ + s390x_emit_bit_xor (); + s390x_emit_log_not (); +} + +/* The "emit_less_signed" emit_ops method for s390x. */ + +static void +s390x_emit_less_signed (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xa7, 0x29, 0x00, 0x01, /* lghi %r2, 1 */ + 0xa7, 0x24, 0x00, 0x04, /* jh .Lend */ + 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */ + /* .Lend: */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_less_unsigned" emit_ops method for s390x. */ + +static void +s390x_emit_less_unsigned (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x21, /* clg %r2, 0(%r15) */ + 0xa7, 0x29, 0x00, 0x01, /* lghi %r2, 1 */ + 0xa7, 0x24, 0x00, 0x04, /* jh .Lend */ + 0xa7, 0x29, 0x00, 0x00, /* lghi %r2, 0 */ + /* .Lend: */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_ref" emit_ops method for s390x. */ + +static void +s390x_emit_ref (int size) +{ + static const unsigned char buf1[] = { + 0xe3, 0x20, 0x20, 0x00, 0x00, 0x90, /* llgc %r2, 0(%r2) */ + }; + static const unsigned char buf2[] = { + 0xe3, 0x20, 0x20, 0x00, 0x00, 0x91 /* llgh %r2, 0(%r2) */ + }; + static const unsigned char buf4[] = { + 0xe3, 0x20, 0x20, 0x00, 0x00, 0x16, /* llgf %r2, 0(%r2) */ + }; + static const unsigned char buf8[] = { + 0xe3, 0x20, 0x20, 0x00, 0x00, 0x04, /* lg %r2, 0(%r2) */ + }; + switch (size) + { + case 1: + add_insns (buf1, sizeof buf1); + break; + case 2: + add_insns (buf2, sizeof buf2); + break; + case 4: + add_insns (buf4, sizeof buf4); + break; + case 8: + add_insns (buf8, sizeof buf8); + break; + default: + emit_error = 1; + } +} + +/* The "emit_if_goto" emit_ops method for s390x. */ + +static void +s390x_emit_if_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xb9, 0x02, 0x00, 0x22, /* ltgr %r2, %r2 */ + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x04, /* lg %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 16; + if (size_p) + *size_p = 4; +} + +/* The "emit_const" emit_ops method for s390x. */ + +static void +s390x_emit_const (LONGEST num) +{ + unsigned long long n = num; + unsigned char buf_s[] = { + /* lghi %r2, */ + 0xa7, 0x29, (unsigned char) (num >> 8), (unsigned char) num, + }; + static const unsigned char buf_l[] = { + 0xe3, 0x20, 0x10, 0x00, 0x00, 0x04, /* lg %r2, 0(%r1) */ + }; + if (num < 0x8000 && num >= -0x8000) + { + add_insns (buf_s, sizeof buf_s); + } + else + { + s390_emit_litpool (8); + add_insns ((unsigned char *) &n, sizeof n); + add_insns (buf_l, sizeof buf_l); + } +} + +/* The "emit_call" emit_ops method for s390x. */ + +static void +s390x_emit_call (CORE_ADDR fn) +{ + unsigned long n = fn; + static const unsigned char buf[] = { + 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, /* lg %r1, 0(%r1) */ + 0xa7, 0xfb, 0xff, 0x60, /* aghi %r15, -0xa0 */ + 0x0d, 0xe1, /* basr %r14, %r1 */ + 0xa7, 0xfb, 0x00, 0xa0, /* aghi %r15, 0xa0 */ + }; + s390_emit_litpool (8); + add_insns ((unsigned char *) &n, sizeof n); + add_insns (buf, sizeof buf); +} + +/* The "emit_reg" emit_ops method for s390x. */ + +static void +s390x_emit_reg (int reg) +{ + unsigned char buf[] = { + /* lgr %r2, %r9 */ + 0xb9, 0x04, 0x00, 0x29, + /* lghi %r3, */ + 0xa7, 0x39, (unsigned char) (reg >> 8), (unsigned char) reg, + }; + add_insns (buf, sizeof buf); + s390x_emit_call (get_raw_reg_func_addr ()); +} + +/* The "emit_pop" emit_ops method for s390x. */ + +static void +s390x_emit_pop (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x04, /* lg %r2, 0(%r15) */ + 0x41, 0xf0, 0xf0, 0x08, /* la %r15, 8(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_stack_flush" emit_ops method for s390x. */ + +static void +s390x_emit_stack_flush (void) +{ + static const unsigned char buf[] = { + 0xa7, 0xfb, 0xff, 0xf8, /* aghi %r15, -8 */ + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r15) */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_zero_ext" emit_ops method for s390x. */ + +static void +s390x_emit_zero_ext (int arg) +{ + unsigned char buf[] = { + /* sllg %r2, %r2, <64-arg> */ + 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0d, + /* srlg %r2, %r2, <64-arg> */ + 0xeb, 0x22, 0x00, (unsigned char) (64 - arg), 0x00, 0x0c, + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_swap" emit_ops method for s390x. */ + +static void +s390x_emit_swap (void) +{ + static const unsigned char buf[] = { + 0xe3, 0x30, 0xf0, 0x00, 0x00, 0x04, /* lg %r3, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x24, /* stg %r2, 0(%r15) */ + 0xb9, 0x04, 0x00, 0x23, /* lgr %r2, %r3 */ + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_stack_adjust" emit_ops method for s390x. */ + +static void +s390x_emit_stack_adjust (int n) +{ + unsigned char buf[] = { + /* aghi %r15, 8*n */ + 0xa7, 0xfb, + (unsigned char) (n * 8 >> 8), (unsigned char) (n * 8), + }; + add_insns (buf, sizeof buf); +} + +/* The "emit_int_call_1" emit_ops method for s390x. */ + +static void +s390x_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + /* FN's prototype is `LONGEST(*fn)(int)'. */ + s390x_emit_const (arg1); + s390x_emit_call (fn); +} + +/* The "emit_void_call_2" emit_ops method for s390x. */ + +static void +s390x_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + /* FN's prototype is `void(*fn)(int,LONGEST)'. */ + static const unsigned char buf[] = { + 0xb9, 0x04, 0x00, 0x32, /* lgr %r3, %r2 */ + 0xb9, 0x04, 0x00, 0xc2, /* lgr %r12, %r2 */ + }; + static const unsigned char buf2[] = { + 0xb9, 0x04, 0x00, 0x2c, /* lgr %r2, %r12 */ + }; + add_insns (buf, sizeof buf); + s390x_emit_const (arg1); + s390x_emit_call (fn); + add_insns (buf2, sizeof buf2); +} + +/* The "emit_eq_goto" emit_ops method for s390x. */ + +static void +s390x_emit_eq_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0x84, 0x00, 0x00, 0x00, 0x00, /* jge */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +/* The "emit_ne_goto" emit_ops method for s390x. */ + +static void +s390x_emit_ne_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, /* jgne */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +/* The "emit_lt_goto" emit_ops method for s390x. */ + +static void +s390x_emit_lt_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0x24, 0x00, 0x00, 0x00, 0x00, /* jgh */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +/* The "emit_le_goto" emit_ops method for s390x. */ + +static void +s390x_emit_le_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0xa4, 0x00, 0x00, 0x00, 0x00, /* jghe */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +/* The "emit_gt_goto" emit_ops method for s390x. */ + +static void +s390x_emit_gt_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0x44, 0x00, 0x00, 0x00, 0x00, /* jgl */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +/* The "emit_ge_goto" emit_ops method for s390x. */ + +static void +s390x_emit_ge_goto (int *offset_p, int *size_p) +{ + static const unsigned char buf[] = { + 0xe3, 0x20, 0xf0, 0x00, 0x00, 0x20, /* cg %r2, 0(%r15) */ + 0xe3, 0x20, 0xf0, 0x08, 0x00, 0x04, /* lg %r2, 8(%r15) */ + 0x41, 0xf0, 0xf0, 0x10, /* la %r15, 16(%r15) */ + 0xc0, 0xc4, 0x00, 0x00, 0x00, 0x00, /* jgle */ + }; + add_insns (buf, sizeof buf); + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +/* The "emit_ops" structure for s390x. */ + +static struct emit_ops s390x_emit_ops = + { + s390x_emit_prologue, + s390x_emit_epilogue, + s390x_emit_add, + s390x_emit_sub, + s390x_emit_mul, + s390x_emit_lsh, + s390x_emit_rsh_signed, + s390x_emit_rsh_unsigned, + s390x_emit_ext, + s390x_emit_log_not, + s390x_emit_bit_and, + s390x_emit_bit_or, + s390x_emit_bit_xor, + s390x_emit_bit_not, + s390x_emit_equal, + s390x_emit_less_signed, + s390x_emit_less_unsigned, + s390x_emit_ref, + s390x_emit_if_goto, + s390_emit_goto, + s390_write_goto_address, + s390x_emit_const, + s390x_emit_call, + s390x_emit_reg, + s390x_emit_pop, + s390x_emit_stack_flush, + s390x_emit_zero_ext, + s390x_emit_swap, + s390x_emit_stack_adjust, + s390x_emit_int_call_1, + s390x_emit_void_call_2, + s390x_emit_eq_goto, + s390x_emit_ne_goto, + s390x_emit_lt_goto, + s390x_emit_le_goto, + s390x_emit_gt_goto, + s390x_emit_ge_goto + }; +#endif + +/* The "emit_ops" linux_target_ops method. */ + +static struct emit_ops * +s390_emit_ops (void) +{ +#ifdef __s390x__ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + + if (register_size (regcache->tdesc, 0) == 8) + return &s390x_emit_ops; + else +#endif + return &s390_emit_ops_impl; +} + +struct linux_target_ops the_low_target = { + s390_arch_setup, + s390_regs_info, + s390_cannot_fetch_register, + s390_cannot_store_register, + NULL, /* fetch_register */ + s390_get_pc, + s390_set_pc, + NULL, /* breakpoint_kind_from_pc */ + s390_sw_breakpoint_from_kind, + NULL, + s390_breakpoint_len, + s390_breakpoint_at, + s390_supports_z_point_type, + NULL, + NULL, + NULL, + NULL, + s390_collect_ptrace_register, + s390_supply_ptrace_register, + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + s390_supports_tracepoints, + s390_get_thread_area, + s390_install_fast_tracepoint_jump_pad, + s390_emit_ops, + s390_get_min_fast_tracepoint_insn_len, + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + s390_supports_hardware_single_step, + NULL, /* get_syscall_trapinfo */ + s390_get_ipa_tdesc_idx, +}; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + + init_registers_s390_linux32 (); + init_registers_s390_linux32v1 (); + init_registers_s390_linux32v2 (); + init_registers_s390_linux64 (); + init_registers_s390_linux64v1 (); + init_registers_s390_linux64v2 (); + init_registers_s390_te_linux64 (); + init_registers_s390_vx_linux64 (); + init_registers_s390_tevx_linux64 (); + init_registers_s390_gs_linux64 (); +#ifdef __s390x__ + init_registers_s390x_linux64 (); + init_registers_s390x_linux64v1 (); + init_registers_s390x_linux64v2 (); + init_registers_s390x_te_linux64 (); + init_registers_s390x_vx_linux64 (); + init_registers_s390x_tevx_linux64 (); + init_registers_s390x_gs_linux64 (); +#endif + + initialize_regsets_info (&s390_regsets_info); + initialize_regsets_info (&s390_regsets_info_3264); +} diff --git a/gdbserver/linux-s390-tdesc.h b/gdbserver/linux-s390-tdesc.h new file mode 100644 index 00000000000..e02d853bf5b --- /dev/null +++ b/gdbserver/linux-s390-tdesc.h @@ -0,0 +1,116 @@ +/* Low level support for s390, shared between gdbserver and IPA. + + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_S390_TDESC_H +#define GDBSERVER_LINUX_S390_TDESC_H + +/* Note: since IPA obviously knows what ABI it's running on (s390 vs s390x), + it's sufficient to pass only the register set here. This, together with + the ABI known at IPA compile time, maps to a tdesc. */ + +enum s390_linux_tdesc { + S390_TDESC_32, + S390_TDESC_32V1, + S390_TDESC_32V2, + S390_TDESC_64, + S390_TDESC_64V1, + S390_TDESC_64V2, + S390_TDESC_TE, + S390_TDESC_VX, + S390_TDESC_TEVX, + S390_TDESC_GS, +}; + +#ifdef __s390x__ + +/* Defined in auto-generated file s390x-linux64.c. */ +void init_registers_s390x_linux64 (void); +extern const struct target_desc *tdesc_s390x_linux64; + +/* Defined in auto-generated file s390x-linux64v1.c. */ +void init_registers_s390x_linux64v1 (void); +extern const struct target_desc *tdesc_s390x_linux64v1; + +/* Defined in auto-generated file s390x-linux64v2.c. */ +void init_registers_s390x_linux64v2 (void); +extern const struct target_desc *tdesc_s390x_linux64v2; + +/* Defined in auto-generated file s390x-te-linux64.c. */ +void init_registers_s390x_te_linux64 (void); +extern const struct target_desc *tdesc_s390x_te_linux64; + +/* Defined in auto-generated file s390x-vx-linux64.c. */ +void init_registers_s390x_vx_linux64 (void); +extern const struct target_desc *tdesc_s390x_vx_linux64; + +/* Defined in auto-generated file s390x-tevx-linux64.c. */ +void init_registers_s390x_tevx_linux64 (void); +extern const struct target_desc *tdesc_s390x_tevx_linux64; + +/* Defined in auto-generated file s390x-gs-linux64.c. */ +void init_registers_s390x_gs_linux64 (void); +extern const struct target_desc *tdesc_s390x_gs_linux64; + +#endif + +#if !defined __s390x__ || !defined IN_PROCESS_AGENT + +/* Defined in auto-generated file s390-linux32.c. */ +void init_registers_s390_linux32 (void); +extern const struct target_desc *tdesc_s390_linux32; + +/* Defined in auto-generated file s390-linux32v1.c. */ +void init_registers_s390_linux32v1 (void); +extern const struct target_desc *tdesc_s390_linux32v1; + +/* Defined in auto-generated file s390-linux32v2.c. */ +void init_registers_s390_linux32v2 (void); +extern const struct target_desc *tdesc_s390_linux32v2; + +/* Defined in auto-generated file s390-linux64.c. */ +void init_registers_s390_linux64 (void); +extern const struct target_desc *tdesc_s390_linux64; + +/* Defined in auto-generated file s390-linux64v1.c. */ +void init_registers_s390_linux64v1 (void); +extern const struct target_desc *tdesc_s390_linux64v1; + +/* Defined in auto-generated file s390-linux64v2.c. */ +void init_registers_s390_linux64v2 (void); +extern const struct target_desc *tdesc_s390_linux64v2; + +/* Defined in auto-generated file s390-te-linux64.c. */ +void init_registers_s390_te_linux64 (void); +extern const struct target_desc *tdesc_s390_te_linux64; + +/* Defined in auto-generated file s390-vx-linux64.c. */ +void init_registers_s390_vx_linux64 (void); +extern const struct target_desc *tdesc_s390_vx_linux64; + +/* Defined in auto-generated file s390-tevx-linux64.c. */ +void init_registers_s390_tevx_linux64 (void); +extern const struct target_desc *tdesc_s390_tevx_linux64; + +/* Defined in auto-generated file s390-gs-linux64.c. */ +void init_registers_s390_gs_linux64 (void); +extern const struct target_desc *tdesc_s390_gs_linux64; + +#endif + +#endif /* GDBSERVER_LINUX_S390_TDESC_H */ diff --git a/gdbserver/linux-sh-low.c b/gdbserver/linux-sh-low.c new file mode 100644 index 00000000000..abe71ff4766 --- /dev/null +++ b/gdbserver/linux-sh-low.c @@ -0,0 +1,189 @@ +/* GNU/Linux/SH specific low level interface, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +/* Defined in auto-generated file reg-sh.c. */ +void init_registers_sh (void); +extern const struct target_desc *tdesc_sh; + +#ifdef HAVE_SYS_REG_H +#include +#endif + +#include + +#define sh_num_regs 41 + +/* Currently, don't check/send MQ. */ +static int sh_regmap[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, + + REG_PC*4, REG_PR*4, REG_GBR*4, -1, + REG_MACH*4, REG_MACL*4, REG_SR*4, + REG_FPUL*4, REG_FPSCR*4, + + REG_FPREG0*4+0, REG_FPREG0*4+4, REG_FPREG0*4+8, REG_FPREG0*4+12, + REG_FPREG0*4+16, REG_FPREG0*4+20, REG_FPREG0*4+24, REG_FPREG0*4+28, + REG_FPREG0*4+32, REG_FPREG0*4+36, REG_FPREG0*4+40, REG_FPREG0*4+44, + REG_FPREG0*4+48, REG_FPREG0*4+52, REG_FPREG0*4+56, REG_FPREG0*4+60, +}; + +static int +sh_cannot_store_register (int regno) +{ + return 0; +} + +static int +sh_cannot_fetch_register (int regno) +{ + return 0; +} + +/* Correct in either endianness, obviously. */ +static const unsigned short sh_breakpoint = 0xc3c3; +#define sh_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +sh_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = sh_breakpoint_len; + return (const gdb_byte *) &sh_breakpoint; +} + +static int +sh_breakpoint_at (CORE_ADDR where) +{ + unsigned short insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 2); + if (insn == sh_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +/* Support for hardware single step. */ + +static int +sh_supports_hardware_single_step (void) +{ + return 1; +} + +/* Provide only a fill function for the general register set. ps_lgetregs + will use this for NPTL support. */ + +static void sh_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + + for (i = 0; i < 23; i++) + if (sh_regmap[i] != -1) + collect_register (regcache, i, (char *) buf + sh_regmap[i]); +} + +static struct regset_info sh_regsets[] = { + { 0, 0, 0, 0, GENERAL_REGS, sh_fill_gregset, NULL }, + NULL_REGSET +}; + +static struct regsets_info sh_regsets_info = + { + sh_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info sh_usrregs_info = + { + sh_num_regs, + sh_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &sh_usrregs_info, + &sh_regsets_info + }; + +static const struct regs_info * +sh_regs_info (void) +{ + return ®s_info; +} + +static void +sh_arch_setup (void) +{ + current_process ()->tdesc = tdesc_sh; +} + +struct linux_target_ops the_low_target = { + sh_arch_setup, + sh_regs_info, + sh_cannot_fetch_register, + sh_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + sh_sw_breakpoint_from_kind, + NULL, + 0, + sh_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + sh_supports_hardware_single_step, +}; + +void +initialize_low_arch (void) +{ + init_registers_sh (); + + initialize_regsets_info (&sh_regsets_info); +} diff --git a/gdbserver/linux-sparc-low.c b/gdbserver/linux-sparc-low.c new file mode 100644 index 00000000000..cfa76c0b8e6 --- /dev/null +++ b/gdbserver/linux-sparc-low.c @@ -0,0 +1,326 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +#include "nat/gdb_ptrace.h" + +#include "gdb_proc_service.h" + +/* The stack pointer is offset from the stack frame by a BIAS of 2047 + (0x7ff) for 64-bit code. BIAS is likely to be defined on SPARC + hosts, so undefine it first. */ +#undef BIAS +#define BIAS 2047 + +#ifdef HAVE_SYS_REG_H +#include +#endif + +#define INSN_SIZE 4 + +#define SPARC_R_REGS_NUM 32 +#define SPARC_F_REGS_NUM 48 +#define SPARC_CONTROL_REGS_NUM 6 + +#define sparc_num_regs \ + (SPARC_R_REGS_NUM + SPARC_F_REGS_NUM + SPARC_CONTROL_REGS_NUM) + +/* Each offset is multiplied by 8, because of the register size. + These offsets apply to the buffer sent/filled by ptrace. + Additionally, the array elements order corresponds to the .dat file, and the + gdb's registers enumeration order. */ + +static int sparc_regmap[] = { + /* These offsets correspond to GET/SETREGSET. */ + -1, 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, /* g0 .. g7 */ + 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, /* o0 .. o5, sp, o7 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* l0 .. l7 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* i0 .. i5, fp, i7 */ + + /* Floating point registers offsets correspond to GET/SETFPREGSET. */ + 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4, /* f0 .. f7 */ + 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4, /* f8 .. f15 */ + 16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4, /* f16 .. f23 */ + 24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4, /* f24 .. f31 */ + + /* F32 offset starts next to f31: 31*4+4 = 16 * 8. */ + 16*8, 17*8, 18*8, 19*8, 20*8, 21*8, 22*8, 23*8, /* f32 .. f46 */ + 24*8, 25*8, 26*8, 27*8, 28*8, 29*8, 30*8, 31*8, /* f48 .. f62 */ + + 17 *8, /* pc */ + 18 *8, /* npc */ + 16 *8, /* state */ + /* FSR offset also corresponds to GET/SETFPREGSET, ans is placed + next to f62. */ + 32 *8, /* fsr */ + -1, /* fprs */ + /* Y register is 32-bits length, but gdb takes care of that. */ + 19 *8, /* y */ + +}; + + +struct regs_range_t +{ + int regno_start; + int regno_end; +}; + +static const struct regs_range_t gregs_ranges[] = { + { 0, 31 }, /* g0 .. i7 */ + { 80, 82 }, /* pc .. state */ + { 84, 85 } /* fprs .. y */ +}; + +#define N_GREGS_RANGES (sizeof (gregs_ranges) / sizeof (struct regs_range_t)) + +static const struct regs_range_t fpregs_ranges[] = { + { 32, 79 }, /* f0 .. f62 */ + { 83, 83 } /* fsr */ +}; + +#define N_FPREGS_RANGES (sizeof (fpregs_ranges) / sizeof (struct regs_range_t)) + +/* Defined in auto-generated file reg-sparc64.c. */ +void init_registers_sparc64 (void); +extern const struct target_desc *tdesc_sparc64; + +static int +sparc_cannot_store_register (int regno) +{ + return (regno >= sparc_num_regs || sparc_regmap[regno] == -1); +} + +static int +sparc_cannot_fetch_register (int regno) +{ + return (regno >= sparc_num_regs || sparc_regmap[regno] == -1); +} + +static void +sparc_fill_gregset_to_stack (struct regcache *regcache, const void *buf) +{ + int i; + CORE_ADDR addr = 0; + unsigned char tmp_reg_buf[8]; + const int l0_regno = find_regno (regcache->tdesc, "l0"); + const int i7_regno = l0_regno + 15; + + /* These registers have to be stored in the stack. */ + memcpy (&addr, + ((char *) buf) + sparc_regmap[find_regno (regcache->tdesc, "sp")], + sizeof (addr)); + + addr += BIAS; + + for (i = l0_regno; i <= i7_regno; i++) + { + collect_register (regcache, i, tmp_reg_buf); + (*the_target->write_memory) (addr, tmp_reg_buf, sizeof (tmp_reg_buf)); + addr += sizeof (tmp_reg_buf); + } +} + +static void +sparc_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + int range; + + for (range = 0; range < N_GREGS_RANGES; range++) + for (i = gregs_ranges[range].regno_start; + i <= gregs_ranges[range].regno_end; i++) + if (sparc_regmap[i] != -1) + collect_register (regcache, i, ((char *) buf) + sparc_regmap[i]); + + sparc_fill_gregset_to_stack (regcache, buf); +} + +static void +sparc_fill_fpregset (struct regcache *regcache, void *buf) +{ + int i; + int range; + + for (range = 0; range < N_FPREGS_RANGES; range++) + for (i = fpregs_ranges[range].regno_start; + i <= fpregs_ranges[range].regno_end; i++) + collect_register (regcache, i, ((char *) buf) + sparc_regmap[i]); + +} + +static void +sparc_store_gregset_from_stack (struct regcache *regcache, const void *buf) +{ + int i; + CORE_ADDR addr = 0; + unsigned char tmp_reg_buf[8]; + const int l0_regno = find_regno (regcache->tdesc, "l0"); + const int i7_regno = l0_regno + 15; + + /* These registers have to be obtained from the stack. */ + memcpy (&addr, + ((char *) buf) + sparc_regmap[find_regno (regcache->tdesc, "sp")], + sizeof (addr)); + + addr += BIAS; + + for (i = l0_regno; i <= i7_regno; i++) + { + (*the_target->read_memory) (addr, tmp_reg_buf, sizeof (tmp_reg_buf)); + supply_register (regcache, i, tmp_reg_buf); + addr += sizeof (tmp_reg_buf); + } +} + +static void +sparc_store_gregset (struct regcache *regcache, const void *buf) +{ + int i; + char zerobuf[8]; + int range; + + memset (zerobuf, 0, sizeof (zerobuf)); + + for (range = 0; range < N_GREGS_RANGES; range++) + for (i = gregs_ranges[range].regno_start; + i <= gregs_ranges[range].regno_end; i++) + if (sparc_regmap[i] != -1) + supply_register (regcache, i, ((char *) buf) + sparc_regmap[i]); + else + supply_register (regcache, i, zerobuf); + + sparc_store_gregset_from_stack (regcache, buf); +} + +static void +sparc_store_fpregset (struct regcache *regcache, const void *buf) +{ + int i; + int range; + + for (range = 0; range < N_FPREGS_RANGES; range++) + for (i = fpregs_ranges[range].regno_start; + i <= fpregs_ranges[range].regno_end; + i++) + supply_register (regcache, i, ((char *) buf) + sparc_regmap[i]); +} + +static const gdb_byte sparc_breakpoint[INSN_SIZE] = { + 0x91, 0xd0, 0x20, 0x01 +}; +#define sparc_breakpoint_len INSN_SIZE + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const unsigned char * +sparc_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = sparc_breakpoint_len; + return sparc_breakpoint; +} + +static int +sparc_breakpoint_at (CORE_ADDR where) +{ + unsigned char insn[INSN_SIZE]; + + (*the_target->read_memory) (where, (unsigned char *) insn, sizeof (insn)); + + if (memcmp (sparc_breakpoint, insn, sizeof (insn)) == 0) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only + uses TRAP Always. */ + + return 0; +} + +static void +sparc_arch_setup (void) +{ + current_process ()->tdesc = tdesc_sparc64; +} + +static struct regset_info sparc_regsets[] = { + { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), + GENERAL_REGS, + sparc_fill_gregset, sparc_store_gregset }, + { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (fpregset_t), + FP_REGS, + sparc_fill_fpregset, sparc_store_fpregset }, + NULL_REGSET +}; + +static struct regsets_info sparc_regsets_info = + { + sparc_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info sparc_usrregs_info = + { + sparc_num_regs, + /* No regmap needs to be provided since this impl. doesn't use + USRREGS. */ + NULL + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &sparc_usrregs_info, + &sparc_regsets_info + }; + +static const struct regs_info * +sparc_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + sparc_arch_setup, + sparc_regs_info, + sparc_cannot_fetch_register, + sparc_cannot_store_register, + NULL, /* fetch_register */ + linux_get_pc_64bit, + /* No sparc_set_pc is needed. */ + NULL, + NULL, /* breakpoint_kind_from_pc */ + sparc_sw_breakpoint_from_kind, + NULL, /* get_next_pcs */ + 0, + sparc_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, NULL, NULL, NULL, + NULL, NULL +}; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_sparc64 (); + + initialize_regsets_info (&sparc_regsets_info); +} diff --git a/gdbserver/linux-tic6x-low.c b/gdbserver/linux-tic6x-low.c new file mode 100644 index 00000000000..51a31c7876a --- /dev/null +++ b/gdbserver/linux-tic6x-low.c @@ -0,0 +1,455 @@ +/* Target dependent code for GDB on TI C6x systems. + + Copyright (C) 2010-2020 Free Software Foundation, Inc. + Contributed by Andrew Jenner + Contributed by Yao Qi + + 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 3 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, see . */ + +#include "server.h" +#include "linux-low.h" +#include "arch/tic6x.h" +#include "tdesc.h" + +#include "nat/gdb_ptrace.h" +#include + +#include "gdb_proc_service.h" + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +/* There are at most 69 registers accessible in ptrace. */ +#define TIC6X_NUM_REGS 69 + +#include + +/* Defined in auto-generated file tic6x-c64xp-linux.c. */ +void init_registers_tic6x_c64xp_linux (void); +extern const struct target_desc *tdesc_tic6x_c64xp_linux; + +/* Defined in auto-generated file tic6x-c64x-linux.c. */ +void init_registers_tic6x_c64x_linux (void); +extern const struct target_desc *tdesc_tic6x_c64x_linux; + +/* Defined in auto-generated file tic62x-c6xp-linux.c. */ +void init_registers_tic6x_c62x_linux (void); +extern const struct target_desc *tdesc_tic6x_c62x_linux; + +union tic6x_register +{ + unsigned char buf[4]; + + int reg32; +}; + +/* Return the ptrace ``address'' of register REGNO. */ + +#if __BYTE_ORDER == __BIG_ENDIAN +static int tic6x_regmap_c64xp[] = { + /* A0 - A15 */ + 53, 52, 55, 54, 57, 56, 59, 58, + 61, 60, 63, 62, 65, 64, 67, 66, + /* B0 - B15 */ + 23, 22, 25, 24, 27, 26, 29, 28, + 31, 30, 33, 32, 35, 34, 69, 68, + /* CSR PC */ + 5, 4, + /* A16 - A31 */ + 37, 36, 39, 38, 41, 40, 43, 42, + 45, 44, 47, 46, 49, 48, 51, 50, + /* B16 - B31 */ + 7, 6, 9, 8, 11, 10, 13, 12, + 15, 14, 17, 16, 19, 18, 21, 20, + /* TSR, ILC, RILC */ + 1, 2, 3 +}; + +static int tic6x_regmap_c64x[] = { + /* A0 - A15 */ + 51, 50, 53, 52, 55, 54, 57, 56, + 59, 58, 61, 60, 63, 62, 65, 64, + /* B0 - B15 */ + 21, 20, 23, 22, 25, 24, 27, 26, + 29, 28, 31, 30, 33, 32, 67, 66, + /* CSR PC */ + 3, 2, + /* A16 - A31 */ + 35, 34, 37, 36, 39, 38, 41, 40, + 43, 42, 45, 44, 47, 46, 49, 48, + /* B16 - B31 */ + 5, 4, 7, 6, 9, 8, 11, 10, + 13, 12, 15, 14, 17, 16, 19, 18, + -1, -1, -1 +}; + +static int tic6x_regmap_c62x[] = { + /* A0 - A15 */ + 19, 18, 21, 20, 23, 22, 25, 24, + 27, 26, 29, 28, 31, 30, 33, 32, + /* B0 - B15 */ + 5, 4, 7, 6, 9, 8, 11, 10, + 13, 12, 15, 14, 17, 16, 35, 34, + /* CSR, PC */ + 3, 2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1 +}; + +#else +static int tic6x_regmap_c64xp[] = { + /* A0 - A15 */ + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, + /* B0 - B15 */ + 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 68, 69, + /* CSR PC */ + 4, 5, + /* A16 - A31 */ + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + /* B16 -B31 */ + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 31, + /* TSR, ILC, RILC */ + 0, 3, 2 +}; + +static int tic6x_regmap_c64x[] = { + /* A0 - A15 */ + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, + /* B0 - B15 */ + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 66, 67, + /* CSR PC */ + 2, 3, + /* A16 - A31 */ + 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, + /* B16 - B31 */ + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + -1, -1, -1 +}; + +static int tic6x_regmap_c62x[] = { + /* A0 - A15 */ + 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, + /* B0 - B15 */ + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 34, 35, + /* CSR PC */ + 2, 3, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1 +}; + +#endif + +extern struct linux_target_ops the_low_target; + +static int *tic6x_regmap; +static unsigned int tic6x_breakpoint; +#define tic6x_breakpoint_len 4 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +tic6x_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = tic6x_breakpoint_len; + return (const gdb_byte *) &tic6x_breakpoint; +} + +static struct usrregs_info tic6x_usrregs_info = + { + TIC6X_NUM_REGS, + NULL, /* Set in tic6x_read_description. */ + }; + +static const struct target_desc * +tic6x_read_description (enum c6x_feature feature) +{ + static target_desc *tdescs[C6X_LAST] = { }; + struct target_desc **tdesc = &tdescs[feature]; + + if (*tdesc == NULL) + { + *tdesc = tic6x_create_target_description (feature); + static const char *expedite_regs[] = { "A15", "PC", NULL }; + init_target_desc (*tdesc, expedite_regs); + } + + return *tdesc; +} + +static int +tic6x_cannot_fetch_register (int regno) +{ + return (tic6x_regmap[regno] == -1); +} + +static int +tic6x_cannot_store_register (int regno) +{ + return (tic6x_regmap[regno] == -1); +} + +static CORE_ADDR +tic6x_get_pc (struct regcache *regcache) +{ + union tic6x_register pc; + + collect_register_by_name (regcache, "PC", pc.buf); + return pc.reg32; +} + +static void +tic6x_set_pc (struct regcache *regcache, CORE_ADDR pc) +{ + union tic6x_register newpc; + + newpc.reg32 = pc; + supply_register_by_name (regcache, "PC", newpc.buf); +} + +static int +tic6x_breakpoint_at (CORE_ADDR where) +{ + unsigned int insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 4); + if (insn == tic6x_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *) *base - idx); + + return PS_OK; +} + +static void +tic6x_collect_register (struct regcache *regcache, int regno, + union tic6x_register *reg) +{ + union tic6x_register tmp_reg; + + collect_register (regcache, regno, &tmp_reg.reg32); + reg->reg32 = tmp_reg.reg32; +} + +static void +tic6x_supply_register (struct regcache *regcache, int regno, + const union tic6x_register *reg) +{ + int offset = 0; + + supply_register (regcache, regno, reg->buf + offset); +} + +static void +tic6x_fill_gregset (struct regcache *regcache, void *buf) +{ + auto regset = static_cast (buf); + int i; + + for (i = 0; i < TIC6X_NUM_REGS; i++) + if (tic6x_regmap[i] != -1) + tic6x_collect_register (regcache, i, regset + tic6x_regmap[i]); +} + +static void +tic6x_store_gregset (struct regcache *regcache, const void *buf) +{ + const auto regset = static_cast (buf); + int i; + + for (i = 0; i < TIC6X_NUM_REGS; i++) + if (tic6x_regmap[i] != -1) + tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]); +} + +static struct regset_info tic6x_regsets[] = { + { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS, + tic6x_fill_gregset, tic6x_store_gregset }, + NULL_REGSET +}; + +static void +tic6x_arch_setup (void) +{ + register unsigned int csr asm ("B2"); + unsigned int cpuid; + enum c6x_feature feature = C6X_CORE; + + /* Determine the CPU we're running on to find the register order. */ + __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :); + cpuid = csr >> 24; + switch (cpuid) + { + case 0x00: /* C62x */ + case 0x02: /* C67x */ + tic6x_regmap = tic6x_regmap_c62x; + tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ + feature = C6X_CORE; + break; + case 0x03: /* C67x+ */ + tic6x_regmap = tic6x_regmap_c64x; + tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ + feature = C6X_GP; + break; + case 0x0c: /* C64x */ + tic6x_regmap = tic6x_regmap_c64x; + tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ + feature = C6X_GP; + break; + case 0x10: /* C64x+ */ + case 0x14: /* C674x */ + case 0x15: /* C66x */ + tic6x_regmap = tic6x_regmap_c64xp; + tic6x_breakpoint = 0x56454314; /* illegal opcode */ + feature = C6X_C6XP; + break; + default: + error ("Unknown CPU ID 0x%02x", cpuid); + } + tic6x_usrregs_info.regmap = tic6x_regmap; + + current_process ()->tdesc = tic6x_read_description (feature); +} + +/* Support for hardware single step. */ + +static int +tic6x_supports_hardware_single_step (void) +{ + return 1; +} + +static struct regsets_info tic6x_regsets_info = + { + tic6x_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &tic6x_usrregs_info, + &tic6x_regsets_info + }; + +static const struct regs_info * +tic6x_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + tic6x_arch_setup, + tic6x_regs_info, + tic6x_cannot_fetch_register, + tic6x_cannot_store_register, + NULL, /* fetch_register */ + tic6x_get_pc, + tic6x_set_pc, + NULL, /* breakpoint_kind_from_pc */ + tic6x_sw_breakpoint_from_kind, + NULL, + 0, + tic6x_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + tic6x_supports_hardware_single_step, +}; + +#if GDB_SELF_TEST +#include "gdbsupport/selftest.h" + +namespace selftests { +namespace tdesc { +static void +tic6x_tdesc_test () +{ + SELF_CHECK (*tdesc_tic6x_c62x_linux == *tic6x_read_description (C6X_CORE)); + SELF_CHECK (*tdesc_tic6x_c64x_linux == *tic6x_read_description (C6X_GP)); + SELF_CHECK (*tdesc_tic6x_c64xp_linux == *tic6x_read_description (C6X_C6XP)); +} +} +} +#endif + +void +initialize_low_arch (void) +{ +#if GDB_SELF_TEST + /* Initialize the Linux target descriptions. */ + init_registers_tic6x_c64xp_linux (); + init_registers_tic6x_c64x_linux (); + init_registers_tic6x_c62x_linux (); + + selftests::register_test ("tic6x-tdesc", selftests::tdesc::tic6x_tdesc_test); +#endif + + initialize_regsets_info (&tic6x_regsets_info); +} diff --git a/gdbserver/linux-tile-low.c b/gdbserver/linux-tile-low.c new file mode 100644 index 00000000000..cd85e945a46 --- /dev/null +++ b/gdbserver/linux-tile-low.c @@ -0,0 +1,222 @@ +/* GNU/Linux/TILE-Gx specific low level interface, GDBserver. + + Copyright (C) 2012-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "linux-low.h" + +#include +#include "nat/gdb_ptrace.h" + +/* Defined in auto-generated file reg-tilegx.c. */ +void init_registers_tilegx (void); +extern const struct target_desc *tdesc_tilegx; + +/* Defined in auto-generated file reg-tilegx32.c. */ +void init_registers_tilegx32 (void); +extern const struct target_desc *tdesc_tilegx32; + +#define tile_num_regs 65 + +static int tile_regmap[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + -1, -1, -1, -1, -1, -1, -1, -1, + 56 +}; + +static int +tile_cannot_fetch_register (int regno) +{ + if (regno >= 0 && regno < 56) + return 0; + else if (regno == 64) + return 0; + else + return 1; +} + +static int +tile_cannot_store_register (int regno) +{ + if (regno >= 0 && regno < 56) + return 0; + else if (regno == 64) + return 0; + else + return 1; +} + +static uint64_t tile_breakpoint = 0x400b3cae70166000ULL; +#define tile_breakpoint_len 8 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +tile_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = tile_breakpoint_len; + return (const gdb_byte *) &tile_breakpoint; +} + +static int +tile_breakpoint_at (CORE_ADDR where) +{ + uint64_t insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, 8); + if (insn == tile_breakpoint) + return 1; + + /* If necessary, recognize more trap instructions here. GDB only uses the + one. */ + return 0; +} + +static void +tile_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + + for (i = 0; i < tile_num_regs; i++) + if (tile_regmap[i] != -1) + collect_register (regcache, i, ((uint_reg_t *) buf) + tile_regmap[i]); +} + +static void +tile_store_gregset (struct regcache *regcache, const void *buf) +{ + int i; + + for (i = 0; i < tile_num_regs; i++) + if (tile_regmap[i] != -1) + supply_register (regcache, i, ((uint_reg_t *) buf) + tile_regmap[i]); +} + +static struct regset_info tile_regsets[] = +{ + { PTRACE_GETREGS, PTRACE_SETREGS, 0, tile_num_regs * 8, + GENERAL_REGS, tile_fill_gregset, tile_store_gregset }, + NULL_REGSET +}; + +static struct regsets_info tile_regsets_info = + { + tile_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info tile_usrregs_info = + { + tile_num_regs, + tile_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &tile_usrregs_info, + &tile_regsets_info, + }; + +static const struct regs_info * +tile_regs_info (void) +{ + return ®s_info; +} + +static void +tile_arch_setup (void) +{ + int pid = pid_of (current_thread); + unsigned int machine; + int is_elf64 = linux_pid_exe_is_elf_64_file (pid, &machine); + + if (sizeof (void *) == 4) + if (is_elf64 > 0) + error (_("Can't debug 64-bit process with 32-bit GDBserver")); + + if (!is_elf64) + current_process ()->tdesc = tdesc_tilegx32; + else + current_process ()->tdesc = tdesc_tilegx; +} + +/* Support for hardware single step. */ + +static int +tile_supports_hardware_single_step (void) +{ + return 1; +} + + +struct linux_target_ops the_low_target = +{ + tile_arch_setup, + tile_regs_info, + tile_cannot_fetch_register, + tile_cannot_store_register, + NULL, + linux_get_pc_64bit, + linux_set_pc_64bit, + NULL, /* breakpoint_kind_from_pc */ + tile_sw_breakpoint_from_kind, + NULL, + 0, + tile_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + tile_supports_hardware_single_step, +}; + +void +initialize_low_arch (void) +{ + init_registers_tilegx32(); + init_registers_tilegx(); + + initialize_regsets_info (&tile_regsets_info); +} diff --git a/gdbserver/linux-x86-low.c b/gdbserver/linux-x86-low.c new file mode 100644 index 00000000000..09ec22ff678 --- /dev/null +++ b/gdbserver/linux-x86-low.c @@ -0,0 +1,2922 @@ +/* GNU/Linux/x86-64 specific low level interface, for the remote server + for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include +#include +#include +#include "linux-low.h" +#include "i387-fp.h" +#include "x86-low.h" +#include "gdbsupport/x86-xstate.h" +#include "nat/gdb_ptrace.h" + +#ifdef __x86_64__ +#include "nat/amd64-linux-siginfo.h" +#endif + +#include "gdb_proc_service.h" +/* Don't include elf/common.h if linux/elf.h got included by + gdb_proc_service.h. */ +#ifndef ELFMAG0 +#include "elf/common.h" +#endif + +#include "gdbsupport/agent.h" +#include "tdesc.h" +#include "tracepoint.h" +#include "ax.h" +#include "nat/linux-nat.h" +#include "nat/x86-linux.h" +#include "nat/x86-linux-dregs.h" +#include "linux-x86-tdesc.h" + +#ifdef __x86_64__ +static struct target_desc *tdesc_amd64_linux_no_xml; +#endif +static struct target_desc *tdesc_i386_linux_no_xml; + + +static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 }; +static unsigned char small_jump_insn[] = { 0x66, 0xe9, 0, 0 }; + +/* Backward compatibility for gdb without XML support. */ + +static const char *xmltarget_i386_linux_no_xml = "@\ +i386\ +GNU/Linux\ +"; + +#ifdef __x86_64__ +static const char *xmltarget_amd64_linux_no_xml = "@\ +i386:x86-64\ +GNU/Linux\ +"; +#endif + +#include +#include +#include + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +/* This definition comes from prctl.h, but some kernels may not have it. */ +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL 30 +#endif + +/* The following definitions come from prctl.h, but may be absent + for certain configurations. */ +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif + +/* Per-process arch-specific data we want to keep. */ + +struct arch_process_info +{ + struct x86_debug_reg_state debug_reg_state; +}; + +#ifdef __x86_64__ + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register array layout. + Note that the transfer layout uses 64-bit regs. */ +static /*const*/ int i386_regmap[] = +{ + RAX * 8, RCX * 8, RDX * 8, RBX * 8, + RSP * 8, RBP * 8, RSI * 8, RDI * 8, + RIP * 8, EFLAGS * 8, CS * 8, SS * 8, + DS * 8, ES * 8, FS * 8, GS * 8 +}; + +#define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) + +/* So code below doesn't have to care, i386 or amd64. */ +#define ORIG_EAX ORIG_RAX +#define REGSIZE 8 + +static const int x86_64_regmap[] = +{ + RAX * 8, RBX * 8, RCX * 8, RDX * 8, + RSI * 8, RDI * 8, RBP * 8, RSP * 8, + R8 * 8, R9 * 8, R10 * 8, R11 * 8, + R12 * 8, R13 * 8, R14 * 8, R15 * 8, + RIP * 8, EFLAGS * 8, CS * 8, SS * 8, + DS * 8, ES * 8, FS * 8, GS * 8, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, + -1, -1, -1, -1, -1, -1, -1, -1, + ORIG_RAX * 8, +#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE + 21 * 8, 22 * 8, +#else + -1, -1, +#endif + -1, -1, -1, -1, /* MPX registers BND0 ... BND3. */ + -1, -1, /* MPX registers BNDCFGU, BNDSTATUS. */ + -1, -1, -1, -1, -1, -1, -1, -1, /* xmm16 ... xmm31 (AVX512) */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* ymm16 ... ymm31 (AVX512) */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* k0 ... k7 (AVX512) */ + -1, -1, -1, -1, -1, -1, -1, -1, /* zmm0 ... zmm31 (AVX512) */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1 /* pkru */ +}; + +#define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0])) +#define X86_64_USER_REGS (GS + 1) + +#else /* ! __x86_64__ */ + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register array layout. */ +static /*const*/ int i386_regmap[] = +{ + EAX * 4, ECX * 4, EDX * 4, EBX * 4, + UESP * 4, EBP * 4, ESI * 4, EDI * 4, + EIP * 4, EFL * 4, CS * 4, SS * 4, + DS * 4, ES * 4, FS * 4, GS * 4 +}; + +#define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) + +#define REGSIZE 4 + +#endif + +#ifdef __x86_64__ + +/* Returns true if the current inferior belongs to a x86-64 process, + per the tdesc. */ + +static int +is_64bit_tdesc (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + + return register_size (regcache->tdesc, 0) == 8; +} + +#endif + + +/* Called by libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ +#ifdef __x86_64__ + int use_64bit = is_64bit_tdesc (); + + if (use_64bit) + { + switch (idx) + { + case FS: + if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0) + return PS_OK; + break; + case GS: + if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0) + return PS_OK; + break; + default: + return PS_BADADDR; + } + return PS_ERR; + } +#endif + + { + unsigned int desc[4]; + + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, + (void *) (intptr_t) idx, (unsigned long) &desc) < 0) + return PS_ERR; + + /* Ensure we properly extend the value to 64-bits for x86_64. */ + *base = (void *) (uintptr_t) desc[1]; + return PS_OK; + } +} + +/* Get the thread area address. This is used to recognize which + thread is which when tracing with the in-process agent library. We + don't read anything from the address, and treat it as opaque; it's + the address itself that we assume is unique per-thread. */ + +static int +x86_get_thread_area (int lwpid, CORE_ADDR *addr) +{ +#ifdef __x86_64__ + int use_64bit = is_64bit_tdesc (); + + if (use_64bit) + { + void *base; + if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_FS) == 0) + { + *addr = (CORE_ADDR) (uintptr_t) base; + return 0; + } + + return -1; + } +#endif + + { + struct lwp_info *lwp = find_lwp_pid (ptid_t (lwpid)); + struct thread_info *thr = get_lwp_thread (lwp); + struct regcache *regcache = get_thread_regcache (thr, 1); + unsigned int desc[4]; + ULONGEST gs = 0; + const int reg_thread_area = 3; /* bits to scale down register value. */ + int idx; + + collect_register_by_name (regcache, "gs", &gs); + + idx = gs >> reg_thread_area; + + if (ptrace (PTRACE_GET_THREAD_AREA, + lwpid_of (thr), + (void *) (long) idx, (unsigned long) &desc) < 0) + return -1; + + *addr = desc[1]; + return 0; + } +} + + + +static int +x86_cannot_store_register (int regno) +{ +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return 0; +#endif + + return regno >= I386_NUM_REGS; +} + +static int +x86_cannot_fetch_register (int regno) +{ +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return 0; +#endif + + return regno >= I386_NUM_REGS; +} + +static void +x86_fill_gregset (struct regcache *regcache, void *buf) +{ + int i; + +#ifdef __x86_64__ + if (register_size (regcache->tdesc, 0) == 8) + { + for (i = 0; i < X86_64_NUM_REGS; i++) + if (x86_64_regmap[i] != -1) + collect_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); + +#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE + { + unsigned long base; + int lwpid = lwpid_of (current_thread); + + collect_register_by_name (regcache, "fs_base", &base); + ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_SET_FS); + + collect_register_by_name (regcache, "gs_base", &base); + ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_SET_GS); + } +#endif + + return; + } + + /* 32-bit inferior registers need to be zero-extended. + Callers would read uninitialized memory otherwise. */ + memset (buf, 0x00, X86_64_USER_REGS * 8); +#endif + + for (i = 0; i < I386_NUM_REGS; i++) + collect_register (regcache, i, ((char *) buf) + i386_regmap[i]); + + collect_register_by_name (regcache, "orig_eax", + ((char *) buf) + ORIG_EAX * REGSIZE); + +#ifdef __x86_64__ + /* Sign extend EAX value to avoid potential syscall restart + problems. + + See amd64_linux_collect_native_gregset() in gdb/amd64-linux-nat.c + for a detailed explanation. */ + if (register_size (regcache->tdesc, 0) == 4) + { + void *ptr = ((gdb_byte *) buf + + i386_regmap[find_regno (regcache->tdesc, "eax")]); + + *(int64_t *) ptr = *(int32_t *) ptr; + } +#endif +} + +static void +x86_store_gregset (struct regcache *regcache, const void *buf) +{ + int i; + +#ifdef __x86_64__ + if (register_size (regcache->tdesc, 0) == 8) + { + for (i = 0; i < X86_64_NUM_REGS; i++) + if (x86_64_regmap[i] != -1) + supply_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); + +#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE + { + unsigned long base; + int lwpid = lwpid_of (current_thread); + + if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_FS) == 0) + supply_register_by_name (regcache, "fs_base", &base); + + if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_GS) == 0) + supply_register_by_name (regcache, "gs_base", &base); + } +#endif + return; + } +#endif + + for (i = 0; i < I386_NUM_REGS; i++) + supply_register (regcache, i, ((char *) buf) + i386_regmap[i]); + + supply_register_by_name (regcache, "orig_eax", + ((char *) buf) + ORIG_EAX * REGSIZE); +} + +static void +x86_fill_fpregset (struct regcache *regcache, void *buf) +{ +#ifdef __x86_64__ + i387_cache_to_fxsave (regcache, buf); +#else + i387_cache_to_fsave (regcache, buf); +#endif +} + +static void +x86_store_fpregset (struct regcache *regcache, const void *buf) +{ +#ifdef __x86_64__ + i387_fxsave_to_cache (regcache, buf); +#else + i387_fsave_to_cache (regcache, buf); +#endif +} + +#ifndef __x86_64__ + +static void +x86_fill_fpxregset (struct regcache *regcache, void *buf) +{ + i387_cache_to_fxsave (regcache, buf); +} + +static void +x86_store_fpxregset (struct regcache *regcache, const void *buf) +{ + i387_fxsave_to_cache (regcache, buf); +} + +#endif + +static void +x86_fill_xstateregset (struct regcache *regcache, void *buf) +{ + i387_cache_to_xsave (regcache, buf); +} + +static void +x86_store_xstateregset (struct regcache *regcache, const void *buf) +{ + i387_xsave_to_cache (regcache, buf); +} + +/* ??? The non-biarch i386 case stores all the i387 regs twice. + Once in i387_.*fsave.* and once in i387_.*fxsave.*. + This is, presumably, to handle the case where PTRACE_[GS]ETFPXREGS + doesn't work. IWBN to avoid the duplication in the case where it + does work. Maybe the arch_setup routine could check whether it works + and update the supported regsets accordingly. */ + +static struct regset_info x86_regsets[] = +{ +#ifdef HAVE_PTRACE_GETREGS + { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), + GENERAL_REGS, + x86_fill_gregset, x86_store_gregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_XSTATE, 0, + EXTENDED_REGS, x86_fill_xstateregset, x86_store_xstateregset }, +# ifndef __x86_64__ +# ifdef HAVE_PTRACE_GETFPXREGS + { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, 0, sizeof (elf_fpxregset_t), + EXTENDED_REGS, + x86_fill_fpxregset, x86_store_fpxregset }, +# endif +# endif + { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t), + FP_REGS, + x86_fill_fpregset, x86_store_fpregset }, +#endif /* HAVE_PTRACE_GETREGS */ + NULL_REGSET +}; + +static CORE_ADDR +x86_get_pc (struct regcache *regcache) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + uint64_t pc; + + collect_register_by_name (regcache, "rip", &pc); + return (CORE_ADDR) pc; + } + else + { + uint32_t pc; + + collect_register_by_name (regcache, "eip", &pc); + return (CORE_ADDR) pc; + } +} + +static void +x86_set_pc (struct regcache *regcache, CORE_ADDR pc) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + uint64_t newpc = pc; + + supply_register_by_name (regcache, "rip", &newpc); + } + else + { + uint32_t newpc = pc; + + supply_register_by_name (regcache, "eip", &newpc); + } +} + +static const gdb_byte x86_breakpoint[] = { 0xCC }; +#define x86_breakpoint_len 1 + +static int +x86_breakpoint_at (CORE_ADDR pc) +{ + unsigned char c; + + (*the_target->read_memory) (pc, &c, 1); + if (c == 0xCC) + return 1; + + return 0; +} + +/* Low-level function vector. */ +struct x86_dr_low_type x86_dr_low = + { + x86_linux_dr_set_control, + x86_linux_dr_set_addr, + x86_linux_dr_get_addr, + x86_linux_dr_get_status, + x86_linux_dr_get_control, + sizeof (void *), + }; + +/* Breakpoint/Watchpoint support. */ + +static int +x86_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + case Z_PACKET_HW_BP: + case Z_PACKET_WRITE_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + return 0; + } +} + +static int +x86_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + struct process_info *proc = current_process (); + + switch (type) + { + case raw_bkpt_type_hw: + case raw_bkpt_type_write_wp: + case raw_bkpt_type_access_wp: + { + enum target_hw_bp_type hw_type + = raw_bkpt_type_to_target_hw_bp_type (type); + struct x86_debug_reg_state *state + = &proc->priv->arch_private->debug_reg_state; + + return x86_dr_insert_watchpoint (state, hw_type, addr, size); + } + + default: + /* Unsupported. */ + return 1; + } +} + +static int +x86_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + struct process_info *proc = current_process (); + + switch (type) + { + case raw_bkpt_type_hw: + case raw_bkpt_type_write_wp: + case raw_bkpt_type_access_wp: + { + enum target_hw_bp_type hw_type + = raw_bkpt_type_to_target_hw_bp_type (type); + struct x86_debug_reg_state *state + = &proc->priv->arch_private->debug_reg_state; + + return x86_dr_remove_watchpoint (state, hw_type, addr, size); + } + default: + /* Unsupported. */ + return 1; + } +} + +static int +x86_stopped_by_watchpoint (void) +{ + struct process_info *proc = current_process (); + return x86_dr_stopped_by_watchpoint (&proc->priv->arch_private->debug_reg_state); +} + +static CORE_ADDR +x86_stopped_data_address (void) +{ + struct process_info *proc = current_process (); + CORE_ADDR addr; + if (x86_dr_stopped_data_address (&proc->priv->arch_private->debug_reg_state, + &addr)) + return addr; + return 0; +} + +/* Called when a new process is created. */ + +static struct arch_process_info * +x86_linux_new_process (void) +{ + struct arch_process_info *info = XCNEW (struct arch_process_info); + + x86_low_init_dregs (&info->debug_reg_state); + + return info; +} + +/* Called when a process is being deleted. */ + +static void +x86_linux_delete_process (struct arch_process_info *info) +{ + xfree (info); +} + +/* Target routine for linux_new_fork. */ + +static void +x86_linux_new_fork (struct process_info *parent, struct process_info *child) +{ + /* These are allocated by linux_add_process. */ + gdb_assert (parent->priv != NULL + && parent->priv->arch_private != NULL); + gdb_assert (child->priv != NULL + && child->priv->arch_private != NULL); + + /* Linux kernel before 2.6.33 commit + 72f674d203cd230426437cdcf7dd6f681dad8b0d + will inherit hardware debug registers from parent + on fork/vfork/clone. Newer Linux kernels create such tasks with + zeroed debug registers. + + GDB core assumes the child inherits the watchpoints/hw + breakpoints of the parent, and will remove them all from the + forked off process. Copy the debug registers mirrors into the + new process so that all breakpoints and watchpoints can be + removed together. The debug registers mirror will become zeroed + in the end before detaching the forked off process, thus making + this compatible with older Linux kernels too. */ + + *child->priv->arch_private = *parent->priv->arch_private; +} + +/* See nat/x86-dregs.h. */ + +struct x86_debug_reg_state * +x86_debug_reg_state (pid_t pid) +{ + struct process_info *proc = find_process_pid (pid); + + return &proc->priv->arch_private->debug_reg_state; +} + +/* When GDBSERVER is built as a 64-bit application on linux, the + PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since + debugging a 32-bit inferior with a 64-bit GDBSERVER should look the same + as debugging it with a 32-bit GDBSERVER, we do the 32-bit <-> 64-bit + conversion in-place ourselves. */ + +/* Convert a ptrace/host siginfo object, into/from the siginfo in the + layout of the inferiors' architecture. Returns true if any + conversion was done; false otherwise. If DIRECTION is 1, then copy + from INF to PTRACE. If DIRECTION is 0, copy from PTRACE to + INF. */ + +static int +x86_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction) +{ +#ifdef __x86_64__ + unsigned int machine; + int tid = lwpid_of (current_thread); + int is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); + + /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ + if (!is_64bit_tdesc ()) + return amd64_linux_siginfo_fixup_common (ptrace, inf, direction, + FIXUP_32); + /* No fixup for native x32 GDB. */ + else if (!is_elf64 && sizeof (void *) == 8) + return amd64_linux_siginfo_fixup_common (ptrace, inf, direction, + FIXUP_X32); +#endif + + return 0; +} + +static int use_xml; + +/* Format of XSAVE extended state is: + struct + { + fxsave_bytes[0..463] + sw_usable_bytes[464..511] + xstate_hdr_bytes[512..575] + avx_bytes[576..831] + future_state etc + }; + + Same memory layout will be used for the coredump NT_X86_XSTATE + representing the XSAVE extended state registers. + + The first 8 bytes of the sw_usable_bytes[464..467] is the OS enabled + extended state mask, which is the same as the extended control register + 0 (the XFEATURE_ENABLED_MASK register), XCR0. We can use this mask + together with the mask saved in the xstate_hdr_bytes to determine what + states the processor/OS supports and what state, used or initialized, + the process/thread is in. */ +#define I386_LINUX_XSAVE_XCR0_OFFSET 464 + +/* Does the current host support the GETFPXREGS request? The header + file may or may not define it, and even if it is defined, the + kernel will return EIO if it's running on a pre-SSE processor. */ +int have_ptrace_getfpxregs = +#ifdef HAVE_PTRACE_GETFPXREGS + -1 +#else + 0 +#endif +; + +/* Get Linux/x86 target description from running target. */ + +static const struct target_desc * +x86_linux_read_description (void) +{ + unsigned int machine; + int is_elf64; + int xcr0_features; + int tid; + static uint64_t xcr0; + struct regset_info *regset; + + tid = lwpid_of (current_thread); + + is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); + + if (sizeof (void *) == 4) + { + if (is_elf64 > 0) + error (_("Can't debug 64-bit process with 32-bit GDBserver")); +#ifndef __x86_64__ + else if (machine == EM_X86_64) + error (_("Can't debug x86-64 process with 32-bit GDBserver")); +#endif + } + +#if !defined __x86_64__ && defined HAVE_PTRACE_GETFPXREGS + if (machine == EM_386 && have_ptrace_getfpxregs == -1) + { + elf_fpxregset_t fpxregs; + + if (ptrace (PTRACE_GETFPXREGS, tid, 0, (long) &fpxregs) < 0) + { + have_ptrace_getfpxregs = 0; + have_ptrace_getregset = 0; + return i386_linux_read_description (X86_XSTATE_X87); + } + else + have_ptrace_getfpxregs = 1; + } +#endif + + if (!use_xml) + { + x86_xcr0 = X86_XSTATE_SSE_MASK; + + /* Don't use XML. */ +#ifdef __x86_64__ + if (machine == EM_X86_64) + return tdesc_amd64_linux_no_xml; + else +#endif + return tdesc_i386_linux_no_xml; + } + + if (have_ptrace_getregset == -1) + { + uint64_t xstateregs[(X86_XSTATE_SSE_SIZE / sizeof (uint64_t))]; + struct iovec iov; + + iov.iov_base = xstateregs; + iov.iov_len = sizeof (xstateregs); + + /* Check if PTRACE_GETREGSET works. */ + if (ptrace (PTRACE_GETREGSET, tid, + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) + have_ptrace_getregset = 0; + else + { + have_ptrace_getregset = 1; + + /* Get XCR0 from XSAVE extended state. */ + xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET + / sizeof (uint64_t))]; + + /* Use PTRACE_GETREGSET if it is available. */ + for (regset = x86_regsets; + regset->fill_function != NULL; regset++) + if (regset->get_request == PTRACE_GETREGSET) + regset->size = X86_XSTATE_SIZE (xcr0); + else if (regset->type != GENERAL_REGS) + regset->size = 0; + } + } + + /* Check the native XCR0 only if PTRACE_GETREGSET is available. */ + xcr0_features = (have_ptrace_getregset + && (xcr0 & X86_XSTATE_ALL_MASK)); + + if (xcr0_features) + x86_xcr0 = xcr0; + + if (machine == EM_X86_64) + { +#ifdef __x86_64__ + const target_desc *tdesc = NULL; + + if (xcr0_features) + { + tdesc = amd64_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK, + !is_elf64); + } + + if (tdesc == NULL) + tdesc = amd64_linux_read_description (X86_XSTATE_SSE_MASK, !is_elf64); + return tdesc; +#endif + } + else + { + const target_desc *tdesc = NULL; + + if (xcr0_features) + tdesc = i386_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK); + + if (tdesc == NULL) + tdesc = i386_linux_read_description (X86_XSTATE_SSE); + + return tdesc; + } + + gdb_assert_not_reached ("failed to return tdesc"); +} + +/* Update all the target description of all processes; a new GDB + connected, and it may or not support xml target descriptions. */ + +static void +x86_linux_update_xmltarget (void) +{ + struct thread_info *saved_thread = current_thread; + + /* Before changing the register cache's internal layout, flush the + contents of the current valid caches back to the threads, and + release the current regcache objects. */ + regcache_release (); + + for_each_process ([] (process_info *proc) { + int pid = proc->pid; + + /* Look up any thread of this process. */ + current_thread = find_any_thread_of_pid (pid); + + the_low_target.arch_setup (); + }); + + current_thread = saved_thread; +} + +/* Process qSupported query, "xmlRegisters=". Update the buffer size for + PTRACE_GETREGSET. */ + +static void +x86_linux_process_qsupported (char **features, int count) +{ + int i; + + /* Return if gdb doesn't support XML. If gdb sends "xmlRegisters=" + with "i386" in qSupported query, it supports x86 XML target + descriptions. */ + use_xml = 0; + for (i = 0; i < count; i++) + { + const char *feature = features[i]; + + if (startswith (feature, "xmlRegisters=")) + { + char *copy = xstrdup (feature + 13); + + char *saveptr; + for (char *p = strtok_r (copy, ",", &saveptr); + p != NULL; + p = strtok_r (NULL, ",", &saveptr)) + { + if (strcmp (p, "i386") == 0) + { + use_xml = 1; + break; + } + } + + free (copy); + } + } + x86_linux_update_xmltarget (); +} + +/* Common for x86/x86-64. */ + +static struct regsets_info x86_regsets_info = + { + x86_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +#ifdef __x86_64__ +static struct regs_info amd64_linux_regs_info = + { + NULL, /* regset_bitmap */ + NULL, /* usrregs_info */ + &x86_regsets_info + }; +#endif +static struct usrregs_info i386_linux_usrregs_info = + { + I386_NUM_REGS, + i386_regmap, + }; + +static struct regs_info i386_linux_regs_info = + { + NULL, /* regset_bitmap */ + &i386_linux_usrregs_info, + &x86_regsets_info + }; + +static const struct regs_info * +x86_linux_regs_info (void) +{ +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return &amd64_linux_regs_info; + else +#endif + return &i386_linux_regs_info; +} + +/* Initialize the target description for the architecture of the + inferior. */ + +static void +x86_arch_setup (void) +{ + current_process ()->tdesc = x86_linux_read_description (); +} + +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ + +static void +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + long l_sysno; + + collect_register_by_name (regcache, "orig_rax", &l_sysno); + *sysno = (int) l_sysno; + } + else + collect_register_by_name (regcache, "orig_eax", sysno); +} + +static int +x86_supports_tracepoints (void) +{ + return 1; +} + +static void +append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf) +{ + target_write_memory (*to, buf, len); + *to += len; +} + +static int +push_opcode (unsigned char *buf, const char *op) +{ + unsigned char *buf_org = buf; + + while (1) + { + char *endptr; + unsigned long ul = strtoul (op, &endptr, 16); + + if (endptr == op) + break; + + *buf++ = ul; + op = endptr; + } + + return buf - buf_org; +} + +#ifdef __x86_64__ + +/* Build a jump pad that saves registers and calls a collection + function. Writes a jump instruction to the jump pad to + JJUMPAD_INSN. The caller is responsible to write it in at the + tracepoint address. */ + +static int +amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + unsigned char buf[40]; + int i, offset; + int64_t loffset; + + CORE_ADDR buildaddr = *jump_entry; + + /* Build the jump pad. */ + + /* First, do tracepoint data collection. Save registers. */ + i = 0; + /* Need to ensure stack pointer saved first. */ + buf[i++] = 0x54; /* push %rsp */ + buf[i++] = 0x55; /* push %rbp */ + buf[i++] = 0x57; /* push %rdi */ + buf[i++] = 0x56; /* push %rsi */ + buf[i++] = 0x52; /* push %rdx */ + buf[i++] = 0x51; /* push %rcx */ + buf[i++] = 0x53; /* push %rbx */ + buf[i++] = 0x50; /* push %rax */ + buf[i++] = 0x41; buf[i++] = 0x57; /* push %r15 */ + buf[i++] = 0x41; buf[i++] = 0x56; /* push %r14 */ + buf[i++] = 0x41; buf[i++] = 0x55; /* push %r13 */ + buf[i++] = 0x41; buf[i++] = 0x54; /* push %r12 */ + buf[i++] = 0x41; buf[i++] = 0x53; /* push %r11 */ + buf[i++] = 0x41; buf[i++] = 0x52; /* push %r10 */ + buf[i++] = 0x41; buf[i++] = 0x51; /* push %r9 */ + buf[i++] = 0x41; buf[i++] = 0x50; /* push %r8 */ + buf[i++] = 0x9c; /* pushfq */ + buf[i++] = 0x48; /* movabs ,%rdi */ + buf[i++] = 0xbf; + memcpy (buf + i, &tpaddr, 8); + i += 8; + buf[i++] = 0x57; /* push %rdi */ + append_insns (&buildaddr, i, buf); + + /* Stack space for the collecting_t object. */ + i = 0; + i += push_opcode (&buf[i], "48 83 ec 18"); /* sub $0x18,%rsp */ + i += push_opcode (&buf[i], "48 b8"); /* mov ,%rax */ + memcpy (buf + i, &tpoint, 8); + i += 8; + i += push_opcode (&buf[i], "48 89 04 24"); /* mov %rax,(%rsp) */ + i += push_opcode (&buf[i], + "64 48 8b 04 25 00 00 00 00"); /* mov %fs:0x0,%rax */ + i += push_opcode (&buf[i], "48 89 44 24 08"); /* mov %rax,0x8(%rsp) */ + append_insns (&buildaddr, i, buf); + + /* spin-lock. */ + i = 0; + i += push_opcode (&buf[i], "48 be"); /* movl ,%rsi */ + memcpy (&buf[i], (void *) &lockaddr, 8); + i += 8; + i += push_opcode (&buf[i], "48 89 e1"); /* mov %rsp,%rcx */ + i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ + i += push_opcode (&buf[i], "f0 48 0f b1 0e"); /* lock cmpxchg %rcx,(%rsi) */ + i += push_opcode (&buf[i], "48 85 c0"); /* test %rax,%rax */ + i += push_opcode (&buf[i], "75 f4"); /* jne */ + append_insns (&buildaddr, i, buf); + + /* Set up the gdb_collect call. */ + /* At this point, (stack pointer + 0x18) is the base of our saved + register block. */ + + i = 0; + i += push_opcode (&buf[i], "48 89 e6"); /* mov %rsp,%rsi */ + i += push_opcode (&buf[i], "48 83 c6 18"); /* add $0x18,%rsi */ + + /* tpoint address may be 64-bit wide. */ + i += push_opcode (&buf[i], "48 bf"); /* movl ,%rdi */ + memcpy (buf + i, &tpoint, 8); + i += 8; + append_insns (&buildaddr, i, buf); + + /* The collector function being in the shared library, may be + >31-bits away off the jump pad. */ + i = 0; + i += push_opcode (&buf[i], "48 b8"); /* mov $collector,%rax */ + memcpy (buf + i, &collector, 8); + i += 8; + i += push_opcode (&buf[i], "ff d0"); /* callq *%rax */ + append_insns (&buildaddr, i, buf); + + /* Clear the spin-lock. */ + i = 0; + i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ + i += push_opcode (&buf[i], "48 a3"); /* mov %rax, lockaddr */ + memcpy (buf + i, &lockaddr, 8); + i += 8; + append_insns (&buildaddr, i, buf); + + /* Remove stack that had been used for the collect_t object. */ + i = 0; + i += push_opcode (&buf[i], "48 83 c4 18"); /* add $0x18,%rsp */ + append_insns (&buildaddr, i, buf); + + /* Restore register state. */ + i = 0; + buf[i++] = 0x48; /* add $0x8,%rsp */ + buf[i++] = 0x83; + buf[i++] = 0xc4; + buf[i++] = 0x08; + buf[i++] = 0x9d; /* popfq */ + buf[i++] = 0x41; buf[i++] = 0x58; /* pop %r8 */ + buf[i++] = 0x41; buf[i++] = 0x59; /* pop %r9 */ + buf[i++] = 0x41; buf[i++] = 0x5a; /* pop %r10 */ + buf[i++] = 0x41; buf[i++] = 0x5b; /* pop %r11 */ + buf[i++] = 0x41; buf[i++] = 0x5c; /* pop %r12 */ + buf[i++] = 0x41; buf[i++] = 0x5d; /* pop %r13 */ + buf[i++] = 0x41; buf[i++] = 0x5e; /* pop %r14 */ + buf[i++] = 0x41; buf[i++] = 0x5f; /* pop %r15 */ + buf[i++] = 0x58; /* pop %rax */ + buf[i++] = 0x5b; /* pop %rbx */ + buf[i++] = 0x59; /* pop %rcx */ + buf[i++] = 0x5a; /* pop %rdx */ + buf[i++] = 0x5e; /* pop %rsi */ + buf[i++] = 0x5f; /* pop %rdi */ + buf[i++] = 0x5d; /* pop %rbp */ + buf[i++] = 0x5c; /* pop %rsp */ + append_insns (&buildaddr, i, buf); + + /* Now, adjust the original instruction to execute in the jump + pad. */ + *adjusted_insn_addr = buildaddr; + relocate_instruction (&buildaddr, tpaddr); + *adjusted_insn_addr_end = buildaddr; + + /* Finally, write a jump back to the program. */ + + loffset = (tpaddr + orig_size) - (buildaddr + sizeof (jump_insn)); + if (loffset > INT_MAX || loffset < INT_MIN) + { + sprintf (err, + "E.Jump back from jump pad too far from tracepoint " + "(offset 0x%" PRIx64 " > int32).", loffset); + return 1; + } + + offset = (int) loffset; + memcpy (buf, jump_insn, sizeof (jump_insn)); + memcpy (buf + 1, &offset, 4); + append_insns (&buildaddr, sizeof (jump_insn), buf); + + /* The jump pad is now built. Wire in a jump to our jump pad. This + is always done last (by our caller actually), so that we can + install fast tracepoints with threads running. This relies on + the agent's atomic write support. */ + loffset = *jump_entry - (tpaddr + sizeof (jump_insn)); + if (loffset > INT_MAX || loffset < INT_MIN) + { + sprintf (err, + "E.Jump pad too far from tracepoint " + "(offset 0x%" PRIx64 " > int32).", loffset); + return 1; + } + + offset = (int) loffset; + + memcpy (buf, jump_insn, sizeof (jump_insn)); + memcpy (buf + 1, &offset, 4); + memcpy (jjump_pad_insn, buf, sizeof (jump_insn)); + *jjump_pad_insn_size = sizeof (jump_insn); + + /* Return the end address of our pad. */ + *jump_entry = buildaddr; + + return 0; +} + +#endif /* __x86_64__ */ + +/* Build a jump pad that saves registers and calls a collection + function. Writes a jump instruction to the jump pad to + JJUMPAD_INSN. The caller is responsible to write it in at the + tracepoint address. */ + +static int +i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + unsigned char buf[0x100]; + int i, offset; + CORE_ADDR buildaddr = *jump_entry; + + /* Build the jump pad. */ + + /* First, do tracepoint data collection. Save registers. */ + i = 0; + buf[i++] = 0x60; /* pushad */ + buf[i++] = 0x68; /* push tpaddr aka $pc */ + *((int *)(buf + i)) = (int) tpaddr; + i += 4; + buf[i++] = 0x9c; /* pushf */ + buf[i++] = 0x1e; /* push %ds */ + buf[i++] = 0x06; /* push %es */ + buf[i++] = 0x0f; /* push %fs */ + buf[i++] = 0xa0; + buf[i++] = 0x0f; /* push %gs */ + buf[i++] = 0xa8; + buf[i++] = 0x16; /* push %ss */ + buf[i++] = 0x0e; /* push %cs */ + append_insns (&buildaddr, i, buf); + + /* Stack space for the collecting_t object. */ + i = 0; + i += push_opcode (&buf[i], "83 ec 08"); /* sub $0x8,%esp */ + + /* Build the object. */ + i += push_opcode (&buf[i], "b8"); /* mov ,%eax */ + memcpy (buf + i, &tpoint, 4); + i += 4; + i += push_opcode (&buf[i], "89 04 24"); /* mov %eax,(%esp) */ + + i += push_opcode (&buf[i], "65 a1 00 00 00 00"); /* mov %gs:0x0,%eax */ + i += push_opcode (&buf[i], "89 44 24 04"); /* mov %eax,0x4(%esp) */ + append_insns (&buildaddr, i, buf); + + /* spin-lock. Note this is using cmpxchg, which leaves i386 behind. + If we cared for it, this could be using xchg alternatively. */ + + i = 0; + i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ + i += push_opcode (&buf[i], "f0 0f b1 25"); /* lock cmpxchg + %esp, */ + memcpy (&buf[i], (void *) &lockaddr, 4); + i += 4; + i += push_opcode (&buf[i], "85 c0"); /* test %eax,%eax */ + i += push_opcode (&buf[i], "75 f2"); /* jne */ + append_insns (&buildaddr, i, buf); + + + /* Set up arguments to the gdb_collect call. */ + i = 0; + i += push_opcode (&buf[i], "89 e0"); /* mov %esp,%eax */ + i += push_opcode (&buf[i], "83 c0 08"); /* add $0x08,%eax */ + i += push_opcode (&buf[i], "89 44 24 fc"); /* mov %eax,-0x4(%esp) */ + append_insns (&buildaddr, i, buf); + + i = 0; + i += push_opcode (&buf[i], "83 ec 08"); /* sub $0x8,%esp */ + append_insns (&buildaddr, i, buf); + + i = 0; + i += push_opcode (&buf[i], "c7 04 24"); /* movl ,(%esp) */ + memcpy (&buf[i], (void *) &tpoint, 4); + i += 4; + append_insns (&buildaddr, i, buf); + + buf[0] = 0xe8; /* call */ + offset = collector - (buildaddr + sizeof (jump_insn)); + memcpy (buf + 1, &offset, 4); + append_insns (&buildaddr, 5, buf); + /* Clean up after the call. */ + buf[0] = 0x83; /* add $0x8,%esp */ + buf[1] = 0xc4; + buf[2] = 0x08; + append_insns (&buildaddr, 3, buf); + + + /* Clear the spin-lock. This would need the LOCK prefix on older + broken archs. */ + i = 0; + i += push_opcode (&buf[i], "31 c0"); /* xor %eax,%eax */ + i += push_opcode (&buf[i], "a3"); /* mov %eax, lockaddr */ + memcpy (buf + i, &lockaddr, 4); + i += 4; + append_insns (&buildaddr, i, buf); + + + /* Remove stack that had been used for the collect_t object. */ + i = 0; + i += push_opcode (&buf[i], "83 c4 08"); /* add $0x08,%esp */ + append_insns (&buildaddr, i, buf); + + i = 0; + buf[i++] = 0x83; /* add $0x4,%esp (no pop of %cs, assume unchanged) */ + buf[i++] = 0xc4; + buf[i++] = 0x04; + buf[i++] = 0x17; /* pop %ss */ + buf[i++] = 0x0f; /* pop %gs */ + buf[i++] = 0xa9; + buf[i++] = 0x0f; /* pop %fs */ + buf[i++] = 0xa1; + buf[i++] = 0x07; /* pop %es */ + buf[i++] = 0x1f; /* pop %ds */ + buf[i++] = 0x9d; /* popf */ + buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */ + buf[i++] = 0xc4; + buf[i++] = 0x04; + buf[i++] = 0x61; /* popad */ + append_insns (&buildaddr, i, buf); + + /* Now, adjust the original instruction to execute in the jump + pad. */ + *adjusted_insn_addr = buildaddr; + relocate_instruction (&buildaddr, tpaddr); + *adjusted_insn_addr_end = buildaddr; + + /* Write the jump back to the program. */ + offset = (tpaddr + orig_size) - (buildaddr + sizeof (jump_insn)); + memcpy (buf, jump_insn, sizeof (jump_insn)); + memcpy (buf + 1, &offset, 4); + append_insns (&buildaddr, sizeof (jump_insn), buf); + + /* The jump pad is now built. Wire in a jump to our jump pad. This + is always done last (by our caller actually), so that we can + install fast tracepoints with threads running. This relies on + the agent's atomic write support. */ + if (orig_size == 4) + { + /* Create a trampoline. */ + *trampoline_size = sizeof (jump_insn); + if (!claim_trampoline_space (*trampoline_size, trampoline)) + { + /* No trampoline space available. */ + strcpy (err, + "E.Cannot allocate trampoline space needed for fast " + "tracepoints on 4-byte instructions."); + return 1; + } + + offset = *jump_entry - (*trampoline + sizeof (jump_insn)); + memcpy (buf, jump_insn, sizeof (jump_insn)); + memcpy (buf + 1, &offset, 4); + target_write_memory (*trampoline, buf, sizeof (jump_insn)); + + /* Use a 16-bit relative jump instruction to jump to the trampoline. */ + offset = (*trampoline - (tpaddr + sizeof (small_jump_insn))) & 0xffff; + memcpy (buf, small_jump_insn, sizeof (small_jump_insn)); + memcpy (buf + 2, &offset, 2); + memcpy (jjump_pad_insn, buf, sizeof (small_jump_insn)); + *jjump_pad_insn_size = sizeof (small_jump_insn); + } + else + { + /* Else use a 32-bit relative jump instruction. */ + offset = *jump_entry - (tpaddr + sizeof (jump_insn)); + memcpy (buf, jump_insn, sizeof (jump_insn)); + memcpy (buf + 1, &offset, 4); + memcpy (jjump_pad_insn, buf, sizeof (jump_insn)); + *jjump_pad_insn_size = sizeof (jump_insn); + } + + /* Return the end address of our pad. */ + *jump_entry = buildaddr; + + return 0; +} + +static int +x86_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr, + collector, lockaddr, + orig_size, jump_entry, + trampoline, trampoline_size, + jjump_pad_insn, + jjump_pad_insn_size, + adjusted_insn_addr, + adjusted_insn_addr_end, + err); +#endif + + return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr, + collector, lockaddr, + orig_size, jump_entry, + trampoline, trampoline_size, + jjump_pad_insn, + jjump_pad_insn_size, + adjusted_insn_addr, + adjusted_insn_addr_end, + err); +} + +/* Return the minimum instruction length for fast tracepoints on x86/x86-64 + architectures. */ + +static int +x86_get_min_fast_tracepoint_insn_len (void) +{ + static int warned_about_fast_tracepoints = 0; + +#ifdef __x86_64__ + /* On x86-64, 5-byte jump instructions with a 4-byte offset are always + used for fast tracepoints. */ + if (is_64bit_tdesc ()) + return 5; +#endif + + if (agent_loaded_p ()) + { + char errbuf[IPA_BUFSIZ]; + + errbuf[0] = '\0'; + + /* On x86, if trampolines are available, then 4-byte jump instructions + with a 2-byte offset may be used, otherwise 5-byte jump instructions + with a 4-byte offset are used instead. */ + if (have_fast_tracepoint_trampoline_buffer (errbuf)) + return 4; + else + { + /* GDB has no channel to explain to user why a shorter fast + tracepoint is not possible, but at least make GDBserver + mention that something has gone awry. */ + if (!warned_about_fast_tracepoints) + { + warning ("4-byte fast tracepoints not available; %s", errbuf); + warned_about_fast_tracepoints = 1; + } + return 5; + } + } + else + { + /* Indicate that the minimum length is currently unknown since the IPA + has not loaded yet. */ + return 0; + } +} + +static void +add_insns (unsigned char *start, int len) +{ + CORE_ADDR buildaddr = current_insn_ptr; + + if (debug_threads) + debug_printf ("Adding %d bytes of insn at %s\n", + len, paddress (buildaddr)); + + append_insns (&buildaddr, len, start); + current_insn_ptr = buildaddr; +} + +/* Our general strategy for emitting code is to avoid specifying raw + bytes whenever possible, and instead copy a block of inline asm + that is embedded in the function. This is a little messy, because + we need to keep the compiler from discarding what looks like dead + code, plus suppress various warnings. */ + +#define EMIT_ASM(NAME, INSNS) \ + do \ + { \ + extern unsigned char start_ ## NAME, end_ ## NAME; \ + add_insns (&start_ ## NAME, &end_ ## NAME - &start_ ## NAME); \ + __asm__ ("jmp end_" #NAME "\n" \ + "\t" "start_" #NAME ":" \ + "\t" INSNS "\n" \ + "\t" "end_" #NAME ":"); \ + } while (0) + +#ifdef __x86_64__ + +#define EMIT_ASM32(NAME,INSNS) \ + do \ + { \ + extern unsigned char start_ ## NAME, end_ ## NAME; \ + add_insns (&start_ ## NAME, &end_ ## NAME - &start_ ## NAME); \ + __asm__ (".code32\n" \ + "\t" "jmp end_" #NAME "\n" \ + "\t" "start_" #NAME ":\n" \ + "\t" INSNS "\n" \ + "\t" "end_" #NAME ":\n" \ + ".code64\n"); \ + } while (0) + +#else + +#define EMIT_ASM32(NAME,INSNS) EMIT_ASM(NAME,INSNS) + +#endif + +#ifdef __x86_64__ + +static void +amd64_emit_prologue (void) +{ + EMIT_ASM (amd64_prologue, + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "sub $0x20,%rsp\n\t" + "movq %rdi,-8(%rbp)\n\t" + "movq %rsi,-16(%rbp)"); +} + + +static void +amd64_emit_epilogue (void) +{ + EMIT_ASM (amd64_epilogue, + "movq -16(%rbp),%rdi\n\t" + "movq %rax,(%rdi)\n\t" + "xor %rax,%rax\n\t" + "leave\n\t" + "ret"); +} + +static void +amd64_emit_add (void) +{ + EMIT_ASM (amd64_add, + "add (%rsp),%rax\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_sub (void) +{ + EMIT_ASM (amd64_sub, + "sub %rax,(%rsp)\n\t" + "pop %rax"); +} + +static void +amd64_emit_mul (void) +{ + emit_error = 1; +} + +static void +amd64_emit_lsh (void) +{ + emit_error = 1; +} + +static void +amd64_emit_rsh_signed (void) +{ + emit_error = 1; +} + +static void +amd64_emit_rsh_unsigned (void) +{ + emit_error = 1; +} + +static void +amd64_emit_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM (amd64_ext_8, + "cbtw\n\t" + "cwtl\n\t" + "cltq"); + break; + case 16: + EMIT_ASM (amd64_ext_16, + "cwtl\n\t" + "cltq"); + break; + case 32: + EMIT_ASM (amd64_ext_32, + "cltq"); + break; + default: + emit_error = 1; + } +} + +static void +amd64_emit_log_not (void) +{ + EMIT_ASM (amd64_log_not, + "test %rax,%rax\n\t" + "sete %cl\n\t" + "movzbq %cl,%rax"); +} + +static void +amd64_emit_bit_and (void) +{ + EMIT_ASM (amd64_and, + "and (%rsp),%rax\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_bit_or (void) +{ + EMIT_ASM (amd64_or, + "or (%rsp),%rax\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_bit_xor (void) +{ + EMIT_ASM (amd64_xor, + "xor (%rsp),%rax\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_bit_not (void) +{ + EMIT_ASM (amd64_bit_not, + "xorq $0xffffffffffffffff,%rax"); +} + +static void +amd64_emit_equal (void) +{ + EMIT_ASM (amd64_equal, + "cmp %rax,(%rsp)\n\t" + "je .Lamd64_equal_true\n\t" + "xor %rax,%rax\n\t" + "jmp .Lamd64_equal_end\n\t" + ".Lamd64_equal_true:\n\t" + "mov $0x1,%rax\n\t" + ".Lamd64_equal_end:\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_less_signed (void) +{ + EMIT_ASM (amd64_less_signed, + "cmp %rax,(%rsp)\n\t" + "jl .Lamd64_less_signed_true\n\t" + "xor %rax,%rax\n\t" + "jmp .Lamd64_less_signed_end\n\t" + ".Lamd64_less_signed_true:\n\t" + "mov $1,%rax\n\t" + ".Lamd64_less_signed_end:\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_less_unsigned (void) +{ + EMIT_ASM (amd64_less_unsigned, + "cmp %rax,(%rsp)\n\t" + "jb .Lamd64_less_unsigned_true\n\t" + "xor %rax,%rax\n\t" + "jmp .Lamd64_less_unsigned_end\n\t" + ".Lamd64_less_unsigned_true:\n\t" + "mov $1,%rax\n\t" + ".Lamd64_less_unsigned_end:\n\t" + "lea 0x8(%rsp),%rsp"); +} + +static void +amd64_emit_ref (int size) +{ + switch (size) + { + case 1: + EMIT_ASM (amd64_ref1, + "movb (%rax),%al"); + break; + case 2: + EMIT_ASM (amd64_ref2, + "movw (%rax),%ax"); + break; + case 4: + EMIT_ASM (amd64_ref4, + "movl (%rax),%eax"); + break; + case 8: + EMIT_ASM (amd64_ref8, + "movq (%rax),%rax"); + break; + } +} + +static void +amd64_emit_if_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_if_goto, + "mov %rax,%rcx\n\t" + "pop %rax\n\t" + "cmp $0,%rcx\n\t" + ".byte 0x0f, 0x85, 0x0, 0x0, 0x0, 0x0"); + if (offset_p) + *offset_p = 10; + if (size_p) + *size_p = 4; +} + +static void +amd64_emit_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_goto, + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0"); + if (offset_p) + *offset_p = 1; + if (size_p) + *size_p = 4; +} + +static void +amd64_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) +{ + int diff = (to - (from + size)); + unsigned char buf[sizeof (int)]; + + if (size != 4) + { + emit_error = 1; + return; + } + + memcpy (buf, &diff, sizeof (int)); + target_write_memory (from, buf, sizeof (int)); +} + +static void +amd64_emit_const (LONGEST num) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr = current_insn_ptr; + + i = 0; + buf[i++] = 0x48; buf[i++] = 0xb8; /* mov $,%rax */ + memcpy (&buf[i], &num, sizeof (num)); + i += 8; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; +} + +static void +amd64_emit_call (CORE_ADDR fn) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + LONGEST offset64; + + /* The destination function being in the shared library, may be + >31-bits away off the compiled code pad. */ + + buildaddr = current_insn_ptr; + + offset64 = fn - (buildaddr + 1 /* call op */ + 4 /* 32-bit offset */); + + i = 0; + + if (offset64 > INT_MAX || offset64 < INT_MIN) + { + /* Offset is too large for a call. Use callq, but that requires + a register, so avoid it if possible. Use r10, since it is + call-clobbered, we don't have to push/pop it. */ + buf[i++] = 0x48; /* mov $fn,%r10 */ + buf[i++] = 0xba; + memcpy (buf + i, &fn, 8); + i += 8; + buf[i++] = 0xff; /* callq *%r10 */ + buf[i++] = 0xd2; + } + else + { + int offset32 = offset64; /* we know we can't overflow here. */ + + buf[i++] = 0xe8; /* call */ + memcpy (buf + i, &offset32, 4); + i += 4; + } + + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; +} + +static void +amd64_emit_reg (int reg) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + + /* Assume raw_regs is still in %rdi. */ + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xbe; /* mov $,%esi */ + memcpy (&buf[i], ®, sizeof (reg)); + i += 4; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; + amd64_emit_call (get_raw_reg_func_addr ()); +} + +static void +amd64_emit_pop (void) +{ + EMIT_ASM (amd64_pop, + "pop %rax"); +} + +static void +amd64_emit_stack_flush (void) +{ + EMIT_ASM (amd64_stack_flush, + "push %rax"); +} + +static void +amd64_emit_zero_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM (amd64_zero_ext_8, + "and $0xff,%rax"); + break; + case 16: + EMIT_ASM (amd64_zero_ext_16, + "and $0xffff,%rax"); + break; + case 32: + EMIT_ASM (amd64_zero_ext_32, + "mov $0xffffffff,%rcx\n\t" + "and %rcx,%rax"); + break; + default: + emit_error = 1; + } +} + +static void +amd64_emit_swap (void) +{ + EMIT_ASM (amd64_swap, + "mov %rax,%rcx\n\t" + "pop %rax\n\t" + "push %rcx"); +} + +static void +amd64_emit_stack_adjust (int n) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr = current_insn_ptr; + + i = 0; + buf[i++] = 0x48; /* lea $(%rsp),%rsp */ + buf[i++] = 0x8d; + buf[i++] = 0x64; + buf[i++] = 0x24; + /* This only handles adjustments up to 16, but we don't expect any more. */ + buf[i++] = n * 8; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; +} + +/* FN's prototype is `LONGEST(*fn)(int)'. */ + +static void +amd64_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xbf; /* movl $,%edi */ + memcpy (&buf[i], &arg1, sizeof (arg1)); + i += 4; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; + amd64_emit_call (fn); +} + +/* FN's prototype is `void(*fn)(int,LONGEST)'. */ + +static void +amd64_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xbf; /* movl $,%edi */ + memcpy (&buf[i], &arg1, sizeof (arg1)); + i += 4; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; + EMIT_ASM (amd64_void_call_2_a, + /* Save away a copy of the stack top. */ + "push %rax\n\t" + /* Also pass top as the second argument. */ + "mov %rax,%rsi"); + amd64_emit_call (fn); + EMIT_ASM (amd64_void_call_2_b, + /* Restore the stack top, %rax may have been trashed. */ + "pop %rax"); +} + +static void +amd64_emit_eq_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_eq, + "cmp %rax,(%rsp)\n\t" + "jne .Lamd64_eq_fallthru\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lamd64_eq_fallthru:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax"); + + if (offset_p) + *offset_p = 13; + if (size_p) + *size_p = 4; +} + +static void +amd64_emit_ne_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_ne, + "cmp %rax,(%rsp)\n\t" + "je .Lamd64_ne_fallthru\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lamd64_ne_fallthru:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax"); + + if (offset_p) + *offset_p = 13; + if (size_p) + *size_p = 4; +} + +static void +amd64_emit_lt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_lt, + "cmp %rax,(%rsp)\n\t" + "jnl .Lamd64_lt_fallthru\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lamd64_lt_fallthru:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax"); + + if (offset_p) + *offset_p = 13; + if (size_p) + *size_p = 4; +} + +static void +amd64_emit_le_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_le, + "cmp %rax,(%rsp)\n\t" + "jnle .Lamd64_le_fallthru\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lamd64_le_fallthru:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax"); + + if (offset_p) + *offset_p = 13; + if (size_p) + *size_p = 4; +} + +static void +amd64_emit_gt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_gt, + "cmp %rax,(%rsp)\n\t" + "jng .Lamd64_gt_fallthru\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lamd64_gt_fallthru:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax"); + + if (offset_p) + *offset_p = 13; + if (size_p) + *size_p = 4; +} + +static void +amd64_emit_ge_goto (int *offset_p, int *size_p) +{ + EMIT_ASM (amd64_ge, + "cmp %rax,(%rsp)\n\t" + "jnge .Lamd64_ge_fallthru\n\t" + ".Lamd64_ge_jump:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lamd64_ge_fallthru:\n\t" + "lea 0x8(%rsp),%rsp\n\t" + "pop %rax"); + + if (offset_p) + *offset_p = 13; + if (size_p) + *size_p = 4; +} + +struct emit_ops amd64_emit_ops = + { + amd64_emit_prologue, + amd64_emit_epilogue, + amd64_emit_add, + amd64_emit_sub, + amd64_emit_mul, + amd64_emit_lsh, + amd64_emit_rsh_signed, + amd64_emit_rsh_unsigned, + amd64_emit_ext, + amd64_emit_log_not, + amd64_emit_bit_and, + amd64_emit_bit_or, + amd64_emit_bit_xor, + amd64_emit_bit_not, + amd64_emit_equal, + amd64_emit_less_signed, + amd64_emit_less_unsigned, + amd64_emit_ref, + amd64_emit_if_goto, + amd64_emit_goto, + amd64_write_goto_address, + amd64_emit_const, + amd64_emit_call, + amd64_emit_reg, + amd64_emit_pop, + amd64_emit_stack_flush, + amd64_emit_zero_ext, + amd64_emit_swap, + amd64_emit_stack_adjust, + amd64_emit_int_call_1, + amd64_emit_void_call_2, + amd64_emit_eq_goto, + amd64_emit_ne_goto, + amd64_emit_lt_goto, + amd64_emit_le_goto, + amd64_emit_gt_goto, + amd64_emit_ge_goto + }; + +#endif /* __x86_64__ */ + +static void +i386_emit_prologue (void) +{ + EMIT_ASM32 (i386_prologue, + "push %ebp\n\t" + "mov %esp,%ebp\n\t" + "push %ebx"); + /* At this point, the raw regs base address is at 8(%ebp), and the + value pointer is at 12(%ebp). */ +} + +static void +i386_emit_epilogue (void) +{ + EMIT_ASM32 (i386_epilogue, + "mov 12(%ebp),%ecx\n\t" + "mov %eax,(%ecx)\n\t" + "mov %ebx,0x4(%ecx)\n\t" + "xor %eax,%eax\n\t" + "pop %ebx\n\t" + "pop %ebp\n\t" + "ret"); +} + +static void +i386_emit_add (void) +{ + EMIT_ASM32 (i386_add, + "add (%esp),%eax\n\t" + "adc 0x4(%esp),%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_sub (void) +{ + EMIT_ASM32 (i386_sub, + "subl %eax,(%esp)\n\t" + "sbbl %ebx,4(%esp)\n\t" + "pop %eax\n\t" + "pop %ebx\n\t"); +} + +static void +i386_emit_mul (void) +{ + emit_error = 1; +} + +static void +i386_emit_lsh (void) +{ + emit_error = 1; +} + +static void +i386_emit_rsh_signed (void) +{ + emit_error = 1; +} + +static void +i386_emit_rsh_unsigned (void) +{ + emit_error = 1; +} + +static void +i386_emit_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM32 (i386_ext_8, + "cbtw\n\t" + "cwtl\n\t" + "movl %eax,%ebx\n\t" + "sarl $31,%ebx"); + break; + case 16: + EMIT_ASM32 (i386_ext_16, + "cwtl\n\t" + "movl %eax,%ebx\n\t" + "sarl $31,%ebx"); + break; + case 32: + EMIT_ASM32 (i386_ext_32, + "movl %eax,%ebx\n\t" + "sarl $31,%ebx"); + break; + default: + emit_error = 1; + } +} + +static void +i386_emit_log_not (void) +{ + EMIT_ASM32 (i386_log_not, + "or %ebx,%eax\n\t" + "test %eax,%eax\n\t" + "sete %cl\n\t" + "xor %ebx,%ebx\n\t" + "movzbl %cl,%eax"); +} + +static void +i386_emit_bit_and (void) +{ + EMIT_ASM32 (i386_and, + "and (%esp),%eax\n\t" + "and 0x4(%esp),%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_bit_or (void) +{ + EMIT_ASM32 (i386_or, + "or (%esp),%eax\n\t" + "or 0x4(%esp),%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_bit_xor (void) +{ + EMIT_ASM32 (i386_xor, + "xor (%esp),%eax\n\t" + "xor 0x4(%esp),%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_bit_not (void) +{ + EMIT_ASM32 (i386_bit_not, + "xor $0xffffffff,%eax\n\t" + "xor $0xffffffff,%ebx\n\t"); +} + +static void +i386_emit_equal (void) +{ + EMIT_ASM32 (i386_equal, + "cmpl %ebx,4(%esp)\n\t" + "jne .Li386_equal_false\n\t" + "cmpl %eax,(%esp)\n\t" + "je .Li386_equal_true\n\t" + ".Li386_equal_false:\n\t" + "xor %eax,%eax\n\t" + "jmp .Li386_equal_end\n\t" + ".Li386_equal_true:\n\t" + "mov $1,%eax\n\t" + ".Li386_equal_end:\n\t" + "xor %ebx,%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_less_signed (void) +{ + EMIT_ASM32 (i386_less_signed, + "cmpl %ebx,4(%esp)\n\t" + "jl .Li386_less_signed_true\n\t" + "jne .Li386_less_signed_false\n\t" + "cmpl %eax,(%esp)\n\t" + "jl .Li386_less_signed_true\n\t" + ".Li386_less_signed_false:\n\t" + "xor %eax,%eax\n\t" + "jmp .Li386_less_signed_end\n\t" + ".Li386_less_signed_true:\n\t" + "mov $1,%eax\n\t" + ".Li386_less_signed_end:\n\t" + "xor %ebx,%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_less_unsigned (void) +{ + EMIT_ASM32 (i386_less_unsigned, + "cmpl %ebx,4(%esp)\n\t" + "jb .Li386_less_unsigned_true\n\t" + "jne .Li386_less_unsigned_false\n\t" + "cmpl %eax,(%esp)\n\t" + "jb .Li386_less_unsigned_true\n\t" + ".Li386_less_unsigned_false:\n\t" + "xor %eax,%eax\n\t" + "jmp .Li386_less_unsigned_end\n\t" + ".Li386_less_unsigned_true:\n\t" + "mov $1,%eax\n\t" + ".Li386_less_unsigned_end:\n\t" + "xor %ebx,%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_ref (int size) +{ + switch (size) + { + case 1: + EMIT_ASM32 (i386_ref1, + "movb (%eax),%al"); + break; + case 2: + EMIT_ASM32 (i386_ref2, + "movw (%eax),%ax"); + break; + case 4: + EMIT_ASM32 (i386_ref4, + "movl (%eax),%eax"); + break; + case 8: + EMIT_ASM32 (i386_ref8, + "movl 4(%eax),%ebx\n\t" + "movl (%eax),%eax"); + break; + } +} + +static void +i386_emit_if_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (i386_if_goto, + "mov %eax,%ecx\n\t" + "or %ebx,%ecx\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + "cmpl $0,%ecx\n\t" + /* Don't trust the assembler to choose the right jump */ + ".byte 0x0f, 0x85, 0x0, 0x0, 0x0, 0x0"); + + if (offset_p) + *offset_p = 11; /* be sure that this matches the sequence above */ + if (size_p) + *size_p = 4; +} + +static void +i386_emit_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (i386_goto, + /* Don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0"); + if (offset_p) + *offset_p = 1; + if (size_p) + *size_p = 4; +} + +static void +i386_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size) +{ + int diff = (to - (from + size)); + unsigned char buf[sizeof (int)]; + + /* We're only doing 4-byte sizes at the moment. */ + if (size != 4) + { + emit_error = 1; + return; + } + + memcpy (buf, &diff, sizeof (int)); + target_write_memory (from, buf, sizeof (int)); +} + +static void +i386_emit_const (LONGEST num) +{ + unsigned char buf[16]; + int i, hi, lo; + CORE_ADDR buildaddr = current_insn_ptr; + + i = 0; + buf[i++] = 0xb8; /* mov $,%eax */ + lo = num & 0xffffffff; + memcpy (&buf[i], &lo, sizeof (lo)); + i += 4; + hi = ((num >> 32) & 0xffffffff); + if (hi) + { + buf[i++] = 0xbb; /* mov $,%ebx */ + memcpy (&buf[i], &hi, sizeof (hi)); + i += 4; + } + else + { + buf[i++] = 0x31; buf[i++] = 0xdb; /* xor %ebx,%ebx */ + } + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; +} + +static void +i386_emit_call (CORE_ADDR fn) +{ + unsigned char buf[16]; + int i, offset; + CORE_ADDR buildaddr; + + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xe8; /* call */ + offset = ((int) fn) - (buildaddr + 5); + memcpy (buf + 1, &offset, 4); + append_insns (&buildaddr, 5, buf); + current_insn_ptr = buildaddr; +} + +static void +i386_emit_reg (int reg) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + + EMIT_ASM32 (i386_reg_a, + "sub $0x8,%esp"); + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xb8; /* mov $,%eax */ + memcpy (&buf[i], ®, sizeof (reg)); + i += 4; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; + EMIT_ASM32 (i386_reg_b, + "mov %eax,4(%esp)\n\t" + "mov 8(%ebp),%eax\n\t" + "mov %eax,(%esp)"); + i386_emit_call (get_raw_reg_func_addr ()); + EMIT_ASM32 (i386_reg_c, + "xor %ebx,%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +static void +i386_emit_pop (void) +{ + EMIT_ASM32 (i386_pop, + "pop %eax\n\t" + "pop %ebx"); +} + +static void +i386_emit_stack_flush (void) +{ + EMIT_ASM32 (i386_stack_flush, + "push %ebx\n\t" + "push %eax"); +} + +static void +i386_emit_zero_ext (int arg) +{ + switch (arg) + { + case 8: + EMIT_ASM32 (i386_zero_ext_8, + "and $0xff,%eax\n\t" + "xor %ebx,%ebx"); + break; + case 16: + EMIT_ASM32 (i386_zero_ext_16, + "and $0xffff,%eax\n\t" + "xor %ebx,%ebx"); + break; + case 32: + EMIT_ASM32 (i386_zero_ext_32, + "xor %ebx,%ebx"); + break; + default: + emit_error = 1; + } +} + +static void +i386_emit_swap (void) +{ + EMIT_ASM32 (i386_swap, + "mov %eax,%ecx\n\t" + "mov %ebx,%edx\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + "push %edx\n\t" + "push %ecx"); +} + +static void +i386_emit_stack_adjust (int n) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr = current_insn_ptr; + + i = 0; + buf[i++] = 0x8d; /* lea $(%esp),%esp */ + buf[i++] = 0x64; + buf[i++] = 0x24; + buf[i++] = n * 8; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; +} + +/* FN's prototype is `LONGEST(*fn)(int)'. */ + +static void +i386_emit_int_call_1 (CORE_ADDR fn, int arg1) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + + EMIT_ASM32 (i386_int_call_1_a, + /* Reserve a bit of stack space. */ + "sub $0x8,%esp"); + /* Put the one argument on the stack. */ + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xc7; /* movl $,(%esp) */ + buf[i++] = 0x04; + buf[i++] = 0x24; + memcpy (&buf[i], &arg1, sizeof (arg1)); + i += 4; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; + i386_emit_call (fn); + EMIT_ASM32 (i386_int_call_1_c, + "mov %edx,%ebx\n\t" + "lea 0x8(%esp),%esp"); +} + +/* FN's prototype is `void(*fn)(int,LONGEST)'. */ + +static void +i386_emit_void_call_2 (CORE_ADDR fn, int arg1) +{ + unsigned char buf[16]; + int i; + CORE_ADDR buildaddr; + + EMIT_ASM32 (i386_void_call_2_a, + /* Preserve %eax only; we don't have to worry about %ebx. */ + "push %eax\n\t" + /* Reserve a bit of stack space for arguments. */ + "sub $0x10,%esp\n\t" + /* Copy "top" to the second argument position. (Note that + we can't assume function won't scribble on its + arguments, so don't try to restore from this.) */ + "mov %eax,4(%esp)\n\t" + "mov %ebx,8(%esp)"); + /* Put the first argument on the stack. */ + buildaddr = current_insn_ptr; + i = 0; + buf[i++] = 0xc7; /* movl $,(%esp) */ + buf[i++] = 0x04; + buf[i++] = 0x24; + memcpy (&buf[i], &arg1, sizeof (arg1)); + i += 4; + append_insns (&buildaddr, i, buf); + current_insn_ptr = buildaddr; + i386_emit_call (fn); + EMIT_ASM32 (i386_void_call_2_b, + "lea 0x10(%esp),%esp\n\t" + /* Restore original stack top. */ + "pop %eax"); +} + + +static void +i386_emit_eq_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (eq, + /* Check low half first, more likely to be decider */ + "cmpl %eax,(%esp)\n\t" + "jne .Leq_fallthru\n\t" + "cmpl %ebx,4(%esp)\n\t" + "jne .Leq_fallthru\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Leq_fallthru:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx"); + + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +static void +i386_emit_ne_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (ne, + /* Check low half first, more likely to be decider */ + "cmpl %eax,(%esp)\n\t" + "jne .Lne_jump\n\t" + "cmpl %ebx,4(%esp)\n\t" + "je .Lne_fallthru\n\t" + ".Lne_jump:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lne_fallthru:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx"); + + if (offset_p) + *offset_p = 18; + if (size_p) + *size_p = 4; +} + +static void +i386_emit_lt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (lt, + "cmpl %ebx,4(%esp)\n\t" + "jl .Llt_jump\n\t" + "jne .Llt_fallthru\n\t" + "cmpl %eax,(%esp)\n\t" + "jnl .Llt_fallthru\n\t" + ".Llt_jump:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Llt_fallthru:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx"); + + if (offset_p) + *offset_p = 20; + if (size_p) + *size_p = 4; +} + +static void +i386_emit_le_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (le, + "cmpl %ebx,4(%esp)\n\t" + "jle .Lle_jump\n\t" + "jne .Lle_fallthru\n\t" + "cmpl %eax,(%esp)\n\t" + "jnle .Lle_fallthru\n\t" + ".Lle_jump:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lle_fallthru:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx"); + + if (offset_p) + *offset_p = 20; + if (size_p) + *size_p = 4; +} + +static void +i386_emit_gt_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (gt, + "cmpl %ebx,4(%esp)\n\t" + "jg .Lgt_jump\n\t" + "jne .Lgt_fallthru\n\t" + "cmpl %eax,(%esp)\n\t" + "jng .Lgt_fallthru\n\t" + ".Lgt_jump:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lgt_fallthru:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx"); + + if (offset_p) + *offset_p = 20; + if (size_p) + *size_p = 4; +} + +static void +i386_emit_ge_goto (int *offset_p, int *size_p) +{ + EMIT_ASM32 (ge, + "cmpl %ebx,4(%esp)\n\t" + "jge .Lge_jump\n\t" + "jne .Lge_fallthru\n\t" + "cmpl %eax,(%esp)\n\t" + "jnge .Lge_fallthru\n\t" + ".Lge_jump:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx\n\t" + /* jmp, but don't trust the assembler to choose the right jump */ + ".byte 0xe9, 0x0, 0x0, 0x0, 0x0\n\t" + ".Lge_fallthru:\n\t" + "lea 0x8(%esp),%esp\n\t" + "pop %eax\n\t" + "pop %ebx"); + + if (offset_p) + *offset_p = 20; + if (size_p) + *size_p = 4; +} + +struct emit_ops i386_emit_ops = + { + i386_emit_prologue, + i386_emit_epilogue, + i386_emit_add, + i386_emit_sub, + i386_emit_mul, + i386_emit_lsh, + i386_emit_rsh_signed, + i386_emit_rsh_unsigned, + i386_emit_ext, + i386_emit_log_not, + i386_emit_bit_and, + i386_emit_bit_or, + i386_emit_bit_xor, + i386_emit_bit_not, + i386_emit_equal, + i386_emit_less_signed, + i386_emit_less_unsigned, + i386_emit_ref, + i386_emit_if_goto, + i386_emit_goto, + i386_write_goto_address, + i386_emit_const, + i386_emit_call, + i386_emit_reg, + i386_emit_pop, + i386_emit_stack_flush, + i386_emit_zero_ext, + i386_emit_swap, + i386_emit_stack_adjust, + i386_emit_int_call_1, + i386_emit_void_call_2, + i386_emit_eq_goto, + i386_emit_ne_goto, + i386_emit_lt_goto, + i386_emit_le_goto, + i386_emit_gt_goto, + i386_emit_ge_goto + }; + + +static struct emit_ops * +x86_emit_ops (void) +{ +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return &amd64_emit_ops; + else +#endif + return &i386_emit_ops; +} + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +x86_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = x86_breakpoint_len; + return x86_breakpoint; +} + +static int +x86_supports_range_stepping (void) +{ + return 1; +} + +/* Implementation of linux_target_ops method "supports_hardware_single_step". + */ + +static int +x86_supports_hardware_single_step (void) +{ + return 1; +} + +static int +x86_get_ipa_tdesc_idx (void) +{ + struct regcache *regcache = get_thread_regcache (current_thread, 0); + const struct target_desc *tdesc = regcache->tdesc; + +#ifdef __x86_64__ + return amd64_get_ipa_tdesc_idx (tdesc); +#endif + + if (tdesc == tdesc_i386_linux_no_xml) + return X86_TDESC_SSE; + + return i386_get_ipa_tdesc_idx (tdesc); +} + +/* This is initialized assuming an amd64 target. + x86_arch_setup will correct it for i386 or amd64 targets. */ + +struct linux_target_ops the_low_target = +{ + x86_arch_setup, + x86_linux_regs_info, + x86_cannot_fetch_register, + x86_cannot_store_register, + NULL, /* fetch_register */ + x86_get_pc, + x86_set_pc, + NULL, /* breakpoint_kind_from_pc */ + x86_sw_breakpoint_from_kind, + NULL, + 1, + x86_breakpoint_at, + x86_supports_z_point_type, + x86_insert_point, + x86_remove_point, + x86_stopped_by_watchpoint, + x86_stopped_data_address, + /* collect_ptrace_register/supply_ptrace_register are not needed in the + native i386 case (no registers smaller than an xfer unit), and are not + used in the biarch case (HAVE_LINUX_USRREGS is not defined). */ + NULL, + NULL, + /* need to fix up i386 siginfo if host is amd64 */ + x86_siginfo_fixup, + x86_linux_new_process, + x86_linux_delete_process, + x86_linux_new_thread, + x86_linux_delete_thread, + x86_linux_new_fork, + x86_linux_prepare_to_resume, + x86_linux_process_qsupported, + x86_supports_tracepoints, + x86_get_thread_area, + x86_install_fast_tracepoint_jump_pad, + x86_emit_ops, + x86_get_min_fast_tracepoint_insn_len, + x86_supports_range_stepping, + NULL, /* breakpoint_kind_from_current_state */ + x86_supports_hardware_single_step, + x86_get_syscall_trapinfo, + x86_get_ipa_tdesc_idx, +}; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ +#ifdef __x86_64__ + tdesc_amd64_linux_no_xml = allocate_target_description (); + copy_target_description (tdesc_amd64_linux_no_xml, + amd64_linux_read_description (X86_XSTATE_SSE_MASK, + false)); + tdesc_amd64_linux_no_xml->xmltarget = xmltarget_amd64_linux_no_xml; +#endif + + tdesc_i386_linux_no_xml = allocate_target_description (); + copy_target_description (tdesc_i386_linux_no_xml, + i386_linux_read_description (X86_XSTATE_SSE_MASK)); + tdesc_i386_linux_no_xml->xmltarget = xmltarget_i386_linux_no_xml; + + initialize_regsets_info (&x86_regsets_info); +} diff --git a/gdbserver/linux-x86-tdesc.c b/gdbserver/linux-x86-tdesc.c new file mode 100644 index 00000000000..96097eecc5e --- /dev/null +++ b/gdbserver/linux-x86-tdesc.c @@ -0,0 +1,164 @@ +/* GNU/Linux/x86-64 specific target description, for the remote server + for GDB. + Copyright (C) 2017-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "tdesc.h" +#include "linux-x86-tdesc.h" +#include "arch/i386.h" +#include "gdbsupport/x86-xstate.h" +#ifdef __x86_64__ +#include "arch/amd64.h" +#endif +#include "x86-tdesc.h" + +/* Return the right x86_linux_tdesc index for a given XCR0. Return + X86_TDESC_LAST if can't find a match. */ + +static enum x86_linux_tdesc +xcr0_to_tdesc_idx (uint64_t xcr0, bool is_x32) +{ + if (xcr0 & X86_XSTATE_PKRU) + { + if (is_x32) + { + /* No x32 MPX and PKU, fall back to avx_avx512. */ + return X86_TDESC_AVX_AVX512; + } + else + return X86_TDESC_AVX_MPX_AVX512_PKU; + } + else if (xcr0 & X86_XSTATE_AVX512) + return X86_TDESC_AVX_AVX512; + else if ((xcr0 & X86_XSTATE_AVX_MPX_MASK) == X86_XSTATE_AVX_MPX_MASK) + { + if (is_x32) /* No MPX on x32. */ + return X86_TDESC_AVX; + else + return X86_TDESC_AVX_MPX; + } + else if (xcr0 & X86_XSTATE_MPX) + { + if (is_x32) /* No MPX on x32. */ + return X86_TDESC_AVX; + else + return X86_TDESC_MPX; + } + else if (xcr0 & X86_XSTATE_AVX) + return X86_TDESC_AVX; + else if (xcr0 & X86_XSTATE_SSE) + return X86_TDESC_SSE; + else if (xcr0 & X86_XSTATE_X87) + return X86_TDESC_MMX; + else + return X86_TDESC_LAST; +} + +#if defined __i386__ || !defined IN_PROCESS_AGENT + +static struct target_desc *i386_tdescs[X86_TDESC_LAST] = { }; + +/* Return the target description according to XCR0. */ + +const struct target_desc * +i386_linux_read_description (uint64_t xcr0) +{ + enum x86_linux_tdesc idx = xcr0_to_tdesc_idx (xcr0, false); + + if (idx == X86_TDESC_LAST) + return NULL; + + struct target_desc **tdesc = &i386_tdescs[idx]; + + if (*tdesc == NULL) + { + *tdesc = i386_create_target_description (xcr0, true, false); + + init_target_desc (*tdesc, i386_expedite_regs); + } + + return *tdesc;; +} +#endif + +#ifdef __x86_64__ + +static target_desc *amd64_tdescs[X86_TDESC_LAST] = { }; +static target_desc *x32_tdescs[X86_TDESC_LAST] = { }; + +const struct target_desc * +amd64_linux_read_description (uint64_t xcr0, bool is_x32) +{ + enum x86_linux_tdesc idx = xcr0_to_tdesc_idx (xcr0, is_x32); + + if (idx == X86_TDESC_LAST) + return NULL; + + struct target_desc **tdesc = NULL; + + if (is_x32) + tdesc = &x32_tdescs[idx]; + else + tdesc = &amd64_tdescs[idx]; + + if (*tdesc == NULL) + { + *tdesc = amd64_create_target_description (xcr0, is_x32, true, true); + + init_target_desc (*tdesc, amd64_expedite_regs); + } + return *tdesc; +} + +#endif + +#ifndef IN_PROCESS_AGENT + +int +i386_get_ipa_tdesc_idx (const struct target_desc *tdesc) +{ + for (int i = 0; i < X86_TDESC_LAST; i++) + { + if (tdesc == i386_tdescs[i]) + return i; + } + + /* If none tdesc is found, return the one with minimum features. */ + return X86_TDESC_MMX; +} + +#if defined __x86_64__ +int +amd64_get_ipa_tdesc_idx (const struct target_desc *tdesc) +{ + for (int i = 0; i < X86_TDESC_LAST; i++) + { + if (tdesc == amd64_tdescs[i]) + return i; + } + for (int i = 0; i < X86_TDESC_LAST; i++) + { + if (tdesc == x32_tdescs[i]) + return i; + } + + return X86_TDESC_SSE; +} + +#endif +#endif diff --git a/gdbserver/linux-x86-tdesc.h b/gdbserver/linux-x86-tdesc.h new file mode 100644 index 00000000000..21c8dfd3934 --- /dev/null +++ b/gdbserver/linux-x86-tdesc.h @@ -0,0 +1,56 @@ +/* Low level support for x86 (i386 and x86-64), shared between gdbserver + and IPA. + + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LINUX_X86_TDESC_H +#define GDBSERVER_LINUX_X86_TDESC_H + +/* Note: since IPA obviously knows what ABI it's running on (i386 vs x86_64 + vs x32), it's sufficient to pass only the register set here. This, + together with the ABI known at IPA compile time, maps to a tdesc. */ + +enum x86_linux_tdesc { + X86_TDESC_MMX = 0, + X86_TDESC_SSE = 1, + X86_TDESC_AVX = 2, + X86_TDESC_MPX = 3, + X86_TDESC_AVX_MPX = 4, + X86_TDESC_AVX_AVX512 = 5, + X86_TDESC_AVX_MPX_AVX512_PKU = 6, + X86_TDESC_LAST = 7, +}; + +#if defined __i386__ || !defined IN_PROCESS_AGENT +int i386_get_ipa_tdesc_idx (const struct target_desc *tdesc); +#endif + +#if defined __x86_64__ && !defined IN_PROCESS_AGENT +int amd64_get_ipa_tdesc_idx (const struct target_desc *tdesc); +#endif + +const struct target_desc *i386_get_ipa_tdesc (int idx); + +#ifdef __x86_64__ +const struct target_desc *amd64_linux_read_description (uint64_t xcr0, + bool is_x32); +#endif + +const struct target_desc *i386_linux_read_description (uint64_t xcr0); + +#endif /* GDBSERVER_LINUX_X86_TDESC_H */ diff --git a/gdbserver/linux-xtensa-low.c b/gdbserver/linux-xtensa-low.c new file mode 100644 index 00000000000..83af11e11dc --- /dev/null +++ b/gdbserver/linux-xtensa-low.c @@ -0,0 +1,315 @@ +/* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB. + Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + + +#include "server.h" +#include "linux-low.h" + +/* Defined in auto-generated file reg-xtensa.c. */ +void init_registers_xtensa (void); +extern const struct target_desc *tdesc_xtensa; + +#include +#include +#include "arch/xtensa.h" +#include "gdb_proc_service.h" + +#include "xtensa-xtregs.c" + +enum regnum { + R_PC=0, R_PS, + R_LBEG, R_LEND, R_LCOUNT, + R_SAR, + R_WS, R_WB, + R_THREADPTR, + R_A0 = 64 +}; + +static void +xtensa_fill_gregset (struct regcache *regcache, void *buf) +{ + elf_greg_t* rset = (elf_greg_t*)buf; + const struct target_desc *tdesc = regcache->tdesc; + int ar0_regnum; + char *ptr; + int i; + + /* Take care of AR registers. */ + + ar0_regnum = find_regno (tdesc, "ar0"); + ptr = (char*)&rset[R_A0]; + + for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) + { + collect_register (regcache, i, ptr); + ptr += register_size (tdesc, i); + } + + if (XSHAL_ABI == XTHAL_ABI_CALL0) + { + int a0_regnum = find_regno (tdesc, "a0"); + ptr = (char *) &rset[R_A0 + 4 * rset[R_WB]]; + + for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++) + { + if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS) + ptr = (char *) &rset[R_A0]; + collect_register (regcache, i, ptr); + ptr += register_size (tdesc, i); + } + } + + /* Loop registers, if hardware has it. */ + +#if XCHAL_HAVE_LOOPS + collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]); + collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]); + collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]); +#endif + + collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]); + collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]); + collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]); + collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]); + collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]); + +#if XCHAL_HAVE_THREADPTR + collect_register_by_name (regcache, "threadptr", + (char *) &rset[R_THREADPTR]); +#endif +} + +static void +xtensa_store_gregset (struct regcache *regcache, const void *buf) +{ + const elf_greg_t* rset = (const elf_greg_t*)buf; + const struct target_desc *tdesc = regcache->tdesc; + int ar0_regnum; + char *ptr; + int i; + + /* Take care of AR registers. */ + + ar0_regnum = find_regno (tdesc, "ar0"); + ptr = (char *)&rset[R_A0]; + + for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) + { + supply_register (regcache, i, ptr); + ptr += register_size (tdesc, i); + } + + if (XSHAL_ABI == XTHAL_ABI_CALL0) + { + int a0_regnum = find_regno (tdesc, "a0"); + ptr = (char *) &rset[R_A0 + (4 * rset[R_WB]) % XCHAL_NUM_AREGS]; + + for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++) + { + if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS) + ptr = (char *) &rset[R_A0]; + supply_register (regcache, i, ptr); + ptr += register_size (tdesc, i); + } + } + + /* Loop registers, if hardware has it. */ + +#if XCHAL_HAVE_LOOPS + supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]); + supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]); + supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]); +#endif + + supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]); + supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]); + supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]); + supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]); + supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]); + +#if XCHAL_HAVE_THREADPTR + supply_register_by_name (regcache, "threadptr", + (char *) &rset[R_THREADPTR]); +#endif +} + +/* Xtensa GNU/Linux PTRACE interface includes extended register set. */ + +static void +xtensa_fill_xtregset (struct regcache *regcache, void *buf) +{ + const xtensa_regtable_t *ptr; + + for (ptr = xtensa_regmap_table; ptr->name; ptr++) + { + collect_register_by_name (regcache, ptr->name, + (char*)buf + ptr->ptrace_offset); + } +} + +static void +xtensa_store_xtregset (struct regcache *regcache, const void *buf) +{ + const xtensa_regtable_t *ptr; + + for (ptr = xtensa_regmap_table; ptr->name; ptr++) + { + supply_register_by_name (regcache, ptr->name, + (char*)buf + ptr->ptrace_offset); + } +} + +static struct regset_info xtensa_regsets[] = { + { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), + GENERAL_REGS, + xtensa_fill_gregset, xtensa_store_gregset }, + { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE, + EXTENDED_REGS, + xtensa_fill_xtregset, xtensa_store_xtregset }, + NULL_REGSET +}; + +#if XCHAL_HAVE_BE +#define XTENSA_BREAKPOINT {0xd2,0x0f} +#else +#define XTENSA_BREAKPOINT {0x2d,0xf0} +#endif + +static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT; +#define xtensa_breakpoint_len 2 + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +xtensa_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = xtensa_breakpoint_len; + return xtensa_breakpoint; +} + +static int +xtensa_breakpoint_at (CORE_ADDR where) +{ + unsigned long insn; + + (*the_target->read_memory) (where, (unsigned char *) &insn, + xtensa_breakpoint_len); + return memcmp((char *) &insn, + xtensa_breakpoint, xtensa_breakpoint_len) == 0; +} + +/* Called by libthread_db. */ + +ps_err_e +ps_get_thread_area (struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + xtensa_elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, lwpid, NULL, ®s) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *) regs.threadptr - idx); + + return PS_OK; +} + +static struct regsets_info xtensa_regsets_info = + { + xtensa_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + NULL, /* usrregs */ + &xtensa_regsets_info + }; + +static void +xtensa_arch_setup (void) +{ + current_process ()->tdesc = tdesc_xtensa; +} + +/* Support for hardware single step. */ + +static int +xtensa_supports_hardware_single_step (void) +{ + return 1; +} + +static const struct regs_info * +xtensa_regs_info (void) +{ + return ®s_info; +} + +struct linux_target_ops the_low_target = { + xtensa_arch_setup, + xtensa_regs_info, + 0, + 0, + NULL, /* fetch_register */ + linux_get_pc_32bit, + linux_set_pc_32bit, + NULL, /* breakpoint_kind_from_pc */ + xtensa_sw_breakpoint_from_kind, + NULL, + 0, + xtensa_breakpoint_at, + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + xtensa_supports_hardware_single_step, +}; + + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_xtensa (); + + initialize_regsets_info (&xtensa_regsets_info); +} diff --git a/gdbserver/lynx-i386-low.c b/gdbserver/lynx-i386-low.c new file mode 100644 index 00000000000..d00e1a16771 --- /dev/null +++ b/gdbserver/lynx-i386-low.c @@ -0,0 +1,358 @@ +/* Copyright (C) 2010-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "lynx-low.h" +#include +#include +#include "gdbsupport/x86-xstate.h" +#include "arch/i386.h" +#include "x86-tdesc.h" + +/* The following two typedefs are defined in a .h file which is not + in the standard include path (/sys/include/family/x86/ucontext.h), + so we just duplicate them here. + + Unfortunately for us, the definition of this structure differs between + LynxOS 5.x and LynxOS 178. Rather than duplicate the code, we use + different definitions depending on the target. */ + +#ifdef VMOS_DEV +#define LYNXOS_178 +#endif + +/* General register context */ +typedef struct usr_econtext { + + uint32_t uec_fault; + uint32_t uec_es; + uint32_t uec_ds; + uint32_t uec_edi; + uint32_t uec_esi; + uint32_t uec_ebp; + uint32_t uec_temp; + uint32_t uec_ebx; + uint32_t uec_edx; + uint32_t uec_ecx; + uint32_t uec_eax; + uint32_t uec_inum; + uint32_t uec_ecode; + uint32_t uec_eip; + uint32_t uec_cs; + uint32_t uec_eflags; + uint32_t uec_esp; + uint32_t uec_ss; + uint32_t uec_fs; + uint32_t uec_gs; +} usr_econtext_t; + +#if defined(LYNXOS_178) + +/* Floating point register context */ +typedef struct usr_fcontext { + uint32_t ufc_control; + uint32_t ufc_status; + uint32_t ufc_tag; + uint8_t *ufc_inst_off; + uint32_t ufc_inst_sel; + uint8_t *ufc_data_off; + uint32_t ufc_data_sel; + struct ufp387_real { + uint16_t umant4; + uint16_t umant3; + uint16_t umant2; + uint16_t umant1; + uint16_t us_and_e; + } ufc_reg[8]; +} usr_fcontext_t; + +#else /* This is LynxOS 5.x. */ + +/* Floating point and SIMD register context */ +typedef struct usr_fcontext { + uint16_t ufc_control; + uint16_t ufc_status; + uint16_t ufc_tag; + uint16_t ufc_opcode; + uint8_t *ufc_inst_off; + uint32_t ufc_inst_sel; + uint8_t *ufc_data_off; + uint32_t ufc_data_sel; + uint32_t usse_mxcsr; + uint32_t usse_mxcsr_mask; + struct ufp387_real { + uint16_t umant4; + uint16_t umant3; + uint16_t umant2; + uint16_t umant1; + uint16_t us_and_e; + uint16_t ureserved_1; + uint16_t ureserved_2; + uint16_t ureserved_3; + } ufc_reg[8]; + struct uxmm_register { + uint16_t uchunk_1; + uint16_t uchunk_2; + uint16_t uchunk_3; + uint16_t uchunk_4; + uint16_t uchunk_5; + uint16_t uchunk_6; + uint16_t uchunk_7; + uint16_t uchunk_8; + } uxmm_reg[8]; + char ureserved[16][14]; +} usr_fcontext_t; + +#endif + +/* The index of various registers inside the regcache. */ + +enum lynx_i386_gdb_regnum +{ + I386_EAX_REGNUM, + I386_ECX_REGNUM, + I386_EDX_REGNUM, + I386_EBX_REGNUM, + I386_ESP_REGNUM, + I386_EBP_REGNUM, + I386_ESI_REGNUM, + I386_EDI_REGNUM, + I386_EIP_REGNUM, + I386_EFLAGS_REGNUM, + I386_CS_REGNUM, + I386_SS_REGNUM, + I386_DS_REGNUM, + I386_ES_REGNUM, + I386_FS_REGNUM, + I386_GS_REGNUM, + I386_ST0_REGNUM, + I386_FCTRL_REGNUM = I386_ST0_REGNUM + 8, + I386_FSTAT_REGNUM, + I386_FTAG_REGNUM, + I386_FISEG_REGNUM, + I386_FIOFF_REGNUM, + I386_FOSEG_REGNUM, + I386_FOOFF_REGNUM, + I386_FOP_REGNUM, + I386_XMM0_REGNUM = 32, + I386_MXCSR_REGNUM = I386_XMM0_REGNUM + 8, + I386_SENTINEL_REGUM +}; + +/* The fill_function for the general-purpose register set. */ + +static void +lynx_i386_fill_gregset (struct regcache *regcache, char *buf) +{ +#define lynx_i386_collect_gp(regnum, fld) \ + collect_register (regcache, regnum, \ + buf + offsetof (usr_econtext_t, uec_##fld)) + + lynx_i386_collect_gp (I386_EAX_REGNUM, eax); + lynx_i386_collect_gp (I386_ECX_REGNUM, ecx); + lynx_i386_collect_gp (I386_EDX_REGNUM, edx); + lynx_i386_collect_gp (I386_EBX_REGNUM, ebx); + lynx_i386_collect_gp (I386_ESP_REGNUM, esp); + lynx_i386_collect_gp (I386_EBP_REGNUM, ebp); + lynx_i386_collect_gp (I386_ESI_REGNUM, esi); + lynx_i386_collect_gp (I386_EDI_REGNUM, edi); + lynx_i386_collect_gp (I386_EIP_REGNUM, eip); + lynx_i386_collect_gp (I386_EFLAGS_REGNUM, eflags); + lynx_i386_collect_gp (I386_CS_REGNUM, cs); + lynx_i386_collect_gp (I386_SS_REGNUM, ss); + lynx_i386_collect_gp (I386_DS_REGNUM, ds); + lynx_i386_collect_gp (I386_ES_REGNUM, es); + lynx_i386_collect_gp (I386_FS_REGNUM, fs); + lynx_i386_collect_gp (I386_GS_REGNUM, gs); +} + +/* The store_function for the general-purpose register set. */ + +static void +lynx_i386_store_gregset (struct regcache *regcache, const char *buf) +{ +#define lynx_i386_supply_gp(regnum, fld) \ + supply_register (regcache, regnum, \ + buf + offsetof (usr_econtext_t, uec_##fld)) + + lynx_i386_supply_gp (I386_EAX_REGNUM, eax); + lynx_i386_supply_gp (I386_ECX_REGNUM, ecx); + lynx_i386_supply_gp (I386_EDX_REGNUM, edx); + lynx_i386_supply_gp (I386_EBX_REGNUM, ebx); + lynx_i386_supply_gp (I386_ESP_REGNUM, esp); + lynx_i386_supply_gp (I386_EBP_REGNUM, ebp); + lynx_i386_supply_gp (I386_ESI_REGNUM, esi); + lynx_i386_supply_gp (I386_EDI_REGNUM, edi); + lynx_i386_supply_gp (I386_EIP_REGNUM, eip); + lynx_i386_supply_gp (I386_EFLAGS_REGNUM, eflags); + lynx_i386_supply_gp (I386_CS_REGNUM, cs); + lynx_i386_supply_gp (I386_SS_REGNUM, ss); + lynx_i386_supply_gp (I386_DS_REGNUM, ds); + lynx_i386_supply_gp (I386_ES_REGNUM, es); + lynx_i386_supply_gp (I386_FS_REGNUM, fs); + lynx_i386_supply_gp (I386_GS_REGNUM, gs); +} + +/* Extract the first 16 bits of register REGNUM in the REGCACHE, + and store these 2 bytes at DEST. + + This is useful to collect certain 16bit registers which are known + by GDBserver as 32bit registers (such as the Control Register + for instance). */ + +static void +collect_16bit_register (struct regcache *regcache, int regnum, char *dest) +{ + gdb_byte word[4]; + + collect_register (regcache, regnum, word); + memcpy (dest, word, 2); +} + +/* The fill_function for the floating-point register set. */ + +static void +lynx_i386_fill_fpregset (struct regcache *regcache, char *buf) +{ + int i; + + /* Collect %st0 .. %st7. */ + for (i = 0; i < 8; i++) + collect_register (regcache, I386_ST0_REGNUM + i, + buf + offsetof (usr_fcontext_t, ufc_reg) + + i * sizeof (struct ufp387_real)); + + /* Collect the other FPU registers. */ + collect_16bit_register (regcache, I386_FCTRL_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_control)); + collect_16bit_register (regcache, I386_FSTAT_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_status)); + collect_16bit_register (regcache, I386_FTAG_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_tag)); + collect_register (regcache, I386_FISEG_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_inst_sel)); + collect_register (regcache, I386_FIOFF_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_inst_off)); + collect_register (regcache, I386_FOSEG_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_data_sel)); + collect_register (regcache, I386_FOOFF_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_data_off)); +#if !defined(LYNXOS_178) + collect_16bit_register (regcache, I386_FOP_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_opcode)); + + /* Collect the XMM registers. */ + for (i = 0; i < 8; i++) + collect_register (regcache, I386_XMM0_REGNUM + i, + buf + offsetof (usr_fcontext_t, uxmm_reg) + + i * sizeof (struct uxmm_register)); + collect_register (regcache, I386_MXCSR_REGNUM, + buf + offsetof (usr_fcontext_t, usse_mxcsr)); +#endif +} + +/* This is the supply counterpart for collect_16bit_register: + It extracts a 2byte value from BUF, and uses that value to + set REGNUM's value in the regcache. + + This is useful to supply the value of certain 16bit registers + which are known by GDBserver as 32bit registers (such as the Control + Register for instance). */ + +static void +supply_16bit_register (struct regcache *regcache, int regnum, const char *buf) +{ + gdb_byte word[4]; + + memcpy (word, buf, 2); + memset (word + 2, 0, 2); + supply_register (regcache, regnum, word); +} + +/* The store_function for the floating-point register set. */ + +static void +lynx_i386_store_fpregset (struct regcache *regcache, const char *buf) +{ + int i; + + /* Store the %st0 .. %st7 registers. */ + for (i = 0; i < 8; i++) + supply_register (regcache, I386_ST0_REGNUM + i, + buf + offsetof (usr_fcontext_t, ufc_reg) + + i * sizeof (struct ufp387_real)); + + /* Store the other FPU registers. */ + supply_16bit_register (regcache, I386_FCTRL_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_control)); + supply_16bit_register (regcache, I386_FSTAT_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_status)); + supply_16bit_register (regcache, I386_FTAG_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_tag)); + supply_register (regcache, I386_FISEG_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_inst_sel)); + supply_register (regcache, I386_FIOFF_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_inst_off)); + supply_register (regcache, I386_FOSEG_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_data_sel)); + supply_register (regcache, I386_FOOFF_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_data_off)); +#if !defined(LYNXOS_178) + supply_16bit_register (regcache, I386_FOP_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_opcode)); + + /* Store the XMM registers. */ + for (i = 0; i < 8; i++) + supply_register (regcache, I386_XMM0_REGNUM + i, + buf + offsetof (usr_fcontext_t, uxmm_reg) + + i * sizeof (struct uxmm_register)); + supply_register (regcache, I386_MXCSR_REGNUM, + buf + offsetof (usr_fcontext_t, usse_mxcsr)); +#endif +} + +/* Implements the lynx_target_ops.arch_setup routine. */ + +static void +lynx_i386_arch_setup (void) +{ + struct target_desc *tdesc + = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); + + init_target_desc (tdesc, i386_expedite_regs); + + lynx_tdesc = tdesc; +} + +/* Description of all the x86-lynx register sets. */ + +struct lynx_regset_info lynx_target_regsets[] = { + /* General Purpose Registers. */ + {PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t), + lynx_i386_fill_gregset, lynx_i386_store_gregset}, + /* Floating Point Registers. */ + { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t), + lynx_i386_fill_fpregset, lynx_i386_store_fpregset }, + /* End of list marker. */ + {0, 0, -1, NULL, NULL } +}; + +/* The lynx_target_ops vector for x86-lynx. */ + +struct lynx_target_ops the_low_target = { + lynx_i386_arch_setup, +}; diff --git a/gdbserver/lynx-low.c b/gdbserver/lynx-low.c new file mode 100644 index 00000000000..a5b019396fa --- /dev/null +++ b/gdbserver/lynx-low.c @@ -0,0 +1,776 @@ +/* Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "target.h" +#include "lynx-low.h" + +#include +#include +#include /* Provides PIDGET, TIDGET, BUILDPID, etc. */ +#include +#include +#include +#include "gdbsupport/gdb_wait.h" +#include +#include "gdbsupport/filestuff.h" +#include "gdbsupport/common-inferior.h" +#include "nat/fork-inferior.h" + +int using_threads = 1; + +const struct target_desc *lynx_tdesc; + +/* Per-process private data. */ + +struct process_info_private +{ + /* The PTID obtained from the last wait performed on this process. + Initialized to null_ptid until the first wait is performed. */ + ptid_t last_wait_event_ptid; +}; + +/* Print a debug trace on standard output if debug_threads is set. */ + +static void +lynx_debug (char *string, ...) +{ + va_list args; + + if (!debug_threads) + return; + + va_start (args, string); + fprintf (stderr, "DEBUG(lynx): "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); +} + +/* Build a ptid_t given a PID and a LynxOS TID. */ + +static ptid_t +lynx_ptid_t (int pid, long tid) +{ + /* brobecker/2010-06-21: It looks like the LWP field in ptids + should be distinct for each thread (see write_ptid where it + writes the thread ID from the LWP). So instead of storing + the LynxOS tid in the tid field of the ptid, we store it in + the lwp field. */ + return ptid_t (pid, tid, 0); +} + +/* Return the process ID of the given PTID. + + This function has little reason to exist, it's just a wrapper around + ptid_get_pid. But since we have a getter function for the lynxos + ptid, it feels cleaner to have a getter for the pid as well. */ + +static int +lynx_ptid_get_pid (ptid_t ptid) +{ + return ptid.pid (); +} + +/* Return the LynxOS tid of the given PTID. */ + +static long +lynx_ptid_get_tid (ptid_t ptid) +{ + /* See lynx_ptid_t: The LynxOS tid is stored inside the lwp field + of the ptid. */ + return ptid.lwp (); +} + +/* For a given PTID, return the associated PID as known by the LynxOS + ptrace layer. */ + +static int +lynx_ptrace_pid_from_ptid (ptid_t ptid) +{ + return BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); +} + +/* Return a string image of the ptrace REQUEST number. */ + +static char * +ptrace_request_to_str (int request) +{ +#define CASE(X) case X: return #X + switch (request) + { + CASE(PTRACE_TRACEME); + CASE(PTRACE_PEEKTEXT); + CASE(PTRACE_PEEKDATA); + CASE(PTRACE_PEEKUSER); + CASE(PTRACE_POKETEXT); + CASE(PTRACE_POKEDATA); + CASE(PTRACE_POKEUSER); + CASE(PTRACE_CONT); + CASE(PTRACE_KILL); + CASE(PTRACE_SINGLESTEP); + CASE(PTRACE_ATTACH); + CASE(PTRACE_DETACH); + CASE(PTRACE_GETREGS); + CASE(PTRACE_SETREGS); + CASE(PTRACE_GETFPREGS); + CASE(PTRACE_SETFPREGS); + CASE(PTRACE_READDATA); + CASE(PTRACE_WRITEDATA); + CASE(PTRACE_READTEXT); + CASE(PTRACE_WRITETEXT); + CASE(PTRACE_GETFPAREGS); + CASE(PTRACE_SETFPAREGS); + CASE(PTRACE_GETWINDOW); + CASE(PTRACE_SETWINDOW); + CASE(PTRACE_SYSCALL); + CASE(PTRACE_DUMPCORE); + CASE(PTRACE_SETWRBKPT); + CASE(PTRACE_SETACBKPT); + CASE(PTRACE_CLRBKPT); + CASE(PTRACE_GET_UCODE); +#ifdef PT_READ_GPR + CASE(PT_READ_GPR); +#endif +#ifdef PT_WRITE_GPR + CASE(PT_WRITE_GPR); +#endif +#ifdef PT_READ_FPR + CASE(PT_READ_FPR); +#endif +#ifdef PT_WRITE_FPR + CASE(PT_WRITE_FPR); +#endif +#ifdef PT_READ_VPR + CASE(PT_READ_VPR); +#endif +#ifdef PT_WRITE_VPR + CASE(PT_WRITE_VPR); +#endif +#ifdef PTRACE_PEEKUSP + CASE(PTRACE_PEEKUSP); +#endif +#ifdef PTRACE_POKEUSP + CASE(PTRACE_POKEUSP); +#endif + CASE(PTRACE_PEEKTHREAD); + CASE(PTRACE_THREADUSER); + CASE(PTRACE_FPREAD); + CASE(PTRACE_FPWRITE); + CASE(PTRACE_SETSIG); + CASE(PTRACE_CONT_ONE); + CASE(PTRACE_KILL_ONE); + CASE(PTRACE_SINGLESTEP_ONE); + CASE(PTRACE_GETLOADINFO); + CASE(PTRACE_GETTRACESIG); +#ifdef PTRACE_GETTHREADLIST + CASE(PTRACE_GETTHREADLIST); +#endif + } +#undef CASE + + return ""; +} + +/* A wrapper around ptrace that allows us to print debug traces of + ptrace calls if debug traces are activated. */ + +static int +lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2) +{ + int result; + const int pid = lynx_ptrace_pid_from_ptid (ptid); + int saved_errno; + + if (debug_threads) + fprintf (stderr, "PTRACE (%s, pid=%d(pid=%d, tid=%d), addr=0x%x, " + "data=0x%x, addr2=0x%x)", + ptrace_request_to_str (request), pid, PIDGET (pid), TIDGET (pid), + addr, data, addr2); + result = ptrace (request, pid, addr, data, addr2); + saved_errno = errno; + if (debug_threads) + fprintf (stderr, " -> %d (=0x%x)\n", result, result); + + errno = saved_errno; + return result; +} + +/* Call add_process with the given parameters, and initializes + the process' private data. */ + +static struct process_info * +lynx_add_process (int pid, int attached) +{ + struct process_info *proc; + + proc = add_process (pid, attached); + proc->tdesc = lynx_tdesc; + proc->priv = XCNEW (struct process_info_private); + proc->priv->last_wait_event_ptid = null_ptid; + + return proc; +} + +/* Callback used by fork_inferior to start tracing the inferior. */ + +static void +lynx_ptrace_fun () +{ + int pgrp; + + /* Switch child to its own process group so that signals won't + directly affect GDBserver. */ + pgrp = getpid(); + if (pgrp < 0) + trace_start_error_with_name ("pgrp"); + if (setpgid (0, pgrp) < 0) + trace_start_error_with_name ("setpgid"); + if (ioctl (0, TIOCSPGRP, &pgrp) < 0) + trace_start_error_with_name ("ioctl"); + if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0) + trace_start_error_with_name ("lynx_ptrace"); +} + +/* Implement the create_inferior method of the target_ops vector. */ + +static int +lynx_create_inferior (const char *program, + const std::vector &program_args) +{ + int pid; + std::string str_program_args = stringify_argv (program_args); + + lynx_debug ("lynx_create_inferior ()"); + + pid = fork_inferior (program, + str_program_args.c_str (), + get_environ ()->envp (), lynx_ptrace_fun, + NULL, NULL, NULL, NULL); + + post_fork_inferior (pid, program); + + lynx_add_process (pid, 0); + /* Do not add the process thread just yet, as we do not know its tid. + We will add it later, during the wait for the STOP event corresponding + to the lynx_ptrace (PTRACE_TRACEME) call above. */ + return pid; +} + +/* Assuming we've just attached to a running inferior whose pid is PID, + add all threads running in that process. */ + +static void +lynx_add_threads_after_attach (int pid) +{ + /* Ugh! There appears to be no way to get the list of threads + in the program we just attached to. So get the list by calling + the "ps" command. This is only needed now, as we will then + keep the thread list up to date thanks to thread creation and + exit notifications. */ + FILE *f; + char buf[256]; + int thread_pid, thread_tid; + + f = popen ("ps atx", "r"); + if (f == NULL) + perror_with_name ("Cannot get thread list"); + + while (fgets (buf, sizeof (buf), f) != NULL) + if ((sscanf (buf, "%d %d", &thread_pid, &thread_tid) == 2 + && thread_pid == pid)) + { + ptid_t thread_ptid = lynx_ptid_t (pid, thread_tid); + + if (!find_thread_ptid (thread_ptid)) + { + lynx_debug ("New thread: (pid = %d, tid = %d)", + pid, thread_tid); + add_thread (thread_ptid, NULL); + } + } + + pclose (f); +} + +/* Implement the attach target_ops method. */ + +static int +lynx_attach (unsigned long pid) +{ + ptid_t ptid = lynx_ptid_t (pid, 0); + + if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0) + error ("Cannot attach to process %lu: %s (%d)\n", pid, + safe_strerror (errno), errno); + + lynx_add_process (pid, 1); + lynx_add_threads_after_attach (pid); + + return 0; +} + +/* Implement the resume target_ops method. */ + +static void +lynx_resume (struct thread_resume *resume_info, size_t n) +{ + ptid_t ptid = resume_info[0].thread; + const int request + = (resume_info[0].kind == resume_step + ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP) + : PTRACE_CONT); + const int signal = resume_info[0].sig; + + /* If given a minus_one_ptid, then try using the current_process' + private->last_wait_event_ptid. On most LynxOS versions, + using any of the process' thread works well enough, but + LynxOS 178 is a little more sensitive, and triggers some + unexpected signals (Eg SIG61) when we resume the inferior + using a different thread. */ + if (ptid == minus_one_ptid) + ptid = current_process()->priv->last_wait_event_ptid; + + /* The ptid might still be minus_one_ptid; this can happen between + the moment we create the inferior or attach to a process, and + the moment we resume its execution for the first time. It is + fine to use the current_thread's ptid in those cases. */ + if (ptid == minus_one_ptid) + ptid = ptid_of (current_thread); + + regcache_invalidate_pid (ptid.pid ()); + + errno = 0; + lynx_ptrace (request, ptid, 1, signal, 0); + if (errno) + perror_with_name ("ptrace"); +} + +/* Resume the execution of the given PTID. */ + +static void +lynx_continue (ptid_t ptid) +{ + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_continue; + resume_info.sig = 0; + + lynx_resume (&resume_info, 1); +} + +/* A wrapper around waitpid that handles the various idiosyncrasies + of LynxOS' waitpid. */ + +static int +lynx_waitpid (int pid, int *stat_loc) +{ + int ret = 0; + + while (1) + { + ret = waitpid (pid, stat_loc, WNOHANG); + if (ret < 0) + { + /* An ECHILD error is not indicative of a real problem. + It happens for instance while waiting for the inferior + to stop after attaching to it. */ + if (errno != ECHILD) + perror_with_name ("waitpid (WNOHANG)"); + } + if (ret > 0) + break; + /* No event with WNOHANG. See if there is one with WUNTRACED. */ + ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED); + if (ret < 0) + { + /* An ECHILD error is not indicative of a real problem. + It happens for instance while waiting for the inferior + to stop after attaching to it. */ + if (errno != ECHILD) + perror_with_name ("waitpid (WNOHANG|WUNTRACED)"); + } + if (ret > 0) + break; + usleep (1000); + } + return ret; +} + +/* Implement the wait target_ops method. */ + +static ptid_t +lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options) +{ + int pid; + int ret; + int wstat; + ptid_t new_ptid; + + if (ptid == minus_one_ptid) + pid = lynx_ptid_get_pid (ptid_of (current_thread)); + else + pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); + +retry: + + ret = lynx_waitpid (pid, &wstat); + new_ptid = lynx_ptid_t (ret, ((union wait *) &wstat)->w_tid); + find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid; + + /* If this is a new thread, then add it now. The reason why we do + this here instead of when handling new-thread events is because + we need to add the thread associated to the "main" thread - even + for non-threaded applications where the new-thread events are not + generated. */ + if (!find_thread_ptid (new_ptid)) + { + lynx_debug ("New thread: (pid = %d, tid = %d)", + lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid)); + add_thread (new_ptid, NULL); + } + + if (WIFSTOPPED (wstat)) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat)); + lynx_debug ("process stopped with signal: %d", + status->value.integer); + } + else if (WIFEXITED (wstat)) + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = WEXITSTATUS (wstat); + lynx_debug ("process exited with code: %d", status->value.integer); + } + else if (WIFSIGNALED (wstat)) + { + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.integer = gdb_signal_from_host (WTERMSIG (wstat)); + lynx_debug ("process terminated with code: %d", + status->value.integer); + } + else + { + /* Not sure what happened if we get here, or whether we can + in fact get here. But if we do, handle the event the best + we can. */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.integer = gdb_signal_from_host (0); + lynx_debug ("unknown event ????"); + } + + /* SIGTRAP events are generated for situations other than single-step/ + breakpoint events (Eg. new-thread events). Handle those other types + of events, and resume the execution if necessary. */ + if (status->kind == TARGET_WAITKIND_STOPPED + && status->value.integer == GDB_SIGNAL_TRAP) + { + const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0); + + lynx_debug ("(realsig = %d)", realsig); + switch (realsig) + { + case SIGNEWTHREAD: + /* We just added the new thread above. No need to do anything + further. Just resume the execution again. */ + lynx_continue (new_ptid); + goto retry; + + case SIGTHREADEXIT: + remove_thread (find_thread_ptid (new_ptid)); + lynx_continue (new_ptid); + goto retry; + } + } + + return new_ptid; +} + +/* A wrapper around lynx_wait_1 that also prints debug traces when + such debug traces have been activated. */ + +static ptid_t +lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options) +{ + ptid_t new_ptid; + + lynx_debug ("lynx_wait (pid = %d, tid = %ld)", + lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); + new_ptid = lynx_wait_1 (ptid, status, options); + lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)", + lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid), + status->kind); + return new_ptid; +} + +/* Implement the kill target_ops method. */ + +static int +lynx_kill (process_info *process) +{ + ptid_t ptid = lynx_ptid_t (process->pid, 0); + struct target_waitstatus status; + + lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0); + lynx_wait (ptid, &status, 0); + the_target->mourn (process); + return 0; +} + +/* Implement the detach target_ops method. */ + +static int +lynx_detach (process_info *process) +{ + ptid_t ptid = lynx_ptid_t (process->pid, 0); + + lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0); + the_target->mourn (process); + return 0; +} + +/* Implement the mourn target_ops method. */ + +static void +lynx_mourn (struct process_info *proc) +{ + for_each_thread (proc->pid, remove_thread); + + /* Free our private data. */ + free (proc->priv); + proc->priv = NULL; + + remove_process (proc); +} + +/* Implement the join target_ops method. */ + +static void +lynx_join (int pid) +{ + /* The PTRACE_DETACH is sufficient to detach from the process. + So no need to do anything extra. */ +} + +/* Implement the thread_alive target_ops method. */ + +static int +lynx_thread_alive (ptid_t ptid) +{ + /* The list of threads is updated at the end of each wait, so it + should be up to date. No need to re-fetch it. */ + return (find_thread_ptid (ptid) != NULL); +} + +/* Implement the fetch_registers target_ops method. */ + +static void +lynx_fetch_registers (struct regcache *regcache, int regno) +{ + struct lynx_regset_info *regset = lynx_target_regsets; + ptid_t inferior_ptid = ptid_of (current_thread); + + lynx_debug ("lynx_fetch_registers (regno = %d)", regno); + + while (regset->size >= 0) + { + char *buf; + int res; + + buf = xmalloc (regset->size); + res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); + if (res < 0) + perror ("ptrace"); + regset->store_function (regcache, buf); + free (buf); + regset++; + } +} + +/* Implement the store_registers target_ops method. */ + +static void +lynx_store_registers (struct regcache *regcache, int regno) +{ + struct lynx_regset_info *regset = lynx_target_regsets; + ptid_t inferior_ptid = ptid_of (current_thread); + + lynx_debug ("lynx_store_registers (regno = %d)", regno); + + while (regset->size >= 0) + { + char *buf; + int res; + + buf = xmalloc (regset->size); + res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); + if (res == 0) + { + /* Then overlay our cached registers on that. */ + regset->fill_function (regcache, buf); + /* Only now do we write the register set. */ + res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf, + 0, 0); + } + if (res < 0) + perror ("ptrace"); + free (buf); + regset++; + } +} + +/* Implement the read_memory target_ops method. */ + +static int +lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + /* On LynxOS, memory reads needs to be performed in chunks the size + of int types, and they should also be aligned accordingly. */ + int buf; + const int xfer_size = sizeof (buf); + CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; + ptid_t inferior_ptid = ptid_of (current_thread); + + while (addr < memaddr + len) + { + int skip = 0; + int truncate = 0; + + errno = 0; + if (addr < memaddr) + skip = memaddr - addr; + if (addr + xfer_size > memaddr + len) + truncate = addr + xfer_size - memaddr - len; + buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0); + if (errno) + return errno; + memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip, + xfer_size - skip - truncate); + addr += xfer_size; + } + + return 0; +} + +/* Implement the write_memory target_ops method. */ + +static int +lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +{ + /* On LynxOS, memory writes needs to be performed in chunks the size + of int types, and they should also be aligned accordingly. */ + int buf; + const int xfer_size = sizeof (buf); + CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; + ptid_t inferior_ptid = ptid_of (current_thread); + + while (addr < memaddr + len) + { + int skip = 0; + int truncate = 0; + + if (addr < memaddr) + skip = memaddr - addr; + if (addr + xfer_size > memaddr + len) + truncate = addr + xfer_size - memaddr - len; + if (skip > 0 || truncate > 0) + { + /* We need to read the memory at this address in order to preserve + the data that we are not overwriting. */ + lynx_read_memory (addr, (unsigned char *) &buf, xfer_size); + if (errno) + return errno; + } + memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip, + xfer_size - skip - truncate); + errno = 0; + lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0); + if (errno) + return errno; + addr += xfer_size; + } + + return 0; +} + +/* Implement the kill_request target_ops method. */ + +static void +lynx_request_interrupt (void) +{ + ptid_t inferior_ptid = ptid_of (get_first_thread ()); + + kill (lynx_ptid_get_pid (inferior_ptid), SIGINT); +} + +/* The LynxOS target_ops vector. */ + +static process_stratum_target lynx_target_ops = { + lynx_create_inferior, + NULL, /* post_create_inferior */ + lynx_attach, + lynx_kill, + lynx_detach, + lynx_mourn, + lynx_join, + lynx_thread_alive, + lynx_resume, + lynx_wait, + lynx_fetch_registers, + lynx_store_registers, + NULL, /* prepare_to_access_memory */ + NULL, /* done_accessing_memory */ + lynx_read_memory, + lynx_write_memory, + NULL, /* look_up_symbols */ + lynx_request_interrupt, + NULL, /* read_auxv */ + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_sw_breakpoint */ + NULL, /* supports_stopped_by_sw_breakpoint */ + NULL, /* stopped_by_hw_breakpoint */ + NULL, /* supports_stopped_by_hw_breakpoint */ + target_can_do_hardware_single_step, + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* read_offsets */ + NULL, /* get_tls_address */ + NULL, /* hostio_last_error */ + NULL, /* qxfer_osdata */ + NULL, /* qxfer_siginfo */ + NULL, /* supports_non_stop */ + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* supports_fork_events */ + NULL, /* supports_vfork_events */ + NULL, /* supports_exec_events */ + NULL, /* handle_new_gdb_connection */ + NULL, /* handle_monitor_command */ +}; + +void +initialize_low (void) +{ + set_target_ops (&lynx_target_ops); + the_low_target.arch_setup (); +} + diff --git a/gdbserver/lynx-low.h b/gdbserver/lynx-low.h new file mode 100644 index 00000000000..b122298fb88 --- /dev/null +++ b/gdbserver/lynx-low.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2010-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_LYNX_LOW_H +#define GDBSERVER_LYNX_LOW_H + +struct regcache; +struct target_desc; + +/* Some information relative to a given register set. */ + +struct lynx_regset_info +{ + /* The ptrace request needed to get/set registers of this set. */ + int get_request, set_request; + /* The size of the register set. */ + int size; + /* Fill the buffer BUF from the contents of the given REGCACHE. */ + void (*fill_function) (struct regcache *regcache, char *buf); + /* Store the register value in BUF in the given REGCACHE. */ + void (*store_function) (struct regcache *regcache, const char *buf); +}; + +/* A list of regsets for the target being debugged, terminated by an entry + where the size is negative. + + This list should be created by the target-specific code. */ + +extern struct lynx_regset_info lynx_target_regsets[]; + +/* The target-specific operations for LynxOS support. */ + +struct lynx_target_ops +{ + /* Architecture-specific setup. */ + void (*arch_setup) (void); +}; + +extern struct lynx_target_ops the_low_target; + +/* The inferior's target description. This is a global because the + LynxOS ports support neither bi-arch nor multi-process. */ +extern const struct target_desc *lynx_tdesc; + +#endif /* GDBSERVER_LYNX_LOW_H */ diff --git a/gdbserver/lynx-ppc-low.c b/gdbserver/lynx-ppc-low.c new file mode 100644 index 00000000000..f93fc1d8d87 --- /dev/null +++ b/gdbserver/lynx-ppc-low.c @@ -0,0 +1,185 @@ +/* Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "lynx-low.h" +#include +#include + +/* The following two typedefs are defined in a .h file which is not + in the standard include path (/sys/include/family/ppc/ucontext.h), + so we just duplicate them here. */ + +/* General register context */ +typedef struct usr_econtext_s +{ + uint32_t uec_iregs[32]; + uint32_t uec_inum; + uint32_t uec_srr0; + uint32_t uec_srr1; + uint32_t uec_lr; + uint32_t uec_ctr; + uint32_t uec_cr; + uint32_t uec_xer; + uint32_t uec_dar; + uint32_t uec_mq; + uint32_t uec_msr; + uint32_t uec_sregs[16]; + uint32_t uec_ss_count; + uint32_t uec_ss_addr1; + uint32_t uec_ss_addr2; + uint32_t uec_ss_code1; + uint32_t uec_ss_code2; +} usr_econtext_t; + +/* Floating point register context */ +typedef struct usr_fcontext_s +{ + uint64_t ufc_freg[32]; + uint32_t ufc_fpscr[2]; +} usr_fcontext_t; + +/* Index of for various registers inside the regcache. */ +#define R0_REGNUM 0 +#define F0_REGNUM 32 +#define PC_REGNUM 64 +#define MSR_REGNUM 65 +#define CR_REGNUM 66 +#define LR_REGNUM 67 +#define CTR_REGNUM 68 +#define XER_REGNUM 69 +#define FPSCR_REGNUM 70 + +/* Defined in auto-generated file powerpc-32.c. */ +extern void init_registers_powerpc_32 (void); +extern const struct target_desc *tdesc_powerpc_32; + +/* The fill_function for the general-purpose register set. */ + +static void +lynx_ppc_fill_gregset (struct regcache *regcache, char *buf) +{ + int i; + + /* r0 - r31 */ + for (i = 0; i < 32; i++) + collect_register (regcache, R0_REGNUM + i, + buf + offsetof (usr_econtext_t, uec_iregs[i])); + + /* The other registers provided in the GP register context. */ + collect_register (regcache, PC_REGNUM, + buf + offsetof (usr_econtext_t, uec_srr0)); + collect_register (regcache, MSR_REGNUM, + buf + offsetof (usr_econtext_t, uec_srr1)); + collect_register (regcache, CR_REGNUM, + buf + offsetof (usr_econtext_t, uec_cr)); + collect_register (regcache, LR_REGNUM, + buf + offsetof (usr_econtext_t, uec_lr)); + collect_register (regcache, CTR_REGNUM, + buf + offsetof (usr_econtext_t, uec_ctr)); + collect_register (regcache, XER_REGNUM, + buf + offsetof (usr_econtext_t, uec_xer)); +} + +/* The store_function for the general-purpose register set. */ + +static void +lynx_ppc_store_gregset (struct regcache *regcache, const char *buf) +{ + int i; + + /* r0 - r31 */ + for (i = 0; i < 32; i++) + supply_register (regcache, R0_REGNUM + i, + buf + offsetof (usr_econtext_t, uec_iregs[i])); + + /* The other registers provided in the GP register context. */ + supply_register (regcache, PC_REGNUM, + buf + offsetof (usr_econtext_t, uec_srr0)); + supply_register (regcache, MSR_REGNUM, + buf + offsetof (usr_econtext_t, uec_srr1)); + supply_register (regcache, CR_REGNUM, + buf + offsetof (usr_econtext_t, uec_cr)); + supply_register (regcache, LR_REGNUM, + buf + offsetof (usr_econtext_t, uec_lr)); + supply_register (regcache, CTR_REGNUM, + buf + offsetof (usr_econtext_t, uec_ctr)); + supply_register (regcache, XER_REGNUM, + buf + offsetof (usr_econtext_t, uec_xer)); +} + +/* The fill_function for the floating-point register set. */ + +static void +lynx_ppc_fill_fpregset (struct regcache *regcache, char *buf) +{ + int i; + + /* f0 - f31 */ + for (i = 0; i < 32; i++) + collect_register (regcache, F0_REGNUM + i, + buf + offsetof (usr_fcontext_t, ufc_freg[i])); + + /* fpscr */ + collect_register (regcache, FPSCR_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_fpscr)); +} + +/* The store_function for the floating-point register set. */ + +static void +lynx_ppc_store_fpregset (struct regcache *regcache, const char *buf) +{ + int i; + + /* f0 - f31 */ + for (i = 0; i < 32; i++) + supply_register (regcache, F0_REGNUM + i, + buf + offsetof (usr_fcontext_t, ufc_freg[i])); + + /* fpscr */ + supply_register (regcache, FPSCR_REGNUM, + buf + offsetof (usr_fcontext_t, ufc_fpscr)); +} + +/* Implements the lynx_target_ops.arch_setup routine. */ + +static void +lynx_ppc_arch_setup (void) +{ + init_registers_powerpc_32 (); + lynx_tdesc = tdesc_powerpc_32; +} + +/* Description of all the powerpc-lynx register sets. */ + +struct lynx_regset_info lynx_target_regsets[] = { + /* General Purpose Registers. */ + {PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t), + lynx_ppc_fill_gregset, lynx_ppc_store_gregset}, + /* Floating Point Registers. */ + { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t), + lynx_ppc_fill_fpregset, lynx_ppc_store_fpregset }, + /* End of list marker. */ + {0, 0, -1, NULL, NULL } +}; + +/* The lynx_target_ops vector for powerpc-lynxos. */ + +struct lynx_target_ops the_low_target = { + lynx_ppc_arch_setup, +}; diff --git a/gdbserver/mem-break.c b/gdbserver/mem-break.c new file mode 100644 index 00000000000..1b6f2365814 --- /dev/null +++ b/gdbserver/mem-break.c @@ -0,0 +1,2237 @@ +/* Memory breakpoint operations for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#include "server.h" +#include "regcache.h" +#include "ax.h" + +#define MAX_BREAKPOINT_LEN 8 + +/* Helper macro used in loops that append multiple items to a singly-linked + list instead of inserting items at the head of the list, as, say, in the + breakpoint lists. LISTPP is a pointer to the pointer that is the head of + the new list. ITEMP is a pointer to the item to be added to the list. + TAILP must be defined to be the same type as ITEMP, and initialized to + NULL. */ + +#define APPEND_TO_LIST(listpp, itemp, tailp) \ + do \ + { \ + if ((tailp) == NULL) \ + *(listpp) = (itemp); \ + else \ + (tailp)->next = (itemp); \ + (tailp) = (itemp); \ + } \ + while (0) + +/* GDB will never try to install multiple breakpoints at the same + address. However, we can see GDB requesting to insert a breakpoint + at an address is had already inserted one previously in a few + situations. + + - The RSP documentation on Z packets says that to avoid potential + problems with duplicate packets, the operations should be + implemented in an idempotent way. + + - A breakpoint is set at ADDR, an address in a shared library. + Then the shared library is unloaded. And then another, unrelated, + breakpoint at ADDR is set. There is not breakpoint removal request + between the first and the second breakpoint. + + - When GDB wants to update the target-side breakpoint conditions or + commands, it re-inserts the breakpoint, with updated + conditions/commands associated. + + Also, we need to keep track of internal breakpoints too, so we do + need to be able to install multiple breakpoints at the same address + transparently. + + We keep track of two different, and closely related structures. A + raw breakpoint, which manages the low level, close to the metal + aspect of a breakpoint. It holds the breakpoint address, and for + software breakpoints, a buffer holding a copy of the instructions + that would be in memory had not been a breakpoint there (we call + that the shadow memory of the breakpoint). We occasionally need to + temporarilly uninsert a breakpoint without the client knowing about + it (e.g., to step over an internal breakpoint), so we keep an + `inserted' state associated with this low level breakpoint + structure. There can only be one such object for a given address. + Then, we have (a bit higher level) breakpoints. This structure + holds a callback to be called whenever a breakpoint is hit, a + high-level type, and a link to a low level raw breakpoint. There + can be many high-level breakpoints at the same address, and all of + them will point to the same raw breakpoint, which is reference + counted. */ + +/* The low level, physical, raw breakpoint. */ +struct raw_breakpoint +{ + struct raw_breakpoint *next; + + /* The low level type of the breakpoint (software breakpoint, + watchpoint, etc.) */ + enum raw_bkpt_type raw_type; + + /* A reference count. Each high level breakpoint referencing this + raw breakpoint accounts for one reference. */ + int refcount; + + /* The breakpoint's insertion address. There can only be one raw + breakpoint for a given PC. */ + CORE_ADDR pc; + + /* The breakpoint's kind. This is target specific. Most + architectures only use one specific instruction for breakpoints, while + others may use more than one. E.g., on ARM, we need to use different + breakpoint instructions on Thumb, Thumb-2, and ARM code. Likewise for + hardware breakpoints -- some architectures (including ARM) need to + setup debug registers differently depending on mode. */ + int kind; + + /* The breakpoint's shadow memory. */ + unsigned char old_data[MAX_BREAKPOINT_LEN]; + + /* Positive if this breakpoint is currently inserted in the + inferior. Negative if it was, but we've detected that it's now + gone. Zero if not inserted. */ + int inserted; +}; + +/* The type of a breakpoint. */ +enum bkpt_type + { + /* A GDB breakpoint, requested with a Z0 packet. */ + gdb_breakpoint_Z0, + + /* A GDB hardware breakpoint, requested with a Z1 packet. */ + gdb_breakpoint_Z1, + + /* A GDB write watchpoint, requested with a Z2 packet. */ + gdb_breakpoint_Z2, + + /* A GDB read watchpoint, requested with a Z3 packet. */ + gdb_breakpoint_Z3, + + /* A GDB access watchpoint, requested with a Z4 packet. */ + gdb_breakpoint_Z4, + + /* A software single-step breakpoint. */ + single_step_breakpoint, + + /* Any other breakpoint type that doesn't require specific + treatment goes here. E.g., an event breakpoint. */ + other_breakpoint, + }; + +struct point_cond_list +{ + /* Pointer to the agent expression that is the breakpoint's + conditional. */ + struct agent_expr *cond; + + /* Pointer to the next condition. */ + struct point_cond_list *next; +}; + +struct point_command_list +{ + /* Pointer to the agent expression that is the breakpoint's + commands. */ + struct agent_expr *cmd; + + /* Flag that is true if this command should run even while GDB is + disconnected. */ + int persistence; + + /* Pointer to the next command. */ + struct point_command_list *next; +}; + +/* A high level (in gdbserver's perspective) breakpoint. */ +struct breakpoint +{ + struct breakpoint *next; + + /* The breakpoint's type. */ + enum bkpt_type type; + + /* Link to this breakpoint's raw breakpoint. This is always + non-NULL. */ + struct raw_breakpoint *raw; +}; + +/* Breakpoint requested by GDB. */ + +struct gdb_breakpoint +{ + struct breakpoint base; + + /* Pointer to the condition list that should be evaluated on + the target or NULL if the breakpoint is unconditional or + if GDB doesn't want us to evaluate the conditionals on the + target's side. */ + struct point_cond_list *cond_list; + + /* Point to the list of commands to run when this is hit. */ + struct point_command_list *command_list; +}; + +/* Breakpoint used by GDBserver. */ + +struct other_breakpoint +{ + struct breakpoint base; + + /* Function to call when we hit this breakpoint. If it returns 1, + the breakpoint shall be deleted; 0 or if this callback is NULL, + it will be left inserted. */ + int (*handler) (CORE_ADDR); +}; + +/* Breakpoint for single step. */ + +struct single_step_breakpoint +{ + struct breakpoint base; + + /* Thread the reinsert breakpoint belongs to. */ + ptid_t ptid; +}; + +/* Return the breakpoint size from its kind. */ + +static int +bp_size (struct raw_breakpoint *bp) +{ + int size = 0; + + the_target->sw_breakpoint_from_kind (bp->kind, &size); + return size; +} + +/* Return the breakpoint opcode from its kind. */ + +static const gdb_byte * +bp_opcode (struct raw_breakpoint *bp) +{ + int size = 0; + + return the_target->sw_breakpoint_from_kind (bp->kind, &size); +} + +/* See mem-break.h. */ + +enum target_hw_bp_type +raw_bkpt_type_to_target_hw_bp_type (enum raw_bkpt_type raw_type) +{ + switch (raw_type) + { + case raw_bkpt_type_hw: + return hw_execute; + case raw_bkpt_type_write_wp: + return hw_write; + case raw_bkpt_type_read_wp: + return hw_read; + case raw_bkpt_type_access_wp: + return hw_access; + default: + internal_error (__FILE__, __LINE__, + "bad raw breakpoint type %d", (int) raw_type); + } +} + +/* See mem-break.h. */ + +static enum bkpt_type +Z_packet_to_bkpt_type (char z_type) +{ + gdb_assert ('0' <= z_type && z_type <= '4'); + + return (enum bkpt_type) (gdb_breakpoint_Z0 + (z_type - '0')); +} + +/* See mem-break.h. */ + +enum raw_bkpt_type +Z_packet_to_raw_bkpt_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + return raw_bkpt_type_sw; + case Z_PACKET_HW_BP: + return raw_bkpt_type_hw; + case Z_PACKET_WRITE_WP: + return raw_bkpt_type_write_wp; + case Z_PACKET_READ_WP: + return raw_bkpt_type_read_wp; + case Z_PACKET_ACCESS_WP: + return raw_bkpt_type_access_wp; + default: + gdb_assert_not_reached ("unhandled Z packet type."); + } +} + +/* Return true if breakpoint TYPE is a GDB breakpoint. */ + +static int +is_gdb_breakpoint (enum bkpt_type type) +{ + return (type == gdb_breakpoint_Z0 + || type == gdb_breakpoint_Z1 + || type == gdb_breakpoint_Z2 + || type == gdb_breakpoint_Z3 + || type == gdb_breakpoint_Z4); +} + +bool +any_persistent_commands (process_info *proc) +{ + struct breakpoint *bp; + struct point_command_list *cl; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (is_gdb_breakpoint (bp->type)) + { + struct gdb_breakpoint *gdb_bp = (struct gdb_breakpoint *) bp; + + for (cl = gdb_bp->command_list; cl != NULL; cl = cl->next) + if (cl->persistence) + return true; + } + } + + return false; +} + +/* Find low-level breakpoint of type TYPE at address ADDR that is not + insert-disabled. Returns NULL if not found. */ + +static struct raw_breakpoint * +find_enabled_raw_code_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if (bp->pc == addr + && bp->raw_type == type + && bp->inserted >= 0) + return bp; + + return NULL; +} + +/* Find low-level breakpoint of type TYPE at address ADDR. Returns + NULL if not found. */ + +static struct raw_breakpoint * +find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int kind) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if (bp->pc == addr && bp->raw_type == type && bp->kind == kind) + return bp; + + return NULL; +} + +/* See mem-break.h. */ + +int +insert_memory_breakpoint (struct raw_breakpoint *bp) +{ + unsigned char buf[MAX_BREAKPOINT_LEN]; + int err; + + /* Note that there can be fast tracepoint jumps installed in the + same memory range, so to get at the original memory, we need to + use read_inferior_memory, which masks those out. */ + err = read_inferior_memory (bp->pc, buf, bp_size (bp)); + if (err != 0) + { + if (debug_threads) + debug_printf ("Failed to read shadow memory of" + " breakpoint at 0x%s (%s).\n", + paddress (bp->pc), safe_strerror (err)); + } + else + { + memcpy (bp->old_data, buf, bp_size (bp)); + + err = (*the_target->write_memory) (bp->pc, bp_opcode (bp), + bp_size (bp)); + if (err != 0) + { + if (debug_threads) + debug_printf ("Failed to insert breakpoint at 0x%s (%s).\n", + paddress (bp->pc), safe_strerror (err)); + } + } + return err != 0 ? -1 : 0; +} + +/* See mem-break.h */ + +int +remove_memory_breakpoint (struct raw_breakpoint *bp) +{ + unsigned char buf[MAX_BREAKPOINT_LEN]; + int err; + + /* Since there can be trap breakpoints inserted in the same address + range, we use `target_write_memory', which takes care of + layering breakpoints on top of fast tracepoints, and on top of + the buffer we pass it. This works because the caller has already + either unlinked the breakpoint or marked it uninserted. Also + note that we need to pass the current shadow contents, because + target_write_memory updates any shadow memory with what we pass + here, and we want that to be a nop. */ + memcpy (buf, bp->old_data, bp_size (bp)); + err = target_write_memory (bp->pc, buf, bp_size (bp)); + if (err != 0) + { + if (debug_threads) + debug_printf ("Failed to uninsert raw breakpoint " + "at 0x%s (%s) while deleting it.\n", + paddress (bp->pc), safe_strerror (err)); + } + return err != 0 ? -1 : 0; +} + +/* Set a RAW breakpoint of type TYPE and kind KIND at WHERE. On + success, a pointer to the new breakpoint is returned. On failure, + returns NULL and writes the error code to *ERR. */ + +static struct raw_breakpoint * +set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind, + int *err) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw) + { + bp = find_enabled_raw_code_breakpoint_at (where, type); + if (bp != NULL && bp->kind != kind) + { + /* A different kind than previously seen. The previous + breakpoint must be gone then. */ + if (debug_threads) + debug_printf ("Inconsistent breakpoint kind? Was %d, now %d.\n", + bp->kind, kind); + bp->inserted = -1; + bp = NULL; + } + } + else + bp = find_raw_breakpoint_at (where, type, kind); + + gdb::unique_xmalloc_ptr bp_holder; + if (bp == NULL) + { + bp_holder.reset (XCNEW (struct raw_breakpoint)); + bp = bp_holder.get (); + bp->pc = where; + bp->kind = kind; + bp->raw_type = type; + } + + if (!bp->inserted) + { + *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); + if (*err != 0) + { + if (debug_threads) + debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n", + paddress (where), *err); + + return NULL; + } + + bp->inserted = 1; + } + + /* If the breakpoint was allocated above, we know we want to keep it + now. */ + bp_holder.release (); + + /* Link the breakpoint in, if this is the first reference. */ + if (++bp->refcount == 1) + { + bp->next = proc->raw_breakpoints; + proc->raw_breakpoints = bp; + } + return bp; +} + +/* Notice that breakpoint traps are always installed on top of fast + tracepoint jumps. This is even if the fast tracepoint is installed + at a later time compared to when the breakpoint was installed. + This means that a stopping breakpoint or tracepoint has higher + "priority". In turn, this allows having fast and slow tracepoints + (and breakpoints) at the same address behave correctly. */ + + +/* A fast tracepoint jump. */ + +struct fast_tracepoint_jump +{ + struct fast_tracepoint_jump *next; + + /* A reference count. GDB can install more than one fast tracepoint + at the same address (each with its own action list, for + example). */ + int refcount; + + /* The fast tracepoint's insertion address. There can only be one + of these for a given PC. */ + CORE_ADDR pc; + + /* Non-zero if this fast tracepoint jump is currently inserted in + the inferior. */ + int inserted; + + /* The length of the jump instruction. */ + int length; + + /* A poor-man's flexible array member, holding both the jump + instruction to insert, and a copy of the instruction that would + be in memory had not been a jump there (the shadow memory of the + tracepoint jump). */ + unsigned char insn_and_shadow[0]; +}; + +/* Fast tracepoint FP's jump instruction to insert. */ +#define fast_tracepoint_jump_insn(fp) \ + ((fp)->insn_and_shadow + 0) + +/* The shadow memory of fast tracepoint jump FP. */ +#define fast_tracepoint_jump_shadow(fp) \ + ((fp)->insn_and_shadow + (fp)->length) + + +/* Return the fast tracepoint jump set at WHERE. */ + +static struct fast_tracepoint_jump * +find_fast_tracepoint_jump_at (CORE_ADDR where) +{ + struct process_info *proc = current_process (); + struct fast_tracepoint_jump *jp; + + for (jp = proc->fast_tracepoint_jumps; jp != NULL; jp = jp->next) + if (jp->pc == where) + return jp; + + return NULL; +} + +int +fast_tracepoint_jump_here (CORE_ADDR where) +{ + struct fast_tracepoint_jump *jp = find_fast_tracepoint_jump_at (where); + + return (jp != NULL); +} + +int +delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel) +{ + struct fast_tracepoint_jump *bp, **bp_link; + int ret; + struct process_info *proc = current_process (); + + bp = proc->fast_tracepoint_jumps; + bp_link = &proc->fast_tracepoint_jumps; + + while (bp) + { + if (bp == todel) + { + if (--bp->refcount == 0) + { + struct fast_tracepoint_jump *prev_bp_link = *bp_link; + unsigned char *buf; + + /* Unlink it. */ + *bp_link = bp->next; + + /* Since there can be breakpoints inserted in the same + address range, we use `target_write_memory', which + takes care of layering breakpoints on top of fast + tracepoints, and on top of the buffer we pass it. + This works because we've already unlinked the fast + tracepoint jump above. Also note that we need to + pass the current shadow contents, because + target_write_memory updates any shadow memory with + what we pass here, and we want that to be a nop. */ + buf = (unsigned char *) alloca (bp->length); + memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length); + ret = target_write_memory (bp->pc, buf, bp->length); + if (ret != 0) + { + /* Something went wrong, relink the jump. */ + *bp_link = prev_bp_link; + + if (debug_threads) + debug_printf ("Failed to uninsert fast tracepoint jump " + "at 0x%s (%s) while deleting it.\n", + paddress (bp->pc), safe_strerror (ret)); + return ret; + } + + free (bp); + } + + return 0; + } + else + { + bp_link = &bp->next; + bp = *bp_link; + } + } + + warning ("Could not find fast tracepoint jump in list."); + return ENOENT; +} + +void +inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp) +{ + jp->refcount++; +} + +struct fast_tracepoint_jump * +set_fast_tracepoint_jump (CORE_ADDR where, + unsigned char *insn, ULONGEST length) +{ + struct process_info *proc = current_process (); + struct fast_tracepoint_jump *jp; + int err; + unsigned char *buf; + + /* We refcount fast tracepoint jumps. Check if we already know + about a jump at this address. */ + jp = find_fast_tracepoint_jump_at (where); + if (jp != NULL) + { + jp->refcount++; + return jp; + } + + /* We don't, so create a new object. Double the length, because the + flexible array member holds both the jump insn, and the + shadow. */ + jp = (struct fast_tracepoint_jump *) xcalloc (1, sizeof (*jp) + (length * 2)); + jp->pc = where; + jp->length = length; + memcpy (fast_tracepoint_jump_insn (jp), insn, length); + jp->refcount = 1; + buf = (unsigned char *) alloca (length); + + /* Note that there can be trap breakpoints inserted in the same + address range. To access the original memory contents, we use + `read_inferior_memory', which masks out breakpoints. */ + err = read_inferior_memory (where, buf, length); + if (err != 0) + { + if (debug_threads) + debug_printf ("Failed to read shadow memory of" + " fast tracepoint at 0x%s (%s).\n", + paddress (where), safe_strerror (err)); + free (jp); + return NULL; + } + memcpy (fast_tracepoint_jump_shadow (jp), buf, length); + + /* Link the jump in. */ + jp->inserted = 1; + jp->next = proc->fast_tracepoint_jumps; + proc->fast_tracepoint_jumps = jp; + + /* Since there can be trap breakpoints inserted in the same address + range, we use use `target_write_memory', which takes care of + layering breakpoints on top of fast tracepoints, on top of the + buffer we pass it. This works because we've already linked in + the fast tracepoint jump above. Also note that we need to pass + the current shadow contents, because target_write_memory + updates any shadow memory with what we pass here, and we want + that to be a nop. */ + err = target_write_memory (where, buf, length); + if (err != 0) + { + if (debug_threads) + debug_printf ("Failed to insert fast tracepoint jump at 0x%s (%s).\n", + paddress (where), safe_strerror (err)); + + /* Unlink it. */ + proc->fast_tracepoint_jumps = jp->next; + free (jp); + + return NULL; + } + + return jp; +} + +void +uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc) +{ + struct fast_tracepoint_jump *jp; + int err; + + jp = find_fast_tracepoint_jump_at (pc); + if (jp == NULL) + { + /* This can happen when we remove all breakpoints while handling + a step-over. */ + if (debug_threads) + debug_printf ("Could not find fast tracepoint jump at 0x%s " + "in list (uninserting).\n", + paddress (pc)); + return; + } + + if (jp->inserted) + { + unsigned char *buf; + + jp->inserted = 0; + + /* Since there can be trap breakpoints inserted in the same + address range, we use use `target_write_memory', which + takes care of layering breakpoints on top of fast + tracepoints, and on top of the buffer we pass it. This works + because we've already marked the fast tracepoint fast + tracepoint jump uninserted above. Also note that we need to + pass the current shadow contents, because + target_write_memory updates any shadow memory with what we + pass here, and we want that to be a nop. */ + buf = (unsigned char *) alloca (jp->length); + memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); + err = target_write_memory (jp->pc, buf, jp->length); + if (err != 0) + { + jp->inserted = 1; + + if (debug_threads) + debug_printf ("Failed to uninsert fast tracepoint jump at" + " 0x%s (%s).\n", + paddress (pc), safe_strerror (err)); + } + } +} + +void +reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) +{ + struct fast_tracepoint_jump *jp; + int err; + unsigned char *buf; + + jp = find_fast_tracepoint_jump_at (where); + if (jp == NULL) + { + /* This can happen when we remove breakpoints when a tracepoint + hit causes a tracing stop, while handling a step-over. */ + if (debug_threads) + debug_printf ("Could not find fast tracepoint jump at 0x%s " + "in list (reinserting).\n", + paddress (where)); + return; + } + + if (jp->inserted) + error ("Jump already inserted at reinsert time."); + + jp->inserted = 1; + + /* Since there can be trap breakpoints inserted in the same address + range, we use `target_write_memory', which takes care of + layering breakpoints on top of fast tracepoints, and on top of + the buffer we pass it. This works because we've already marked + the fast tracepoint jump inserted above. Also note that we need + to pass the current shadow contents, because + target_write_memory updates any shadow memory with what we pass + here, and we want that to be a nop. */ + buf = (unsigned char *) alloca (jp->length); + memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); + err = target_write_memory (where, buf, jp->length); + if (err != 0) + { + jp->inserted = 0; + + if (debug_threads) + debug_printf ("Failed to reinsert fast tracepoint jump at" + " 0x%s (%s).\n", + paddress (where), safe_strerror (err)); + } +} + +/* Set a high-level breakpoint of type TYPE, with low level type + RAW_TYPE and kind KIND, at WHERE. On success, a pointer to the new + breakpoint is returned. On failure, returns NULL and writes the + error code to *ERR. HANDLER is called when the breakpoint is hit. + HANDLER should return 1 if the breakpoint should be deleted, 0 + otherwise. */ + +static struct breakpoint * +set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type, + CORE_ADDR where, int kind, + int (*handler) (CORE_ADDR), int *err) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + struct raw_breakpoint *raw; + + raw = set_raw_breakpoint_at (raw_type, where, kind, err); + + if (raw == NULL) + { + /* warn? */ + return NULL; + } + + if (is_gdb_breakpoint (type)) + { + struct gdb_breakpoint *gdb_bp = XCNEW (struct gdb_breakpoint); + + bp = (struct breakpoint *) gdb_bp; + gdb_assert (handler == NULL); + } + else if (type == other_breakpoint) + { + struct other_breakpoint *other_bp = XCNEW (struct other_breakpoint); + + other_bp->handler = handler; + bp = (struct breakpoint *) other_bp; + } + else if (type == single_step_breakpoint) + { + struct single_step_breakpoint *ss_bp + = XCNEW (struct single_step_breakpoint); + + bp = (struct breakpoint *) ss_bp; + } + else + gdb_assert_not_reached ("unhandled breakpoint type"); + + bp->type = type; + bp->raw = raw; + + bp->next = proc->breakpoints; + proc->breakpoints = bp; + + return bp; +} + +/* Set breakpoint of TYPE on address WHERE with handler HANDLER. */ + +static struct breakpoint * +set_breakpoint_type_at (enum bkpt_type type, CORE_ADDR where, + int (*handler) (CORE_ADDR)) +{ + int err_ignored; + CORE_ADDR placed_address = where; + int breakpoint_kind = target_breakpoint_kind_from_pc (&placed_address); + + return set_breakpoint (type, raw_bkpt_type_sw, + placed_address, breakpoint_kind, handler, + &err_ignored); +} + +/* See mem-break.h */ + +struct breakpoint * +set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) +{ + return set_breakpoint_type_at (other_breakpoint, where, handler); +} + + +static int +delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) +{ + struct raw_breakpoint *bp, **bp_link; + int ret; + + bp = proc->raw_breakpoints; + bp_link = &proc->raw_breakpoints; + + while (bp) + { + if (bp == todel) + { + if (bp->inserted > 0) + { + struct raw_breakpoint *prev_bp_link = *bp_link; + + *bp_link = bp->next; + + ret = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, + bp); + if (ret != 0) + { + /* Something went wrong, relink the breakpoint. */ + *bp_link = prev_bp_link; + + if (debug_threads) + debug_printf ("Failed to uninsert raw breakpoint " + "at 0x%s while deleting it.\n", + paddress (bp->pc)); + return ret; + } + } + else + *bp_link = bp->next; + + free (bp); + return 0; + } + else + { + bp_link = &bp->next; + bp = *bp_link; + } + } + + warning ("Could not find raw breakpoint in list."); + return ENOENT; +} + +static int +release_breakpoint (struct process_info *proc, struct breakpoint *bp) +{ + int newrefcount; + int ret; + + newrefcount = bp->raw->refcount - 1; + if (newrefcount == 0) + { + ret = delete_raw_breakpoint (proc, bp->raw); + if (ret != 0) + return ret; + } + else + bp->raw->refcount = newrefcount; + + free (bp); + + return 0; +} + +static int +delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel) +{ + struct breakpoint *bp, **bp_link; + int err; + + bp = proc->breakpoints; + bp_link = &proc->breakpoints; + + while (bp) + { + if (bp == todel) + { + *bp_link = bp->next; + + err = release_breakpoint (proc, bp); + if (err != 0) + return err; + + bp = *bp_link; + return 0; + } + else + { + bp_link = &bp->next; + bp = *bp_link; + } + } + + warning ("Could not find breakpoint in list."); + return ENOENT; +} + +int +delete_breakpoint (struct breakpoint *todel) +{ + struct process_info *proc = current_process (); + return delete_breakpoint_1 (proc, todel); +} + +/* Locate a GDB breakpoint of type Z_TYPE and kind KIND placed at + address ADDR and return a pointer to its structure. If KIND is -1, + the breakpoint's kind is ignored. */ + +static struct gdb_breakpoint * +find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + enum bkpt_type type = Z_packet_to_bkpt_type (z_type); + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + if (bp->type == type && bp->raw->pc == addr + && (kind == -1 || bp->raw->kind == kind)) + return (struct gdb_breakpoint *) bp; + + return NULL; +} + +static int +z_type_supported (char z_type) +{ + return (z_type >= '0' && z_type <= '4' + && the_target->supports_z_point_type != NULL + && the_target->supports_z_point_type (z_type)); +} + +/* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND. + Returns a pointer to the newly created breakpoint on success. On + failure returns NULL and sets *ERR to either -1 for error, or 1 if + Z_TYPE breakpoints are not supported on this target. */ + +static struct gdb_breakpoint * +set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err) +{ + struct gdb_breakpoint *bp; + enum bkpt_type type; + enum raw_bkpt_type raw_type; + + /* If we see GDB inserting a second code breakpoint at the same + address, then either: GDB is updating the breakpoint's conditions + or commands; or, the first breakpoint must have disappeared due + to a shared library unload. On targets where the shared + libraries are handled by userspace, like SVR4, for example, + GDBserver can't tell if a library was loaded or unloaded. Since + we refcount raw breakpoints, we must be careful to make sure GDB + breakpoints never contribute more than one reference. if we + didn't do this, in case the previous breakpoint is gone due to a + shared library unload, we'd just increase the refcount of the + previous breakpoint at this address, but the trap was not planted + in the inferior anymore, thus the breakpoint would never be hit. + Note this must be careful to not create a window where + breakpoints are removed from the target, for non-stop, in case + the target can poke at memory while the program is running. */ + if (z_type == Z_PACKET_SW_BP + || z_type == Z_PACKET_HW_BP) + { + bp = find_gdb_breakpoint (z_type, addr, -1); + + if (bp != NULL) + { + if (bp->base.raw->kind != kind) + { + /* A different kind than previously seen. The previous + breakpoint must be gone then. */ + bp->base.raw->inserted = -1; + delete_breakpoint ((struct breakpoint *) bp); + bp = NULL; + } + else if (z_type == Z_PACKET_SW_BP) + { + /* Check if the breakpoint is actually gone from the + target, due to an solib unload, for example. Might + as well validate _all_ breakpoints. */ + validate_breakpoints (); + + /* Breakpoints that don't pass validation are + deleted. */ + bp = find_gdb_breakpoint (z_type, addr, -1); + } + } + } + else + { + /* Data breakpoints for the same address but different kind are + expected. GDB doesn't merge these. The backend gets to do + that if it wants/can. */ + bp = find_gdb_breakpoint (z_type, addr, kind); + } + + if (bp != NULL) + { + /* We already know about this breakpoint, there's nothing else + to do - GDB's reference is already accounted for. Note that + whether the breakpoint inserted is left as is - we may be + stepping over it, for example, in which case we don't want to + force-reinsert it. */ + return bp; + } + + raw_type = Z_packet_to_raw_bkpt_type (z_type); + type = Z_packet_to_bkpt_type (z_type); + return (struct gdb_breakpoint *) set_breakpoint (type, raw_type, addr, + kind, NULL, err); +} + +static int +check_gdb_bp_preconditions (char z_type, int *err) +{ + /* As software/memory breakpoints work by poking at memory, we need + to prepare to access memory. If that operation fails, we need to + return error. Seeing an error, if this is the first breakpoint + of that type that GDB tries to insert, GDB would then assume the + breakpoint type is supported, but it may actually not be. So we + need to check whether the type is supported at all before + preparing to access memory. */ + if (!z_type_supported (z_type)) + { + *err = 1; + return 0; + } + + return 1; +} + +/* See mem-break.h. This is a wrapper for set_gdb_breakpoint_1 that + knows to prepare to access memory for Z0 breakpoints. */ + +struct gdb_breakpoint * +set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err) +{ + struct gdb_breakpoint *bp; + + if (!check_gdb_bp_preconditions (z_type, err)) + return NULL; + + /* If inserting a software/memory breakpoint, need to prepare to + access memory. */ + if (z_type == Z_PACKET_SW_BP) + { + if (prepare_to_access_memory () != 0) + { + *err = -1; + return NULL; + } + } + + bp = set_gdb_breakpoint_1 (z_type, addr, kind, err); + + if (z_type == Z_PACKET_SW_BP) + done_accessing_memory (); + + return bp; +} + +/* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously + inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success, + -1 on error, and 1 if Z_TYPE breakpoints are not supported on this + target. */ + +static int +delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind) +{ + struct gdb_breakpoint *bp; + int err; + + bp = find_gdb_breakpoint (z_type, addr, kind); + if (bp == NULL) + return -1; + + /* Before deleting the breakpoint, make sure to free its condition + and command lists. */ + clear_breakpoint_conditions_and_commands (bp); + err = delete_breakpoint ((struct breakpoint *) bp); + if (err != 0) + return -1; + + return 0; +} + +/* See mem-break.h. This is a wrapper for delete_gdb_breakpoint that + knows to prepare to access memory for Z0 breakpoints. */ + +int +delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) +{ + int ret; + + if (!check_gdb_bp_preconditions (z_type, &ret)) + return ret; + + /* If inserting a software/memory breakpoint, need to prepare to + access memory. */ + if (z_type == Z_PACKET_SW_BP) + { + int err; + + err = prepare_to_access_memory (); + if (err != 0) + return -1; + } + + ret = delete_gdb_breakpoint_1 (z_type, addr, kind); + + if (z_type == Z_PACKET_SW_BP) + done_accessing_memory (); + + return ret; +} + +/* Clear all conditions associated with a breakpoint. */ + +static void +clear_breakpoint_conditions (struct gdb_breakpoint *bp) +{ + struct point_cond_list *cond; + + if (bp->cond_list == NULL) + return; + + cond = bp->cond_list; + + while (cond != NULL) + { + struct point_cond_list *cond_next; + + cond_next = cond->next; + gdb_free_agent_expr (cond->cond); + free (cond); + cond = cond_next; + } + + bp->cond_list = NULL; +} + +/* Clear all commands associated with a breakpoint. */ + +static void +clear_breakpoint_commands (struct gdb_breakpoint *bp) +{ + struct point_command_list *cmd; + + if (bp->command_list == NULL) + return; + + cmd = bp->command_list; + + while (cmd != NULL) + { + struct point_command_list *cmd_next; + + cmd_next = cmd->next; + gdb_free_agent_expr (cmd->cmd); + free (cmd); + cmd = cmd_next; + } + + bp->command_list = NULL; +} + +void +clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp) +{ + clear_breakpoint_conditions (bp); + clear_breakpoint_commands (bp); +} + +/* Add condition CONDITION to GDBserver's breakpoint BP. */ + +static void +add_condition_to_breakpoint (struct gdb_breakpoint *bp, + struct agent_expr *condition) +{ + struct point_cond_list *new_cond; + + /* Create new condition. */ + new_cond = XCNEW (struct point_cond_list); + new_cond->cond = condition; + + /* Add condition to the list. */ + new_cond->next = bp->cond_list; + bp->cond_list = new_cond; +} + +/* Add a target-side condition CONDITION to a breakpoint. */ + +int +add_breakpoint_condition (struct gdb_breakpoint *bp, const char **condition) +{ + const char *actparm = *condition; + struct agent_expr *cond; + + if (condition == NULL) + return 1; + + if (bp == NULL) + return 0; + + cond = gdb_parse_agent_expr (&actparm); + + if (cond == NULL) + { + warning ("Condition evaluation failed. Assuming unconditional."); + return 0; + } + + add_condition_to_breakpoint (bp, cond); + + *condition = actparm; + + return 1; +} + +/* Evaluate condition (if any) at breakpoint BP. Return 1 if + true and 0 otherwise. */ + +static int +gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr) +{ + /* Fetch registers for the current inferior. */ + struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); + ULONGEST value = 0; + struct point_cond_list *cl; + int err = 0; + struct eval_agent_expr_context ctx; + + if (bp == NULL) + return 0; + + /* Check if the breakpoint is unconditional. If it is, + the condition always evaluates to TRUE. */ + if (bp->cond_list == NULL) + return 1; + + ctx.regcache = get_thread_regcache (current_thread, 1); + ctx.tframe = NULL; + ctx.tpoint = NULL; + + /* Evaluate each condition in the breakpoint's list of conditions. + Return true if any of the conditions evaluates to TRUE. + + If we failed to evaluate the expression, TRUE is returned. This + forces GDB to reevaluate the conditions. */ + for (cl = bp->cond_list; + cl && !value && !err; cl = cl->next) + { + /* Evaluate the condition. */ + err = gdb_eval_agent_expr (&ctx, cl->cond, &value); + } + + if (err) + return 1; + + return (value != 0); +} + +int +gdb_condition_true_at_breakpoint (CORE_ADDR where) +{ + /* Only check code (software or hardware) breakpoints. */ + return (gdb_condition_true_at_breakpoint_z_type (Z_PACKET_SW_BP, where) + || gdb_condition_true_at_breakpoint_z_type (Z_PACKET_HW_BP, where)); +} + +/* Add commands COMMANDS to GDBserver's breakpoint BP. */ + +static void +add_commands_to_breakpoint (struct gdb_breakpoint *bp, + struct agent_expr *commands, int persist) +{ + struct point_command_list *new_cmd; + + /* Create new command. */ + new_cmd = XCNEW (struct point_command_list); + new_cmd->cmd = commands; + new_cmd->persistence = persist; + + /* Add commands to the list. */ + new_cmd->next = bp->command_list; + bp->command_list = new_cmd; +} + +/* Add a target-side command COMMAND to the breakpoint at ADDR. */ + +int +add_breakpoint_commands (struct gdb_breakpoint *bp, const char **command, + int persist) +{ + const char *actparm = *command; + struct agent_expr *cmd; + + if (command == NULL) + return 1; + + if (bp == NULL) + return 0; + + cmd = gdb_parse_agent_expr (&actparm); + + if (cmd == NULL) + { + warning ("Command evaluation failed. Disabling."); + return 0; + } + + add_commands_to_breakpoint (bp, cmd, persist); + + *command = actparm; + + return 1; +} + +/* Return true if there are no commands to run at this location, + which likely means we want to report back to GDB. */ + +static int +gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr) +{ + struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); + + if (bp == NULL) + return 1; + + if (debug_threads) + debug_printf ("at 0x%s, type Z%c, bp command_list is 0x%s\n", + paddress (addr), z_type, + phex_nz ((uintptr_t) bp->command_list, 0)); + return (bp->command_list == NULL); +} + +/* Return true if there are no commands to run at this location, + which likely means we want to report back to GDB. */ + +int +gdb_no_commands_at_breakpoint (CORE_ADDR where) +{ + /* Only check code (software or hardware) breakpoints. */ + return (gdb_no_commands_at_breakpoint_z_type (Z_PACKET_SW_BP, where) + && gdb_no_commands_at_breakpoint_z_type (Z_PACKET_HW_BP, where)); +} + +/* Run a breakpoint's commands. Returns 0 if there was a problem + running any command, 1 otherwise. */ + +static int +run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr) +{ + /* Fetch registers for the current inferior. */ + struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); + ULONGEST value = 0; + struct point_command_list *cl; + int err = 0; + struct eval_agent_expr_context ctx; + + if (bp == NULL) + return 1; + + ctx.regcache = get_thread_regcache (current_thread, 1); + ctx.tframe = NULL; + ctx.tpoint = NULL; + + for (cl = bp->command_list; + cl && !value && !err; cl = cl->next) + { + /* Run the command. */ + err = gdb_eval_agent_expr (&ctx, cl->cmd, &value); + + /* If one command has a problem, stop digging the hole deeper. */ + if (err) + return 0; + } + + return 1; +} + +void +run_breakpoint_commands (CORE_ADDR where) +{ + /* Only check code (software or hardware) breakpoints. If one + command has a problem, stop digging the hole deeper. */ + if (run_breakpoint_commands_z_type (Z_PACKET_SW_BP, where)) + run_breakpoint_commands_z_type (Z_PACKET_HW_BP, where); +} + +/* See mem-break.h. */ + +int +gdb_breakpoint_here (CORE_ADDR where) +{ + /* Only check code (software or hardware) breakpoints. */ + return (find_gdb_breakpoint (Z_PACKET_SW_BP, where, -1) != NULL + || find_gdb_breakpoint (Z_PACKET_HW_BP, where, -1) != NULL); +} + +void +set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid) +{ + struct single_step_breakpoint *bp; + + gdb_assert (current_ptid.pid () == ptid.pid ()); + + bp = (struct single_step_breakpoint *) set_breakpoint_type_at (single_step_breakpoint, + stop_at, NULL); + bp->ptid = ptid; +} + +void +delete_single_step_breakpoints (struct thread_info *thread) +{ + struct process_info *proc = get_thread_process (thread); + struct breakpoint *bp, **bp_link; + + bp = proc->breakpoints; + bp_link = &proc->breakpoints; + + while (bp) + { + if (bp->type == single_step_breakpoint + && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) + { + struct thread_info *saved_thread = current_thread; + + current_thread = thread; + *bp_link = bp->next; + release_breakpoint (proc, bp); + bp = *bp_link; + current_thread = saved_thread; + } + else + { + bp_link = &bp->next; + bp = *bp_link; + } + } +} + +static void +uninsert_raw_breakpoint (struct raw_breakpoint *bp) +{ + if (bp->inserted < 0) + { + if (debug_threads) + debug_printf ("Breakpoint at %s is marked insert-disabled.\n", + paddress (bp->pc)); + } + else if (bp->inserted > 0) + { + int err; + + bp->inserted = 0; + + err = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp); + if (err != 0) + { + bp->inserted = 1; + + if (debug_threads) + debug_printf ("Failed to uninsert raw breakpoint at 0x%s.\n", + paddress (bp->pc)); + } + } +} + +void +uninsert_breakpoints_at (CORE_ADDR pc) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + int found = 0; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if ((bp->raw_type == raw_bkpt_type_sw + || bp->raw_type == raw_bkpt_type_hw) + && bp->pc == pc) + { + found = 1; + + if (bp->inserted) + uninsert_raw_breakpoint (bp); + } + + if (!found) + { + /* This can happen when we remove all breakpoints while handling + a step-over. */ + if (debug_threads) + debug_printf ("Could not find breakpoint at 0x%s " + "in list (uninserting).\n", + paddress (pc)); + } +} + +void +uninsert_all_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if ((bp->raw_type == raw_bkpt_type_sw + || bp->raw_type == raw_bkpt_type_hw) + && bp->inserted) + uninsert_raw_breakpoint (bp); +} + +void +uninsert_single_step_breakpoints (struct thread_info *thread) +{ + struct process_info *proc = get_thread_process (thread); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (bp->type == single_step_breakpoint + && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) + { + gdb_assert (bp->raw->inserted > 0); + + /* Only uninsert the raw breakpoint if it only belongs to a + reinsert breakpoint. */ + if (bp->raw->refcount == 1) + { + struct thread_info *saved_thread = current_thread; + + current_thread = thread; + uninsert_raw_breakpoint (bp->raw); + current_thread = saved_thread; + } + } + } +} + +static void +reinsert_raw_breakpoint (struct raw_breakpoint *bp) +{ + int err; + + if (bp->inserted) + return; + + err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); + if (err == 0) + bp->inserted = 1; + else if (debug_threads) + debug_printf ("Failed to reinsert breakpoint at 0x%s (%d).\n", + paddress (bp->pc), err); +} + +void +reinsert_breakpoints_at (CORE_ADDR pc) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + int found = 0; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if ((bp->raw_type == raw_bkpt_type_sw + || bp->raw_type == raw_bkpt_type_hw) + && bp->pc == pc) + { + found = 1; + + reinsert_raw_breakpoint (bp); + } + + if (!found) + { + /* This can happen when we remove all breakpoints while handling + a step-over. */ + if (debug_threads) + debug_printf ("Could not find raw breakpoint at 0x%s " + "in list (reinserting).\n", + paddress (pc)); + } +} + +int +has_single_step_breakpoints (struct thread_info *thread) +{ + struct process_info *proc = get_thread_process (thread); + struct breakpoint *bp, **bp_link; + + bp = proc->breakpoints; + bp_link = &proc->breakpoints; + + while (bp) + { + if (bp->type == single_step_breakpoint + && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) + return 1; + else + { + bp_link = &bp->next; + bp = *bp_link; + } + } + + return 0; +} + +void +reinsert_all_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if ((bp->raw_type == raw_bkpt_type_sw + || bp->raw_type == raw_bkpt_type_hw) + && !bp->inserted) + reinsert_raw_breakpoint (bp); +} + +void +reinsert_single_step_breakpoints (struct thread_info *thread) +{ + struct process_info *proc = get_thread_process (thread); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (bp->type == single_step_breakpoint + && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) + { + gdb_assert (bp->raw->inserted > 0); + + if (bp->raw->refcount == 1) + { + struct thread_info *saved_thread = current_thread; + + current_thread = thread; + reinsert_raw_breakpoint (bp->raw); + current_thread = saved_thread; + } + } + } +} + +void +check_breakpoints (CORE_ADDR stop_pc) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp, **bp_link; + + bp = proc->breakpoints; + bp_link = &proc->breakpoints; + + while (bp) + { + struct raw_breakpoint *raw = bp->raw; + + if ((raw->raw_type == raw_bkpt_type_sw + || raw->raw_type == raw_bkpt_type_hw) + && raw->pc == stop_pc) + { + if (!raw->inserted) + { + warning ("Hit a removed breakpoint?"); + return; + } + + if (bp->type == other_breakpoint) + { + struct other_breakpoint *other_bp + = (struct other_breakpoint *) bp; + + if (other_bp->handler != NULL && (*other_bp->handler) (stop_pc)) + { + *bp_link = bp->next; + + release_breakpoint (proc, bp); + + bp = *bp_link; + continue; + } + } + } + + bp_link = &bp->next; + bp = *bp_link; + } +} + +int +breakpoint_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if ((bp->raw_type == raw_bkpt_type_sw + || bp->raw_type == raw_bkpt_type_hw) + && bp->pc == addr) + return 1; + + return 0; +} + +int +breakpoint_inserted_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if ((bp->raw_type == raw_bkpt_type_sw + || bp->raw_type == raw_bkpt_type_hw) + && bp->pc == addr + && bp->inserted) + return 1; + + return 0; +} + +/* See mem-break.h. */ + +int +software_breakpoint_inserted_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if (bp->raw_type == raw_bkpt_type_sw + && bp->pc == addr + && bp->inserted) + return 1; + + return 0; +} + +/* See mem-break.h. */ + +int +hardware_breakpoint_inserted_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if (bp->raw_type == raw_bkpt_type_hw + && bp->pc == addr + && bp->inserted) + return 1; + + return 0; +} + +/* See mem-break.h. */ + +int +single_step_breakpoint_inserted_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + if (bp->type == single_step_breakpoint + && bp->raw->pc == addr + && bp->raw->inserted) + return 1; + + return 0; +} + +static int +validate_inserted_breakpoint (struct raw_breakpoint *bp) +{ + unsigned char *buf; + int err; + + gdb_assert (bp->inserted); + gdb_assert (bp->raw_type == raw_bkpt_type_sw); + + buf = (unsigned char *) alloca (bp_size (bp)); + err = (*the_target->read_memory) (bp->pc, buf, bp_size (bp)); + if (err || memcmp (buf, bp_opcode (bp), bp_size (bp)) != 0) + { + /* Tag it as gone. */ + bp->inserted = -1; + return 0; + } + + return 1; +} + +static void +delete_disabled_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp, *next; + + for (bp = proc->breakpoints; bp != NULL; bp = next) + { + next = bp->next; + if (bp->raw->inserted < 0) + { + /* If single_step_breakpoints become disabled, that means the + manipulations (insertion and removal) of them are wrong. */ + gdb_assert (bp->type != single_step_breakpoint); + delete_breakpoint_1 (proc, bp); + } + } +} + +/* Check if breakpoints we inserted still appear to be inserted. They + may disappear due to a shared library unload, and worse, a new + shared library may be reloaded at the same address as the + previously unloaded one. If that happens, we should make sure that + the shadow memory of the old breakpoints isn't used when reading or + writing memory. */ + +void +validate_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + struct raw_breakpoint *raw = bp->raw; + + if (raw->raw_type == raw_bkpt_type_sw && raw->inserted > 0) + validate_inserted_breakpoint (raw); + } + + delete_disabled_breakpoints (); +} + +void +check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp = proc->raw_breakpoints; + struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; + CORE_ADDR mem_end = mem_addr + mem_len; + int disabled_one = 0; + + for (; jp != NULL; jp = jp->next) + { + CORE_ADDR bp_end = jp->pc + jp->length; + CORE_ADDR start, end; + int copy_offset, copy_len, buf_offset; + + gdb_assert (fast_tracepoint_jump_shadow (jp) >= buf + mem_len + || buf >= fast_tracepoint_jump_shadow (jp) + (jp)->length); + + if (mem_addr >= bp_end) + continue; + if (jp->pc >= mem_end) + continue; + + start = jp->pc; + if (mem_addr > start) + start = mem_addr; + + end = bp_end; + if (end > mem_end) + end = mem_end; + + copy_len = end - start; + copy_offset = start - jp->pc; + buf_offset = start - mem_addr; + + if (jp->inserted) + memcpy (buf + buf_offset, + fast_tracepoint_jump_shadow (jp) + copy_offset, + copy_len); + } + + for (; bp != NULL; bp = bp->next) + { + CORE_ADDR bp_end = bp->pc + bp_size (bp); + CORE_ADDR start, end; + int copy_offset, copy_len, buf_offset; + + if (bp->raw_type != raw_bkpt_type_sw) + continue; + + gdb_assert (bp->old_data >= buf + mem_len + || buf >= &bp->old_data[sizeof (bp->old_data)]); + + if (mem_addr >= bp_end) + continue; + if (bp->pc >= mem_end) + continue; + + start = bp->pc; + if (mem_addr > start) + start = mem_addr; + + end = bp_end; + if (end > mem_end) + end = mem_end; + + copy_len = end - start; + copy_offset = start - bp->pc; + buf_offset = start - mem_addr; + + if (bp->inserted > 0) + { + if (validate_inserted_breakpoint (bp)) + memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len); + else + disabled_one = 1; + } + } + + if (disabled_one) + delete_disabled_breakpoints (); +} + +void +check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, + const unsigned char *myaddr, int mem_len) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp = proc->raw_breakpoints; + struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; + CORE_ADDR mem_end = mem_addr + mem_len; + int disabled_one = 0; + + /* First fast tracepoint jumps, then breakpoint traps on top. */ + + for (; jp != NULL; jp = jp->next) + { + CORE_ADDR jp_end = jp->pc + jp->length; + CORE_ADDR start, end; + int copy_offset, copy_len, buf_offset; + + gdb_assert (fast_tracepoint_jump_shadow (jp) >= myaddr + mem_len + || myaddr >= fast_tracepoint_jump_shadow (jp) + (jp)->length); + gdb_assert (fast_tracepoint_jump_insn (jp) >= buf + mem_len + || buf >= fast_tracepoint_jump_insn (jp) + (jp)->length); + + if (mem_addr >= jp_end) + continue; + if (jp->pc >= mem_end) + continue; + + start = jp->pc; + if (mem_addr > start) + start = mem_addr; + + end = jp_end; + if (end > mem_end) + end = mem_end; + + copy_len = end - start; + copy_offset = start - jp->pc; + buf_offset = start - mem_addr; + + memcpy (fast_tracepoint_jump_shadow (jp) + copy_offset, + myaddr + buf_offset, copy_len); + if (jp->inserted) + memcpy (buf + buf_offset, + fast_tracepoint_jump_insn (jp) + copy_offset, copy_len); + } + + for (; bp != NULL; bp = bp->next) + { + CORE_ADDR bp_end = bp->pc + bp_size (bp); + CORE_ADDR start, end; + int copy_offset, copy_len, buf_offset; + + if (bp->raw_type != raw_bkpt_type_sw) + continue; + + gdb_assert (bp->old_data >= myaddr + mem_len + || myaddr >= &bp->old_data[sizeof (bp->old_data)]); + + if (mem_addr >= bp_end) + continue; + if (bp->pc >= mem_end) + continue; + + start = bp->pc; + if (mem_addr > start) + start = mem_addr; + + end = bp_end; + if (end > mem_end) + end = mem_end; + + copy_len = end - start; + copy_offset = start - bp->pc; + buf_offset = start - mem_addr; + + memcpy (bp->old_data + copy_offset, myaddr + buf_offset, copy_len); + if (bp->inserted > 0) + { + if (validate_inserted_breakpoint (bp)) + memcpy (buf + buf_offset, bp_opcode (bp) + copy_offset, copy_len); + else + disabled_one = 1; + } + } + + if (disabled_one) + delete_disabled_breakpoints (); +} + +/* Delete all breakpoints, and un-insert them from the inferior. */ + +void +delete_all_breakpoints (void) +{ + struct process_info *proc = current_process (); + + while (proc->breakpoints) + delete_breakpoint_1 (proc, proc->breakpoints); +} + +/* Clear the "inserted" flag in all breakpoints. */ + +void +mark_breakpoints_out (struct process_info *proc) +{ + struct raw_breakpoint *raw_bp; + + for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next) + raw_bp->inserted = 0; +} + +/* Release all breakpoints, but do not try to un-insert them from the + inferior. */ + +void +free_all_breakpoints (struct process_info *proc) +{ + mark_breakpoints_out (proc); + + /* Note: use PROC explicitly instead of deferring to + delete_all_breakpoints --- CURRENT_INFERIOR may already have been + released when we get here. There should be no call to + current_process from here on. */ + while (proc->breakpoints) + delete_breakpoint_1 (proc, proc->breakpoints); +} + +/* Clone an agent expression. */ + +static struct agent_expr * +clone_agent_expr (const struct agent_expr *src_ax) +{ + struct agent_expr *ax; + + ax = XCNEW (struct agent_expr); + ax->length = src_ax->length; + ax->bytes = (unsigned char *) xcalloc (ax->length, 1); + memcpy (ax->bytes, src_ax->bytes, ax->length); + return ax; +} + +/* Deep-copy the contents of one breakpoint to another. */ + +static struct breakpoint * +clone_one_breakpoint (const struct breakpoint *src, ptid_t ptid) +{ + struct breakpoint *dest; + struct raw_breakpoint *dest_raw; + + /* Clone the raw breakpoint. */ + dest_raw = XCNEW (struct raw_breakpoint); + dest_raw->raw_type = src->raw->raw_type; + dest_raw->refcount = src->raw->refcount; + dest_raw->pc = src->raw->pc; + dest_raw->kind = src->raw->kind; + memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN); + dest_raw->inserted = src->raw->inserted; + + /* Clone the high-level breakpoint. */ + if (is_gdb_breakpoint (src->type)) + { + struct gdb_breakpoint *gdb_dest = XCNEW (struct gdb_breakpoint); + struct point_cond_list *current_cond; + struct point_cond_list *new_cond; + struct point_cond_list *cond_tail = NULL; + struct point_command_list *current_cmd; + struct point_command_list *new_cmd; + struct point_command_list *cmd_tail = NULL; + + /* Clone the condition list. */ + for (current_cond = ((struct gdb_breakpoint *) src)->cond_list; + current_cond != NULL; + current_cond = current_cond->next) + { + new_cond = XCNEW (struct point_cond_list); + new_cond->cond = clone_agent_expr (current_cond->cond); + APPEND_TO_LIST (&gdb_dest->cond_list, new_cond, cond_tail); + } + + /* Clone the command list. */ + for (current_cmd = ((struct gdb_breakpoint *) src)->command_list; + current_cmd != NULL; + current_cmd = current_cmd->next) + { + new_cmd = XCNEW (struct point_command_list); + new_cmd->cmd = clone_agent_expr (current_cmd->cmd); + new_cmd->persistence = current_cmd->persistence; + APPEND_TO_LIST (&gdb_dest->command_list, new_cmd, cmd_tail); + } + + dest = (struct breakpoint *) gdb_dest; + } + else if (src->type == other_breakpoint) + { + struct other_breakpoint *other_dest = XCNEW (struct other_breakpoint); + + other_dest->handler = ((struct other_breakpoint *) src)->handler; + dest = (struct breakpoint *) other_dest; + } + else if (src->type == single_step_breakpoint) + { + struct single_step_breakpoint *ss_dest + = XCNEW (struct single_step_breakpoint); + + dest = (struct breakpoint *) ss_dest; + /* Since single-step breakpoint is thread specific, don't copy + thread id from SRC, use ID instead. */ + ss_dest->ptid = ptid; + } + else + gdb_assert_not_reached ("unhandled breakpoint type"); + + dest->type = src->type; + dest->raw = dest_raw; + + return dest; +} + +/* See mem-break.h. */ + +void +clone_all_breakpoints (struct thread_info *child_thread, + const struct thread_info *parent_thread) +{ + const struct breakpoint *bp; + struct breakpoint *new_bkpt; + struct breakpoint *bkpt_tail = NULL; + struct raw_breakpoint *raw_bkpt_tail = NULL; + struct process_info *child_proc = get_thread_process (child_thread); + struct process_info *parent_proc = get_thread_process (parent_thread); + struct breakpoint **new_list = &child_proc->breakpoints; + struct raw_breakpoint **new_raw_list = &child_proc->raw_breakpoints; + + for (bp = parent_proc->breakpoints; bp != NULL; bp = bp->next) + { + new_bkpt = clone_one_breakpoint (bp, ptid_of (child_thread)); + APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail); + APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail); + } +} diff --git a/gdbserver/mem-break.h b/gdbserver/mem-break.h new file mode 100644 index 00000000000..bbe1ff1a5fb --- /dev/null +++ b/gdbserver/mem-break.h @@ -0,0 +1,279 @@ +/* Memory breakpoint interfaces for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#ifndef GDBSERVER_MEM_BREAK_H +#define GDBSERVER_MEM_BREAK_H + +#include "gdbsupport/break-common.h" + +/* Breakpoints are opaque. */ +struct breakpoint; +struct gdb_breakpoint; +struct fast_tracepoint_jump; +struct raw_breakpoint; +struct process_info; + +#define Z_PACKET_SW_BP '0' +#define Z_PACKET_HW_BP '1' +#define Z_PACKET_WRITE_WP '2' +#define Z_PACKET_READ_WP '3' +#define Z_PACKET_ACCESS_WP '4' + +/* The low level breakpoint types. */ + +enum raw_bkpt_type + { + /* Software/memory breakpoint. */ + raw_bkpt_type_sw, + + /* Hardware-assisted breakpoint. */ + raw_bkpt_type_hw, + + /* Hardware-assisted write watchpoint. */ + raw_bkpt_type_write_wp, + + /* Hardware-assisted read watchpoint. */ + raw_bkpt_type_read_wp, + + /* Hardware-assisted access watchpoint. */ + raw_bkpt_type_access_wp + }; + +/* Map the protocol breakpoint/watchpoint type Z_TYPE to the internal + raw breakpoint type. */ + +enum raw_bkpt_type Z_packet_to_raw_bkpt_type (char z_type); + +/* Map a raw breakpoint type to an enum target_hw_bp_type. */ + +enum target_hw_bp_type raw_bkpt_type_to_target_hw_bp_type + (enum raw_bkpt_type raw_type); + +/* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND. + Returns a pointer to the newly created breakpoint on success. On + failure returns NULL and sets *ERR to either -1 for error, or 1 if + Z_TYPE breakpoints are not supported on this target. */ + +struct gdb_breakpoint *set_gdb_breakpoint (char z_type, CORE_ADDR addr, + int kind, int *err); + +/* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously + inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success, + -1 on error, and 1 if Z_TYPE breakpoints are not supported on this + target. */ + +int delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind); + +/* Returns TRUE if there's a software or hardware (code) breakpoint at + ADDR in our tables, inserted, or not. */ + +int breakpoint_here (CORE_ADDR addr); + +/* Returns TRUE if there's any inserted software or hardware (code) + breakpoint set at ADDR. */ + +int breakpoint_inserted_here (CORE_ADDR addr); + +/* Returns TRUE if there's any inserted software breakpoint at + ADDR. */ + +int software_breakpoint_inserted_here (CORE_ADDR addr); + +/* Returns TRUE if there's any inserted hardware (code) breakpoint at + ADDR. */ + +int hardware_breakpoint_inserted_here (CORE_ADDR addr); + +/* Returns TRUE if there's any single-step breakpoint at ADDR. */ + +int single_step_breakpoint_inserted_here (CORE_ADDR addr); + +/* Clear all breakpoint conditions and commands associated with a + breakpoint. */ + +void clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp); + +/* Set target-side condition CONDITION to the breakpoint at ADDR. + Returns false on failure. On success, advances CONDITION pointer + past the condition and returns true. */ + +int add_breakpoint_condition (struct gdb_breakpoint *bp, + const char **condition); + +/* Set target-side commands COMMANDS to the breakpoint at ADDR. + Returns false on failure. On success, advances COMMANDS past the + commands and returns true. If PERSIST, the commands should run + even while GDB is disconnected. */ + +int add_breakpoint_commands (struct gdb_breakpoint *bp, const char **commands, + int persist); + +/* Return true if PROC has any persistent command. */ +bool any_persistent_commands (process_info *proc); + +/* Evaluation condition (if any) at breakpoint BP. Return 1 if + true and 0 otherwise. */ + +int gdb_condition_true_at_breakpoint (CORE_ADDR where); + +int gdb_no_commands_at_breakpoint (CORE_ADDR where); + +void run_breakpoint_commands (CORE_ADDR where); + +/* Returns TRUE if there's a GDB breakpoint (Z0 or Z1) set at + WHERE. */ + +int gdb_breakpoint_here (CORE_ADDR where); + +/* Create a new breakpoint at WHERE, and call HANDLER when + it is hit. HANDLER should return 1 if the breakpoint + should be deleted, 0 otherwise. The type of the created + breakpoint is other_breakpoint. */ + +struct breakpoint *set_breakpoint_at (CORE_ADDR where, + int (*handler) (CORE_ADDR)); + +/* Delete a breakpoint. */ + +int delete_breakpoint (struct breakpoint *bkpt); + +/* Set a single-step breakpoint at STOP_AT for thread represented by + PTID. */ + +void set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid); + +/* Delete all single-step breakpoints of THREAD. */ + +void delete_single_step_breakpoints (struct thread_info *thread); + +/* Reinsert all single-step breakpoints of THREAD. */ + +void reinsert_single_step_breakpoints (struct thread_info *thread); + +/* Uninsert all single-step breakpoints of THREAD. This still leaves + the single-step breakpoints in the table. */ + +void uninsert_single_step_breakpoints (struct thread_info *thread); + +/* Reinsert breakpoints at WHERE (and change their status to + inserted). */ + +void reinsert_breakpoints_at (CORE_ADDR where); + +/* The THREAD has single-step breakpoints or not. */ + +int has_single_step_breakpoints (struct thread_info *thread); + +/* Uninsert breakpoints at WHERE (and change their status to + uninserted). This still leaves the breakpoints in the table. */ + +void uninsert_breakpoints_at (CORE_ADDR where); + +/* Reinsert all breakpoints of the current process (and change their + status to inserted). */ + +void reinsert_all_breakpoints (void); + +/* Uninsert all breakpoints of the current process (and change their + status to uninserted). This still leaves the breakpoints in the + table. */ + +void uninsert_all_breakpoints (void); + +/* See if any breakpoint claims ownership of STOP_PC. Call the handler for + the breakpoint, if found. */ + +void check_breakpoints (CORE_ADDR stop_pc); + +/* See if any breakpoints shadow the target memory area from MEM_ADDR + to MEM_ADDR + MEM_LEN. Update the data already read from the target + (in BUF) if necessary. */ + +void check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len); + +/* See if any breakpoints shadow the target memory area from MEM_ADDR + to MEM_ADDR + MEM_LEN. Update the data to be written to the target + (in BUF, a copy of MYADDR on entry) if necessary, as well as the + original data for any breakpoints. */ + +void check_mem_write (CORE_ADDR mem_addr, + unsigned char *buf, const unsigned char *myaddr, int mem_len); + +/* Delete all breakpoints. */ + +void delete_all_breakpoints (void); + +/* Clear the "inserted" flag in all breakpoints of PROC. */ + +void mark_breakpoints_out (struct process_info *proc); + +/* Delete all breakpoints, but do not try to un-insert them from the + inferior. */ + +void free_all_breakpoints (struct process_info *proc); + +/* Check if breakpoints still seem to be inserted in the inferior. */ + +void validate_breakpoints (void); + +/* Insert a fast tracepoint jump at WHERE, using instruction INSN, of + LENGTH bytes. */ + +struct fast_tracepoint_jump *set_fast_tracepoint_jump (CORE_ADDR where, + unsigned char *insn, + ULONGEST length); + +/* Increment reference counter of JP. */ +void inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp); + +/* Delete fast tracepoint jump TODEL from our tables, and uninsert if + from memory. */ + +int delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel); + +/* Returns true if there's fast tracepoint jump set at WHERE. */ + +int fast_tracepoint_jump_here (CORE_ADDR); + +/* Uninsert fast tracepoint jumps at WHERE (and change their status to + uninserted). This still leaves the tracepoints in the table. */ + +void uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc); + +/* Reinsert fast tracepoint jumps at WHERE (and change their status to + inserted). */ + +void reinsert_fast_tracepoint_jumps_at (CORE_ADDR where); + +/* Insert a memory breakpoint. */ + +int insert_memory_breakpoint (struct raw_breakpoint *bp); + +/* Remove a previously inserted memory breakpoint. */ + +int remove_memory_breakpoint (struct raw_breakpoint *bp); + +/* Create a new breakpoint list in CHILD_THREAD's process that is a + copy of breakpoint list in PARENT_THREAD's process. */ + +void clone_all_breakpoints (struct thread_info *child_thread, + const struct thread_info *parent_thread); + +#endif /* GDBSERVER_MEM_BREAK_H */ diff --git a/gdbserver/notif.c b/gdbserver/notif.c new file mode 100644 index 00000000000..e18cecde53b --- /dev/null +++ b/gdbserver/notif.c @@ -0,0 +1,154 @@ +/* Notification to GDB. + Copyright (C) 1989-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +/* Async notifications to GDB. When the state of remote target is + changed or something interesting to GDB happened, async + notifications are used to tell GDB. + + Each type of notification is represented by an object + 'struct notif_server', in which there is a queue for events to GDB + represented by 'struct notif_event'. GDBserver writes (by means of + 'write' field) each event in the queue into the buffer and send the + contents in buffer to GDB. The contents in buffer is specified in + RSP. See more in the comments to field 'queue' of + 'struct notif_server'. + + Here is the workflow of sending events and managing queue: + 1. At any time, when something interesting FOO happens, a object + of 'struct notif_event' or its sub-class EVENT is created for FOO. + + 2. Enque EVENT to the 'queue' field of 'struct notif_server' for + FOO and send corresponding notification packet to GDB if EVENT is + the first one. + #1 and #2 are done by function 'notif_push'. + + 3. EVENT is not deque'ed until the ack of FOO from GDB arrives. + Before ack of FOO arrives, FOO happens again, a new object of + EVENT is created and enque EVENT silently. + Once GDB has a chance to ack to FOO, it sends an ack to GDBserver, + and GDBserver repeatedly sends events to GDB and gets ack of FOO, + until queue is empty. Then, GDBserver sends 'OK' to GDB that all + queued notification events are done. + + # 3 is done by function 'handle_notif_ack'. */ + +#include "server.h" +#include "notif.h" + +static struct notif_server *notifs[] = +{ + ¬if_stop, +}; + +/* Write another event or an OK, if there are no more left, to + OWN_BUF. */ + +void +notif_write_event (struct notif_server *notif, char *own_buf) +{ + if (!notif->queue.empty ()) + { + struct notif_event *event = notif->queue.front (); + + notif->write (event, own_buf); + } + else + write_ok (own_buf); +} + +/* Handle the ack in buffer OWN_BUF,and packet length is PACKET_LEN. + Return 1 if the ack is handled, and return 0 if the contents + in OWN_BUF is not a ack. */ + +int +handle_notif_ack (char *own_buf, int packet_len) +{ + size_t i; + struct notif_server *np; + + for (i = 0; i < ARRAY_SIZE (notifs); i++) + { + const char *ack_name = notifs[i]->ack_name; + + if (startswith (own_buf, ack_name) + && packet_len == strlen (ack_name)) + break; + } + + if (i == ARRAY_SIZE (notifs)) + return 0; + + np = notifs[i]; + + /* If we're waiting for GDB to acknowledge a pending event, + consider that done. */ + if (!np->queue.empty ()) + { + struct notif_event *head = np->queue.front (); + np->queue.pop_front (); + + if (remote_debug) + debug_printf ("%s: acking %d\n", np->ack_name, + (int) np->queue.size ()); + + delete head; + } + + notif_write_event (np, own_buf); + + return 1; +} + +/* Put EVENT to the queue of NOTIF. */ + +void +notif_event_enque (struct notif_server *notif, + struct notif_event *event) +{ + notif->queue.push_back (event); + + if (remote_debug) + debug_printf ("pending events: %s %d\n", notif->notif_name, + (int) notif->queue.size ()); + +} + +/* Push one event NEW_EVENT of notification NP into NP->queue. */ + +void +notif_push (struct notif_server *np, struct notif_event *new_event) +{ + bool is_first_event = np->queue.empty (); + + /* Something interesting. Tell GDB about it. */ + notif_event_enque (np, new_event); + + /* If this is the first stop reply in the queue, then inform GDB + about it, by sending a corresponding notification. */ + if (is_first_event) + { + char buf[PBUFSIZ]; + char *p = buf; + + xsnprintf (p, PBUFSIZ, "%s:", np->notif_name); + p += strlen (p); + + np->write (new_event, p); + putpkt_notif (buf); + } +} diff --git a/gdbserver/notif.h b/gdbserver/notif.h new file mode 100644 index 00000000000..c5d48c0f3b6 --- /dev/null +++ b/gdbserver/notif.h @@ -0,0 +1,68 @@ +/* Notification to GDB. + Copyright (C) 1989-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_NOTIF_H +#define GDBSERVER_NOTIF_H + +#include "target.h" +#include + +/* Structure holding information related to a single event. We + keep a queue of these to push to GDB. It can be extended if + the event of given notification contains more information. */ + +struct notif_event +{ + virtual ~notif_event () + { + } + + /* No payload needed. */ +}; + +/* A type notification to GDB. An object of 'struct notif_server' + represents a type of notification. */ + +typedef struct notif_server +{ + /* The name of ack packet, for example, 'vStopped'. */ + const char *ack_name; + + /* The notification packet, for example, '%Stop'. Note that '%' is + not in 'notif_name'. */ + const char *notif_name; + + /* A queue of events to GDB. A new notif_event can be enque'ed + into QUEUE at any appropriate time, and the notif_reply is + deque'ed only when the ack from GDB arrives. */ + std::list queue; + + /* Write event EVENT to OWN_BUF. */ + void (*write) (struct notif_event *event, char *own_buf); +} *notif_server_p; + +extern struct notif_server notif_stop; + +int handle_notif_ack (char *own_buf, int packet_len); +void notif_write_event (struct notif_server *notif, char *own_buf); + +void notif_push (struct notif_server *np, struct notif_event *event); +void notif_event_enque (struct notif_server *notif, + struct notif_event *event); + +#endif /* GDBSERVER_NOTIF_H */ diff --git a/gdbserver/nto-low.c b/gdbserver/nto-low.c new file mode 100644 index 00000000000..b4dea479b9c --- /dev/null +++ b/gdbserver/nto-low.c @@ -0,0 +1,1026 @@ +/* QNX Neutrino specific low level interface, for the remote server + for GDB. + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + + +#include "server.h" +#include "gdbthread.h" +#include "nto-low.h" +#include "hostio.h" +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include + + +int using_threads = 1; + +const struct target_desc *nto_tdesc; + +static void +nto_trace (const char *fmt, ...) +{ + va_list arg_list; + + if (debug_threads == 0) + return; + fprintf (stderr, "nto:"); + va_start (arg_list, fmt); + vfprintf (stderr, fmt, arg_list); + va_end (arg_list); +} + +#define TRACE nto_trace + +/* Structure holding neutrino specific information about + inferior. */ + +struct nto_inferior +{ + char nto_procfs_path[PATH_MAX]; + int ctl_fd; + pid_t pid; + int exit_signo; /* For tracking exit status. */ +}; + +static struct nto_inferior nto_inferior; + +static void +init_nto_inferior (struct nto_inferior *nto_inferior) +{ + memset (nto_inferior, 0, sizeof (struct nto_inferior)); + nto_inferior->ctl_fd = -1; + nto_inferior->pid = -1; +} + +static void +do_detach (void) +{ + if (nto_inferior.ctl_fd != -1) + { + nto_trace ("Closing fd\n"); + close (nto_inferior.ctl_fd); + init_nto_inferior (&nto_inferior); + } +} + +/* Set current thread. Return 1 on success, 0 otherwise. */ + +static int +nto_set_thread (ptid_t ptid) +{ + int res = 0; + + TRACE ("%s pid: %d tid: %ld\n", __func__, ptid.pid (), + ptid.lwp ()); + if (nto_inferior.ctl_fd != -1 + && ptid != null_ptid + && ptid != minus_one_ptid) + { + pthread_t tid = ptid.lwp (); + + if (EOK == devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid, + sizeof (tid), 0)) + res = 1; + else + TRACE ("%s: Error: failed to set current thread\n", __func__); + } + return res; +} + +/* This function will determine all alive threads. Note that we do not list + dead but unjoined threads even though they are still in the process' thread + list. + + NTO_INFERIOR must not be NULL. */ + +static void +nto_find_new_threads (struct nto_inferior *nto_inferior) +{ + pthread_t tid; + + TRACE ("%s pid:%d\n", __func__, nto_inferior->pid); + + if (nto_inferior->ctl_fd == -1) + return; + + for (tid = 1;; ++tid) + { + procfs_status status; + ptid_t ptid; + int err; + + status.tid = tid; + err = devctl (nto_inferior->ctl_fd, DCMD_PROC_TIDSTATUS, &status, + sizeof (status), 0); + + if (err != EOK || status.tid == 0) + break; + + /* All threads in between are gone. */ + while (tid != status.tid || status.state == STATE_DEAD) + { + struct thread_info *ti; + + ptid = ptid_t (nto_inferior->pid, tid, 0); + ti = find_thread_ptid (ptid); + if (ti != NULL) + { + TRACE ("Removing thread %d\n", tid); + remove_thread (ti); + } + if (tid == status.tid) + break; + ++tid; + } + + if (status.state != STATE_DEAD) + { + TRACE ("Adding thread %d\n", tid); + ptid = ptid_t (nto_inferior->pid, tid, 0); + if (!find_thread_ptid (ptid)) + add_thread (ptid, NULL); + } + } +} + +/* Given pid, open procfs path. */ + +static pid_t +do_attach (pid_t pid) +{ + procfs_status status; + struct sigevent event; + + if (nto_inferior.ctl_fd != -1) + { + close (nto_inferior.ctl_fd); + init_nto_inferior (&nto_inferior); + } + xsnprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", pid); + nto_inferior.ctl_fd = open (nto_inferior.nto_procfs_path, O_RDWR); + if (nto_inferior.ctl_fd == -1) + { + TRACE ("Failed to open %s\n", nto_inferior.nto_procfs_path); + init_nto_inferior (&nto_inferior); + return -1; + } + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) + != EOK) + { + do_detach (); + return -1; + } + nto_inferior.pid = pid; + /* Define a sigevent for process stopped notification. */ + event.sigev_notify = SIGEV_SIGNAL_THREAD; + event.sigev_signo = SIGUSR1; + event.sigev_code = 0; + event.sigev_value.sival_ptr = NULL; + event.sigev_priority = -1; + devctl (nto_inferior.ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0); + + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), + 0) == EOK + && (status.flags & _DEBUG_FLAG_STOPPED)) + { + ptid_t ptid; + struct process_info *proc; + + kill (pid, SIGCONT); + ptid = ptid_t (status.pid, status.tid, 0); + the_low_target.arch_setup (); + proc = add_process (status.pid, 1); + proc->tdesc = nto_tdesc; + TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid, + ptid.lwp ()); + nto_find_new_threads (&nto_inferior); + } + else + { + do_detach (); + return -1; + } + + return pid; +} + +/* Read or write LEN bytes from/to inferior's MEMADDR memory address + into gdbservers's MYADDR buffer. Return number of bytes actually + transfered. */ + +static int +nto_xfer_memory (off_t memaddr, unsigned char *myaddr, int len, + int dowrite) +{ + int nbytes = 0; + + if (lseek (nto_inferior.ctl_fd, memaddr, SEEK_SET) == memaddr) + { + if (dowrite) + nbytes = write (nto_inferior.ctl_fd, myaddr, len); + else + nbytes = read (nto_inferior.ctl_fd, myaddr, len); + if (nbytes < 0) + nbytes = 0; + } + if (nbytes == 0) + { + int e = errno; + TRACE ("Error in %s : errno=%d (%s)\n", __func__, e, safe_strerror (e)); + } + return nbytes; +} + +/* Insert or remove breakpoint or watchpoint at address ADDR. + TYPE can be one of Neutrino breakpoint types. SIZE must be 0 for + inserting the point, -1 for removing it. + + Return 0 on success, 1 otherwise. */ + +static int +nto_breakpoint (CORE_ADDR addr, int type, int size) +{ + procfs_break brk; + + brk.type = type; + brk.addr = addr; + brk.size = size; + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0) + != EOK) + return 1; + return 0; +} + +/* Read auxiliary vector from inferior's initial stack into gdbserver's + MYADDR buffer, up to LEN bytes. + + Return number of bytes read. */ + +static int +nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack, + unsigned char *myaddr, + unsigned int len) +{ + int data_ofs = 0; + int anint; + unsigned int len_read = 0; + + /* Skip over argc, argv and envp... Comment from ldd.c: + + The startup frame is set-up so that we have: + auxv + NULL + ... + envp2 + envp1 <----- void *frame + (argc + 2) * sizeof(char *) + NULL + ... + argv2 + argv1 + argc <------ void * frame + + On entry to ldd, frame gives the address of argc on the stack. */ + if (nto_xfer_memory (initial_stack, (unsigned char *)&anint, + sizeof (anint), 0) != sizeof (anint)) + return 0; + + /* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */ + data_ofs += (anint + 2) * sizeof (void *); /* + 2 comes from argc itself and + NULL terminating pointer in + argv. */ + + /* Now loop over env table: */ + while (nto_xfer_memory (initial_stack + data_ofs, + (unsigned char *)&anint, sizeof (anint), 0) + == sizeof (anint)) + { + data_ofs += sizeof (anint); + if (anint == 0) + break; + } + initial_stack += data_ofs; + + memset (myaddr, 0, len); + while (len_read <= len - sizeof (auxv_t)) + { + auxv_t *auxv = (auxv_t *)myaddr; + + /* Search backwards until we have read AT_PHDR (num. 3), + AT_PHENT (num 4), AT_PHNUM (num 5) */ + if (nto_xfer_memory (initial_stack, (unsigned char *)auxv, + sizeof (auxv_t), 0) == sizeof (auxv_t)) + { + if (auxv->a_type != AT_NULL) + { + auxv++; + len_read += sizeof (auxv_t); + } + if (auxv->a_type == AT_PHNUM) /* That's all we need. */ + break; + initial_stack += sizeof (auxv_t); + } + else + break; + } + TRACE ("auxv: len_read: %d\n", len_read); + return len_read; +} + +/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its + arguments. */ + +static int +nto_create_inferior (const char *program, + const std::vector &program_args) +{ + struct inheritance inherit; + pid_t pid; + sigset_t set; + std::string str_program_args = stringify_argv (program_args); + + TRACE ("%s %s\n", __func__, program); + /* Clear any pending SIGUSR1's but keep the behavior the same. */ + signal (SIGUSR1, signal (SIGUSR1, SIG_IGN)); + + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + sigprocmask (SIG_UNBLOCK, &set, NULL); + + memset (&inherit, 0, sizeof (inherit)); + inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD; + inherit.pgroup = SPAWN_NEWPGROUP; + pid = spawnp (program, 0, NULL, &inherit, + (char *) str_program_args.c_str (), 0); + sigprocmask (SIG_BLOCK, &set, NULL); + + if (pid == -1) + return -1; + + if (do_attach (pid) != pid) + return -1; + + return pid; +} + +/* Attach to process PID. */ + +static int +nto_attach (unsigned long pid) +{ + TRACE ("%s %ld\n", __func__, pid); + if (do_attach (pid) != pid) + error ("Unable to attach to %ld\n", pid); + return 0; +} + +/* Send signal to process PID. */ + +static int +nto_kill (process_info *proc) +{ + int pid = proc->pid; + + TRACE ("%s %d\n", __func__, pid); + kill (pid, SIGKILL); + do_detach (); + return 0; +} + +/* Detach from process PID. */ + +static int +nto_detach (process_info *proc) +{ + TRACE ("%s %d\n", __func__, proc->pid); + do_detach (); + return 0; +} + +static void +nto_mourn (struct process_info *process) +{ + remove_process (process); +} + +/* Check if the given thread is alive. + + Return 1 if alive, 0 otherwise. */ + +static int +nto_thread_alive (ptid_t ptid) +{ + int res; + + TRACE ("%s pid:%d tid:%d\n", __func__, ptid.pid (), + ptid.lwp ()); + if (SignalKill (0, ptid.pid (), ptid.lwp (), + 0, 0, 0) == -1) + res = 0; + else + res = 1; + TRACE ("%s: %s\n", __func__, res ? "yes" : "no"); + return res; +} + +/* Resume inferior's execution. */ + +static void +nto_resume (struct thread_resume *resume_info, size_t n) +{ + /* We can only work in all-stop mode. */ + procfs_status status; + procfs_run run; + int err; + + TRACE ("%s\n", __func__); + /* Workaround for aliasing rules violation. */ + sigset_t *run_fault = (sigset_t *) (void *) &run.fault; + + nto_set_thread (resume_info->thread); + + run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE; + if (resume_info->kind == resume_step) + run.flags |= _DEBUG_RUN_STEP; + run.flags |= _DEBUG_RUN_ARM; + + sigemptyset (run_fault); + sigaddset (run_fault, FLTBPT); + sigaddset (run_fault, FLTTRACE); + sigaddset (run_fault, FLTILL); + sigaddset (run_fault, FLTPRIV); + sigaddset (run_fault, FLTBOUNDS); + sigaddset (run_fault, FLTIOVF); + sigaddset (run_fault, FLTIZDIV); + sigaddset (run_fault, FLTFPE); + sigaddset (run_fault, FLTPAGE); + sigaddset (run_fault, FLTSTACK); + sigaddset (run_fault, FLTACCESS); + + sigemptyset (&run.trace); + if (resume_info->sig) + { + int signal_to_pass; + + devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), + 0); + signal_to_pass = resume_info->sig; + if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED)) + { + if (signal_to_pass != status.info.si_signo) + { + kill (status.pid, signal_to_pass); + run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG; + } + else /* Let it kill the program without telling us. */ + sigdelset (&run.trace, signal_to_pass); + } + } + else + run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT; + + sigfillset (&run.trace); + + regcache_invalidate (); + + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0); + if (err != EOK) + TRACE ("Error: %d \"%s\"\n", err, safe_strerror (err)); +} + +/* Wait for inferior's event. + + Return ptid of thread that caused the event. */ + +static ptid_t +nto_wait (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) +{ + sigset_t set; + siginfo_t info; + procfs_status status; + const int trace_mask = (_DEBUG_FLAG_TRACE_EXEC | _DEBUG_FLAG_TRACE_RD + | _DEBUG_FLAG_TRACE_WR | _DEBUG_FLAG_TRACE_MODIFY); + + TRACE ("%s\n", __func__); + + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + + devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); + while (!(status.flags & _DEBUG_FLAG_ISTOP)) + { + sigwaitinfo (&set, &info); + devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), + 0); + } + nto_find_new_threads (&nto_inferior); + + if (status.flags & _DEBUG_FLAG_SSTEP) + { + TRACE ("SSTEP\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = GDB_SIGNAL_TRAP; + } + /* Was it a breakpoint? */ + else if (status.flags & trace_mask) + { + TRACE ("STOPPED\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = GDB_SIGNAL_TRAP; + } + else if (status.flags & _DEBUG_FLAG_ISTOP) + { + TRACE ("ISTOP\n"); + switch (status.why) + { + case _DEBUG_WHY_SIGNALLED: + TRACE (" SIGNALLED\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = + gdb_signal_from_host (status.info.si_signo); + nto_inferior.exit_signo = ourstatus->value.sig; + break; + case _DEBUG_WHY_FAULTED: + TRACE (" FAULTED\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + if (status.info.si_signo == SIGTRAP) + { + ourstatus->value.sig = 0; + nto_inferior.exit_signo = 0; + } + else + { + ourstatus->value.sig = + gdb_signal_from_host (status.info.si_signo); + nto_inferior.exit_signo = ourstatus->value.sig; + } + break; + + case _DEBUG_WHY_TERMINATED: + { + int waitval = 0; + + TRACE (" TERMINATED\n"); + waitpid (ptid.pid (), &waitval, WNOHANG); + if (nto_inferior.exit_signo) + { + /* Abnormal death. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = nto_inferior.exit_signo; + } + else + { + /* Normal death. */ + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (waitval); + } + nto_inferior.exit_signo = 0; + break; + } + + case _DEBUG_WHY_REQUESTED: + TRACE ("REQUESTED\n"); + /* We are assuming a requested stop is due to a SIGINT. */ + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = GDB_SIGNAL_INT; + nto_inferior.exit_signo = 0; + break; + } + } + + return ptid_t (status.pid, status.tid, 0); +} + +/* Fetch inferior's registers for currently selected thread (CURRENT_INFERIOR). + If REGNO is -1, fetch all registers, or REGNO register only otherwise. */ + +static void +nto_fetch_registers (struct regcache *regcache, int regno) +{ + int regsize; + procfs_greg greg; + + TRACE ("%s (regno=%d)\n", __func__, regno); + if (regno >= the_low_target.num_regs) + return; + + if (current_thread == NULL) + { + TRACE ("current_thread is NULL\n"); + return; + } + ptid_t ptid = ptid_of (current_thread); + if (!nto_set_thread (ptid)) + return; + + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg), + ®size) == EOK) + { + if (regno == -1) /* All registers. */ + { + for (regno = 0; regno != the_low_target.num_regs; ++regno) + { + const unsigned int registeroffset + = the_low_target.register_offset (regno); + supply_register (regcache, regno, + ((char *)&greg) + registeroffset); + } + } + else + { + const unsigned int registeroffset + = the_low_target.register_offset (regno); + if (registeroffset == -1) + return; + supply_register (regcache, regno, ((char *)&greg) + registeroffset); + } + } + else + TRACE ("ERROR reading registers from inferior.\n"); +} + +/* Store registers for currently selected thread (CURRENT_INFERIOR). + We always store all registers, regardless of REGNO. */ + +static void +nto_store_registers (struct regcache *regcache, int regno) +{ + procfs_greg greg; + int err; + + TRACE ("%s (regno:%d)\n", __func__, regno); + + if (current_thread == NULL) + { + TRACE ("current_thread is NULL\n"); + return; + } + ptid_t ptid = ptid_of (current_thread); + if (!nto_set_thread (ptid)) + return; + + memset (&greg, 0, sizeof (greg)); + for (regno = 0; regno != the_low_target.num_regs; ++regno) + { + const unsigned int regoffset + = the_low_target.register_offset (regno); + collect_register (regcache, regno, ((char *)&greg) + regoffset); + } + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg), + 0); + if (err != EOK) + TRACE ("Error: setting registers.\n"); +} + +/* Read LEN bytes from inferior's memory address MEMADDR into + gdbserver's MYADDR buffer. + + Return 0 on success -1 otherwise. */ + +static int +nto_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + TRACE ("%s memaddr:0x%08lx, len:%d\n", __func__, memaddr, len); + + if (nto_xfer_memory (memaddr, myaddr, len, 0) != len) + { + TRACE ("Failed to read memory\n"); + return -1; + } + + return 0; +} + +/* Write LEN bytes from gdbserver's buffer MYADDR into inferior's + memory at address MEMADDR. + + Return 0 on success -1 otherwise. */ + +static int +nto_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +{ + int len_written; + + TRACE ("%s memaddr: 0x%08llx len: %d\n", __func__, memaddr, len); + if ((len_written = nto_xfer_memory (memaddr, (unsigned char *)myaddr, len, + 1)) + != len) + { + TRACE ("Wanted to write: %d but written: %d\n", len, len_written); + return -1; + } + + return 0; +} + +/* Stop inferior. We always stop all threads. */ + +static void +nto_request_interrupt (void) +{ + TRACE ("%s\n", __func__); + nto_set_thread (ptid_t (nto_inferior.pid, 1, 0)); + if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0)) + TRACE ("Error stopping inferior.\n"); +} + +/* Read auxiliary vector from inferior's memory into gdbserver's buffer + MYADDR. We always read whole auxv. + + Return number of bytes stored in MYADDR buffer, 0 if OFFSET > 0 + or -1 on error. */ + +static int +nto_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len) +{ + int err; + CORE_ADDR initial_stack; + procfs_info procinfo; + + TRACE ("%s\n", __func__); + if (offset > 0) + return 0; + + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_INFO, &procinfo, + sizeof procinfo, 0); + if (err != EOK) + return -1; + + initial_stack = procinfo.initial_stack; + + return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len); +} + +static int +nto_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_SW_BP: + case Z_PACKET_HW_BP: + case Z_PACKET_WRITE_WP: + case Z_PACKET_READ_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + return 0; + } +} + +/* Insert {break/watch}point at address ADDR. SIZE is not used. */ + +static int +nto_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + int wtype = _DEBUG_BREAK_HW; /* Always request HW. */ + + TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, size); + switch (type) + { + case raw_bkpt_type_sw: + wtype = _DEBUG_BREAK_EXEC; + break; + case raw_bkpt_type_hw: + wtype |= _DEBUG_BREAK_EXEC; + break; + case raw_bkpt_type_write_wp: + wtype |= _DEBUG_BREAK_RW; + break; + case raw_bkpt_type_read_wp: + wtype |= _DEBUG_BREAK_RD; + break; + case raw_bkpt_type_access_wp: + wtype |= _DEBUG_BREAK_RW; + break; + default: + return 1; /* Not supported. */ + } + return nto_breakpoint (addr, wtype, 0); +} + +/* Remove {break/watch}point at address ADDR. SIZE is not used. */ + +static int +nto_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + int wtype = _DEBUG_BREAK_HW; /* Always request HW. */ + + TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, size); + switch (type) + { + case raw_bkpt_type_sw: + wtype = _DEBUG_BREAK_EXEC; + break; + case raw_bkpt_type_hw: + wtype |= _DEBUG_BREAK_EXEC; + break; + case raw_bkpt_type_write_wp: + wtype |= _DEBUG_BREAK_RW; + break; + case raw_bkpt_type_read_wp: + wtype |= _DEBUG_BREAK_RD; + break; + case raw_bkpt_type_access_wp: + wtype |= _DEBUG_BREAK_RW; + break; + default: + return 1; /* Not supported. */ + } + return nto_breakpoint (addr, wtype, -1); +} + +/* Check if the reason of stop for current thread (CURRENT_INFERIOR) is + a watchpoint. + + Return 1 if stopped by watchpoint, 0 otherwise. */ + +static int +nto_stopped_by_watchpoint (void) +{ + int ret = 0; + + TRACE ("%s\n", __func__); + if (nto_inferior.ctl_fd != -1 && current_thread != NULL) + { + ptid_t ptid = ptid_of (current_thread); + if (nto_set_thread (ptid)) + { + const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR + | _DEBUG_FLAG_TRACE_MODIFY; + procfs_status status; + int err; + + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, + sizeof (status), 0); + if (err == EOK && (status.flags & watchmask)) + ret = 1; + } + } + TRACE ("%s: %s\n", __func__, ret ? "yes" : "no"); + return ret; +} + +/* Get instruction pointer for CURRENT_INFERIOR thread. + + Return inferior's instruction pointer value, or 0 on error. */ + +static CORE_ADDR +nto_stopped_data_address (void) +{ + CORE_ADDR ret = (CORE_ADDR)0; + + TRACE ("%s\n", __func__); + if (nto_inferior.ctl_fd != -1 && current_thread != NULL) + { + ptid_t ptid = ptid_of (current_thread); + + if (nto_set_thread (ptid)) + { + procfs_status status; + + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, + sizeof (status), 0) == EOK) + ret = status.ip; + } + } + TRACE ("%s: 0x%08lx\n", __func__, ret); + return ret; +} + +/* We do not currently support non-stop. */ + +static int +nto_supports_non_stop (void) +{ + TRACE ("%s\n", __func__); + return 0; +} + +/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +nto_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = the_low_target.breakpoint_len; + return the_low_target.breakpoint; +} + + +static process_stratum_target nto_target_ops = { + nto_create_inferior, + NULL, /* post_create_inferior */ + nto_attach, + nto_kill, + nto_detach, + nto_mourn, + NULL, /* nto_join */ + nto_thread_alive, + nto_resume, + nto_wait, + nto_fetch_registers, + nto_store_registers, + NULL, /* prepare_to_access_memory */ + NULL, /* done_accessing_memory */ + nto_read_memory, + nto_write_memory, + NULL, /* nto_look_up_symbols */ + nto_request_interrupt, + nto_read_auxv, + nto_supports_z_point_type, + nto_insert_point, + nto_remove_point, + NULL, /* stopped_by_sw_breakpoint */ + NULL, /* supports_stopped_by_sw_breakpoint */ + NULL, /* stopped_by_hw_breakpoint */ + NULL, /* supports_stopped_by_hw_breakpoint */ + target_can_do_hardware_single_step, + nto_stopped_by_watchpoint, + nto_stopped_data_address, + NULL, /* nto_read_offsets */ + NULL, /* thread_db_set_tls_address */ + hostio_last_error_from_errno, + NULL, /* nto_qxfer_osdata */ + NULL, /* xfer_siginfo */ + nto_supports_non_stop, + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* supports_fork_events */ + NULL, /* supports_vfork_events */ + NULL, /* supports_exec_events */ + NULL, /* handle_new_gdb_connection */ + NULL, /* handle_monitor_command */ + NULL, /* core_of_thread */ + NULL, /* read_loadmap */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* read_pc */ + NULL, /* write_pc */ + NULL, /* thread_stopped */ + NULL, /* get_tib_address */ + NULL, /* pause_all */ + NULL, /* unpause_all */ + NULL, /* stabilize_threads */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* supports_disable_randomization */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* qxfer_libraries_svr4 */ + NULL, /* support_agent */ + NULL, /* enable_btrace */ + NULL, /* disable_btrace */ + NULL, /* read_btrace */ + NULL, /* read_btrace_conf */ + NULL, /* supports_range_stepping */ + NULL, /* pid_to_exec_file */ + NULL, /* multifs_open */ + NULL, /* multifs_unlink */ + NULL, /* multifs_readlink */ + NULL, /* breakpoint_kind_from_pc */ + nto_sw_breakpoint_from_kind, +}; + + +/* Global function called by server.c. Initializes QNX Neutrino + gdbserver. */ + +void +initialize_low (void) +{ + sigset_t set; + + TRACE ("%s\n", __func__); + set_target_ops (&nto_target_ops); + + /* We use SIGUSR1 to gain control after we block waiting for a process. + We use sigwaitevent to wait. */ + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + sigprocmask (SIG_BLOCK, &set, NULL); +} + diff --git a/gdbserver/nto-low.h b/gdbserver/nto-low.h new file mode 100644 index 00000000000..393b8a98695 --- /dev/null +++ b/gdbserver/nto-low.h @@ -0,0 +1,49 @@ +/* Internal interfaces for the QNX Neutrino specific target code for gdbserver. + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_NTO_LOW_H +#define GDBSERVER_NTO_LOW_H + +struct target_desc; + +enum regset_type +{ + NTO_REG_GENERAL, + NTO_REG_FLOAT, + NTO_REG_SYSTEM, + NTO_REG_ALT, + NTO_REG_END +}; + +struct nto_target_ops +{ + /* Architecture specific setup. */ + void (*arch_setup) (void); + int num_regs; + int (*register_offset) (int gdbregno); + const unsigned char *breakpoint; + int breakpoint_len; +}; + +extern struct nto_target_ops the_low_target; + +/* The inferior's target description. This is a global because the + LynxOS ports support neither bi-arch nor multi-process. */ +extern const struct target_desc *nto_tdesc; + +#endif /* GDBSERVER_NTO_LOW_H */ diff --git a/gdbserver/nto-x86-low.c b/gdbserver/nto-x86-low.c new file mode 100644 index 00000000000..efee9573622 --- /dev/null +++ b/gdbserver/nto-x86-low.c @@ -0,0 +1,109 @@ +/* QNX Neutrino specific low level interface, for the remote server + for GDB. + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "nto-low.h" +#include "regdef.h" +#include "regcache.h" + +#include +#include "gdbsupport/x86-xstate.h" +#include "arch/i386.h" +#include "x86-tdesc.h" + +const unsigned char x86_breakpoint[] = { 0xCC }; +#define x86_breakpoint_len 1 + +/* Returns offset in appropriate Neutrino's context structure. + Defined in x86/context.h. + GDBREGNO is index into regs_i386 array. It is autogenerated and + hopefully doesn't change. */ +static int +nto_x86_register_offset (int gdbregno) +{ + if (gdbregno >= 0 && gdbregno < 16) + { + X86_CPU_REGISTERS *dummy = (void*)0; + /* GPRs */ + switch (gdbregno) + { + case 0: + return (int)&(dummy->eax); + case 1: + return (int)&(dummy->ecx); + case 2: + return (int)&(dummy->edx); + case 3: + return (int)&(dummy->ebx); + case 4: + return (int)&(dummy->esp); + case 5: + return (int)&(dummy->ebp); + case 6: + return (int)&(dummy->esi); + case 7: + return (int)&(dummy->edi); + case 8: + return (int)&(dummy->eip); + case 9: + return (int)&(dummy->efl); + case 10: + return (int)&(dummy->cs); + case 11: + return (int)&(dummy->ss); +#ifdef __SEGMENTS__ + case 12: + return (int)&(dummy->ds); + case 13: + return (int)&(dummy->es); + case 14: + return (int)&(dummy->fs); + case 15: + return (int)&(dummy->gs); +#endif + default: + return -1; + } + } + return -1; +} + +static void +nto_x86_arch_setup (void) +{ + the_low_target.num_regs = 16; + struct target_desc *tdesc + = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); + + init_target_desc (tdesc, i386_expedite_regs); + + nto_tdesc = tdesc; +} + +struct nto_target_ops the_low_target = +{ + nto_x86_arch_setup, + 0, /* num_regs */ + nto_x86_register_offset, + x86_breakpoint, + x86_breakpoint_len +}; + + + diff --git a/gdbserver/proc-service.c b/gdbserver/proc-service.c new file mode 100644 index 00000000000..9c8885ea912 --- /dev/null +++ b/gdbserver/proc-service.c @@ -0,0 +1,165 @@ +/* libthread_db helper functions for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#include "server.h" + +/* This file is currently tied to GNU/Linux. It should scale well to + another libthread_db implementation, with the appropriate gdbserver + hooks, but for now this means we can use GNU/Linux's target data. */ + +#include "linux-low.h" + +#include "gdb_proc_service.h" + +typedef struct ps_prochandle *gdb_ps_prochandle_t; +typedef void *gdb_ps_read_buf_t; +typedef const void *gdb_ps_write_buf_t; +typedef size_t gdb_ps_size_t; + +#ifdef HAVE_LINUX_REGSETS +#define HAVE_REGSETS +#endif + +#ifdef HAVE_REGSETS +static struct regset_info * +gregset_info (void) +{ + int i = 0; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct regsets_info *regsets_info = regs_info->regsets_info; + + while (regsets_info->regsets[i].size != -1) + { + if (regsets_info->regsets[i].type == GENERAL_REGS) + break; + i++; + } + + return ®sets_info->regsets[i]; +} +#endif + +/* Search for the symbol named NAME within the object named OBJ within + the target process PH. If the symbol is found the address of the + symbol is stored in SYM_ADDR. */ + +ps_err_e +ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj, + const char *name, psaddr_t *sym_addr) +{ + CORE_ADDR addr; + + if (thread_db_look_up_one_symbol (name, &addr) == 0) + return PS_NOSYM; + + *sym_addr = (psaddr_t) (unsigned long) addr; + return PS_OK; +} + +/* Read SIZE bytes from the target process PH at address ADDR and copy + them into BUF. */ + +ps_err_e +ps_pdread (gdb_ps_prochandle_t ph, psaddr_t addr, + gdb_ps_read_buf_t buf, gdb_ps_size_t size) +{ + if (read_inferior_memory ((uintptr_t) addr, (gdb_byte *) buf, size) != 0) + return PS_ERR; + return PS_OK; +} + +/* Write SIZE bytes from BUF into the target process PH at address ADDR. */ + +ps_err_e +ps_pdwrite (gdb_ps_prochandle_t ph, psaddr_t addr, + gdb_ps_write_buf_t buf, gdb_ps_size_t size) +{ + if (target_write_memory ((uintptr_t) addr, (const gdb_byte *) buf, size) + != 0) + return PS_ERR; + return PS_OK; +} + +/* Get the general registers of LWP LWPID within the target process PH + and store them in GREGSET. */ + +ps_err_e +ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset) +{ +#ifdef HAVE_REGSETS + struct lwp_info *lwp; + struct thread_info *reg_thread, *saved_thread; + struct regcache *regcache; + + lwp = find_lwp_pid (ptid_t (lwpid)); + if (lwp == NULL) + return PS_ERR; + + reg_thread = get_lwp_thread (lwp); + saved_thread = current_thread; + current_thread = reg_thread; + regcache = get_thread_regcache (current_thread, 1); + gregset_info ()->fill_function (regcache, gregset); + + current_thread = saved_thread; + return PS_OK; +#else + return PS_ERR; +#endif +} + +/* Set the general registers of LWP LWPID within the target process PH + from GREGSET. */ + +ps_err_e +ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset) +{ + /* Unneeded. */ + return PS_ERR; +} + +/* Get the floating-point registers of LWP LWPID within the target + process PH and store them in FPREGSET. */ + +ps_err_e +ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prfpregset_t *fpregset) +{ + /* Unneeded. */ + return PS_ERR; +} + +/* Set the floating-point registers of LWP LWPID within the target + process PH from FPREGSET. */ + +ps_err_e +ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prfpregset_t *fpregset) +{ + /* Unneeded. */ + return PS_ERR; +} + +/* Return overall process id of the target PH. Special for GNU/Linux + -- not used on Solaris. */ + +pid_t +ps_getpid (gdb_ps_prochandle_t ph) +{ + return pid_of (current_thread); +} diff --git a/gdbserver/proc-service.list b/gdbserver/proc-service.list new file mode 100644 index 00000000000..61330453885 --- /dev/null +++ b/gdbserver/proc-service.list @@ -0,0 +1,30 @@ +/* -Wl,--dynamic-list symbols exported for libthread_db. + + Copyright (C) 2010-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +{ + ps_get_thread_area; + ps_getpid; + ps_lgetfpregs; + ps_lgetregs; + ps_lsetfpregs; + ps_lsetregs; + ps_pdread; + ps_pdwrite; + ps_pglobal_lookup; +}; diff --git a/gdbserver/regcache.c b/gdbserver/regcache.c new file mode 100644 index 00000000000..f63463344af --- /dev/null +++ b/gdbserver/regcache.c @@ -0,0 +1,528 @@ +/* Register support routines for the remote server for GDB. + Copyright (C) 2001-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "regdef.h" +#include "gdbthread.h" +#include "tdesc.h" +#include "gdbsupport/rsp-low.h" +#ifndef IN_PROCESS_AGENT + +struct regcache * +get_thread_regcache (struct thread_info *thread, int fetch) +{ + struct regcache *regcache; + + regcache = thread_regcache_data (thread); + + /* Threads' regcaches are created lazily, because biarch targets add + the main thread/lwp before seeing it stop for the first time, and + it is only after the target sees the thread stop for the first + time that the target has a chance of determining the process's + architecture. IOW, when we first add the process's main thread + we don't know which architecture/tdesc its regcache should + have. */ + if (regcache == NULL) + { + struct process_info *proc = get_thread_process (thread); + + gdb_assert (proc->tdesc != NULL); + + regcache = new_register_cache (proc->tdesc); + set_thread_regcache_data (thread, regcache); + } + + if (fetch && regcache->registers_valid == 0) + { + struct thread_info *saved_thread = current_thread; + + current_thread = thread; + /* Invalidate all registers, to prevent stale left-overs. */ + memset (regcache->register_status, REG_UNAVAILABLE, + regcache->tdesc->reg_defs.size ()); + fetch_inferior_registers (regcache, -1); + current_thread = saved_thread; + regcache->registers_valid = 1; + } + + return regcache; +} + +/* See gdbsupport/common-regcache.h. */ + +struct regcache * +get_thread_regcache_for_ptid (ptid_t ptid) +{ + return get_thread_regcache (find_thread_ptid (ptid), 1); +} + +void +regcache_invalidate_thread (struct thread_info *thread) +{ + struct regcache *regcache; + + regcache = thread_regcache_data (thread); + + if (regcache == NULL) + return; + + if (regcache->registers_valid) + { + struct thread_info *saved_thread = current_thread; + + current_thread = thread; + store_inferior_registers (regcache, -1); + current_thread = saved_thread; + } + + regcache->registers_valid = 0; +} + +/* See regcache.h. */ + +void +regcache_invalidate_pid (int pid) +{ + /* Only invalidate the regcaches of threads of this process. */ + for_each_thread (pid, regcache_invalidate_thread); +} + +/* See regcache.h. */ + +void +regcache_invalidate (void) +{ + /* Only update the threads of the current process. */ + int pid = current_thread->id.pid (); + + regcache_invalidate_pid (pid); +} + +#endif + +struct regcache * +init_register_cache (struct regcache *regcache, + const struct target_desc *tdesc, + unsigned char *regbuf) +{ + if (regbuf == NULL) + { +#ifndef IN_PROCESS_AGENT + /* Make sure to zero-initialize the register cache when it is + created, in case there are registers the target never + fetches. This way they'll read as zero instead of + garbage. */ + regcache->tdesc = tdesc; + regcache->registers + = (unsigned char *) xcalloc (1, tdesc->registers_size); + regcache->registers_owned = 1; + regcache->register_status + = (unsigned char *) xmalloc (tdesc->reg_defs.size ()); + memset ((void *) regcache->register_status, REG_UNAVAILABLE, + tdesc->reg_defs.size ()); +#else + gdb_assert_not_reached ("can't allocate memory from the heap"); +#endif + } + else + { + regcache->tdesc = tdesc; + regcache->registers = regbuf; + regcache->registers_owned = 0; +#ifndef IN_PROCESS_AGENT + regcache->register_status = NULL; +#endif + } + + regcache->registers_valid = 0; + + return regcache; +} + +#ifndef IN_PROCESS_AGENT + +struct regcache * +new_register_cache (const struct target_desc *tdesc) +{ + struct regcache *regcache = new struct regcache; + + gdb_assert (tdesc->registers_size != 0); + + return init_register_cache (regcache, tdesc, NULL); +} + +void +free_register_cache (struct regcache *regcache) +{ + if (regcache) + { + if (regcache->registers_owned) + free (regcache->registers); + free (regcache->register_status); + delete regcache; + } +} + +#endif + +void +regcache_cpy (struct regcache *dst, struct regcache *src) +{ + gdb_assert (src != NULL && dst != NULL); + gdb_assert (src->tdesc == dst->tdesc); + gdb_assert (src != dst); + + memcpy (dst->registers, src->registers, src->tdesc->registers_size); +#ifndef IN_PROCESS_AGENT + if (dst->register_status != NULL && src->register_status != NULL) + memcpy (dst->register_status, src->register_status, + src->tdesc->reg_defs.size ()); +#endif + dst->registers_valid = src->registers_valid; +} + +/* Return a reference to the description of register N. */ + +static const struct reg & +find_register_by_number (const struct target_desc *tdesc, int n) +{ + return tdesc->reg_defs[n]; +} + +#ifndef IN_PROCESS_AGENT + +void +registers_to_string (struct regcache *regcache, char *buf) +{ + unsigned char *registers = regcache->registers; + const struct target_desc *tdesc = regcache->tdesc; + + for (int i = 0; i < tdesc->reg_defs.size (); ++i) + { + if (regcache->register_status[i] == REG_VALID) + { + bin2hex (registers, buf, register_size (tdesc, i)); + buf += register_size (tdesc, i) * 2; + } + else + { + memset (buf, 'x', register_size (tdesc, i) * 2); + buf += register_size (tdesc, i) * 2; + } + registers += register_size (tdesc, i); + } + *buf = '\0'; +} + +void +registers_from_string (struct regcache *regcache, char *buf) +{ + int len = strlen (buf); + unsigned char *registers = regcache->registers; + const struct target_desc *tdesc = regcache->tdesc; + + if (len != tdesc->registers_size * 2) + { + warning ("Wrong sized register packet (expected %d bytes, got %d)", + 2 * tdesc->registers_size, len); + if (len > tdesc->registers_size * 2) + len = tdesc->registers_size * 2; + } + hex2bin (buf, registers, len / 2); +} + +int +find_regno (const struct target_desc *tdesc, const char *name) +{ + for (int i = 0; i < tdesc->reg_defs.size (); ++i) + { + if (strcmp (name, find_register_by_number (tdesc, i).name) == 0) + return i; + } + internal_error (__FILE__, __LINE__, "Unknown register %s requested", + name); +} + +static void +free_register_cache_thread (struct thread_info *thread) +{ + struct regcache *regcache = thread_regcache_data (thread); + + if (regcache != NULL) + { + regcache_invalidate_thread (thread); + free_register_cache (regcache); + set_thread_regcache_data (thread, NULL); + } +} + +void +regcache_release (void) +{ + /* Flush and release all pre-existing register caches. */ + for_each_thread (free_register_cache_thread); +} +#endif + +int +register_cache_size (const struct target_desc *tdesc) +{ + return tdesc->registers_size; +} + +int +register_size (const struct target_desc *tdesc, int n) +{ + return find_register_by_number (tdesc, n).size / 8; +} + +/* See gdbsupport/common-regcache.h. */ + +int +regcache_register_size (const struct regcache *regcache, int n) +{ + return register_size (regcache->tdesc, n); +} + +static unsigned char * +register_data (const struct regcache *regcache, int n, int fetch) +{ + return (regcache->registers + + find_register_by_number (regcache->tdesc, n).offset / 8); +} + +void +supply_register (struct regcache *regcache, int n, const void *buf) +{ + return regcache->raw_supply (n, buf); +} + +/* See gdbsupport/common-regcache.h. */ + +void +regcache::raw_supply (int n, const void *buf) +{ + if (buf) + { + memcpy (register_data (this, n, 0), buf, register_size (tdesc, n)); +#ifndef IN_PROCESS_AGENT + if (register_status != NULL) + register_status[n] = REG_VALID; +#endif + } + else + { + memset (register_data (this, n, 0), 0, register_size (tdesc, n)); +#ifndef IN_PROCESS_AGENT + if (register_status != NULL) + register_status[n] = REG_UNAVAILABLE; +#endif + } +} + +/* Supply register N with value zero to REGCACHE. */ + +void +supply_register_zeroed (struct regcache *regcache, int n) +{ + memset (register_data (regcache, n, 0), 0, + register_size (regcache->tdesc, n)); +#ifndef IN_PROCESS_AGENT + if (regcache->register_status != NULL) + regcache->register_status[n] = REG_VALID; +#endif +} + +#ifndef IN_PROCESS_AGENT + +/* Supply register called NAME with value zero to REGCACHE. */ + +void +supply_register_by_name_zeroed (struct regcache *regcache, + const char *name) +{ + supply_register_zeroed (regcache, find_regno (regcache->tdesc, name)); +} + +#endif + +/* Supply the whole register set whose contents are stored in BUF, to + REGCACHE. If BUF is NULL, all the registers' values are recorded + as unavailable. */ + +void +supply_regblock (struct regcache *regcache, const void *buf) +{ + if (buf) + { + const struct target_desc *tdesc = regcache->tdesc; + + memcpy (regcache->registers, buf, tdesc->registers_size); +#ifndef IN_PROCESS_AGENT + { + int i; + + for (i = 0; i < tdesc->reg_defs.size (); i++) + regcache->register_status[i] = REG_VALID; + } +#endif + } + else + { + const struct target_desc *tdesc = regcache->tdesc; + + memset (regcache->registers, 0, tdesc->registers_size); +#ifndef IN_PROCESS_AGENT + { + int i; + + for (i = 0; i < tdesc->reg_defs.size (); i++) + regcache->register_status[i] = REG_UNAVAILABLE; + } +#endif + } +} + +#ifndef IN_PROCESS_AGENT + +void +supply_register_by_name (struct regcache *regcache, + const char *name, const void *buf) +{ + supply_register (regcache, find_regno (regcache->tdesc, name), buf); +} + +#endif + +void +collect_register (struct regcache *regcache, int n, void *buf) +{ + regcache->raw_collect (n, buf); +} + +/* See gdbsupport/common-regcache.h. */ + +void +regcache::raw_collect (int n, void *buf) const +{ + memcpy (buf, register_data (this, n, 1), register_size (tdesc, n)); +} + +enum register_status +regcache_raw_read_unsigned (struct regcache *regcache, int regnum, + ULONGEST *val) +{ + int size; + + gdb_assert (regcache != NULL); + gdb_assert (regnum >= 0 + && regnum < regcache->tdesc->reg_defs.size ()); + + size = register_size (regcache->tdesc, regnum); + + if (size > (int) sizeof (ULONGEST)) + error (_("That operation is not available on integers of more than" + "%d bytes."), + (int) sizeof (ULONGEST)); + + *val = 0; + collect_register (regcache, regnum, val); + + return REG_VALID; +} + +#ifndef IN_PROCESS_AGENT + +/* See regcache.h. */ + +ULONGEST +regcache_raw_get_unsigned_by_name (struct regcache *regcache, + const char *name) +{ + return regcache_raw_get_unsigned (regcache, + find_regno (regcache->tdesc, name)); +} + +void +collect_register_as_string (struct regcache *regcache, int n, char *buf) +{ + bin2hex (register_data (regcache, n, 1), buf, + register_size (regcache->tdesc, n)); +} + +void +collect_register_by_name (struct regcache *regcache, + const char *name, void *buf) +{ + collect_register (regcache, find_regno (regcache->tdesc, name), buf); +} + +/* Special handling for register PC. */ + +CORE_ADDR +regcache_read_pc (struct regcache *regcache) +{ + CORE_ADDR pc_val; + + if (the_target->read_pc) + pc_val = the_target->read_pc (regcache); + else + internal_error (__FILE__, __LINE__, + "regcache_read_pc: Unable to find PC"); + + return pc_val; +} + +void +regcache_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + if (the_target->write_pc) + the_target->write_pc (regcache, pc); + else + internal_error (__FILE__, __LINE__, + "regcache_write_pc: Unable to update PC"); +} + +#endif + +/* See gdbsupport/common-regcache.h. */ + +enum register_status +regcache::get_register_status (int regnum) const +{ +#ifndef IN_PROCESS_AGENT + gdb_assert (regnum >= 0 && regnum < tdesc->reg_defs.size ()); + return (enum register_status) (register_status[regnum]); +#else + return REG_VALID; +#endif +} + +/* See gdbsupport/common-regcache.h. */ + +bool +regcache::raw_compare (int regnum, const void *buf, int offset) const +{ + gdb_assert (buf != NULL); + + const unsigned char *regbuf = register_data (this, regnum, 1); + int size = register_size (tdesc, regnum); + gdb_assert (size >= offset); + + return (memcmp (buf, regbuf + offset, size - offset) == 0); +} diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h new file mode 100644 index 00000000000..8725707c685 --- /dev/null +++ b/gdbserver/regcache.h @@ -0,0 +1,141 @@ +/* Register support routines for the remote server for GDB. + Copyright (C) 2001-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_REGCACHE_H +#define GDBSERVER_REGCACHE_H + +#include "gdbsupport/common-regcache.h" + +struct thread_info; +struct target_desc; + +/* The data for the register cache. Note that we have one per + inferior; this is primarily for simplicity, as the performance + benefit is minimal. */ + +struct regcache : public reg_buffer_common +{ + /* The regcache's target description. */ + const struct target_desc *tdesc = nullptr; + + /* Whether the REGISTERS buffer's contents are valid. If false, we + haven't fetched the registers from the target yet. Not that this + register cache is _not_ pass-through, unlike GDB's. Note that + "valid" here is unrelated to whether the registers are available + in a traceframe. For that, check REGISTER_STATUS below. */ + int registers_valid = 0; + int registers_owned = 0; + unsigned char *registers = nullptr; +#ifndef IN_PROCESS_AGENT + /* One of REG_UNAVAILABLE or REG_VALID. */ + unsigned char *register_status = nullptr; +#endif + + /* See gdbsupport/common-regcache.h. */ + enum register_status get_register_status (int regnum) const override; + + /* See gdbsupport/common-regcache.h. */ + void raw_supply (int regnum, const void *buf) override; + + /* See gdbsupport/common-regcache.h. */ + void raw_collect (int regnum, void *buf) const override; + + /* See gdbsupport/common-regcache.h. */ + bool raw_compare (int regnum, const void *buf, int offset) const override; +}; + +struct regcache *init_register_cache (struct regcache *regcache, + const struct target_desc *tdesc, + unsigned char *regbuf); + +void regcache_cpy (struct regcache *dst, struct regcache *src); + +/* Create a new register cache for INFERIOR. */ + +struct regcache *new_register_cache (const struct target_desc *tdesc); + +struct regcache *get_thread_regcache (struct thread_info *thread, int fetch); + +/* Release all memory associated with the register cache for INFERIOR. */ + +void free_register_cache (struct regcache *regcache); + +/* Invalidate cached registers for one thread. */ + +void regcache_invalidate_thread (struct thread_info *); + +/* Invalidate cached registers for all threads of the given process. */ + +void regcache_invalidate_pid (int pid); + +/* Invalidate cached registers for all threads of the current + process. */ + +void regcache_invalidate (void); + +/* Invalidate and release the register cache of all threads of the + current process. */ + +void regcache_release (void); + +/* Convert all registers to a string in the currently specified remote + format. */ + +void registers_to_string (struct regcache *regcache, char *buf); + +/* Convert a string to register values and fill our register cache. */ + +void registers_from_string (struct regcache *regcache, char *buf); + +/* For regcache_read_pc see gdbsupport/common-regcache.h. */ + +void regcache_write_pc (struct regcache *regcache, CORE_ADDR pc); + +int register_cache_size (const struct target_desc *tdesc); + +int register_size (const struct target_desc *tdesc, int n); + +int find_regno (const struct target_desc *tdesc, const char *name); + +void supply_register (struct regcache *regcache, int n, const void *buf); + +void supply_register_zeroed (struct regcache *regcache, int n); + +void supply_register_by_name (struct regcache *regcache, + const char *name, const void *buf); + +void supply_register_by_name_zeroed (struct regcache *regcache, + const char *name); + +void supply_regblock (struct regcache *regcache, const void *buf); + +void collect_register (struct regcache *regcache, int n, void *buf); + +void collect_register_as_string (struct regcache *regcache, int n, char *buf); + +void collect_register_by_name (struct regcache *regcache, + const char *name, void *buf); + +/* Read a raw register as an unsigned integer. Convenience wrapper + around regcache_raw_get_unsigned that takes a register name instead + of a register number. */ + +ULONGEST regcache_raw_get_unsigned_by_name (struct regcache *regcache, + const char *name); + +#endif /* GDBSERVER_REGCACHE_H */ diff --git a/gdbserver/remote-utils.c b/gdbserver/remote-utils.c new file mode 100644 index 00000000000..b8a8c6576f9 --- /dev/null +++ b/gdbserver/remote-utils.c @@ -0,0 +1,1691 @@ +/* Remote utility routines for the remote server for GDB. + Copyright (C) 1986-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#if HAVE_TERMIOS_H +#include +#endif +#include "target.h" +#include "gdbthread.h" +#include "tdesc.h" +#include "debug.h" +#include "dll.h" +#include "gdbsupport/rsp-low.h" +#include "gdbsupport/netstuff.h" +#include "gdbsupport/filestuff.h" +#include "gdbsupport/gdb-sigmask.h" +#include +#if HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_SYS_FILE_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#if HAVE_NETINET_TCP_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#include "gdbsupport/gdb_sys_time.h" +#include +#if HAVE_ARPA_INET_H +#include +#endif +#include + +#if USE_WIN32API +#include +#endif + +#if __QNX__ +#include +#endif /* __QNX__ */ + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +#ifndef IN_PROCESS_AGENT + +#if USE_WIN32API +# define INVALID_DESCRIPTOR INVALID_SOCKET +#else +# define INVALID_DESCRIPTOR -1 +#endif + +/* Extra value for readchar_callback. */ +enum { + /* The callback is currently not scheduled. */ + NOT_SCHEDULED = -1 +}; + +/* Status of the readchar callback. + Either NOT_SCHEDULED or the callback id. */ +static int readchar_callback = NOT_SCHEDULED; + +static int readchar (void); +static void reset_readchar (void); +static void reschedule (void); + +/* A cache entry for a successfully looked-up symbol. */ +struct sym_cache +{ + char *name; + CORE_ADDR addr; + struct sym_cache *next; +}; + +static int remote_is_stdio = 0; + +static gdb_fildes_t remote_desc = INVALID_DESCRIPTOR; +static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR; + +#ifdef USE_WIN32API +# define read(fd, buf, len) recv (fd, (char *) buf, len, 0) +# define write(fd, buf, len) send (fd, (char *) buf, len, 0) +#endif + +int +gdb_connected (void) +{ + return remote_desc != INVALID_DESCRIPTOR; +} + +/* Return true if the remote connection is over stdio. */ + +int +remote_connection_is_stdio (void) +{ + return remote_is_stdio; +} + +static void +enable_async_notification (int fd) +{ +#if defined(F_SETFL) && defined (FASYNC) + int save_fcntl_flags; + + save_fcntl_flags = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, save_fcntl_flags | FASYNC); +#if defined (F_SETOWN) + fcntl (fd, F_SETOWN, getpid ()); +#endif +#endif +} + +static int +handle_accept_event (int err, gdb_client_data client_data) +{ + struct sockaddr_storage sockaddr; + socklen_t len = sizeof (sockaddr); + + if (debug_threads) + debug_printf ("handling possible accept event\n"); + + remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &len); + if (remote_desc == -1) + perror_with_name ("Accept failed"); + + /* Enable TCP keep alive process. */ + socklen_t tmp = 1; + setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE, + (char *) &tmp, sizeof (tmp)); + + /* Tell TCP not to delay small packets. This greatly speeds up + interactive response. */ + tmp = 1; + setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (tmp)); + +#ifndef USE_WIN32API + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply + exits when the remote side dies. */ +#endif + + if (run_once) + { +#ifndef USE_WIN32API + close (listen_desc); /* No longer need this */ +#else + closesocket (listen_desc); /* No longer need this */ +#endif + } + + /* Even if !RUN_ONCE no longer notice new connections. Still keep the + descriptor open for add_file_handler to wait for a new connection. */ + delete_file_handler (listen_desc); + + /* Convert IP address to string. */ + char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT]; + + int r = getnameinfo ((struct sockaddr *) &sockaddr, len, + orig_host, sizeof (orig_host), + orig_port, sizeof (orig_port), + NI_NUMERICHOST | NI_NUMERICSERV); + + if (r != 0) + fprintf (stderr, _("Could not obtain remote address: %s\n"), + gai_strerror (r)); + else + fprintf (stderr, _("Remote debugging from host %s, port %s\n"), + orig_host, orig_port); + + enable_async_notification (remote_desc); + + /* Register the event loop handler. */ + add_file_handler (remote_desc, handle_serial_event, NULL); + + /* We have a new GDB connection now. If we were disconnected + tracing, there's a window where the target could report a stop + event to the event loop, and since we have a connection now, we'd + try to send vStopped notifications to GDB. But, don't do that + until GDB as selected all-stop/non-stop, and has queried the + threads' status ('?'). */ + target_async (0); + + return 0; +} + +/* Prepare for a later connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_prepare (const char *name) +{ + client_state &cs = get_client_state (); +#ifdef USE_WIN32API + static int winsock_initialized; +#endif + socklen_t tmp; + + remote_is_stdio = 0; + if (strcmp (name, STDIO_CONNECTION_NAME) == 0) + { + /* We need to record fact that we're using stdio sooner than the + call to remote_open so start_inferior knows the connection is + via stdio. */ + remote_is_stdio = 1; + cs.transport_is_reliable = 1; + return; + } + + struct addrinfo hint; + struct addrinfo *ainfo; + + memset (&hint, 0, sizeof (hint)); + /* Assume no prefix will be passed, therefore we should use + AF_UNSPEC. */ + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = IPPROTO_TCP; + + parsed_connection_spec parsed + = parse_connection_spec_without_prefix (name, &hint); + + if (parsed.port_str.empty ()) + { + cs.transport_is_reliable = 0; + return; + } + +#ifdef USE_WIN32API + if (!winsock_initialized) + { + WSADATA wsad; + + WSAStartup (MAKEWORD (1, 0), &wsad); + winsock_initialized = 1; + } +#endif + + int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (), + &hint, &ainfo); + + if (r != 0) + error (_("%s: cannot resolve name: %s"), name, gai_strerror (r)); + + scoped_free_addrinfo freeaddrinfo (ainfo); + + struct addrinfo *iter; + + for (iter = ainfo; iter != NULL; iter = iter->ai_next) + { + listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype, + iter->ai_protocol); + + if (listen_desc >= 0) + break; + } + + if (iter == NULL) + perror_with_name ("Can't open socket"); + + /* Allow rapid reuse of this port. */ + tmp = 1; + setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, + sizeof (tmp)); + + switch (iter->ai_family) + { + case AF_INET: + ((struct sockaddr_in *) iter->ai_addr)->sin_addr.s_addr = INADDR_ANY; + break; + case AF_INET6: + ((struct sockaddr_in6 *) iter->ai_addr)->sin6_addr = in6addr_any; + break; + default: + internal_error (__FILE__, __LINE__, + _("Invalid 'ai_family' %d\n"), iter->ai_family); + } + + if (bind (listen_desc, iter->ai_addr, iter->ai_addrlen) != 0) + perror_with_name ("Can't bind address"); + + if (listen (listen_desc, 1) != 0) + perror_with_name ("Can't listen on socket"); + + cs.transport_is_reliable = 1; +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_open (const char *name) +{ + const char *port_str; + + port_str = strchr (name, ':'); +#ifdef USE_WIN32API + if (port_str == NULL) + error ("Only HOST:PORT is supported on this platform."); +#endif + + if (strcmp (name, STDIO_CONNECTION_NAME) == 0) + { + fprintf (stderr, "Remote debugging using stdio\n"); + + /* Use stdin as the handle of the connection. + We only select on reads, for example. */ + remote_desc = fileno (stdin); + + enable_async_notification (remote_desc); + + /* Register the event loop handler. */ + add_file_handler (remote_desc, handle_serial_event, NULL); + } +#ifndef USE_WIN32API + else if (port_str == NULL) + { + struct stat statbuf; + + if (stat (name, &statbuf) == 0 + && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))) + remote_desc = open (name, O_RDWR); + else + { + errno = EINVAL; + remote_desc = -1; + } + + if (remote_desc < 0) + perror_with_name ("Could not open remote device"); + +#if HAVE_TERMIOS_H + { + struct termios termios; + tcgetattr (remote_desc, &termios); + + termios.c_iflag = 0; + termios.c_oflag = 0; + termios.c_lflag = 0; + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CLOCAL | CS8; + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; + + tcsetattr (remote_desc, TCSANOW, &termios); + } +#endif + + fprintf (stderr, "Remote debugging using %s\n", name); + + enable_async_notification (remote_desc); + + /* Register the event loop handler. */ + add_file_handler (remote_desc, handle_serial_event, NULL); + } +#endif /* USE_WIN32API */ + else + { + char listen_port[GDB_NI_MAX_PORT]; + struct sockaddr_storage sockaddr; + socklen_t len = sizeof (sockaddr); + + if (getsockname (listen_desc, (struct sockaddr *) &sockaddr, &len) < 0) + perror_with_name ("Can't determine port"); + + int r = getnameinfo ((struct sockaddr *) &sockaddr, len, + NULL, 0, + listen_port, sizeof (listen_port), + NI_NUMERICSERV); + + if (r != 0) + fprintf (stderr, _("Can't obtain port where we are listening: %s"), + gai_strerror (r)); + else + fprintf (stderr, _("Listening on port %s\n"), listen_port); + + fflush (stderr); + + /* Register the event loop handler. */ + add_file_handler (listen_desc, handle_accept_event, NULL); + } +} + +void +remote_close (void) +{ + delete_file_handler (remote_desc); + + disable_async_io (); + +#ifdef USE_WIN32API + closesocket (remote_desc); +#else + if (! remote_connection_is_stdio ()) + close (remote_desc); +#endif + remote_desc = INVALID_DESCRIPTOR; + + reset_readchar (); +} + +#endif + +#ifndef IN_PROCESS_AGENT + +void +decode_address (CORE_ADDR *addrp, const char *start, int len) +{ + CORE_ADDR addr; + char ch; + int i; + + addr = 0; + for (i = 0; i < len; i++) + { + ch = start[i]; + addr = addr << 4; + addr = addr | (fromhex (ch) & 0x0f); + } + *addrp = addr; +} + +const char * +decode_address_to_semicolon (CORE_ADDR *addrp, const char *start) +{ + const char *end; + + end = start; + while (*end != '\0' && *end != ';') + end++; + + decode_address (addrp, start, end - start); + + if (*end == ';') + end++; + return end; +} + +#endif + +#ifndef IN_PROCESS_AGENT + +/* Look for a sequence of characters which can be run-length encoded. + If there are any, update *CSUM and *P. Otherwise, output the + single character. Return the number of characters consumed. */ + +static int +try_rle (char *buf, int remaining, unsigned char *csum, char **p) +{ + int n; + + /* Always output the character. */ + *csum += buf[0]; + *(*p)++ = buf[0]; + + /* Don't go past '~'. */ + if (remaining > 97) + remaining = 97; + + for (n = 1; n < remaining; n++) + if (buf[n] != buf[0]) + break; + + /* N is the index of the first character not the same as buf[0]. + buf[0] is counted twice, so by decrementing N, we get the number + of characters the RLE sequence will replace. */ + n--; + + if (n < 3) + return 1; + + /* Skip the frame characters. The manual says to skip '+' and '-' + also, but there's no reason to. Unfortunately these two unusable + characters double the encoded length of a four byte zero + value. */ + while (n + 29 == '$' || n + 29 == '#') + n--; + + *csum += '*'; + *(*p)++ = '*'; + *csum += n + 29; + *(*p)++ = n + 29; + + return n + 1; +} + +#endif + +#ifndef IN_PROCESS_AGENT + +/* Write a PTID to BUF. Returns BUF+CHARACTERS_WRITTEN. */ + +char * +write_ptid (char *buf, ptid_t ptid) +{ + client_state &cs = get_client_state (); + int pid, tid; + + if (cs.multi_process) + { + pid = ptid.pid (); + if (pid < 0) + buf += sprintf (buf, "p-%x.", -pid); + else + buf += sprintf (buf, "p%x.", pid); + } + tid = ptid.lwp (); + if (tid < 0) + buf += sprintf (buf, "-%x", -tid); + else + buf += sprintf (buf, "%x", tid); + + return buf; +} + +static ULONGEST +hex_or_minus_one (const char *buf, const char **obuf) +{ + ULONGEST ret; + + if (startswith (buf, "-1")) + { + ret = (ULONGEST) -1; + buf += 2; + } + else + buf = unpack_varlen_hex (buf, &ret); + + if (obuf) + *obuf = buf; + + return ret; +} + +/* Extract a PTID from BUF. If non-null, OBUF is set to the to one + passed the last parsed char. Returns null_ptid on error. */ +ptid_t +read_ptid (const char *buf, const char **obuf) +{ + const char *p = buf; + const char *pp; + ULONGEST pid = 0, tid = 0; + + if (*p == 'p') + { + /* Multi-process ptid. */ + pp = unpack_varlen_hex (p + 1, &pid); + if (*pp != '.') + error ("invalid remote ptid: %s\n", p); + + p = pp + 1; + + tid = hex_or_minus_one (p, &pp); + + if (obuf) + *obuf = pp; + return ptid_t (pid, tid, 0); + } + + /* No multi-process. Just a tid. */ + tid = hex_or_minus_one (p, &pp); + + /* Since GDB is not sending a process id (multi-process extensions + are off), then there's only one process. Default to the first in + the list. */ + pid = pid_of (get_first_process ()); + + if (obuf) + *obuf = pp; + return ptid_t (pid, tid, 0); +} + +/* Write COUNT bytes in BUF to the client. + The result is the number of bytes written or -1 if error. + This may return less than COUNT. */ + +static int +write_prim (const void *buf, int count) +{ + if (remote_connection_is_stdio ()) + return write (fileno (stdout), buf, count); + else + return write (remote_desc, buf, count); +} + +/* Read COUNT bytes from the client and store in BUF. + The result is the number of bytes read or -1 if error. + This may return less than COUNT. */ + +static int +read_prim (void *buf, int count) +{ + if (remote_connection_is_stdio ()) + return read (fileno (stdin), buf, count); + else + return read (remote_desc, buf, count); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF, and the length of the + packet is in CNT. Returns >= 0 on success, -1 otherwise. */ + +static int +putpkt_binary_1 (char *buf, int cnt, int is_notif) +{ + client_state &cs = get_client_state (); + int i; + unsigned char csum = 0; + char *buf2; + char *p; + int cc; + + buf2 = (char *) xmalloc (strlen ("$") + cnt + strlen ("#nn") + 1); + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + p = buf2; + if (is_notif) + *p++ = '%'; + else + *p++ = '$'; + + for (i = 0; i < cnt;) + i += try_rle (buf + i, cnt - i, &csum, &p); + + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + *p = '\0'; + + /* Send it over and over until we get a positive ack. */ + + do + { + if (write_prim (buf2, p - buf2) != p - buf2) + { + perror ("putpkt(write)"); + free (buf2); + return -1; + } + + if (cs.noack_mode || is_notif) + { + /* Don't expect an ack then. */ + if (remote_debug) + { + if (is_notif) + debug_printf ("putpkt (\"%s\"); [notif]\n", buf2); + else + debug_printf ("putpkt (\"%s\"); [noack mode]\n", buf2); + debug_flush (); + } + break; + } + + if (remote_debug) + { + debug_printf ("putpkt (\"%s\"); [looking for ack]\n", buf2); + debug_flush (); + } + + cc = readchar (); + + if (cc < 0) + { + free (buf2); + return -1; + } + + if (remote_debug) + { + debug_printf ("[received '%c' (0x%x)]\n", cc, cc); + debug_flush (); + } + + /* Check for an input interrupt while we're here. */ + if (cc == '\003' && current_thread != NULL) + (*the_target->request_interrupt) (); + } + while (cc != '+'); + + free (buf2); + return 1; /* Success! */ +} + +int +putpkt_binary (char *buf, int cnt) +{ + return putpkt_binary_1 (buf, cnt, 0); +} + +/* Send a packet to the remote machine, with error checking. The data + of the packet is in BUF, and the packet should be a NUL-terminated + string. Returns >= 0 on success, -1 otherwise. */ + +int +putpkt (char *buf) +{ + return putpkt_binary (buf, strlen (buf)); +} + +int +putpkt_notif (char *buf) +{ + return putpkt_binary_1 (buf, strlen (buf), 1); +} + +/* Come here when we get an input interrupt from the remote side. This + interrupt should only be active while we are waiting for the child to do + something. Thus this assumes readchar:bufcnt is 0. + About the only thing that should come through is a ^C, which + will cause us to request child interruption. */ + +static void +input_interrupt (int unused) +{ + fd_set readset; + struct timeval immediate = { 0, 0 }; + + /* Protect against spurious interrupts. This has been observed to + be a problem under NetBSD 1.4 and 1.5. */ + + FD_ZERO (&readset); + FD_SET (remote_desc, &readset); + if (select (remote_desc + 1, &readset, 0, 0, &immediate) > 0) + { + int cc; + char c = 0; + + cc = read_prim (&c, 1); + + if (cc == 0) + { + fprintf (stderr, "client connection closed\n"); + return; + } + else if (cc != 1 || c != '\003') + { + fprintf (stderr, "input_interrupt, count = %d c = %d ", cc, c); + if (isprint (c)) + fprintf (stderr, "('%c')\n", c); + else + fprintf (stderr, "('\\x%02x')\n", c & 0xff); + return; + } + + (*the_target->request_interrupt) (); + } +} + +/* Check if the remote side sent us an interrupt request (^C). */ +void +check_remote_input_interrupt_request (void) +{ + /* This function may be called before establishing communications, + therefore we need to validate the remote descriptor. */ + + if (remote_desc == INVALID_DESCRIPTOR) + return; + + input_interrupt (0); +} + +/* Asynchronous I/O support. SIGIO must be unblocked when waiting, + in order to accept Control-C from the client, and must be blocked + when talking to the client. */ + +static void +block_unblock_async_io (int block) +{ +#ifndef USE_WIN32API + sigset_t sigio_set; + + sigemptyset (&sigio_set); + sigaddset (&sigio_set, SIGIO); + gdb_sigmask (block ? SIG_BLOCK : SIG_UNBLOCK, &sigio_set, NULL); +#endif +} + +#ifdef __QNX__ +static void +nto_comctrl (int enable) +{ + struct sigevent event; + + if (enable) + { + event.sigev_notify = SIGEV_SIGNAL_THREAD; + event.sigev_signo = SIGIO; + event.sigev_code = 0; + event.sigev_value.sival_ptr = NULL; + event.sigev_priority = -1; + ionotify (remote_desc, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT, + &event); + } + else + ionotify (remote_desc, _NOTIFY_ACTION_POLL, _NOTIFY_COND_INPUT, NULL); +} +#endif /* __QNX__ */ + + +/* Current state of asynchronous I/O. */ +static int async_io_enabled; + +/* Enable asynchronous I/O. */ +void +enable_async_io (void) +{ + if (async_io_enabled) + return; + + block_unblock_async_io (0); + + async_io_enabled = 1; +#ifdef __QNX__ + nto_comctrl (1); +#endif /* __QNX__ */ +} + +/* Disable asynchronous I/O. */ +void +disable_async_io (void) +{ + if (!async_io_enabled) + return; + + block_unblock_async_io (1); + + async_io_enabled = 0; +#ifdef __QNX__ + nto_comctrl (0); +#endif /* __QNX__ */ + +} + +void +initialize_async_io (void) +{ + /* Make sure that async I/O starts blocked. */ + async_io_enabled = 1; + disable_async_io (); + + /* Install the signal handler. */ +#ifndef USE_WIN32API + signal (SIGIO, input_interrupt); +#endif +} + +/* Internal buffer used by readchar. + These are global to readchar because reschedule_remote needs to be + able to tell whether the buffer is empty. */ + +static unsigned char readchar_buf[BUFSIZ]; +static int readchar_bufcnt = 0; +static unsigned char *readchar_bufp; + +/* Returns next char from remote GDB. -1 if error. */ + +static int +readchar (void) +{ + int ch; + + if (readchar_bufcnt == 0) + { + readchar_bufcnt = read_prim (readchar_buf, sizeof (readchar_buf)); + + if (readchar_bufcnt <= 0) + { + if (readchar_bufcnt == 0) + { + if (remote_debug) + debug_printf ("readchar: Got EOF\n"); + } + else + perror ("readchar"); + + return -1; + } + + readchar_bufp = readchar_buf; + } + + readchar_bufcnt--; + ch = *readchar_bufp++; + reschedule (); + return ch; +} + +/* Reset the readchar state machine. */ + +static void +reset_readchar (void) +{ + readchar_bufcnt = 0; + if (readchar_callback != NOT_SCHEDULED) + { + delete_callback_event (readchar_callback); + readchar_callback = NOT_SCHEDULED; + } +} + +/* Process remaining data in readchar_buf. */ + +static int +process_remaining (void *context) +{ + int res; + + /* This is a one-shot event. */ + readchar_callback = NOT_SCHEDULED; + + if (readchar_bufcnt > 0) + res = handle_serial_event (0, NULL); + else + res = 0; + + return res; +} + +/* If there is still data in the buffer, queue another event to process it, + we can't sleep in select yet. */ + +static void +reschedule (void) +{ + if (readchar_bufcnt > 0 && readchar_callback == NOT_SCHEDULED) + readchar_callback = append_callback_event (process_remaining, NULL); +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. Returns length of packet, or negative if error. */ + +int +getpkt (char *buf) +{ + client_state &cs = get_client_state (); + char *bp; + unsigned char csum, c1, c2; + int c; + + while (1) + { + csum = 0; + + while (1) + { + c = readchar (); + + /* The '\003' may appear before or after each packet, so + check for an input interrupt. */ + if (c == '\003') + { + (*the_target->request_interrupt) (); + continue; + } + + if (c == '$') + break; + if (remote_debug) + { + debug_printf ("[getpkt: discarding char '%c']\n", c); + debug_flush (); + } + + if (c < 0) + return -1; + } + + bp = buf; + while (1) + { + c = readchar (); + if (c < 0) + return -1; + if (c == '#') + break; + *bp++ = c; + csum += c; + } + *bp = 0; + + c1 = fromhex (readchar ()); + c2 = fromhex (readchar ()); + + if (csum == (c1 << 4) + c2) + break; + + if (cs.noack_mode) + { + fprintf (stderr, + "Bad checksum, sentsum=0x%x, csum=0x%x, " + "buf=%s [no-ack-mode, Bad medium?]\n", + (c1 << 4) + c2, csum, buf); + /* Not much we can do, GDB wasn't expecting an ack/nac. */ + break; + } + + fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + if (write_prim ("-", 1) != 1) + return -1; + } + + if (!cs.noack_mode) + { + if (remote_debug) + { + debug_printf ("getpkt (\"%s\"); [sending ack] \n", buf); + debug_flush (); + } + + if (write_prim ("+", 1) != 1) + return -1; + + if (remote_debug) + { + debug_printf ("[sent ack]\n"); + debug_flush (); + } + } + else + { + if (remote_debug) + { + debug_printf ("getpkt (\"%s\"); [no ack sent] \n", buf); + debug_flush (); + } + } + + /* The readchar above may have already read a '\003' out of the socket + and moved it to the local buffer. For example, when GDB sends + vCont;c immediately followed by interrupt (see + gdb.base/interrupt-noterm.exp). As soon as we see the vCont;c, we'll + resume the inferior and wait. Since we've already moved the '\003' + to the local buffer, SIGIO won't help. In that case, if we don't + check for interrupt after the vCont;c packet, the interrupt character + would stay in the buffer unattended until after the next (unrelated) + stop. */ + while (readchar_bufcnt > 0 && *readchar_bufp == '\003') + { + /* Consume the interrupt character in the buffer. */ + readchar (); + (*the_target->request_interrupt) (); + } + + return bp - buf; +} + +void +write_ok (char *buf) +{ + buf[0] = 'O'; + buf[1] = 'K'; + buf[2] = '\0'; +} + +void +write_enn (char *buf) +{ + /* Some day, we should define the meanings of the error codes... */ + buf[0] = 'E'; + buf[1] = '0'; + buf[2] = '1'; + buf[3] = '\0'; +} + +#endif + +#ifndef IN_PROCESS_AGENT + +static char * +outreg (struct regcache *regcache, int regno, char *buf) +{ + if ((regno >> 12) != 0) + *buf++ = tohex ((regno >> 12) & 0xf); + if ((regno >> 8) != 0) + *buf++ = tohex ((regno >> 8) & 0xf); + *buf++ = tohex ((regno >> 4) & 0xf); + *buf++ = tohex (regno & 0xf); + *buf++ = ':'; + collect_register_as_string (regcache, regno, buf); + buf += 2 * register_size (regcache->tdesc, regno); + *buf++ = ';'; + + return buf; +} + +void +prepare_resume_reply (char *buf, ptid_t ptid, + struct target_waitstatus *status) +{ + client_state &cs = get_client_state (); + if (debug_threads) + debug_printf ("Writing resume reply for %s:%d\n", + target_pid_to_str (ptid), status->kind); + + switch (status->kind) + { + case TARGET_WAITKIND_STOPPED: + case TARGET_WAITKIND_FORKED: + case TARGET_WAITKIND_VFORKED: + case TARGET_WAITKIND_VFORK_DONE: + case TARGET_WAITKIND_EXECD: + case TARGET_WAITKIND_THREAD_CREATED: + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: + { + struct thread_info *saved_thread; + const char **regp; + struct regcache *regcache; + + if ((status->kind == TARGET_WAITKIND_FORKED && cs.report_fork_events) + || (status->kind == TARGET_WAITKIND_VFORKED + && cs.report_vfork_events)) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = (status->kind == TARGET_WAITKIND_FORKED + ? "fork" : "vfork"); + + sprintf (buf, "T%02x%s:", signal, event); + buf += strlen (buf); + buf = write_ptid (buf, status->value.related_pid); + strcat (buf, ";"); + } + else if (status->kind == TARGET_WAITKIND_VFORK_DONE + && cs.report_vfork_events) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + + sprintf (buf, "T%02xvforkdone:;", signal); + } + else if (status->kind == TARGET_WAITKIND_EXECD && cs.report_exec_events) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = "exec"; + char hexified_pathname[PATH_MAX * 2]; + + sprintf (buf, "T%02x%s:", signal, event); + buf += strlen (buf); + + /* Encode pathname to hexified format. */ + bin2hex ((const gdb_byte *) status->value.execd_pathname, + hexified_pathname, + strlen (status->value.execd_pathname)); + + sprintf (buf, "%s;", hexified_pathname); + xfree (status->value.execd_pathname); + status->value.execd_pathname = NULL; + buf += strlen (buf); + } + else if (status->kind == TARGET_WAITKIND_THREAD_CREATED + && cs.report_thread_events) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + + sprintf (buf, "T%02xcreate:;", signal); + } + else if (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + || status->kind == TARGET_WAITKIND_SYSCALL_RETURN) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + ? "syscall_entry" : "syscall_return"); + + sprintf (buf, "T%02x%s:%x;", signal, event, + status->value.syscall_number); + } + else + sprintf (buf, "T%02x", status->value.sig); + + buf += strlen (buf); + + saved_thread = current_thread; + + switch_to_thread (the_target, ptid); + + regp = current_target_desc ()->expedite_regs; + + regcache = get_thread_regcache (current_thread, 1); + + if (the_target->stopped_by_watchpoint != NULL + && (*the_target->stopped_by_watchpoint) ()) + { + CORE_ADDR addr; + int i; + + memcpy (buf, "watch:", 6); + buf += 6; + + addr = (*the_target->stopped_data_address) (); + + /* Convert each byte of the address into two hexadecimal + chars. Note that we take sizeof (void *) instead of + sizeof (addr); this is to avoid sending a 64-bit + address to a 32-bit GDB. */ + for (i = sizeof (void *) * 2; i > 0; i--) + *buf++ = tohex ((addr >> (i - 1) * 4) & 0xf); + *buf++ = ';'; + } + else if (cs.swbreak_feature && target_stopped_by_sw_breakpoint ()) + { + sprintf (buf, "swbreak:;"); + buf += strlen (buf); + } + else if (cs.hwbreak_feature && target_stopped_by_hw_breakpoint ()) + { + sprintf (buf, "hwbreak:;"); + buf += strlen (buf); + } + + while (*regp) + { + buf = outreg (regcache, find_regno (regcache->tdesc, *regp), buf); + regp ++; + } + *buf = '\0'; + + /* Formerly, if the debugger had not used any thread features + we would not burden it with a thread status response. This + was for the benefit of GDB 4.13 and older. However, in + recent GDB versions the check (``if (cont_thread != 0)'') + does not have the desired effect because of sillyness in + the way that the remote protocol handles specifying a + thread. Since thread support relies on qSymbol support + anyway, assume GDB can handle threads. */ + + if (using_threads && !disable_packet_Tthread) + { + /* This if (1) ought to be unnecessary. But remote_wait + in GDB will claim this event belongs to inferior_ptid + if we do not specify a thread, and there's no way for + gdbserver to know what inferior_ptid is. */ + if (1 || cs.general_thread != ptid) + { + int core = -1; + /* In non-stop, don't change the general thread behind + GDB's back. */ + if (!non_stop) + cs.general_thread = ptid; + sprintf (buf, "thread:"); + buf += strlen (buf); + buf = write_ptid (buf, ptid); + strcat (buf, ";"); + buf += strlen (buf); + + core = target_core_of_thread (ptid); + + if (core != -1) + { + sprintf (buf, "core:"); + buf += strlen (buf); + sprintf (buf, "%x", core); + strcat (buf, ";"); + buf += strlen (buf); + } + } + } + + if (dlls_changed) + { + strcpy (buf, "library:;"); + buf += strlen (buf); + dlls_changed = 0; + } + + current_thread = saved_thread; + } + break; + case TARGET_WAITKIND_EXITED: + if (cs.multi_process) + sprintf (buf, "W%x;process:%x", + status->value.integer, ptid.pid ()); + else + sprintf (buf, "W%02x", status->value.integer); + break; + case TARGET_WAITKIND_SIGNALLED: + if (cs.multi_process) + sprintf (buf, "X%x;process:%x", + status->value.sig, ptid.pid ()); + else + sprintf (buf, "X%02x", status->value.sig); + break; + case TARGET_WAITKIND_THREAD_EXITED: + sprintf (buf, "w%x;", status->value.integer); + buf += strlen (buf); + buf = write_ptid (buf, ptid); + break; + case TARGET_WAITKIND_NO_RESUMED: + sprintf (buf, "N"); + break; + default: + error ("unhandled waitkind"); + break; + } +} + +void +decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr) +{ + int i = 0, j = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + for (j = 0; j < 4; j++) + { + if ((ch = from[i++]) == 0) + break; + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } +} + +void +decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, + unsigned char **to_p) +{ + int i = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + while ((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } + + if (*to_p == NULL) + *to_p = (unsigned char *) xmalloc (*len_ptr); + + hex2bin (&from[i++], *to_p, *len_ptr); +} + +int +decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr, + unsigned int *len_ptr, unsigned char **to_p) +{ + int i = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + while ((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } + + if (*to_p == NULL) + *to_p = (unsigned char *) xmalloc (*len_ptr); + + if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i, + *to_p, *len_ptr) != *len_ptr) + return -1; + + return 0; +} + +/* Decode a qXfer write request. */ + +int +decode_xfer_write (char *buf, int packet_len, CORE_ADDR *offset, + unsigned int *len, unsigned char *data) +{ + char ch; + char *b = buf; + + /* Extract the offset. */ + *offset = 0; + while ((ch = *buf++) != ':') + { + *offset = *offset << 4; + *offset |= fromhex (ch) & 0x0f; + } + + /* Get encoded data. */ + packet_len -= buf - b; + *len = remote_unescape_input ((const gdb_byte *) buf, packet_len, + data, packet_len); + return 0; +} + +/* Decode the parameters of a qSearch:memory packet. */ + +int +decode_search_memory_packet (const char *buf, int packet_len, + CORE_ADDR *start_addrp, + CORE_ADDR *search_space_lenp, + gdb_byte *pattern, unsigned int *pattern_lenp) +{ + const char *p = buf; + + p = decode_address_to_semicolon (start_addrp, p); + p = decode_address_to_semicolon (search_space_lenp, p); + packet_len -= p - buf; + *pattern_lenp = remote_unescape_input ((const gdb_byte *) p, packet_len, + pattern, packet_len); + return 0; +} + +static void +free_sym_cache (struct sym_cache *sym) +{ + if (sym != NULL) + { + free (sym->name); + free (sym); + } +} + +void +clear_symbol_cache (struct sym_cache **symcache_p) +{ + struct sym_cache *sym, *next; + + /* Check the cache first. */ + for (sym = *symcache_p; sym; sym = next) + { + next = sym->next; + free_sym_cache (sym); + } + + *symcache_p = NULL; +} + +/* Get the address of NAME, and return it in ADDRP if found. if + MAY_ASK_GDB is false, assume symbol cache misses are failures. + Returns 1 if the symbol is found, 0 if it is not, -1 on error. */ + +int +look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb) +{ + client_state &cs = get_client_state (); + char *p, *q; + int len; + struct sym_cache *sym; + struct process_info *proc; + + proc = current_process (); + + /* Check the cache first. */ + for (sym = proc->symbol_cache; sym; sym = sym->next) + if (strcmp (name, sym->name) == 0) + { + *addrp = sym->addr; + return 1; + } + + /* It might not be an appropriate time to look up a symbol, + e.g. while we're trying to fetch registers. */ + if (!may_ask_gdb) + return 0; + + /* Send the request. */ + strcpy (cs.own_buf, "qSymbol:"); + bin2hex ((const gdb_byte *) name, cs.own_buf + strlen ("qSymbol:"), + strlen (name)); + if (putpkt (cs.own_buf) < 0) + return -1; + + /* FIXME: Eventually add buffer overflow checking (to getpkt?) */ + len = getpkt (cs.own_buf); + if (len < 0) + return -1; + + /* We ought to handle pretty much any packet at this point while we + wait for the qSymbol "response". That requires re-entering the + main loop. For now, this is an adequate approximation; allow + GDB to read from memory and handle 'v' packets (for vFile transfers) + while it figures out the address of the symbol. */ + while (1) + { + if (cs.own_buf[0] == 'm') + { + CORE_ADDR mem_addr; + unsigned char *mem_buf; + unsigned int mem_len; + + decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len); + mem_buf = (unsigned char *) xmalloc (mem_len); + if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0) + bin2hex (mem_buf, cs.own_buf, mem_len); + else + write_enn (cs.own_buf); + free (mem_buf); + if (putpkt (cs.own_buf) < 0) + return -1; + } + else if (cs.own_buf[0] == 'v') + { + int new_len = -1; + handle_v_requests (cs.own_buf, len, &new_len); + if (new_len != -1) + putpkt_binary (cs.own_buf, new_len); + else + putpkt (cs.own_buf); + } + else + break; + len = getpkt (cs.own_buf); + if (len < 0) + return -1; + } + + if (!startswith (cs.own_buf, "qSymbol:")) + { + warning ("Malformed response to qSymbol, ignoring: %s", cs.own_buf); + return -1; + } + + p = cs.own_buf + strlen ("qSymbol:"); + q = p; + while (*q && *q != ':') + q++; + + /* Make sure we found a value for the symbol. */ + if (p == q || *q == '\0') + return 0; + + decode_address (addrp, p, q - p); + + /* Save the symbol in our cache. */ + sym = XNEW (struct sym_cache); + sym->name = xstrdup (name); + sym->addr = *addrp; + sym->next = proc->symbol_cache; + proc->symbol_cache = sym; + + return 1; +} + +/* Relocate an instruction to execute at a different address. OLDLOC + is the address in the inferior memory where the instruction to + relocate is currently at. On input, TO points to the destination + where we want the instruction to be copied (and possibly adjusted) + to. On output, it points to one past the end of the resulting + instruction(s). The effect of executing the instruction at TO + shall be the same as if executing it at OLDLOC. For example, call + instructions that implicitly push the return address on the stack + should be adjusted to return to the instruction after OLDLOC; + relative branches, and other PC-relative instructions need the + offset adjusted; etc. Returns 0 on success, -1 on failure. */ + +int +relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc) +{ + client_state &cs = get_client_state (); + int len; + ULONGEST written = 0; + + /* Send the request. */ + sprintf (cs.own_buf, "qRelocInsn:%s;%s", paddress (oldloc), + paddress (*to)); + if (putpkt (cs.own_buf) < 0) + return -1; + + /* FIXME: Eventually add buffer overflow checking (to getpkt?) */ + len = getpkt (cs.own_buf); + if (len < 0) + return -1; + + /* We ought to handle pretty much any packet at this point while we + wait for the qRelocInsn "response". That requires re-entering + the main loop. For now, this is an adequate approximation; allow + GDB to access memory. */ + while (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'M' || cs.own_buf[0] == 'X') + { + CORE_ADDR mem_addr; + unsigned char *mem_buf = NULL; + unsigned int mem_len; + + if (cs.own_buf[0] == 'm') + { + decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len); + mem_buf = (unsigned char *) xmalloc (mem_len); + if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0) + bin2hex (mem_buf, cs.own_buf, mem_len); + else + write_enn (cs.own_buf); + } + else if (cs.own_buf[0] == 'X') + { + if (decode_X_packet (&cs.own_buf[1], len - 1, &mem_addr, + &mem_len, &mem_buf) < 0 + || target_write_memory (mem_addr, mem_buf, mem_len) != 0) + write_enn (cs.own_buf); + else + write_ok (cs.own_buf); + } + else + { + decode_M_packet (&cs.own_buf[1], &mem_addr, &mem_len, &mem_buf); + if (target_write_memory (mem_addr, mem_buf, mem_len) == 0) + write_ok (cs.own_buf); + else + write_enn (cs.own_buf); + } + free (mem_buf); + if (putpkt (cs.own_buf) < 0) + return -1; + len = getpkt (cs.own_buf); + if (len < 0) + return -1; + } + + if (cs.own_buf[0] == 'E') + { + warning ("An error occurred while relocating an instruction: %s", + cs.own_buf); + return -1; + } + + if (!startswith (cs.own_buf, "qRelocInsn:")) + { + warning ("Malformed response to qRelocInsn, ignoring: %s", + cs.own_buf); + return -1; + } + + unpack_varlen_hex (cs.own_buf + strlen ("qRelocInsn:"), &written); + + *to += written; + return 0; +} + +void +monitor_output (const char *msg) +{ + int len = strlen (msg); + char *buf = (char *) xmalloc (len * 2 + 2); + + buf[0] = 'O'; + bin2hex ((const gdb_byte *) msg, buf + 1, len); + + putpkt (buf); + free (buf); +} + +#endif diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h new file mode 100644 index 00000000000..1b31456798b --- /dev/null +++ b/gdbserver/remote-utils.h @@ -0,0 +1,70 @@ +/* Remote utility routines for the remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_REMOTE_UTILS_H +#define GDBSERVER_REMOTE_UTILS_H + +int gdb_connected (void); + +#define STDIO_CONNECTION_NAME "stdio" +int remote_connection_is_stdio (void); + +ptid_t read_ptid (const char *buf, const char **obuf); +char *write_ptid (char *buf, ptid_t ptid); + +int putpkt (char *buf); +int putpkt_binary (char *buf, int len); +int putpkt_notif (char *buf); +int getpkt (char *buf); +void remote_prepare (const char *name); +void remote_open (const char *name); +void remote_close (void); +void write_ok (char *buf); +void write_enn (char *buf); +void initialize_async_io (void); +void enable_async_io (void); +void disable_async_io (void); +void check_remote_input_interrupt_request (void); +void prepare_resume_reply (char *buf, ptid_t ptid, + struct target_waitstatus *status); + +const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start); +void decode_address (CORE_ADDR *addrp, const char *start, int len); +void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr, + unsigned int *len_ptr); +void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr, + unsigned int *len_ptr, unsigned char **to_p); +int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr, + unsigned int *len_ptr, unsigned char **to_p); +int decode_xfer_write (char *buf, int packet_len, + CORE_ADDR *offset, unsigned int *len, + unsigned char *data); +int decode_search_memory_packet (const char *buf, int packet_len, + CORE_ADDR *start_addrp, + CORE_ADDR *search_space_lenp, + gdb_byte *pattern, + unsigned int *pattern_lenp); + +void clear_symbol_cache (struct sym_cache **symcache_p); +int look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb); + +int relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc); + +void monitor_output (const char *msg); + +#endif /* GDBSERVER_REMOTE_UTILS_H */ diff --git a/gdbserver/server.c b/gdbserver/server.c new file mode 100644 index 00000000000..3fc026f78eb --- /dev/null +++ b/gdbserver/server.c @@ -0,0 +1,4485 @@ +/* Main code for remote server for GDB. + Copyright (C) 1989-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "gdbthread.h" +#include "gdbsupport/agent.h" +#include "notif.h" +#include "tdesc.h" +#include "gdbsupport/rsp-low.h" +#include "gdbsupport/signals-state-save-restore.h" +#include +#include +#if HAVE_SIGNAL_H +#include +#endif +#include "gdbsupport/gdb_vecs.h" +#include "gdbsupport/gdb_wait.h" +#include "gdbsupport/btrace-common.h" +#include "gdbsupport/filestuff.h" +#include "tracepoint.h" +#include "dll.h" +#include "hostio.h" +#include +#include "gdbsupport/common-inferior.h" +#include "gdbsupport/job-control.h" +#include "gdbsupport/environ.h" +#include "filenames.h" +#include "gdbsupport/pathstuff.h" +#ifdef USE_XML +#include "xml-builtin.h" +#endif + +#include "gdbsupport/selftest.h" +#include "gdbsupport/scope-exit.h" + +#define require_running_or_return(BUF) \ + if (!target_running ()) \ + { \ + write_enn (BUF); \ + return; \ + } + +#define require_running_or_break(BUF) \ + if (!target_running ()) \ + { \ + write_enn (BUF); \ + break; \ + } + +/* String containing the current directory (what getwd would return). */ + +char *current_directory; + +/* The environment to pass to the inferior when creating it. */ + +static gdb_environ our_environ; + +bool server_waiting; + +static bool extended_protocol; +static bool response_needed; +static bool exit_requested; + +/* --once: Exit after the first connection has closed. */ +bool run_once; + +/* Whether to report TARGET_WAITKIND_NO_RESUMED events. */ +static bool report_no_resumed; + +bool non_stop; + +static struct { + /* Set the PROGRAM_PATH. Here we adjust the path of the provided + binary if needed. */ + void set (gdb::unique_xmalloc_ptr &&path) + { + m_path = std::move (path); + + /* Make sure we're using the absolute path of the inferior when + creating it. */ + if (!contains_dir_separator (m_path.get ())) + { + int reg_file_errno; + + /* Check if the file is in our CWD. If it is, then we prefix + its name with CURRENT_DIRECTORY. Otherwise, we leave the + name as-is because we'll try searching for it in $PATH. */ + if (is_regular_file (m_path.get (), ®_file_errno)) + m_path = gdb_abspath (m_path.get ()); + } + } + + /* Return the PROGRAM_PATH. */ + char *get () + { return m_path.get (); } + +private: + /* The program name, adjusted if needed. */ + gdb::unique_xmalloc_ptr m_path; +} program_path; +static std::vector program_args; +static std::string wrapper_argv; + +/* The PID of the originally created or attached inferior. Used to + send signals to the process when GDB sends us an asynchronous interrupt + (user hitting Control-C in the client), and to wait for the child to exit + when no longer debugging it. */ + +unsigned long signal_pid; + +/* Set if you want to disable optional thread related packets support + in gdbserver, for the sake of testing GDB against stubs that don't + support them. */ +bool disable_packet_vCont; +bool disable_packet_Tthread; +bool disable_packet_qC; +bool disable_packet_qfThreadInfo; + +static unsigned char *mem_buf; + +/* A sub-class of 'struct notif_event' for stop, holding information + relative to a single stop reply. We keep a queue of these to + push to GDB in non-stop mode. */ + +struct vstop_notif : public notif_event +{ + /* Thread or process that got the event. */ + ptid_t ptid; + + /* Event info. */ + struct target_waitstatus status; +}; + +/* The current btrace configuration. This is gdbserver's mirror of GDB's + btrace configuration. */ +static struct btrace_config current_btrace_conf; + +/* The client remote protocol state. */ + +static client_state g_client_state; + +client_state & +get_client_state () +{ + client_state &cs = g_client_state; + return cs; +} + + +/* Put a stop reply to the stop reply queue. */ + +static void +queue_stop_reply (ptid_t ptid, struct target_waitstatus *status) +{ + struct vstop_notif *new_notif = new struct vstop_notif; + + new_notif->ptid = ptid; + new_notif->status = *status; + + notif_event_enque (¬if_stop, new_notif); +} + +static bool +remove_all_on_match_ptid (struct notif_event *event, ptid_t filter_ptid) +{ + struct vstop_notif *vstop_event = (struct vstop_notif *) event; + + return vstop_event->ptid.matches (filter_ptid); +} + +/* See server.h. */ + +void +discard_queued_stop_replies (ptid_t ptid) +{ + std::list::iterator iter, next, end; + end = notif_stop.queue.end (); + for (iter = notif_stop.queue.begin (); iter != end; iter = next) + { + next = iter; + ++next; + + if (remove_all_on_match_ptid (*iter, ptid)) + { + delete *iter; + notif_stop.queue.erase (iter); + } + } +} + +static void +vstop_notif_reply (struct notif_event *event, char *own_buf) +{ + struct vstop_notif *vstop = (struct vstop_notif *) event; + + prepare_resume_reply (own_buf, vstop->ptid, &vstop->status); +} + +/* Helper for in_queued_stop_replies. */ + +static bool +in_queued_stop_replies_ptid (struct notif_event *event, ptid_t filter_ptid) +{ + struct vstop_notif *vstop_event = (struct vstop_notif *) event; + + if (vstop_event->ptid.matches (filter_ptid)) + return true; + + /* Don't resume fork children that GDB does not know about yet. */ + if ((vstop_event->status.kind == TARGET_WAITKIND_FORKED + || vstop_event->status.kind == TARGET_WAITKIND_VFORKED) + && vstop_event->status.value.related_pid.matches (filter_ptid)) + return true; + + return false; +} + +/* See server.h. */ + +int +in_queued_stop_replies (ptid_t ptid) +{ + for (notif_event *event : notif_stop.queue) + { + if (in_queued_stop_replies_ptid (event, ptid)) + return true; + } + + return false; +} + +struct notif_server notif_stop = +{ + "vStopped", "Stop", {}, vstop_notif_reply, +}; + +static int +target_running (void) +{ + return get_first_thread () != NULL; +} + +/* See gdbsupport/common-inferior.h. */ + +const char * +get_exec_wrapper () +{ + return !wrapper_argv.empty () ? wrapper_argv.c_str () : NULL; +} + +/* See gdbsupport/common-inferior.h. */ + +const char * +get_exec_file (int err) +{ + if (err && program_path.get () == NULL) + error (_("No executable file specified.")); + + return program_path.get (); +} + +/* See server.h. */ + +gdb_environ * +get_environ () +{ + return &our_environ; +} + +static int +attach_inferior (int pid) +{ + client_state &cs = get_client_state (); + /* myattach should return -1 if attaching is unsupported, + 0 if it succeeded, and call error() otherwise. */ + + if (find_process_pid (pid) != nullptr) + error ("Already attached to process %d\n", pid); + + if (myattach (pid) != 0) + return -1; + + fprintf (stderr, "Attached; pid = %d\n", pid); + fflush (stderr); + + /* FIXME - It may be that we should get the SIGNAL_PID from the + attach function, so that it can be the main thread instead of + whichever we were told to attach to. */ + signal_pid = pid; + + if (!non_stop) + { + cs.last_ptid = mywait (ptid_t (pid), &cs.last_status, 0, 0); + + /* GDB knows to ignore the first SIGSTOP after attaching to a running + process using the "attach" command, but this is different; it's + just using "target remote". Pretend it's just starting up. */ + if (cs.last_status.kind == TARGET_WAITKIND_STOPPED + && cs.last_status.value.sig == GDB_SIGNAL_STOP) + cs.last_status.value.sig = GDB_SIGNAL_TRAP; + + current_thread->last_resume_kind = resume_stop; + current_thread->last_status = cs.last_status; + } + + return 0; +} + +/* Decode a qXfer read request. Return 0 if everything looks OK, + or -1 otherwise. */ + +static int +decode_xfer_read (char *buf, CORE_ADDR *ofs, unsigned int *len) +{ + /* After the read marker and annex, qXfer looks like a + traditional 'm' packet. */ + decode_m_packet (buf, ofs, len); + + return 0; +} + +static int +decode_xfer (char *buf, char **object, char **rw, char **annex, char **offset) +{ + /* Extract and NUL-terminate the object. */ + *object = buf; + while (*buf && *buf != ':') + buf++; + if (*buf == '\0') + return -1; + *buf++ = 0; + + /* Extract and NUL-terminate the read/write action. */ + *rw = buf; + while (*buf && *buf != ':') + buf++; + if (*buf == '\0') + return -1; + *buf++ = 0; + + /* Extract and NUL-terminate the annex. */ + *annex = buf; + while (*buf && *buf != ':') + buf++; + if (*buf == '\0') + return -1; + *buf++ = 0; + + *offset = buf; + return 0; +} + +/* Write the response to a successful qXfer read. Returns the + length of the (binary) data stored in BUF, corresponding + to as much of DATA/LEN as we could fit. IS_MORE controls + the first character of the response. */ +static int +write_qxfer_response (char *buf, const gdb_byte *data, int len, int is_more) +{ + int out_len; + + if (is_more) + buf[0] = 'm'; + else + buf[0] = 'l'; + + return remote_escape_output (data, len, 1, (unsigned char *) buf + 1, + &out_len, PBUFSIZ - 2) + 1; +} + +/* Handle btrace enabling in BTS format. */ + +static void +handle_btrace_enable_bts (struct thread_info *thread) +{ + if (thread->btrace != NULL) + error (_("Btrace already enabled.")); + + current_btrace_conf.format = BTRACE_FORMAT_BTS; + thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf); +} + +/* Handle btrace enabling in Intel Processor Trace format. */ + +static void +handle_btrace_enable_pt (struct thread_info *thread) +{ + if (thread->btrace != NULL) + error (_("Btrace already enabled.")); + + current_btrace_conf.format = BTRACE_FORMAT_PT; + thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf); +} + +/* Handle btrace disabling. */ + +static void +handle_btrace_disable (struct thread_info *thread) +{ + + if (thread->btrace == NULL) + error (_("Branch tracing not enabled.")); + + if (target_disable_btrace (thread->btrace) != 0) + error (_("Could not disable branch tracing.")); + + thread->btrace = NULL; +} + +/* Handle the "Qbtrace" packet. */ + +static int +handle_btrace_general_set (char *own_buf) +{ + client_state &cs = get_client_state (); + struct thread_info *thread; + char *op; + + if (!startswith (own_buf, "Qbtrace:")) + return 0; + + op = own_buf + strlen ("Qbtrace:"); + + if (cs.general_thread == null_ptid + || cs.general_thread == minus_one_ptid) + { + strcpy (own_buf, "E.Must select a single thread."); + return -1; + } + + thread = find_thread_ptid (cs.general_thread); + if (thread == NULL) + { + strcpy (own_buf, "E.No such thread."); + return -1; + } + + try + { + if (strcmp (op, "bts") == 0) + handle_btrace_enable_bts (thread); + else if (strcmp (op, "pt") == 0) + handle_btrace_enable_pt (thread); + else if (strcmp (op, "off") == 0) + handle_btrace_disable (thread); + else + error (_("Bad Qbtrace operation. Use bts, pt, or off.")); + + write_ok (own_buf); + } + catch (const gdb_exception_error &exception) + { + sprintf (own_buf, "E.%s", exception.what ()); + } + + return 1; +} + +/* Handle the "Qbtrace-conf" packet. */ + +static int +handle_btrace_conf_general_set (char *own_buf) +{ + client_state &cs = get_client_state (); + struct thread_info *thread; + char *op; + + if (!startswith (own_buf, "Qbtrace-conf:")) + return 0; + + op = own_buf + strlen ("Qbtrace-conf:"); + + if (cs.general_thread == null_ptid + || cs.general_thread == minus_one_ptid) + { + strcpy (own_buf, "E.Must select a single thread."); + return -1; + } + + thread = find_thread_ptid (cs.general_thread); + if (thread == NULL) + { + strcpy (own_buf, "E.No such thread."); + return -1; + } + + if (startswith (op, "bts:size=")) + { + unsigned long size; + char *endp = NULL; + + errno = 0; + size = strtoul (op + strlen ("bts:size="), &endp, 16); + if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX) + { + strcpy (own_buf, "E.Bad size value."); + return -1; + } + + current_btrace_conf.bts.size = (unsigned int) size; + } + else if (strncmp (op, "pt:size=", strlen ("pt:size=")) == 0) + { + unsigned long size; + char *endp = NULL; + + errno = 0; + size = strtoul (op + strlen ("pt:size="), &endp, 16); + if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX) + { + strcpy (own_buf, "E.Bad size value."); + return -1; + } + + current_btrace_conf.pt.size = (unsigned int) size; + } + else + { + strcpy (own_buf, "E.Bad Qbtrace configuration option."); + return -1; + } + + write_ok (own_buf); + return 1; +} + +/* Handle all of the extended 'Q' packets. */ + +static void +handle_general_set (char *own_buf) +{ + client_state &cs = get_client_state (); + if (startswith (own_buf, "QPassSignals:")) + { + int numsigs = (int) GDB_SIGNAL_LAST, i; + const char *p = own_buf + strlen ("QPassSignals:"); + CORE_ADDR cursig; + + p = decode_address_to_semicolon (&cursig, p); + for (i = 0; i < numsigs; i++) + { + if (i == cursig) + { + cs.pass_signals[i] = 1; + if (*p == '\0') + /* Keep looping, to clear the remaining signals. */ + cursig = -1; + else + p = decode_address_to_semicolon (&cursig, p); + } + else + cs.pass_signals[i] = 0; + } + strcpy (own_buf, "OK"); + return; + } + + if (startswith (own_buf, "QProgramSignals:")) + { + int numsigs = (int) GDB_SIGNAL_LAST, i; + const char *p = own_buf + strlen ("QProgramSignals:"); + CORE_ADDR cursig; + + cs.program_signals_p = 1; + + p = decode_address_to_semicolon (&cursig, p); + for (i = 0; i < numsigs; i++) + { + if (i == cursig) + { + cs.program_signals[i] = 1; + if (*p == '\0') + /* Keep looping, to clear the remaining signals. */ + cursig = -1; + else + p = decode_address_to_semicolon (&cursig, p); + } + else + cs.program_signals[i] = 0; + } + strcpy (own_buf, "OK"); + return; + } + + if (startswith (own_buf, "QCatchSyscalls:")) + { + const char *p = own_buf + sizeof ("QCatchSyscalls:") - 1; + int enabled = -1; + CORE_ADDR sysno; + struct process_info *process; + + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + if (strcmp (p, "0") == 0) + enabled = 0; + else if (p[0] == '1' && (p[1] == ';' || p[1] == '\0')) + enabled = 1; + else + { + fprintf (stderr, "Unknown catch-syscalls mode requested: %s\n", + own_buf); + write_enn (own_buf); + return; + } + + process = current_process (); + process->syscalls_to_catch.clear (); + + if (enabled) + { + p += 1; + if (*p == ';') + { + p += 1; + while (*p != '\0') + { + p = decode_address_to_semicolon (&sysno, p); + process->syscalls_to_catch.push_back (sysno); + } + } + else + process->syscalls_to_catch.push_back (ANY_SYSCALL); + } + + write_ok (own_buf); + return; + } + + if (strcmp (own_buf, "QEnvironmentReset") == 0) + { + our_environ = gdb_environ::from_host_environ (); + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QEnvironmentHexEncoded:")) + { + const char *p = own_buf + sizeof ("QEnvironmentHexEncoded:") - 1; + /* The final form of the environment variable. FINAL_VAR will + hold the 'VAR=VALUE' format. */ + std::string final_var = hex2str (p); + std::string var_name, var_value; + + if (remote_debug) + { + debug_printf (_("[QEnvironmentHexEncoded received '%s']\n"), p); + debug_printf (_("[Environment variable to be set: '%s']\n"), + final_var.c_str ()); + debug_flush (); + } + + size_t pos = final_var.find ('='); + if (pos == std::string::npos) + { + warning (_("Unexpected format for environment variable: '%s'"), + final_var.c_str ()); + write_enn (own_buf); + return; + } + + var_name = final_var.substr (0, pos); + var_value = final_var.substr (pos + 1, std::string::npos); + + our_environ.set (var_name.c_str (), var_value.c_str ()); + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QEnvironmentUnset:")) + { + const char *p = own_buf + sizeof ("QEnvironmentUnset:") - 1; + std::string varname = hex2str (p); + + if (remote_debug) + { + debug_printf (_("[QEnvironmentUnset received '%s']\n"), p); + debug_printf (_("[Environment variable to be unset: '%s']\n"), + varname.c_str ()); + debug_flush (); + } + + our_environ.unset (varname.c_str ()); + + write_ok (own_buf); + return; + } + + if (strcmp (own_buf, "QStartNoAckMode") == 0) + { + if (remote_debug) + { + debug_printf ("[noack mode enabled]\n"); + debug_flush (); + } + + cs.noack_mode = 1; + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QNonStop:")) + { + char *mode = own_buf + 9; + int req = -1; + const char *req_str; + + if (strcmp (mode, "0") == 0) + req = 0; + else if (strcmp (mode, "1") == 0) + req = 1; + else + { + /* We don't know what this mode is, so complain to + GDB. */ + fprintf (stderr, "Unknown non-stop mode requested: %s\n", + own_buf); + write_enn (own_buf); + return; + } + + req_str = req ? "non-stop" : "all-stop"; + if (start_non_stop (req) != 0) + { + fprintf (stderr, "Setting %s mode failed\n", req_str); + write_enn (own_buf); + return; + } + + non_stop = (req != 0); + + if (remote_debug) + debug_printf ("[%s mode enabled]\n", req_str); + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QDisableRandomization:")) + { + char *packet = own_buf + strlen ("QDisableRandomization:"); + ULONGEST setting; + + unpack_varlen_hex (packet, &setting); + cs.disable_randomization = setting; + + if (remote_debug) + { + debug_printf (cs.disable_randomization + ? "[address space randomization disabled]\n" + : "[address space randomization enabled]\n"); + } + + write_ok (own_buf); + return; + } + + if (target_supports_tracepoints () + && handle_tracepoint_general_set (own_buf)) + return; + + if (startswith (own_buf, "QAgent:")) + { + char *mode = own_buf + strlen ("QAgent:"); + int req = 0; + + if (strcmp (mode, "0") == 0) + req = 0; + else if (strcmp (mode, "1") == 0) + req = 1; + else + { + /* We don't know what this value is, so complain to GDB. */ + sprintf (own_buf, "E.Unknown QAgent value"); + return; + } + + /* Update the flag. */ + use_agent = req; + if (remote_debug) + debug_printf ("[%s agent]\n", req ? "Enable" : "Disable"); + write_ok (own_buf); + return; + } + + if (handle_btrace_general_set (own_buf)) + return; + + if (handle_btrace_conf_general_set (own_buf)) + return; + + if (startswith (own_buf, "QThreadEvents:")) + { + char *mode = own_buf + strlen ("QThreadEvents:"); + enum tribool req = TRIBOOL_UNKNOWN; + + if (strcmp (mode, "0") == 0) + req = TRIBOOL_FALSE; + else if (strcmp (mode, "1") == 0) + req = TRIBOOL_TRUE; + else + { + /* We don't know what this mode is, so complain to GDB. */ + sprintf (own_buf, "E.Unknown thread-events mode requested: %s\n", + mode); + return; + } + + cs.report_thread_events = (req == TRIBOOL_TRUE); + + if (remote_debug) + { + const char *req_str = cs.report_thread_events ? "enabled" : "disabled"; + + debug_printf ("[thread events are now %s]\n", req_str); + } + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QStartupWithShell:")) + { + const char *value = own_buf + strlen ("QStartupWithShell:"); + + if (strcmp (value, "1") == 0) + startup_with_shell = true; + else if (strcmp (value, "0") == 0) + startup_with_shell = false; + else + { + /* Unknown value. */ + fprintf (stderr, "Unknown value to startup-with-shell: %s\n", + own_buf); + write_enn (own_buf); + return; + } + + if (remote_debug) + debug_printf (_("[Inferior will %s started with shell]"), + startup_with_shell ? "be" : "not be"); + + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "QSetWorkingDir:")) + { + const char *p = own_buf + strlen ("QSetWorkingDir:"); + + if (*p != '\0') + { + std::string path = hex2str (p); + + set_inferior_cwd (path.c_str ()); + + if (remote_debug) + debug_printf (_("[Set the inferior's current directory to %s]\n"), + path.c_str ()); + } + else + { + /* An empty argument means that we should clear out any + previously set cwd for the inferior. */ + set_inferior_cwd (NULL); + + if (remote_debug) + debug_printf (_("\ +[Unset the inferior's current directory; will use gdbserver's cwd]\n")); + } + write_ok (own_buf); + + return; + } + + /* Otherwise we didn't know what packet it was. Say we didn't + understand it. */ + own_buf[0] = 0; +} + +static const char * +get_features_xml (const char *annex) +{ + const struct target_desc *desc = current_target_desc (); + + /* `desc->xmltarget' defines what to return when looking for the + "target.xml" file. Its contents can either be verbatim XML code + (prefixed with a '@') or else the name of the actual XML file to + be used in place of "target.xml". + + This variable is set up from the auto-generated + init_registers_... routine for the current target. */ + + if (strcmp (annex, "target.xml") == 0) + { + const char *ret = tdesc_get_features_xml (desc); + + if (*ret == '@') + return ret + 1; + else + annex = ret; + } + +#ifdef USE_XML + { + int i; + + /* Look for the annex. */ + for (i = 0; xml_builtin[i][0] != NULL; i++) + if (strcmp (annex, xml_builtin[i][0]) == 0) + break; + + if (xml_builtin[i][0] != NULL) + return xml_builtin[i][1]; + } +#endif + + return NULL; +} + +static void +monitor_show_help (void) +{ + monitor_output ("The following monitor commands are supported:\n"); + monitor_output (" set debug <0|1>\n"); + monitor_output (" Enable general debugging messages\n"); + monitor_output (" set debug-hw-points <0|1>\n"); + monitor_output (" Enable h/w breakpoint/watchpoint debugging messages\n"); + monitor_output (" set remote-debug <0|1>\n"); + monitor_output (" Enable remote protocol debugging messages\n"); + monitor_output (" set debug-format option1[,option2,...]\n"); + monitor_output (" Add additional information to debugging messages\n"); + monitor_output (" Options: all, none"); + monitor_output (", timestamp"); + monitor_output ("\n"); + monitor_output (" exit\n"); + monitor_output (" Quit GDBserver\n"); +} + +/* Read trace frame or inferior memory. Returns the number of bytes + actually read, zero when no further transfer is possible, and -1 on + error. Return of a positive value smaller than LEN does not + indicate there's no more to be read, only the end of the transfer. + E.g., when GDB reads memory from a traceframe, a first request may + be served from a memory block that does not cover the whole request + length. A following request gets the rest served from either + another block (of the same traceframe) or from the read-only + regions. */ + +static int +gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + client_state &cs = get_client_state (); + int res; + + if (cs.current_traceframe >= 0) + { + ULONGEST nbytes; + ULONGEST length = len; + + if (traceframe_read_mem (cs.current_traceframe, + memaddr, myaddr, len, &nbytes)) + return -1; + /* Data read from trace buffer, we're done. */ + if (nbytes > 0) + return nbytes; + if (!in_readonly_region (memaddr, length)) + return -1; + /* Otherwise we have a valid readonly case, fall through. */ + /* (assume no half-trace half-real blocks for now) */ + } + + res = prepare_to_access_memory (); + if (res == 0) + { + if (set_desired_thread ()) + res = read_inferior_memory (memaddr, myaddr, len); + else + res = 1; + done_accessing_memory (); + + return res == 0 ? len : -1; + } + else + return -1; +} + +/* Write trace frame or inferior memory. Actually, writing to trace + frames is forbidden. */ + +static int +gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +{ + client_state &cs = get_client_state (); + if (cs.current_traceframe >= 0) + return EIO; + else + { + int ret; + + ret = prepare_to_access_memory (); + if (ret == 0) + { + if (set_desired_thread ()) + ret = target_write_memory (memaddr, myaddr, len); + else + ret = EIO; + done_accessing_memory (); + } + return ret; + } +} + +/* Subroutine of handle_search_memory to simplify it. */ + +static int +handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len, + gdb_byte *pattern, unsigned pattern_len, + gdb_byte *search_buf, + unsigned chunk_size, unsigned search_buf_size, + CORE_ADDR *found_addrp) +{ + /* Prime the search buffer. */ + + if (gdb_read_memory (start_addr, search_buf, search_buf_size) + != search_buf_size) + { + warning ("Unable to access %ld bytes of target " + "memory at 0x%lx, halting search.", + (long) search_buf_size, (long) start_addr); + return -1; + } + + /* Perform the search. + + The loop is kept simple by allocating [N + pattern-length - 1] bytes. + When we've scanned N bytes we copy the trailing bytes to the start and + read in another N bytes. */ + + while (search_space_len >= pattern_len) + { + gdb_byte *found_ptr; + unsigned nr_search_bytes = (search_space_len < search_buf_size + ? search_space_len + : search_buf_size); + + found_ptr = (gdb_byte *) memmem (search_buf, nr_search_bytes, pattern, + pattern_len); + + if (found_ptr != NULL) + { + CORE_ADDR found_addr = start_addr + (found_ptr - search_buf); + *found_addrp = found_addr; + return 1; + } + + /* Not found in this chunk, skip to next chunk. */ + + /* Don't let search_space_len wrap here, it's unsigned. */ + if (search_space_len >= chunk_size) + search_space_len -= chunk_size; + else + search_space_len = 0; + + if (search_space_len >= pattern_len) + { + unsigned keep_len = search_buf_size - chunk_size; + CORE_ADDR read_addr = start_addr + chunk_size + keep_len; + int nr_to_read; + + /* Copy the trailing part of the previous iteration to the front + of the buffer for the next iteration. */ + memcpy (search_buf, search_buf + chunk_size, keep_len); + + nr_to_read = (search_space_len - keep_len < chunk_size + ? search_space_len - keep_len + : chunk_size); + + if (gdb_read_memory (read_addr, search_buf + keep_len, + nr_to_read) != search_buf_size) + { + warning ("Unable to access %ld bytes of target memory " + "at 0x%lx, halting search.", + (long) nr_to_read, (long) read_addr); + return -1; + } + + start_addr += chunk_size; + } + } + + /* Not found. */ + + return 0; +} + +/* Handle qSearch:memory packets. */ + +static void +handle_search_memory (char *own_buf, int packet_len) +{ + CORE_ADDR start_addr; + CORE_ADDR search_space_len; + gdb_byte *pattern; + unsigned int pattern_len; + /* NOTE: also defined in find.c testcase. */ +#define SEARCH_CHUNK_SIZE 16000 + const unsigned chunk_size = SEARCH_CHUNK_SIZE; + /* Buffer to hold memory contents for searching. */ + gdb_byte *search_buf; + unsigned search_buf_size; + int found; + CORE_ADDR found_addr; + int cmd_name_len = sizeof ("qSearch:memory:") - 1; + + pattern = (gdb_byte *) malloc (packet_len); + if (pattern == NULL) + { + error ("Unable to allocate memory to perform the search"); + strcpy (own_buf, "E00"); + return; + } + if (decode_search_memory_packet (own_buf + cmd_name_len, + packet_len - cmd_name_len, + &start_addr, &search_space_len, + pattern, &pattern_len) < 0) + { + free (pattern); + error ("Error in parsing qSearch:memory packet"); + strcpy (own_buf, "E00"); + return; + } + + search_buf_size = chunk_size + pattern_len - 1; + + /* No point in trying to allocate a buffer larger than the search space. */ + if (search_space_len < search_buf_size) + search_buf_size = search_space_len; + + search_buf = (gdb_byte *) malloc (search_buf_size); + if (search_buf == NULL) + { + free (pattern); + error ("Unable to allocate memory to perform the search"); + strcpy (own_buf, "E00"); + return; + } + + found = handle_search_memory_1 (start_addr, search_space_len, + pattern, pattern_len, + search_buf, chunk_size, search_buf_size, + &found_addr); + + if (found > 0) + sprintf (own_buf, "1,%lx", (long) found_addr); + else if (found == 0) + strcpy (own_buf, "0"); + else + strcpy (own_buf, "E00"); + + free (search_buf); + free (pattern); +} + +/* Handle the "D" packet. */ + +static void +handle_detach (char *own_buf) +{ + client_state &cs = get_client_state (); + + process_info *process; + + if (cs.multi_process) + { + /* skip 'D;' */ + int pid = strtol (&own_buf[2], NULL, 16); + + process = find_process_pid (pid); + } + else + { + process = (current_thread != nullptr + ? get_thread_process (current_thread) + : nullptr); + } + + if (process == NULL) + { + write_enn (own_buf); + return; + } + + if ((tracing && disconnected_tracing) || any_persistent_commands (process)) + { + if (tracing && disconnected_tracing) + fprintf (stderr, + "Disconnected tracing in effect, " + "leaving gdbserver attached to the process\n"); + + if (any_persistent_commands (process)) + fprintf (stderr, + "Persistent commands are present, " + "leaving gdbserver attached to the process\n"); + + /* Make sure we're in non-stop/async mode, so we we can both + wait for an async socket accept, and handle async target + events simultaneously. There's also no point either in + having the target stop all threads, when we're going to + pass signals down without informing GDB. */ + if (!non_stop) + { + if (debug_threads) + debug_printf ("Forcing non-stop mode\n"); + + non_stop = true; + start_non_stop (1); + } + + process->gdb_detached = 1; + + /* Detaching implicitly resumes all threads. */ + target_continue_no_signal (minus_one_ptid); + + write_ok (own_buf); + return; + } + + fprintf (stderr, "Detaching from process %d\n", process->pid); + stop_tracing (); + + /* We'll need this after PROCESS has been destroyed. */ + int pid = process->pid; + + if (detach_inferior (process) != 0) + write_enn (own_buf); + else + { + discard_queued_stop_replies (ptid_t (pid)); + write_ok (own_buf); + + if (extended_protocol || target_running ()) + { + /* There is still at least one inferior remaining or + we are in extended mode, so don't terminate gdbserver, + and instead treat this like a normal program exit. */ + cs.last_status.kind = TARGET_WAITKIND_EXITED; + cs.last_status.value.integer = 0; + cs.last_ptid = ptid_t (pid); + + current_thread = NULL; + } + else + { + putpkt (own_buf); + remote_close (); + + /* If we are attached, then we can exit. Otherwise, we + need to hang around doing nothing, until the child is + gone. */ + join_inferior (pid); + exit (0); + } + } +} + +/* Parse options to --debug-format= and "monitor set debug-format". + ARG is the text after "--debug-format=" or "monitor set debug-format". + IS_MONITOR is non-zero if we're invoked via "monitor set debug-format". + This triggers calls to monitor_output. + The result is an empty string if all options were parsed ok, otherwise an + error message which the caller must free. + + N.B. These commands affect all debug format settings, they are not + cumulative. If a format is not specified, it is turned off. + However, we don't go to extra trouble with things like + "monitor set debug-format all,none,timestamp". + Instead we just parse them one at a time, in order. + + The syntax for "monitor set debug" we support here is not identical + to gdb's "set debug foo on|off" because we also use this function to + parse "--debug-format=foo,bar". */ + +static std::string +parse_debug_format_options (const char *arg, int is_monitor) +{ + /* First turn all debug format options off. */ + debug_timestamp = 0; + + /* First remove leading spaces, for "monitor set debug-format". */ + while (isspace (*arg)) + ++arg; + + std::vector> options + = delim_string_to_char_ptr_vec (arg, ','); + + for (const gdb::unique_xmalloc_ptr &option : options) + { + if (strcmp (option.get (), "all") == 0) + { + debug_timestamp = 1; + if (is_monitor) + monitor_output ("All extra debug format options enabled.\n"); + } + else if (strcmp (option.get (), "none") == 0) + { + debug_timestamp = 0; + if (is_monitor) + monitor_output ("All extra debug format options disabled.\n"); + } + else if (strcmp (option.get (), "timestamp") == 0) + { + debug_timestamp = 1; + if (is_monitor) + monitor_output ("Timestamps will be added to debug output.\n"); + } + else if (*option == '\0') + { + /* An empty option, e.g., "--debug-format=foo,,bar", is ignored. */ + continue; + } + else + return string_printf ("Unknown debug-format argument: \"%s\"\n", + option.get ()); + } + + return std::string (); +} + +/* Handle monitor commands not handled by target-specific handlers. */ + +static void +handle_monitor_command (char *mon, char *own_buf) +{ + if (strcmp (mon, "set debug 1") == 0) + { + debug_threads = 1; + monitor_output ("Debug output enabled.\n"); + } + else if (strcmp (mon, "set debug 0") == 0) + { + debug_threads = 0; + monitor_output ("Debug output disabled.\n"); + } + else if (strcmp (mon, "set debug-hw-points 1") == 0) + { + show_debug_regs = 1; + monitor_output ("H/W point debugging output enabled.\n"); + } + else if (strcmp (mon, "set debug-hw-points 0") == 0) + { + show_debug_regs = 0; + monitor_output ("H/W point debugging output disabled.\n"); + } + else if (strcmp (mon, "set remote-debug 1") == 0) + { + remote_debug = 1; + monitor_output ("Protocol debug output enabled.\n"); + } + else if (strcmp (mon, "set remote-debug 0") == 0) + { + remote_debug = 0; + monitor_output ("Protocol debug output disabled.\n"); + } + else if (startswith (mon, "set debug-format ")) + { + std::string error_msg + = parse_debug_format_options (mon + sizeof ("set debug-format ") - 1, + 1); + + if (!error_msg.empty ()) + { + monitor_output (error_msg.c_str ()); + monitor_show_help (); + write_enn (own_buf); + } + } + else if (strcmp (mon, "set debug-file") == 0) + debug_set_output (nullptr); + else if (startswith (mon, "set debug-file ")) + debug_set_output (mon + sizeof ("set debug-file ") - 1); + else if (strcmp (mon, "help") == 0) + monitor_show_help (); + else if (strcmp (mon, "exit") == 0) + exit_requested = true; + else + { + monitor_output ("Unknown monitor command.\n\n"); + monitor_show_help (); + write_enn (own_buf); + } +} + +/* Associates a callback with each supported qXfer'able object. */ + +struct qxfer +{ + /* The object this handler handles. */ + const char *object; + + /* Request that the target transfer up to LEN 8-bit bytes of the + target's OBJECT. The OFFSET, for a seekable object, specifies + the starting point. The ANNEX can be used to provide additional + data-specific information to the target. + + Return the number of bytes actually transfered, zero when no + further transfer is possible, -1 on error, -2 when the transfer + is not supported, and -3 on a verbose error message that should + be preserved. Return of a positive value smaller than LEN does + not indicate the end of the object, only the end of the transfer. + + One, and only one, of readbuf or writebuf must be non-NULL. */ + int (*xfer) (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len); +}; + +/* Handle qXfer:auxv:read. */ + +static int +handle_qxfer_auxv (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->read_auxv == NULL || writebuf != NULL) + return -2; + + if (annex[0] != '\0' || current_thread == NULL) + return -1; + + return (*the_target->read_auxv) (offset, readbuf, len); +} + +/* Handle qXfer:exec-file:read. */ + +static int +handle_qxfer_exec_file (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + char *file; + ULONGEST pid; + int total_len; + + if (the_target->pid_to_exec_file == NULL || writebuf != NULL) + return -2; + + if (annex[0] == '\0') + { + if (current_thread == NULL) + return -1; + + pid = pid_of (current_thread); + } + else + { + annex = unpack_varlen_hex (annex, &pid); + if (annex[0] != '\0') + return -1; + } + + if (pid <= 0) + return -1; + + file = (*the_target->pid_to_exec_file) (pid); + if (file == NULL) + return -1; + + total_len = strlen (file); + + if (offset > total_len) + return -1; + + if (offset + len > total_len) + len = total_len - offset; + + memcpy (readbuf, file + offset, len); + return len; +} + +/* Handle qXfer:features:read. */ + +static int +handle_qxfer_features (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + const char *document; + size_t total_len; + + if (writebuf != NULL) + return -2; + + if (!target_running ()) + return -1; + + /* Grab the correct annex. */ + document = get_features_xml (annex); + if (document == NULL) + return -1; + + total_len = strlen (document); + + if (offset > total_len) + return -1; + + if (offset + len > total_len) + len = total_len - offset; + + memcpy (readbuf, document + offset, len); + return len; +} + +/* Handle qXfer:libraries:read. */ + +static int +handle_qxfer_libraries (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0' || current_thread == NULL) + return -1; + + std::string document = "\n"; + + for (const dll_info &dll : all_dlls) + document += string_printf + (" \n", + dll.name.c_str (), paddress (dll.base_addr)); + + document += "\n"; + + if (offset > document.length ()) + return -1; + + if (offset + len > document.length ()) + len = document.length () - offset; + + memcpy (readbuf, &document[offset], len); + + return len; +} + +/* Handle qXfer:libraries-svr4:read. */ + +static int +handle_qxfer_libraries_svr4 (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (writebuf != NULL) + return -2; + + if (current_thread == NULL || the_target->qxfer_libraries_svr4 == NULL) + return -1; + + return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len); +} + +/* Handle qXfer:osadata:read. */ + +static int +handle_qxfer_osdata (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->qxfer_osdata == NULL || writebuf != NULL) + return -2; + + return (*the_target->qxfer_osdata) (annex, readbuf, NULL, offset, len); +} + +/* Handle qXfer:siginfo:read and qXfer:siginfo:write. */ + +static int +handle_qxfer_siginfo (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->qxfer_siginfo == NULL) + return -2; + + if (annex[0] != '\0' || current_thread == NULL) + return -1; + + return (*the_target->qxfer_siginfo) (annex, readbuf, writebuf, offset, len); +} + +/* Handle qXfer:statictrace:read. */ + +static int +handle_qxfer_statictrace (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + client_state &cs = get_client_state (); + ULONGEST nbytes; + + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0' || current_thread == NULL + || cs.current_traceframe == -1) + return -1; + + if (traceframe_read_sdata (cs.current_traceframe, offset, + readbuf, len, &nbytes)) + return -1; + return nbytes; +} + +/* Helper for handle_qxfer_threads_proper. + Emit the XML to describe the thread of INF. */ + +static void +handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer) +{ + ptid_t ptid = ptid_of (thread); + char ptid_s[100]; + int core = target_core_of_thread (ptid); + char core_s[21]; + const char *name = target_thread_name (ptid); + int handle_len; + gdb_byte *handle; + bool handle_status = target_thread_handle (ptid, &handle, &handle_len); + + write_ptid (ptid_s, ptid); + + buffer_xml_printf (buffer, "\n"); +} + +/* Helper for handle_qxfer_threads. */ + +static void +handle_qxfer_threads_proper (struct buffer *buffer) +{ + buffer_grow_str (buffer, "\n"); + + for_each_thread ([&] (thread_info *thread) + { + handle_qxfer_threads_worker (thread, buffer); + }); + + buffer_grow_str0 (buffer, "\n"); +} + +/* Handle qXfer:threads:read. */ + +static int +handle_qxfer_threads (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + static char *result = 0; + static unsigned int result_length = 0; + + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0') + return -1; + + if (offset == 0) + { + struct buffer buffer; + /* When asked for data at offset 0, generate everything and store into + 'result'. Successive reads will be served off 'result'. */ + if (result) + free (result); + + buffer_init (&buffer); + + handle_qxfer_threads_proper (&buffer); + + result = buffer_finish (&buffer); + result_length = strlen (result); + buffer_free (&buffer); + } + + if (offset >= result_length) + { + /* We're out of data. */ + free (result); + result = NULL; + result_length = 0; + return 0; + } + + if (len > result_length - offset) + len = result_length - offset; + + memcpy (readbuf, result + offset, len); + + return len; +} + +/* Handle qXfer:traceframe-info:read. */ + +static int +handle_qxfer_traceframe_info (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + client_state &cs = get_client_state (); + static char *result = 0; + static unsigned int result_length = 0; + + if (writebuf != NULL) + return -2; + + if (!target_running () || annex[0] != '\0' || cs.current_traceframe == -1) + return -1; + + if (offset == 0) + { + struct buffer buffer; + + /* When asked for data at offset 0, generate everything and + store into 'result'. Successive reads will be served off + 'result'. */ + free (result); + + buffer_init (&buffer); + + traceframe_read_info (cs.current_traceframe, &buffer); + + result = buffer_finish (&buffer); + result_length = strlen (result); + buffer_free (&buffer); + } + + if (offset >= result_length) + { + /* We're out of data. */ + free (result); + result = NULL; + result_length = 0; + return 0; + } + + if (len > result_length - offset) + len = result_length - offset; + + memcpy (readbuf, result + offset, len); + return len; +} + +/* Handle qXfer:fdpic:read. */ + +static int +handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +{ + if (the_target->read_loadmap == NULL) + return -2; + + if (current_thread == NULL) + return -1; + + return (*the_target->read_loadmap) (annex, offset, readbuf, len); +} + +/* Handle qXfer:btrace:read. */ + +static int +handle_qxfer_btrace (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + client_state &cs = get_client_state (); + static struct buffer cache; + struct thread_info *thread; + enum btrace_read_type type; + int result; + + if (writebuf != NULL) + return -2; + + if (cs.general_thread == null_ptid + || cs.general_thread == minus_one_ptid) + { + strcpy (cs.own_buf, "E.Must select a single thread."); + return -3; + } + + thread = find_thread_ptid (cs.general_thread); + if (thread == NULL) + { + strcpy (cs.own_buf, "E.No such thread."); + return -3; + } + + if (thread->btrace == NULL) + { + strcpy (cs.own_buf, "E.Btrace not enabled."); + return -3; + } + + if (strcmp (annex, "all") == 0) + type = BTRACE_READ_ALL; + else if (strcmp (annex, "new") == 0) + type = BTRACE_READ_NEW; + else if (strcmp (annex, "delta") == 0) + type = BTRACE_READ_DELTA; + else + { + strcpy (cs.own_buf, "E.Bad annex."); + return -3; + } + + if (offset == 0) + { + buffer_free (&cache); + + try + { + result = target_read_btrace (thread->btrace, &cache, type); + if (result != 0) + memcpy (cs.own_buf, cache.buffer, cache.used_size); + } + catch (const gdb_exception_error &exception) + { + sprintf (cs.own_buf, "E.%s", exception.what ()); + result = -1; + } + + if (result != 0) + return -3; + } + else if (offset > cache.used_size) + { + buffer_free (&cache); + return -3; + } + + if (len > cache.used_size - offset) + len = cache.used_size - offset; + + memcpy (readbuf, cache.buffer + offset, len); + + return len; +} + +/* Handle qXfer:btrace-conf:read. */ + +static int +handle_qxfer_btrace_conf (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + client_state &cs = get_client_state (); + static struct buffer cache; + struct thread_info *thread; + int result; + + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0') + return -1; + + if (cs.general_thread == null_ptid + || cs.general_thread == minus_one_ptid) + { + strcpy (cs.own_buf, "E.Must select a single thread."); + return -3; + } + + thread = find_thread_ptid (cs.general_thread); + if (thread == NULL) + { + strcpy (cs.own_buf, "E.No such thread."); + return -3; + } + + if (thread->btrace == NULL) + { + strcpy (cs.own_buf, "E.Btrace not enabled."); + return -3; + } + + if (offset == 0) + { + buffer_free (&cache); + + try + { + result = target_read_btrace_conf (thread->btrace, &cache); + if (result != 0) + memcpy (cs.own_buf, cache.buffer, cache.used_size); + } + catch (const gdb_exception_error &exception) + { + sprintf (cs.own_buf, "E.%s", exception.what ()); + result = -1; + } + + if (result != 0) + return -3; + } + else if (offset > cache.used_size) + { + buffer_free (&cache); + return -3; + } + + if (len > cache.used_size - offset) + len = cache.used_size - offset; + + memcpy (readbuf, cache.buffer + offset, len); + + return len; +} + +static const struct qxfer qxfer_packets[] = + { + { "auxv", handle_qxfer_auxv }, + { "btrace", handle_qxfer_btrace }, + { "btrace-conf", handle_qxfer_btrace_conf }, + { "exec-file", handle_qxfer_exec_file}, + { "fdpic", handle_qxfer_fdpic}, + { "features", handle_qxfer_features }, + { "libraries", handle_qxfer_libraries }, + { "libraries-svr4", handle_qxfer_libraries_svr4 }, + { "osdata", handle_qxfer_osdata }, + { "siginfo", handle_qxfer_siginfo }, + { "statictrace", handle_qxfer_statictrace }, + { "threads", handle_qxfer_threads }, + { "traceframe-info", handle_qxfer_traceframe_info }, + }; + +static int +handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p) +{ + int i; + char *object; + char *rw; + char *annex; + char *offset; + + if (!startswith (own_buf, "qXfer:")) + return 0; + + /* Grab the object, r/w and annex. */ + if (decode_xfer (own_buf + 6, &object, &rw, &annex, &offset) < 0) + { + write_enn (own_buf); + return 1; + } + + for (i = 0; + i < sizeof (qxfer_packets) / sizeof (qxfer_packets[0]); + i++) + { + const struct qxfer *q = &qxfer_packets[i]; + + if (strcmp (object, q->object) == 0) + { + if (strcmp (rw, "read") == 0) + { + unsigned char *data; + int n; + CORE_ADDR ofs; + unsigned int len; + + /* Grab the offset and length. */ + if (decode_xfer_read (offset, &ofs, &len) < 0) + { + write_enn (own_buf); + return 1; + } + + /* Read one extra byte, as an indicator of whether there is + more. */ + if (len > PBUFSIZ - 2) + len = PBUFSIZ - 2; + data = (unsigned char *) malloc (len + 1); + if (data == NULL) + { + write_enn (own_buf); + return 1; + } + n = (*q->xfer) (annex, data, NULL, ofs, len + 1); + if (n == -2) + { + free (data); + return 0; + } + else if (n == -3) + { + /* Preserve error message. */ + } + else if (n < 0) + write_enn (own_buf); + else if (n > len) + *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); + else + *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); + + free (data); + return 1; + } + else if (strcmp (rw, "write") == 0) + { + int n; + unsigned int len; + CORE_ADDR ofs; + unsigned char *data; + + strcpy (own_buf, "E00"); + data = (unsigned char *) malloc (packet_len - (offset - own_buf)); + if (data == NULL) + { + write_enn (own_buf); + return 1; + } + if (decode_xfer_write (offset, packet_len - (offset - own_buf), + &ofs, &len, data) < 0) + { + free (data); + write_enn (own_buf); + return 1; + } + + n = (*q->xfer) (annex, NULL, data, ofs, len); + if (n == -2) + { + free (data); + return 0; + } + else if (n == -3) + { + /* Preserve error message. */ + } + else if (n < 0) + write_enn (own_buf); + else + sprintf (own_buf, "%x", n); + + free (data); + return 1; + } + + return 0; + } + } + + return 0; +} + +/* Compute 32 bit CRC from inferior memory. + + On success, return 32 bit CRC. + On failure, return (unsigned long long) -1. */ + +static unsigned long long +crc32 (CORE_ADDR base, int len, unsigned int crc) +{ + while (len--) + { + unsigned char byte = 0; + + /* Return failure if memory read fails. */ + if (read_inferior_memory (base, &byte, 1) != 0) + return (unsigned long long) -1; + + crc = xcrc32 (&byte, 1, crc); + base++; + } + return (unsigned long long) crc; +} + +/* Add supported btrace packets to BUF. */ + +static void +supported_btrace_packets (char *buf) +{ + strcat (buf, ";Qbtrace:bts+"); + strcat (buf, ";Qbtrace-conf:bts:size+"); + strcat (buf, ";Qbtrace:pt+"); + strcat (buf, ";Qbtrace-conf:pt:size+"); + strcat (buf, ";Qbtrace:off+"); + strcat (buf, ";qXfer:btrace:read+"); + strcat (buf, ";qXfer:btrace-conf:read+"); +} + +/* Handle all of the extended 'q' packets. */ + +static void +handle_query (char *own_buf, int packet_len, int *new_packet_len_p) +{ + client_state &cs = get_client_state (); + static std::list::const_iterator thread_iter; + + /* Reply the current thread id. */ + if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC) + { + ptid_t ptid; + require_running_or_return (own_buf); + + if (cs.general_thread != null_ptid && cs.general_thread != minus_one_ptid) + ptid = cs.general_thread; + else + { + thread_iter = all_threads.begin (); + ptid = (*thread_iter)->id; + } + + sprintf (own_buf, "QC"); + own_buf += 2; + write_ptid (own_buf, ptid); + return; + } + + if (strcmp ("qSymbol::", own_buf) == 0) + { + struct thread_info *save_thread = current_thread; + + /* For qSymbol, GDB only changes the current thread if the + previous current thread was of a different process. So if + the previous thread is gone, we need to pick another one of + the same process. This can happen e.g., if we followed an + exec in a non-leader thread. */ + if (current_thread == NULL) + { + current_thread + = find_any_thread_of_pid (cs.general_thread.pid ()); + + /* Just in case, if we didn't find a thread, then bail out + instead of crashing. */ + if (current_thread == NULL) + { + write_enn (own_buf); + current_thread = save_thread; + return; + } + } + + /* GDB is suggesting new symbols have been loaded. This may + mean a new shared library has been detected as loaded, so + take the opportunity to check if breakpoints we think are + inserted, still are. Note that it isn't guaranteed that + we'll see this when a shared library is loaded, and nor will + we see this for unloads (although breakpoints in unloaded + libraries shouldn't trigger), as GDB may not find symbols for + the library at all. We also re-validate breakpoints when we + see a second GDB breakpoint for the same address, and or when + we access breakpoint shadows. */ + validate_breakpoints (); + + if (target_supports_tracepoints ()) + tracepoint_look_up_symbols (); + + if (current_thread != NULL && the_target->look_up_symbols != NULL) + (*the_target->look_up_symbols) (); + + current_thread = save_thread; + + strcpy (own_buf, "OK"); + return; + } + + if (!disable_packet_qfThreadInfo) + { + if (strcmp ("qfThreadInfo", own_buf) == 0) + { + require_running_or_return (own_buf); + thread_iter = all_threads.begin (); + + *own_buf++ = 'm'; + ptid_t ptid = (*thread_iter)->id; + write_ptid (own_buf, ptid); + thread_iter++; + return; + } + + if (strcmp ("qsThreadInfo", own_buf) == 0) + { + require_running_or_return (own_buf); + if (thread_iter != all_threads.end ()) + { + *own_buf++ = 'm'; + ptid_t ptid = (*thread_iter)->id; + write_ptid (own_buf, ptid); + thread_iter++; + return; + } + else + { + sprintf (own_buf, "l"); + return; + } + } + } + + if (the_target->read_offsets != NULL + && strcmp ("qOffsets", own_buf) == 0) + { + CORE_ADDR text, data; + + require_running_or_return (own_buf); + if (the_target->read_offsets (&text, &data)) + sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX", + (long)text, (long)data, (long)data); + else + write_enn (own_buf); + + return; + } + + /* Protocol features query. */ + if (startswith (own_buf, "qSupported") + && (own_buf[10] == ':' || own_buf[10] == '\0')) + { + char *p = &own_buf[10]; + int gdb_supports_qRelocInsn = 0; + + /* Process each feature being provided by GDB. The first + feature will follow a ':', and latter features will follow + ';'. */ + if (*p == ':') + { + char **qsupported = NULL; + int count = 0; + int unknown = 0; + int i; + + /* Two passes, to avoid nested strtok calls in + target_process_qsupported. */ + char *saveptr; + for (p = strtok_r (p + 1, ";", &saveptr); + p != NULL; + p = strtok_r (NULL, ";", &saveptr)) + { + count++; + qsupported = XRESIZEVEC (char *, qsupported, count); + qsupported[count - 1] = xstrdup (p); + } + + for (i = 0; i < count; i++) + { + p = qsupported[i]; + if (strcmp (p, "multiprocess+") == 0) + { + /* GDB supports and wants multi-process support if + possible. */ + if (target_supports_multi_process ()) + cs.multi_process = 1; + } + else if (strcmp (p, "qRelocInsn+") == 0) + { + /* GDB supports relocate instruction requests. */ + gdb_supports_qRelocInsn = 1; + } + else if (strcmp (p, "swbreak+") == 0) + { + /* GDB wants us to report whether a trap is caused + by a software breakpoint and for us to handle PC + adjustment if necessary on this target. */ + if (target_supports_stopped_by_sw_breakpoint ()) + cs.swbreak_feature = 1; + } + else if (strcmp (p, "hwbreak+") == 0) + { + /* GDB wants us to report whether a trap is caused + by a hardware breakpoint. */ + if (target_supports_stopped_by_hw_breakpoint ()) + cs.hwbreak_feature = 1; + } + else if (strcmp (p, "fork-events+") == 0) + { + /* GDB supports and wants fork events if possible. */ + if (target_supports_fork_events ()) + cs.report_fork_events = 1; + } + else if (strcmp (p, "vfork-events+") == 0) + { + /* GDB supports and wants vfork events if possible. */ + if (target_supports_vfork_events ()) + cs.report_vfork_events = 1; + } + else if (strcmp (p, "exec-events+") == 0) + { + /* GDB supports and wants exec events if possible. */ + if (target_supports_exec_events ()) + cs.report_exec_events = 1; + } + else if (strcmp (p, "vContSupported+") == 0) + cs.vCont_supported = 1; + else if (strcmp (p, "QThreadEvents+") == 0) + ; + else if (strcmp (p, "no-resumed+") == 0) + { + /* GDB supports and wants TARGET_WAITKIND_NO_RESUMED + events. */ + report_no_resumed = true; + } + else + { + /* Move the unknown features all together. */ + qsupported[i] = NULL; + qsupported[unknown] = p; + unknown++; + } + } + + /* Give the target backend a chance to process the unknown + features. */ + target_process_qsupported (qsupported, unknown); + + for (i = 0; i < count; i++) + free (qsupported[i]); + free (qsupported); + } + + sprintf (own_buf, + "PacketSize=%x;QPassSignals+;QProgramSignals+;" + "QStartupWithShell+;QEnvironmentHexEncoded+;" + "QEnvironmentReset+;QEnvironmentUnset+;" + "QSetWorkingDir+", + PBUFSIZ - 1); + + if (target_supports_catch_syscall ()) + strcat (own_buf, ";QCatchSyscalls+"); + + if (the_target->qxfer_libraries_svr4 != NULL) + strcat (own_buf, ";qXfer:libraries-svr4:read+" + ";augmented-libraries-svr4-read+"); + else + { + /* We do not have any hook to indicate whether the non-SVR4 target + backend supports qXfer:libraries:read, so always report it. */ + strcat (own_buf, ";qXfer:libraries:read+"); + } + + if (the_target->read_auxv != NULL) + strcat (own_buf, ";qXfer:auxv:read+"); + + if (the_target->qxfer_siginfo != NULL) + strcat (own_buf, ";qXfer:siginfo:read+;qXfer:siginfo:write+"); + + if (the_target->read_loadmap != NULL) + strcat (own_buf, ";qXfer:fdpic:read+"); + + /* We always report qXfer:features:read, as targets may + install XML files on a subsequent call to arch_setup. + If we reported to GDB on startup that we don't support + qXfer:feature:read at all, we will never be re-queried. */ + strcat (own_buf, ";qXfer:features:read+"); + + if (cs.transport_is_reliable) + strcat (own_buf, ";QStartNoAckMode+"); + + if (the_target->qxfer_osdata != NULL) + strcat (own_buf, ";qXfer:osdata:read+"); + + if (target_supports_multi_process ()) + strcat (own_buf, ";multiprocess+"); + + if (target_supports_fork_events ()) + strcat (own_buf, ";fork-events+"); + + if (target_supports_vfork_events ()) + strcat (own_buf, ";vfork-events+"); + + if (target_supports_exec_events ()) + strcat (own_buf, ";exec-events+"); + + if (target_supports_non_stop ()) + strcat (own_buf, ";QNonStop+"); + + if (target_supports_disable_randomization ()) + strcat (own_buf, ";QDisableRandomization+"); + + strcat (own_buf, ";qXfer:threads:read+"); + + if (target_supports_tracepoints ()) + { + strcat (own_buf, ";ConditionalTracepoints+"); + strcat (own_buf, ";TraceStateVariables+"); + strcat (own_buf, ";TracepointSource+"); + strcat (own_buf, ";DisconnectedTracing+"); + if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ()) + strcat (own_buf, ";FastTracepoints+"); + strcat (own_buf, ";StaticTracepoints+"); + strcat (own_buf, ";InstallInTrace+"); + strcat (own_buf, ";qXfer:statictrace:read+"); + strcat (own_buf, ";qXfer:traceframe-info:read+"); + strcat (own_buf, ";EnableDisableTracepoints+"); + strcat (own_buf, ";QTBuffer:size+"); + strcat (own_buf, ";tracenz+"); + } + + if (target_supports_hardware_single_step () + || target_supports_software_single_step () ) + { + strcat (own_buf, ";ConditionalBreakpoints+"); + } + strcat (own_buf, ";BreakpointCommands+"); + + if (target_supports_agent ()) + strcat (own_buf, ";QAgent+"); + + supported_btrace_packets (own_buf); + + if (target_supports_stopped_by_sw_breakpoint ()) + strcat (own_buf, ";swbreak+"); + + if (target_supports_stopped_by_hw_breakpoint ()) + strcat (own_buf, ";hwbreak+"); + + if (the_target->pid_to_exec_file != NULL) + strcat (own_buf, ";qXfer:exec-file:read+"); + + strcat (own_buf, ";vContSupported+"); + + strcat (own_buf, ";QThreadEvents+"); + + strcat (own_buf, ";no-resumed+"); + + /* Reinitialize components as needed for the new connection. */ + hostio_handle_new_gdb_connection (); + target_handle_new_gdb_connection (); + + return; + } + + /* Thread-local storage support. */ + if (the_target->get_tls_address != NULL + && startswith (own_buf, "qGetTLSAddr:")) + { + char *p = own_buf + 12; + CORE_ADDR parts[2], address = 0; + int i, err; + ptid_t ptid = null_ptid; + + require_running_or_return (own_buf); + + for (i = 0; i < 3; i++) + { + char *p2; + int len; + + if (p == NULL) + break; + + p2 = strchr (p, ','); + if (p2) + { + len = p2 - p; + p2++; + } + else + { + len = strlen (p); + p2 = NULL; + } + + if (i == 0) + ptid = read_ptid (p, NULL); + else + decode_address (&parts[i - 1], p, len); + p = p2; + } + + if (p != NULL || i < 3) + err = 1; + else + { + struct thread_info *thread = find_thread_ptid (ptid); + + if (thread == NULL) + err = 2; + else + err = the_target->get_tls_address (thread, parts[0], parts[1], + &address); + } + + if (err == 0) + { + strcpy (own_buf, paddress(address)); + return; + } + else if (err > 0) + { + write_enn (own_buf); + return; + } + + /* Otherwise, pretend we do not understand this packet. */ + } + + /* Windows OS Thread Information Block address support. */ + if (the_target->get_tib_address != NULL + && startswith (own_buf, "qGetTIBAddr:")) + { + const char *annex; + int n; + CORE_ADDR tlb; + ptid_t ptid = read_ptid (own_buf + 12, &annex); + + n = (*the_target->get_tib_address) (ptid, &tlb); + if (n == 1) + { + strcpy (own_buf, paddress(tlb)); + return; + } + else if (n == 0) + { + write_enn (own_buf); + return; + } + return; + } + + /* Handle "monitor" commands. */ + if (startswith (own_buf, "qRcmd,")) + { + char *mon = (char *) malloc (PBUFSIZ); + int len = strlen (own_buf + 6); + + if (mon == NULL) + { + write_enn (own_buf); + return; + } + + if ((len % 2) != 0 + || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2) + { + write_enn (own_buf); + free (mon); + return; + } + mon[len / 2] = '\0'; + + write_ok (own_buf); + + if (the_target->handle_monitor_command == NULL + || (*the_target->handle_monitor_command) (mon) == 0) + /* Default processing. */ + handle_monitor_command (mon, own_buf); + + free (mon); + return; + } + + if (startswith (own_buf, "qSearch:memory:")) + { + require_running_or_return (own_buf); + handle_search_memory (own_buf, packet_len); + return; + } + + if (strcmp (own_buf, "qAttached") == 0 + || startswith (own_buf, "qAttached:")) + { + struct process_info *process; + + if (own_buf[sizeof ("qAttached") - 1]) + { + int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16); + process = find_process_pid (pid); + } + else + { + require_running_or_return (own_buf); + process = current_process (); + } + + if (process == NULL) + { + write_enn (own_buf); + return; + } + + strcpy (own_buf, process->attached ? "1" : "0"); + return; + } + + if (startswith (own_buf, "qCRC:")) + { + /* CRC check (compare-section). */ + const char *comma; + ULONGEST base; + int len; + unsigned long long crc; + + require_running_or_return (own_buf); + comma = unpack_varlen_hex (own_buf + 5, &base); + if (*comma++ != ',') + { + write_enn (own_buf); + return; + } + len = strtoul (comma, NULL, 16); + crc = crc32 (base, len, 0xffffffff); + /* Check for memory failure. */ + if (crc == (unsigned long long) -1) + { + write_enn (own_buf); + return; + } + sprintf (own_buf, "C%lx", (unsigned long) crc); + return; + } + + if (handle_qxfer (own_buf, packet_len, new_packet_len_p)) + return; + + if (target_supports_tracepoints () && handle_tracepoint_query (own_buf)) + return; + + /* Otherwise we didn't know what packet it was. Say we didn't + understand it. */ + own_buf[0] = 0; +} + +static void gdb_wants_all_threads_stopped (void); +static void resume (struct thread_resume *actions, size_t n); + +/* The callback that is passed to visit_actioned_threads. */ +typedef int (visit_actioned_threads_callback_ftype) + (const struct thread_resume *, struct thread_info *); + +/* Call CALLBACK for any thread to which ACTIONS applies to. Returns + true if CALLBACK returns true. Returns false if no matching thread + is found or CALLBACK results false. + Note: This function is itself a callback for find_thread. */ + +static bool +visit_actioned_threads (thread_info *thread, + const struct thread_resume *actions, + size_t num_actions, + visit_actioned_threads_callback_ftype *callback) +{ + for (size_t i = 0; i < num_actions; i++) + { + const struct thread_resume *action = &actions[i]; + + if (action->thread == minus_one_ptid + || action->thread == thread->id + || ((action->thread.pid () + == thread->id.pid ()) + && action->thread.lwp () == -1)) + { + if ((*callback) (action, thread)) + return true; + } + } + + return false; +} + +/* Callback for visit_actioned_threads. If the thread has a pending + status to report, report it now. */ + +static int +handle_pending_status (const struct thread_resume *resumption, + struct thread_info *thread) +{ + client_state &cs = get_client_state (); + if (thread->status_pending_p) + { + thread->status_pending_p = 0; + + cs.last_status = thread->last_status; + cs.last_ptid = thread->id; + prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status); + return 1; + } + return 0; +} + +/* Parse vCont packets. */ +static void +handle_v_cont (char *own_buf) +{ + const char *p; + int n = 0, i = 0; + struct thread_resume *resume_info; + struct thread_resume default_action { null_ptid }; + + /* Count the number of semicolons in the packet. There should be one + for every action. */ + p = &own_buf[5]; + while (p) + { + n++; + p++; + p = strchr (p, ';'); + } + + resume_info = (struct thread_resume *) malloc (n * sizeof (resume_info[0])); + if (resume_info == NULL) + goto err; + + p = &own_buf[5]; + while (*p) + { + p++; + + memset (&resume_info[i], 0, sizeof resume_info[i]); + + if (p[0] == 's' || p[0] == 'S') + resume_info[i].kind = resume_step; + else if (p[0] == 'r') + resume_info[i].kind = resume_step; + else if (p[0] == 'c' || p[0] == 'C') + resume_info[i].kind = resume_continue; + else if (p[0] == 't') + resume_info[i].kind = resume_stop; + else + goto err; + + if (p[0] == 'S' || p[0] == 'C') + { + char *q; + int sig = strtol (p + 1, &q, 16); + if (p == q) + goto err; + p = q; + + if (!gdb_signal_to_host_p ((enum gdb_signal) sig)) + goto err; + resume_info[i].sig = gdb_signal_to_host ((enum gdb_signal) sig); + } + else if (p[0] == 'r') + { + ULONGEST addr; + + p = unpack_varlen_hex (p + 1, &addr); + resume_info[i].step_range_start = addr; + + if (*p != ',') + goto err; + + p = unpack_varlen_hex (p + 1, &addr); + resume_info[i].step_range_end = addr; + } + else + { + p = p + 1; + } + + if (p[0] == 0) + { + resume_info[i].thread = minus_one_ptid; + default_action = resume_info[i]; + + /* Note: we don't increment i here, we'll overwrite this entry + the next time through. */ + } + else if (p[0] == ':') + { + const char *q; + ptid_t ptid = read_ptid (p + 1, &q); + + if (p == q) + goto err; + p = q; + if (p[0] != ';' && p[0] != 0) + goto err; + + resume_info[i].thread = ptid; + + i++; + } + } + + if (i < n) + resume_info[i] = default_action; + + resume (resume_info, n); + free (resume_info); + return; + +err: + write_enn (own_buf); + free (resume_info); + return; +} + +/* Resume target with ACTIONS, an array of NUM_ACTIONS elements. */ + +static void +resume (struct thread_resume *actions, size_t num_actions) +{ + client_state &cs = get_client_state (); + if (!non_stop) + { + /* Check if among the threads that GDB wants actioned, there's + one with a pending status to report. If so, skip actually + resuming/stopping and report the pending event + immediately. */ + + thread_info *thread_with_status = find_thread ([&] (thread_info *thread) + { + return visit_actioned_threads (thread, actions, num_actions, + handle_pending_status); + }); + + if (thread_with_status != NULL) + return; + + enable_async_io (); + } + + (*the_target->resume) (actions, num_actions); + + if (non_stop) + write_ok (cs.own_buf); + else + { + cs.last_ptid = mywait (minus_one_ptid, &cs.last_status, 0, 1); + + if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED + && !report_no_resumed) + { + /* The client does not support this stop reply. At least + return error. */ + sprintf (cs.own_buf, "E.No unwaited-for children left."); + disable_async_io (); + return; + } + + if (cs.last_status.kind != TARGET_WAITKIND_EXITED + && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED + && cs.last_status.kind != TARGET_WAITKIND_NO_RESUMED) + current_thread->last_status = cs.last_status; + + /* From the client's perspective, all-stop mode always stops all + threads implicitly (and the target backend has already done + so by now). Tag all threads as "want-stopped", so we don't + resume them implicitly without the client telling us to. */ + gdb_wants_all_threads_stopped (); + prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status); + disable_async_io (); + + if (cs.last_status.kind == TARGET_WAITKIND_EXITED + || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED) + target_mourn_inferior (cs.last_ptid); + } +} + +/* Attach to a new program. Return 1 if successful, 0 if failure. */ +static int +handle_v_attach (char *own_buf) +{ + client_state &cs = get_client_state (); + int pid; + + pid = strtol (own_buf + 8, NULL, 16); + if (pid != 0 && attach_inferior (pid) == 0) + { + /* Don't report shared library events after attaching, even if + some libraries are preloaded. GDB will always poll the + library list. Avoids the "stopped by shared library event" + notice on the GDB side. */ + dlls_changed = 0; + + if (non_stop) + { + /* In non-stop, we don't send a resume reply. Stop events + will follow up using the normal notification + mechanism. */ + write_ok (own_buf); + } + else + prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status); + + return 1; + } + else + { + write_enn (own_buf); + return 0; + } +} + +/* Run a new program. Return 1 if successful, 0 if failure. */ +static int +handle_v_run (char *own_buf) +{ + client_state &cs = get_client_state (); + char *p, *next_p; + std::vector new_argv; + char *new_program_name = NULL; + int i, new_argc; + + new_argc = 0; + for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';')) + { + p++; + new_argc++; + } + + for (i = 0, p = own_buf + strlen ("vRun;"); *p; p = next_p, ++i) + { + next_p = strchr (p, ';'); + if (next_p == NULL) + next_p = p + strlen (p); + + if (i == 0 && p == next_p) + { + /* No program specified. */ + new_program_name = NULL; + } + else if (p == next_p) + { + /* Empty argument. */ + new_argv.push_back (xstrdup ("''")); + } + else + { + size_t len = (next_p - p) / 2; + /* ARG is the unquoted argument received via the RSP. */ + char *arg = (char *) xmalloc (len + 1); + /* FULL_ARGS will contain the quoted version of ARG. */ + char *full_arg = (char *) xmalloc ((len + 1) * 2); + /* These are pointers used to navigate the strings above. */ + char *tmp_arg = arg; + char *tmp_full_arg = full_arg; + int need_quote = 0; + + hex2bin (p, (gdb_byte *) arg, len); + arg[len] = '\0'; + + while (*tmp_arg != '\0') + { + switch (*tmp_arg) + { + case '\n': + /* Quote \n. */ + *tmp_full_arg = '\''; + ++tmp_full_arg; + need_quote = 1; + break; + + case '\'': + /* Quote single quote. */ + *tmp_full_arg = '\\'; + ++tmp_full_arg; + break; + + default: + break; + } + + *tmp_full_arg = *tmp_arg; + ++tmp_full_arg; + ++tmp_arg; + } + + if (need_quote) + *tmp_full_arg++ = '\''; + + /* Finish FULL_ARG and push it into the vector containing + the argv. */ + *tmp_full_arg = '\0'; + if (i == 0) + new_program_name = full_arg; + else + new_argv.push_back (full_arg); + xfree (arg); + } + if (*next_p) + next_p++; + } + new_argv.push_back (NULL); + + if (new_program_name == NULL) + { + /* GDB didn't specify a program to run. Use the program from the + last run with the new argument list. */ + if (program_path.get () == NULL) + { + write_enn (own_buf); + free_vector_argv (new_argv); + return 0; + } + } + else + program_path.set (gdb::unique_xmalloc_ptr (new_program_name)); + + /* Free the old argv and install the new one. */ + free_vector_argv (program_args); + program_args = new_argv; + + create_inferior (program_path.get (), program_args); + + if (cs.last_status.kind == TARGET_WAITKIND_STOPPED) + { + prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status); + + /* In non-stop, sending a resume reply doesn't set the general + thread, but GDB assumes a vRun sets it (this is so GDB can + query which is the main thread of the new inferior. */ + if (non_stop) + cs.general_thread = cs.last_ptid; + + return 1; + } + else + { + write_enn (own_buf); + return 0; + } +} + +/* Kill process. Return 1 if successful, 0 if failure. */ +static int +handle_v_kill (char *own_buf) +{ + client_state &cs = get_client_state (); + int pid; + char *p = &own_buf[6]; + if (cs.multi_process) + pid = strtol (p, NULL, 16); + else + pid = signal_pid; + + process_info *proc = find_process_pid (pid); + + if (proc != nullptr && kill_inferior (proc) == 0) + { + cs.last_status.kind = TARGET_WAITKIND_SIGNALLED; + cs.last_status.value.sig = GDB_SIGNAL_KILL; + cs.last_ptid = ptid_t (pid); + discard_queued_stop_replies (cs.last_ptid); + write_ok (own_buf); + return 1; + } + else + { + write_enn (own_buf); + return 0; + } +} + +/* Handle all of the extended 'v' packets. */ +void +handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) +{ + client_state &cs = get_client_state (); + if (!disable_packet_vCont) + { + if (strcmp (own_buf, "vCtrlC") == 0) + { + (*the_target->request_interrupt) (); + write_ok (own_buf); + return; + } + + if (startswith (own_buf, "vCont;")) + { + handle_v_cont (own_buf); + return; + } + + if (startswith (own_buf, "vCont?")) + { + strcpy (own_buf, "vCont;c;C;t"); + + if (target_supports_hardware_single_step () + || target_supports_software_single_step () + || !cs.vCont_supported) + { + /* If target supports single step either by hardware or by + software, add actions s and S to the list of supported + actions. On the other hand, if GDB doesn't request the + supported vCont actions in qSupported packet, add s and + S to the list too. */ + own_buf = own_buf + strlen (own_buf); + strcpy (own_buf, ";s;S"); + } + + if (target_supports_range_stepping ()) + { + own_buf = own_buf + strlen (own_buf); + strcpy (own_buf, ";r"); + } + return; + } + } + + if (startswith (own_buf, "vFile:") + && handle_vFile (own_buf, packet_len, new_packet_len)) + return; + + if (startswith (own_buf, "vAttach;")) + { + if ((!extended_protocol || !cs.multi_process) && target_running ()) + { + fprintf (stderr, "Already debugging a process\n"); + write_enn (own_buf); + return; + } + handle_v_attach (own_buf); + return; + } + + if (startswith (own_buf, "vRun;")) + { + if ((!extended_protocol || !cs.multi_process) && target_running ()) + { + fprintf (stderr, "Already debugging a process\n"); + write_enn (own_buf); + return; + } + handle_v_run (own_buf); + return; + } + + if (startswith (own_buf, "vKill;")) + { + if (!target_running ()) + { + fprintf (stderr, "No process to kill\n"); + write_enn (own_buf); + return; + } + handle_v_kill (own_buf); + return; + } + + if (handle_notif_ack (own_buf, packet_len)) + return; + + /* Otherwise we didn't know what packet it was. Say we didn't + understand it. */ + own_buf[0] = 0; + return; +} + +/* Resume thread and wait for another event. In non-stop mode, + don't really wait here, but return immediatelly to the event + loop. */ +static void +myresume (char *own_buf, int step, int sig) +{ + client_state &cs = get_client_state (); + struct thread_resume resume_info[2]; + int n = 0; + int valid_cont_thread; + + valid_cont_thread = (cs.cont_thread != null_ptid + && cs.cont_thread != minus_one_ptid); + + if (step || sig || valid_cont_thread) + { + resume_info[0].thread = current_ptid; + if (step) + resume_info[0].kind = resume_step; + else + resume_info[0].kind = resume_continue; + resume_info[0].sig = sig; + n++; + } + + if (!valid_cont_thread) + { + resume_info[n].thread = minus_one_ptid; + resume_info[n].kind = resume_continue; + resume_info[n].sig = 0; + n++; + } + + resume (resume_info, n); +} + +/* Callback for for_each_thread. Make a new stop reply for each + stopped thread. */ + +static void +queue_stop_reply_callback (thread_info *thread) +{ + /* For now, assume targets that don't have this callback also don't + manage the thread's last_status field. */ + if (the_target->thread_stopped == NULL) + { + struct vstop_notif *new_notif = new struct vstop_notif; + + new_notif->ptid = thread->id; + new_notif->status = thread->last_status; + /* Pass the last stop reply back to GDB, but don't notify + yet. */ + notif_event_enque (¬if_stop, new_notif); + } + else + { + if (thread_stopped (thread)) + { + if (debug_threads) + { + std::string status_string + = target_waitstatus_to_string (&thread->last_status); + + debug_printf ("Reporting thread %s as already stopped with %s\n", + target_pid_to_str (thread->id), + status_string.c_str ()); + } + + gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE); + + /* Pass the last stop reply back to GDB, but don't notify + yet. */ + queue_stop_reply (thread->id, &thread->last_status); + } + } +} + +/* Set this inferior threads's state as "want-stopped". We won't + resume this thread until the client gives us another action for + it. */ + +static void +gdb_wants_thread_stopped (thread_info *thread) +{ + thread->last_resume_kind = resume_stop; + + if (thread->last_status.kind == TARGET_WAITKIND_IGNORE) + { + /* Most threads are stopped implicitly (all-stop); tag that with + signal 0. */ + thread->last_status.kind = TARGET_WAITKIND_STOPPED; + thread->last_status.value.sig = GDB_SIGNAL_0; + } +} + +/* Set all threads' states as "want-stopped". */ + +static void +gdb_wants_all_threads_stopped (void) +{ + for_each_thread (gdb_wants_thread_stopped); +} + +/* Callback for for_each_thread. If the thread is stopped with an + interesting event, mark it as having a pending event. */ + +static void +set_pending_status_callback (thread_info *thread) +{ + if (thread->last_status.kind != TARGET_WAITKIND_STOPPED + || (thread->last_status.value.sig != GDB_SIGNAL_0 + /* A breakpoint, watchpoint or finished step from a previous + GDB run isn't considered interesting for a new GDB run. + If we left those pending, the new GDB could consider them + random SIGTRAPs. This leaves out real async traps. We'd + have to peek into the (target-specific) siginfo to + distinguish those. */ + && thread->last_status.value.sig != GDB_SIGNAL_TRAP)) + thread->status_pending_p = 1; +} + +/* Status handler for the '?' packet. */ + +static void +handle_status (char *own_buf) +{ + client_state &cs = get_client_state (); + + /* GDB is connected, don't forward events to the target anymore. */ + for_each_process ([] (process_info *process) { + process->gdb_detached = 0; + }); + + /* In non-stop mode, we must send a stop reply for each stopped + thread. In all-stop mode, just send one for the first stopped + thread we find. */ + + if (non_stop) + { + for_each_thread (queue_stop_reply_callback); + + /* The first is sent immediatly. OK is sent if there is no + stopped thread, which is the same handling of the vStopped + packet (by design). */ + notif_write_event (¬if_stop, cs.own_buf); + } + else + { + thread_info *thread = NULL; + + pause_all (0); + stabilize_threads (); + gdb_wants_all_threads_stopped (); + + /* We can only report one status, but we might be coming out of + non-stop -- if more than one thread is stopped with + interesting events, leave events for the threads we're not + reporting now pending. They'll be reported the next time the + threads are resumed. Start by marking all interesting events + as pending. */ + for_each_thread (set_pending_status_callback); + + /* Prefer the last thread that reported an event to GDB (even if + that was a GDB_SIGNAL_TRAP). */ + if (cs.last_status.kind != TARGET_WAITKIND_IGNORE + && cs.last_status.kind != TARGET_WAITKIND_EXITED + && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED) + thread = find_thread_ptid (cs.last_ptid); + + /* If the last event thread is not found for some reason, look + for some other thread that might have an event to report. */ + if (thread == NULL) + thread = find_thread ([] (thread_info *thr_arg) + { + return thr_arg->status_pending_p; + }); + + /* If we're still out of luck, simply pick the first thread in + the thread list. */ + if (thread == NULL) + thread = get_first_thread (); + + if (thread != NULL) + { + struct thread_info *tp = (struct thread_info *) thread; + + /* We're reporting this event, so it's no longer + pending. */ + tp->status_pending_p = 0; + + /* GDB assumes the current thread is the thread we're + reporting the status for. */ + cs.general_thread = thread->id; + set_desired_thread (); + + gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE); + prepare_resume_reply (own_buf, tp->id, &tp->last_status); + } + else + strcpy (own_buf, "W00"); + } +} + +static void +gdbserver_version (void) +{ + printf ("GNU gdbserver %s%s\n" + "Copyright (C) 2020 Free Software Foundation, Inc.\n" + "gdbserver is free software, covered by the " + "GNU General Public License.\n" + "This gdbserver was configured as \"%s\"\n", + PKGVERSION, version, host_name); +} + +static void +gdbserver_usage (FILE *stream) +{ + fprintf (stream, "Usage:\tgdbserver [OPTIONS] COMM PROG [ARGS ...]\n" + "\tgdbserver [OPTIONS] --attach COMM PID\n" + "\tgdbserver [OPTIONS] --multi COMM\n" + "\n" + "COMM may either be a tty device (for serial debugging),\n" + "HOST:PORT to listen for a TCP connection, or '-' or 'stdio' to use \n" + "stdin/stdout of gdbserver.\n" + "PROG is the executable program. ARGS are arguments passed to inferior.\n" + "PID is the process ID to attach to, when --attach is specified.\n" + "\n" + "Operating modes:\n" + "\n" + " --attach Attach to running process PID.\n" + " --multi Start server without a specific program, and\n" + " only quit when explicitly commanded.\n" + " --once Exit after the first connection has closed.\n" + " --help Print this message and then exit.\n" + " --version Display version information and exit.\n" + "\n" + "Other options:\n" + "\n" + " --wrapper WRAPPER -- Run WRAPPER to start new programs.\n" + " --disable-randomization\n" + " Run PROG with address space randomization disabled.\n" + " --no-disable-randomization\n" + " Don't disable address space randomization when\n" + " starting PROG.\n" + " --startup-with-shell\n" + " Start PROG using a shell. I.e., execs a shell that\n" + " then execs PROG. (default)\n" + " --no-startup-with-shell\n" + " Exec PROG directly instead of using a shell.\n" + " Disables argument globbing and variable substitution\n" + " on UNIX-like systems.\n" + "\n" + "Debug options:\n" + "\n" + " --debug Enable general debugging output.\n" + " --debug-format=OPT1[,OPT2,...]\n" + " Specify extra content in debugging output.\n" + " Options:\n" + " all\n" + " none\n" + " timestamp\n" + " --remote-debug Enable remote protocol debugging output.\n" + " --disable-packet=OPT1[,OPT2,...]\n" + " Disable support for RSP packets or features.\n" + " Options:\n" + " vCont, Tthread, qC, qfThreadInfo and \n" + " threads (disable all threading packets).\n" + "\n" + "For more information, consult the GDB manual (available as on-line \n" + "info or a printed manual).\n"); + if (REPORT_BUGS_TO[0] && stream == stdout) + fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO); +} + +static void +gdbserver_show_disableable (FILE *stream) +{ + fprintf (stream, "Disableable packets:\n" + " vCont \tAll vCont packets\n" + " qC \tQuerying the current thread\n" + " qfThreadInfo\tThread listing\n" + " Tthread \tPassing the thread specifier in the " + "T stop reply packet\n" + " threads \tAll of the above\n"); +} + +static void +kill_inferior_callback (process_info *process) +{ + kill_inferior (process); + discard_queued_stop_replies (ptid_t (process->pid)); +} + +/* Call this when exiting gdbserver with possible inferiors that need + to be killed or detached from. */ + +static void +detach_or_kill_for_exit (void) +{ + /* First print a list of the inferiors we will be killing/detaching. + This is to assist the user, for example, in case the inferior unexpectedly + dies after we exit: did we screw up or did the inferior exit on its own? + Having this info will save some head-scratching. */ + + if (have_started_inferiors_p ()) + { + fprintf (stderr, "Killing process(es):"); + + for_each_process ([] (process_info *process) { + if (!process->attached) + fprintf (stderr, " %d", process->pid); + }); + + fprintf (stderr, "\n"); + } + if (have_attached_inferiors_p ()) + { + fprintf (stderr, "Detaching process(es):"); + + for_each_process ([] (process_info *process) { + if (process->attached) + fprintf (stderr, " %d", process->pid); + }); + + fprintf (stderr, "\n"); + } + + /* Now we can kill or detach the inferiors. */ + for_each_process ([] (process_info *process) { + int pid = process->pid; + + if (process->attached) + detach_inferior (process); + else + kill_inferior (process); + + discard_queued_stop_replies (ptid_t (pid)); + }); +} + +/* Value that will be passed to exit(3) when gdbserver exits. */ +static int exit_code; + +/* Wrapper for detach_or_kill_for_exit that catches and prints + errors. */ + +static void +detach_or_kill_for_exit_cleanup () +{ + try + { + detach_or_kill_for_exit (); + } + catch (const gdb_exception &exception) + { + fflush (stdout); + fprintf (stderr, "Detach or kill failed: %s\n", + exception.what ()); + exit_code = 1; + } +} + +/* Main function. This is called by the real "main" function, + wrapped in a TRY_CATCH that handles any uncaught exceptions. */ + +static void ATTRIBUTE_NORETURN +captured_main (int argc, char *argv[]) +{ + int bad_attach; + int pid; + char *arg_end; + const char *port = NULL; + char **next_arg = &argv[1]; + volatile int multi_mode = 0; + volatile int attach = 0; + int was_running; + bool selftest = false; +#if GDB_SELF_TEST + const char *selftest_filter = NULL; +#endif + + current_directory = getcwd (NULL, 0); + client_state &cs = get_client_state (); + + if (current_directory == NULL) + { + error (_("Could not find current working directory: %s"), + safe_strerror (errno)); + } + + while (*next_arg != NULL && **next_arg == '-') + { + if (strcmp (*next_arg, "--version") == 0) + { + gdbserver_version (); + exit (0); + } + else if (strcmp (*next_arg, "--help") == 0) + { + gdbserver_usage (stdout); + exit (0); + } + else if (strcmp (*next_arg, "--attach") == 0) + attach = 1; + else if (strcmp (*next_arg, "--multi") == 0) + multi_mode = 1; + else if (strcmp (*next_arg, "--wrapper") == 0) + { + char **tmp; + + next_arg++; + + tmp = next_arg; + while (*next_arg != NULL && strcmp (*next_arg, "--") != 0) + { + wrapper_argv += *next_arg; + wrapper_argv += ' '; + next_arg++; + } + + if (!wrapper_argv.empty ()) + { + /* Erase the last whitespace. */ + wrapper_argv.erase (wrapper_argv.end () - 1); + } + + if (next_arg == tmp || *next_arg == NULL) + { + gdbserver_usage (stderr); + exit (1); + } + + /* Consume the "--". */ + *next_arg = NULL; + } + else if (strcmp (*next_arg, "--debug") == 0) + debug_threads = 1; + else if (startswith (*next_arg, "--debug-format=")) + { + std::string error_msg + = parse_debug_format_options ((*next_arg) + + sizeof ("--debug-format=") - 1, 0); + + if (!error_msg.empty ()) + { + fprintf (stderr, "%s", error_msg.c_str ()); + exit (1); + } + } + else if (strcmp (*next_arg, "--remote-debug") == 0) + remote_debug = 1; + else if (startswith (*next_arg, "--debug-file=")) + debug_set_output ((*next_arg) + sizeof ("--debug-file=") -1); + else if (strcmp (*next_arg, "--disable-packet") == 0) + { + gdbserver_show_disableable (stdout); + exit (0); + } + else if (startswith (*next_arg, "--disable-packet=")) + { + char *packets = *next_arg += sizeof ("--disable-packet=") - 1; + char *saveptr; + for (char *tok = strtok_r (packets, ",", &saveptr); + tok != NULL; + tok = strtok_r (NULL, ",", &saveptr)) + { + if (strcmp ("vCont", tok) == 0) + disable_packet_vCont = true; + else if (strcmp ("Tthread", tok) == 0) + disable_packet_Tthread = true; + else if (strcmp ("qC", tok) == 0) + disable_packet_qC = true; + else if (strcmp ("qfThreadInfo", tok) == 0) + disable_packet_qfThreadInfo = true; + else if (strcmp ("threads", tok) == 0) + { + disable_packet_vCont = true; + disable_packet_Tthread = true; + disable_packet_qC = true; + disable_packet_qfThreadInfo = true; + } + else + { + fprintf (stderr, "Don't know how to disable \"%s\".\n\n", + tok); + gdbserver_show_disableable (stderr); + exit (1); + } + } + } + else if (strcmp (*next_arg, "-") == 0) + { + /* "-" specifies a stdio connection and is a form of port + specification. */ + port = STDIO_CONNECTION_NAME; + next_arg++; + break; + } + else if (strcmp (*next_arg, "--disable-randomization") == 0) + cs.disable_randomization = 1; + else if (strcmp (*next_arg, "--no-disable-randomization") == 0) + cs.disable_randomization = 0; + else if (strcmp (*next_arg, "--startup-with-shell") == 0) + startup_with_shell = true; + else if (strcmp (*next_arg, "--no-startup-with-shell") == 0) + startup_with_shell = false; + else if (strcmp (*next_arg, "--once") == 0) + run_once = true; + else if (strcmp (*next_arg, "--selftest") == 0) + selftest = true; + else if (startswith (*next_arg, "--selftest=")) + { + selftest = true; +#if GDB_SELF_TEST + selftest_filter = *next_arg + strlen ("--selftest="); +#endif + } + else + { + fprintf (stderr, "Unknown argument: %s\n", *next_arg); + exit (1); + } + + next_arg++; + continue; + } + + if (port == NULL) + { + port = *next_arg; + next_arg++; + } + if ((port == NULL || (!attach && !multi_mode && *next_arg == NULL)) + && !selftest) + { + gdbserver_usage (stderr); + exit (1); + } + + /* Remember stdio descriptors. LISTEN_DESC must not be listed, it will be + opened by remote_prepare. */ + notice_open_fds (); + + save_original_signals_state (false); + + /* We need to know whether the remote connection is stdio before + starting the inferior. Inferiors created in this scenario have + stdin,stdout redirected. So do this here before we call + start_inferior. */ + if (port != NULL) + remote_prepare (port); + + bad_attach = 0; + pid = 0; + + /* --attach used to come after PORT, so allow it there for + compatibility. */ + if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0) + { + attach = 1; + next_arg++; + } + + if (attach + && (*next_arg == NULL + || (*next_arg)[0] == '\0' + || (pid = strtoul (*next_arg, &arg_end, 0)) == 0 + || *arg_end != '\0' + || next_arg[1] != NULL)) + bad_attach = 1; + + if (bad_attach) + { + gdbserver_usage (stderr); + exit (1); + } + + /* Gather information about the environment. */ + our_environ = gdb_environ::from_host_environ (); + + initialize_async_io (); + initialize_low (); + have_job_control (); + initialize_event_loop (); + if (target_supports_tracepoints ()) + initialize_tracepoint (); + + mem_buf = (unsigned char *) xmalloc (PBUFSIZ); + + if (selftest) + { +#if GDB_SELF_TEST + selftests::run_tests (selftest_filter); +#else + printf (_("Selftests have been disabled for this build.\n")); +#endif + throw_quit ("Quit"); + } + + if (pid == 0 && *next_arg != NULL) + { + int i, n; + + n = argc - (next_arg - argv); + program_path.set (make_unique_xstrdup (next_arg[0])); + for (i = 1; i < n; i++) + program_args.push_back (xstrdup (next_arg[i])); + program_args.push_back (NULL); + + /* Wait till we are at first instruction in program. */ + create_inferior (program_path.get (), program_args); + + /* We are now (hopefully) stopped at the first instruction of + the target process. This assumes that the target process was + successfully created. */ + } + else if (pid != 0) + { + if (attach_inferior (pid) == -1) + error ("Attaching not supported on this target"); + + /* Otherwise succeeded. */ + } + else + { + cs.last_status.kind = TARGET_WAITKIND_EXITED; + cs.last_status.value.integer = 0; + cs.last_ptid = minus_one_ptid; + } + + SCOPE_EXIT { detach_or_kill_for_exit_cleanup (); }; + + /* Don't report shared library events on the initial connection, + even if some libraries are preloaded. Avoids the "stopped by + shared library event" notice on gdb side. */ + dlls_changed = 0; + + if (cs.last_status.kind == TARGET_WAITKIND_EXITED + || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED) + was_running = 0; + else + was_running = 1; + + if (!was_running && !multi_mode) + error ("No program to debug"); + + while (1) + { + cs.noack_mode = 0; + cs.multi_process = 0; + cs.report_fork_events = 0; + cs.report_vfork_events = 0; + cs.report_exec_events = 0; + /* Be sure we're out of tfind mode. */ + cs.current_traceframe = -1; + cs.cont_thread = null_ptid; + cs.swbreak_feature = 0; + cs.hwbreak_feature = 0; + cs.vCont_supported = 0; + + remote_open (port); + + try + { + /* Wait for events. This will return when all event sources + are removed from the event loop. */ + start_event_loop (); + + /* If an exit was requested (using the "monitor exit" + command), terminate now. */ + if (exit_requested) + throw_quit ("Quit"); + + /* The only other way to get here is for getpkt to fail: + + - If --once was specified, we're done. + + - If not in extended-remote mode, and we're no longer + debugging anything, simply exit: GDB has disconnected + after processing the last process exit. + + - Otherwise, close the connection and reopen it at the + top of the loop. */ + if (run_once || (!extended_protocol && !target_running ())) + throw_quit ("Quit"); + + fprintf (stderr, + "Remote side has terminated connection. " + "GDBserver will reopen the connection.\n"); + + /* Get rid of any pending statuses. An eventual reconnection + (by the same GDB instance or another) will refresh all its + state from scratch. */ + discard_queued_stop_replies (minus_one_ptid); + for_each_thread ([] (thread_info *thread) + { + thread->status_pending_p = 0; + }); + + if (tracing) + { + if (disconnected_tracing) + { + /* Try to enable non-stop/async mode, so we we can + both wait for an async socket accept, and handle + async target events simultaneously. There's also + no point either in having the target always stop + all threads, when we're going to pass signals + down without informing GDB. */ + if (!non_stop) + { + if (start_non_stop (1)) + non_stop = 1; + + /* Detaching implicitly resumes all threads; + simply disconnecting does not. */ + } + } + else + { + fprintf (stderr, + "Disconnected tracing disabled; " + "stopping trace run.\n"); + stop_tracing (); + } + } + } + catch (const gdb_exception_error &exception) + { + fflush (stdout); + fprintf (stderr, "gdbserver: %s\n", exception.what ()); + + if (response_needed) + { + write_enn (cs.own_buf); + putpkt (cs.own_buf); + } + + if (run_once) + throw_quit ("Quit"); + } + } +} + +/* Main function. */ + +int +main (int argc, char *argv[]) +{ + + try + { + captured_main (argc, argv); + } + catch (const gdb_exception &exception) + { + if (exception.reason == RETURN_ERROR) + { + fflush (stdout); + fprintf (stderr, "%s\n", exception.what ()); + fprintf (stderr, "Exiting\n"); + exit_code = 1; + } + + exit (exit_code); + } + + gdb_assert_not_reached ("captured_main should never return"); +} + +/* Process options coming from Z packets for a breakpoint. PACKET is + the packet buffer. *PACKET is updated to point to the first char + after the last processed option. */ + +static void +process_point_options (struct gdb_breakpoint *bp, const char **packet) +{ + const char *dataptr = *packet; + int persist; + + /* Check if data has the correct format. */ + if (*dataptr != ';') + return; + + dataptr++; + + while (*dataptr) + { + if (*dataptr == ';') + ++dataptr; + + if (*dataptr == 'X') + { + /* Conditional expression. */ + if (debug_threads) + debug_printf ("Found breakpoint condition.\n"); + if (!add_breakpoint_condition (bp, &dataptr)) + dataptr = strchrnul (dataptr, ';'); + } + else if (startswith (dataptr, "cmds:")) + { + dataptr += strlen ("cmds:"); + if (debug_threads) + debug_printf ("Found breakpoint commands %s.\n", dataptr); + persist = (*dataptr == '1'); + dataptr += 2; + if (add_breakpoint_commands (bp, &dataptr, persist)) + dataptr = strchrnul (dataptr, ';'); + } + else + { + fprintf (stderr, "Unknown token %c, ignoring.\n", + *dataptr); + /* Skip tokens until we find one that we recognize. */ + dataptr = strchrnul (dataptr, ';'); + } + } + *packet = dataptr; +} + +/* Event loop callback that handles a serial event. The first byte in + the serial buffer gets us here. We expect characters to arrive at + a brisk pace, so we read the rest of the packet with a blocking + getpkt call. */ + +static int +process_serial_event (void) +{ + client_state &cs = get_client_state (); + int signal; + unsigned int len; + CORE_ADDR mem_addr; + unsigned char sig; + int packet_len; + int new_packet_len = -1; + + disable_async_io (); + + response_needed = false; + packet_len = getpkt (cs.own_buf); + if (packet_len <= 0) + { + remote_close (); + /* Force an event loop break. */ + return -1; + } + response_needed = true; + + char ch = cs.own_buf[0]; + switch (ch) + { + case 'q': + handle_query (cs.own_buf, packet_len, &new_packet_len); + break; + case 'Q': + handle_general_set (cs.own_buf); + break; + case 'D': + handle_detach (cs.own_buf); + break; + case '!': + extended_protocol = true; + write_ok (cs.own_buf); + break; + case '?': + handle_status (cs.own_buf); + break; + case 'H': + if (cs.own_buf[1] == 'c' || cs.own_buf[1] == 'g' || cs.own_buf[1] == 's') + { + require_running_or_break (cs.own_buf); + + ptid_t thread_id = read_ptid (&cs.own_buf[2], NULL); + + if (thread_id == null_ptid || thread_id == minus_one_ptid) + thread_id = null_ptid; + else if (thread_id.is_pid ()) + { + /* The ptid represents a pid. */ + thread_info *thread = find_any_thread_of_pid (thread_id.pid ()); + + if (thread == NULL) + { + write_enn (cs.own_buf); + break; + } + + thread_id = thread->id; + } + else + { + /* The ptid represents a lwp/tid. */ + if (find_thread_ptid (thread_id) == NULL) + { + write_enn (cs.own_buf); + break; + } + } + + if (cs.own_buf[1] == 'g') + { + if (thread_id == null_ptid) + { + /* GDB is telling us to choose any thread. Check if + the currently selected thread is still valid. If + it is not, select the first available. */ + thread_info *thread = find_thread_ptid (cs.general_thread); + if (thread == NULL) + thread = get_first_thread (); + thread_id = thread->id; + } + + cs.general_thread = thread_id; + set_desired_thread (); + gdb_assert (current_thread != NULL); + } + else if (cs.own_buf[1] == 'c') + cs.cont_thread = thread_id; + + write_ok (cs.own_buf); + } + else + { + /* Silently ignore it so that gdb can extend the protocol + without compatibility headaches. */ + cs.own_buf[0] = '\0'; + } + break; + case 'g': + require_running_or_break (cs.own_buf); + if (cs.current_traceframe >= 0) + { + struct regcache *regcache + = new_register_cache (current_target_desc ()); + + if (fetch_traceframe_registers (cs.current_traceframe, + regcache, -1) == 0) + registers_to_string (regcache, cs.own_buf); + else + write_enn (cs.own_buf); + free_register_cache (regcache); + } + else + { + struct regcache *regcache; + + if (!set_desired_thread ()) + write_enn (cs.own_buf); + else + { + regcache = get_thread_regcache (current_thread, 1); + registers_to_string (regcache, cs.own_buf); + } + } + break; + case 'G': + require_running_or_break (cs.own_buf); + if (cs.current_traceframe >= 0) + write_enn (cs.own_buf); + else + { + struct regcache *regcache; + + if (!set_desired_thread ()) + write_enn (cs.own_buf); + else + { + regcache = get_thread_regcache (current_thread, 1); + registers_from_string (regcache, &cs.own_buf[1]); + write_ok (cs.own_buf); + } + } + break; + case 'm': + { + require_running_or_break (cs.own_buf); + decode_m_packet (&cs.own_buf[1], &mem_addr, &len); + int res = gdb_read_memory (mem_addr, mem_buf, len); + if (res < 0) + write_enn (cs.own_buf); + else + bin2hex (mem_buf, cs.own_buf, res); + } + break; + case 'M': + require_running_or_break (cs.own_buf); + decode_M_packet (&cs.own_buf[1], &mem_addr, &len, &mem_buf); + if (gdb_write_memory (mem_addr, mem_buf, len) == 0) + write_ok (cs.own_buf); + else + write_enn (cs.own_buf); + break; + case 'X': + require_running_or_break (cs.own_buf); + if (decode_X_packet (&cs.own_buf[1], packet_len - 1, + &mem_addr, &len, &mem_buf) < 0 + || gdb_write_memory (mem_addr, mem_buf, len) != 0) + write_enn (cs.own_buf); + else + write_ok (cs.own_buf); + break; + case 'C': + require_running_or_break (cs.own_buf); + hex2bin (cs.own_buf + 1, &sig, 1); + if (gdb_signal_to_host_p ((enum gdb_signal) sig)) + signal = gdb_signal_to_host ((enum gdb_signal) sig); + else + signal = 0; + myresume (cs.own_buf, 0, signal); + break; + case 'S': + require_running_or_break (cs.own_buf); + hex2bin (cs.own_buf + 1, &sig, 1); + if (gdb_signal_to_host_p ((enum gdb_signal) sig)) + signal = gdb_signal_to_host ((enum gdb_signal) sig); + else + signal = 0; + myresume (cs.own_buf, 1, signal); + break; + case 'c': + require_running_or_break (cs.own_buf); + signal = 0; + myresume (cs.own_buf, 0, signal); + break; + case 's': + require_running_or_break (cs.own_buf); + signal = 0; + myresume (cs.own_buf, 1, signal); + break; + case 'Z': /* insert_ ... */ + /* Fallthrough. */ + case 'z': /* remove_ ... */ + { + char *dataptr; + ULONGEST addr; + int kind; + char type = cs.own_buf[1]; + int res; + const int insert = ch == 'Z'; + const char *p = &cs.own_buf[3]; + + p = unpack_varlen_hex (p, &addr); + kind = strtol (p + 1, &dataptr, 16); + + if (insert) + { + struct gdb_breakpoint *bp; + + bp = set_gdb_breakpoint (type, addr, kind, &res); + if (bp != NULL) + { + res = 0; + + /* GDB may have sent us a list of *point parameters to + be evaluated on the target's side. Read such list + here. If we already have a list of parameters, GDB + is telling us to drop that list and use this one + instead. */ + clear_breakpoint_conditions_and_commands (bp); + const char *options = dataptr; + process_point_options (bp, &options); + } + } + else + res = delete_gdb_breakpoint (type, addr, kind); + + if (res == 0) + write_ok (cs.own_buf); + else if (res == 1) + /* Unsupported. */ + cs.own_buf[0] = '\0'; + else + write_enn (cs.own_buf); + break; + } + case 'k': + response_needed = false; + if (!target_running ()) + /* The packet we received doesn't make sense - but we can't + reply to it, either. */ + return 0; + + fprintf (stderr, "Killing all inferiors\n"); + + for_each_process (kill_inferior_callback); + + /* When using the extended protocol, we wait with no program + running. The traditional protocol will exit instead. */ + if (extended_protocol) + { + cs.last_status.kind = TARGET_WAITKIND_EXITED; + cs.last_status.value.sig = GDB_SIGNAL_KILL; + return 0; + } + else + exit (0); + + case 'T': + { + require_running_or_break (cs.own_buf); + + ptid_t thread_id = read_ptid (&cs.own_buf[1], NULL); + if (find_thread_ptid (thread_id) == NULL) + { + write_enn (cs.own_buf); + break; + } + + if (mythread_alive (thread_id)) + write_ok (cs.own_buf); + else + write_enn (cs.own_buf); + } + break; + case 'R': + response_needed = false; + + /* Restarting the inferior is only supported in the extended + protocol. */ + if (extended_protocol) + { + if (target_running ()) + for_each_process (kill_inferior_callback); + + fprintf (stderr, "GDBserver restarting\n"); + + /* Wait till we are at 1st instruction in prog. */ + if (program_path.get () != NULL) + { + create_inferior (program_path.get (), program_args); + + if (cs.last_status.kind == TARGET_WAITKIND_STOPPED) + { + /* Stopped at the first instruction of the target + process. */ + cs.general_thread = cs.last_ptid; + } + else + { + /* Something went wrong. */ + cs.general_thread = null_ptid; + } + } + else + { + cs.last_status.kind = TARGET_WAITKIND_EXITED; + cs.last_status.value.sig = GDB_SIGNAL_KILL; + } + return 0; + } + else + { + /* It is a request we don't understand. Respond with an + empty packet so that gdb knows that we don't support this + request. */ + cs.own_buf[0] = '\0'; + break; + } + case 'v': + /* Extended (long) request. */ + handle_v_requests (cs.own_buf, packet_len, &new_packet_len); + break; + + default: + /* It is a request we don't understand. Respond with an empty + packet so that gdb knows that we don't support this + request. */ + cs.own_buf[0] = '\0'; + break; + } + + if (new_packet_len != -1) + putpkt_binary (cs.own_buf, new_packet_len); + else + putpkt (cs.own_buf); + + response_needed = false; + + if (exit_requested) + return -1; + + return 0; +} + +/* Event-loop callback for serial events. */ + +int +handle_serial_event (int err, gdb_client_data client_data) +{ + if (debug_threads) + debug_printf ("handling possible serial event\n"); + + /* Really handle it. */ + if (process_serial_event () < 0) + return -1; + + /* Be sure to not change the selected thread behind GDB's back. + Important in the non-stop mode asynchronous protocol. */ + set_desired_thread (); + + return 0; +} + +/* Push a stop notification on the notification queue. */ + +static void +push_stop_notification (ptid_t ptid, struct target_waitstatus *status) +{ + struct vstop_notif *vstop_notif = new struct vstop_notif; + + vstop_notif->status = *status; + vstop_notif->ptid = ptid; + /* Push Stop notification. */ + notif_push (¬if_stop, vstop_notif); +} + +/* Event-loop callback for target events. */ + +int +handle_target_event (int err, gdb_client_data client_data) +{ + client_state &cs = get_client_state (); + if (debug_threads) + debug_printf ("handling possible target event\n"); + + cs.last_ptid = mywait (minus_one_ptid, &cs.last_status, + TARGET_WNOHANG, 1); + + if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED) + { + if (gdb_connected () && report_no_resumed) + push_stop_notification (null_ptid, &cs.last_status); + } + else if (cs.last_status.kind != TARGET_WAITKIND_IGNORE) + { + int pid = cs.last_ptid.pid (); + struct process_info *process = find_process_pid (pid); + int forward_event = !gdb_connected () || process->gdb_detached; + + if (cs.last_status.kind == TARGET_WAITKIND_EXITED + || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED) + { + mark_breakpoints_out (process); + target_mourn_inferior (cs.last_ptid); + } + else if (cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED) + ; + else + { + /* We're reporting this thread as stopped. Update its + "want-stopped" state to what the client wants, until it + gets a new resume action. */ + current_thread->last_resume_kind = resume_stop; + current_thread->last_status = cs.last_status; + } + + if (forward_event) + { + if (!target_running ()) + { + /* The last process exited. We're done. */ + exit (0); + } + + if (cs.last_status.kind == TARGET_WAITKIND_EXITED + || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED + || cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED) + ; + else + { + /* A thread stopped with a signal, but gdb isn't + connected to handle it. Pass it down to the + inferior, as if it wasn't being traced. */ + enum gdb_signal signal; + + if (debug_threads) + debug_printf ("GDB not connected; forwarding event %d for" + " [%s]\n", + (int) cs.last_status.kind, + target_pid_to_str (cs.last_ptid)); + + if (cs.last_status.kind == TARGET_WAITKIND_STOPPED) + signal = cs.last_status.value.sig; + else + signal = GDB_SIGNAL_0; + target_continue (cs.last_ptid, signal); + } + } + else + push_stop_notification (cs.last_ptid, &cs.last_status); + } + + /* Be sure to not change the selected thread behind GDB's back. + Important in the non-stop mode asynchronous protocol. */ + set_desired_thread (); + + return 0; +} + +#if GDB_SELF_TEST +namespace selftests +{ + +void +reset () +{} + +} // namespace selftests +#endif /* GDB_SELF_TEST */ diff --git a/gdbserver/server.h b/gdbserver/server.h new file mode 100644 index 00000000000..3c286862349 --- /dev/null +++ b/gdbserver/server.h @@ -0,0 +1,210 @@ +/* Common definitions for remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_SERVER_H +#define GDBSERVER_SERVER_H + +#include "gdbsupport/common-defs.h" + +#undef PACKAGE +#undef PACKAGE_NAME +#undef PACKAGE_VERSION +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME + +#include + +gdb_static_assert (sizeof (CORE_ADDR) >= sizeof (void *)); + +#ifdef __MINGW32CE__ +#include "wincecompat.h" +#endif + +#include "gdbsupport/version.h" + +#if !HAVE_DECL_PERROR +#ifndef perror +extern void perror (const char *); +#endif +#endif + +#if !HAVE_DECL_VASPRINTF +extern int vasprintf(char **strp, const char *fmt, va_list ap); +#endif +#if !HAVE_DECL_VSNPRINTF +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif + +#ifdef IN_PROCESS_AGENT +# define PROG "ipa" +#else +# define PROG "gdbserver" +#endif + +#include "gdbsupport/buffer.h" +#include "gdbsupport/xml-utils.h" +#include "regcache.h" +#include "gdbsupport/gdb_signals.h" +#include "target.h" +#include "mem-break.h" +#include "gdbsupport/environ.h" + +/* Target-specific functions */ + +void initialize_low (); + +/* Public variables in server.c */ + +extern bool server_waiting; + +extern bool disable_packet_vCont; +extern bool disable_packet_Tthread; +extern bool disable_packet_qC; +extern bool disable_packet_qfThreadInfo; + +extern bool run_once; +extern bool non_stop; + +#if USE_WIN32API +#include +typedef SOCKET gdb_fildes_t; +#else +typedef int gdb_fildes_t; +#endif + +#include "event-loop.h" + +/* Functions from server.c. */ +extern void handle_v_requests (char *own_buf, int packet_len, + int *new_packet_len); +extern int handle_serial_event (int err, gdb_client_data client_data); +extern int handle_target_event (int err, gdb_client_data client_data); + +/* Get rid of the currently pending stop replies that match PTID. */ +extern void discard_queued_stop_replies (ptid_t ptid); + +/* Returns true if there's a pending stop reply that matches PTID in + the vStopped notifications queue. */ +extern int in_queued_stop_replies (ptid_t ptid); + +#include "remote-utils.h" + +#include "utils.h" +#include "debug.h" +#include "gdbsupport/gdb_vecs.h" + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet (the headers account for the 32). */ +#define MAXBUFBYTES(N) (((N)-32)/2) + +/* Buffer sizes for transferring memory, registers, etc. Set to a constant + value to accomodate multiple register formats. This value must be at least + as large as the largest register set supported by gdbserver. */ +#define PBUFSIZ 18432 + +/* Definition for an unknown syscall, used basically in error-cases. */ +#define UNKNOWN_SYSCALL (-1) + +/* Definition for any syscall, used for unfiltered syscall reporting. */ +#define ANY_SYSCALL (-2) + +/* After fork_inferior has been called, we need to adjust a few + signals and call startup_inferior to start the inferior and consume + its first events. This is done here. PID is the pid of the new + inferior and PROGRAM is its name. */ +extern void post_fork_inferior (int pid, const char *program); + +/* Get the gdb_environ being used in the current session. */ +extern gdb_environ *get_environ (); + +extern unsigned long signal_pid; + + +/* Description of the client remote protocol state for the currently + connected client. */ + +struct client_state +{ + client_state (): + own_buf ((char *) xmalloc (PBUFSIZ + 1)) + {} + + /* The thread set with an `Hc' packet. `Hc' is deprecated in favor of + `vCont'. Note the multi-process extensions made `vCont' a + requirement, so `Hc pPID.TID' is pretty much undefined. So + CONT_THREAD can be null_ptid for no `Hc' thread, minus_one_ptid for + resuming all threads of the process (again, `Hc' isn't used for + multi-process), or a specific thread ptid_t. */ + ptid_t cont_thread; + + /* The thread set with an `Hg' packet. */ + ptid_t general_thread; + + int multi_process = 0; + int report_fork_events = 0; + int report_vfork_events = 0; + int report_exec_events = 0; + int report_thread_events = 0; + + /* True if the "swbreak+" feature is active. In that case, GDB wants + us to report whether a trap is explained by a software breakpoint + and for the server to handle PC adjustment if necessary on this + target. Only enabled if the target supports it. */ + int swbreak_feature = 0; + /* True if the "hwbreak+" feature is active. In that case, GDB wants + us to report whether a trap is explained by a hardware breakpoint. + Only enabled if the target supports it. */ + int hwbreak_feature = 0; + + /* True if the "vContSupported" feature is active. In that case, GDB + wants us to report whether single step is supported in the reply to + "vCont?" packet. */ + int vCont_supported = 0; + + /* Whether we should attempt to disable the operating system's address + space randomization feature before starting an inferior. */ + int disable_randomization = 1; + + int pass_signals[GDB_SIGNAL_LAST]; + int program_signals[GDB_SIGNAL_LAST]; + int program_signals_p = 0; + + /* Last status reported to GDB. */ + struct target_waitstatus last_status; + ptid_t last_ptid; + + char *own_buf; + + /* If true, then GDB has requested noack mode. */ + int noack_mode = 0; + /* If true, then we tell GDB to use noack mode by default. */ + int transport_is_reliable = 0; + + /* The traceframe to be used as the source of data to send back to + GDB. A value of -1 means to get data from the live program. */ + + int current_traceframe = -1; + +}; + +client_state &get_client_state (); + +#include "gdbthread.h" +#include "inferiors.h" + +#endif /* GDBSERVER_SERVER_H */ diff --git a/gdbserver/symbol.c b/gdbserver/symbol.c new file mode 100644 index 00000000000..467524f0faf --- /dev/null +++ b/gdbserver/symbol.c @@ -0,0 +1,32 @@ +/* Symbol manipulating routines for the remote server for GDB. + + Copyright (C) 2014-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "gdbsupport/symbol.h" + +/* See gdbsupport/symbol.h. */ + +int +find_minimal_symbol_address (const char *name, CORE_ADDR *addr, + struct objfile *objfile) +{ + gdb_assert (objfile == NULL); + + return look_up_one_symbol (name, addr, 1) != 1; +} diff --git a/gdbserver/target.c b/gdbserver/target.c new file mode 100644 index 00000000000..a4593cf6df9 --- /dev/null +++ b/gdbserver/target.c @@ -0,0 +1,395 @@ +/* Target operations for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#include "server.h" +#include "tracepoint.h" +#include "gdbsupport/byte-vector.h" + +process_stratum_target *the_target; + +int +set_desired_thread () +{ + client_state &cs = get_client_state (); + thread_info *found = find_thread_ptid (cs.general_thread); + + current_thread = found; + return (current_thread != NULL); +} + +/* The thread that was current before prepare_to_access_memory was + called. done_accessing_memory uses this to restore the previous + selected thread. */ +static ptid_t prev_general_thread; + +/* See target.h. */ + +int +prepare_to_access_memory (void) +{ + client_state &cs = get_client_state (); + + /* The first thread found. */ + struct thread_info *first = NULL; + /* The first stopped thread found. */ + struct thread_info *stopped = NULL; + /* The current general thread, if found. */ + struct thread_info *current = NULL; + + /* Save the general thread value, since prepare_to_access_memory could change + it. */ + prev_general_thread = cs.general_thread; + + if (the_target->prepare_to_access_memory != NULL) + { + int res; + + res = the_target->prepare_to_access_memory (); + if (res != 0) + return res; + } + + for_each_thread (prev_general_thread.pid (), [&] (thread_info *thread) + { + if (mythread_alive (thread->id)) + { + if (stopped == NULL && the_target->thread_stopped != NULL + && thread_stopped (thread)) + stopped = thread; + + if (first == NULL) + first = thread; + + if (current == NULL && prev_general_thread == thread->id) + current = thread; + } + }); + + /* The thread we end up choosing. */ + struct thread_info *thread; + + /* Prefer a stopped thread. If none is found, try the current + thread. Otherwise, take the first thread in the process. If + none is found, undo the effects of + target->prepare_to_access_memory() and return error. */ + if (stopped != NULL) + thread = stopped; + else if (current != NULL) + thread = current; + else if (first != NULL) + thread = first; + else + { + done_accessing_memory (); + return 1; + } + + current_thread = thread; + cs.general_thread = ptid_of (thread); + + return 0; +} + +/* See target.h. */ + +void +done_accessing_memory (void) +{ + client_state &cs = get_client_state (); + + if (the_target->done_accessing_memory != NULL) + the_target->done_accessing_memory (); + + /* Restore the previous selected thread. */ + cs.general_thread = prev_general_thread; + switch_to_thread (the_target, cs.general_thread); +} + +int +read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + int res; + res = (*the_target->read_memory) (memaddr, myaddr, len); + check_mem_read (memaddr, myaddr, len); + return res; +} + +/* See target/target.h. */ + +int +target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) +{ + return read_inferior_memory (memaddr, myaddr, len); +} + +/* See target/target.h. */ + +int +target_read_uint32 (CORE_ADDR memaddr, uint32_t *result) +{ + return read_inferior_memory (memaddr, (gdb_byte *) result, sizeof (*result)); +} + +/* See target/target.h. */ + +int +target_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, + ssize_t len) +{ + /* Make a copy of the data because check_mem_write may need to + update it. */ + gdb::byte_vector buffer (myaddr, myaddr + len); + check_mem_write (memaddr, buffer.data (), myaddr, len); + return (*the_target->write_memory) (memaddr, buffer.data (), len); +} + +ptid_t +mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, + int connected_wait) +{ + ptid_t ret; + + if (connected_wait) + server_waiting = 1; + + ret = target_wait (ptid, ourstatus, options); + + /* We don't expose _LOADED events to gdbserver core. See the + `dlls_changed' global. */ + if (ourstatus->kind == TARGET_WAITKIND_LOADED) + ourstatus->kind = TARGET_WAITKIND_STOPPED; + + /* If GDB is connected through TCP/serial, then GDBserver will most + probably be running on its own terminal/console, so it's nice to + print there why is GDBserver exiting. If however, GDB is + connected through stdio, then there's no need to spam the GDB + console with this -- the user will already see the exit through + regular GDB output, in that same terminal. */ + if (!remote_connection_is_stdio ()) + { + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + fprintf (stderr, + "\nChild exited with status %d\n", ourstatus->value.integer); + else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) + fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", + gdb_signal_to_host (ourstatus->value.sig), + gdb_signal_to_name (ourstatus->value.sig)); + } + + if (connected_wait) + server_waiting = 0; + + return ret; +} + +/* See target/target.h. */ + +void +target_stop_and_wait (ptid_t ptid) +{ + struct target_waitstatus status; + bool was_non_stop = non_stop; + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_stop; + resume_info.sig = GDB_SIGNAL_0; + (*the_target->resume) (&resume_info, 1); + + non_stop = true; + mywait (ptid, &status, 0, 0); + non_stop = was_non_stop; +} + +/* See target/target.h. */ + +ptid_t +target_wait (ptid_t ptid, struct target_waitstatus *status, int options) +{ + return (*the_target->wait) (ptid, status, options); +} + +/* See target/target.h. */ + +void +target_mourn_inferior (ptid_t ptid) +{ + (*the_target->mourn) (find_process_pid (ptid.pid ())); +} + +/* See target/target.h. */ + +void +target_continue_no_signal (ptid_t ptid) +{ + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_continue; + resume_info.sig = GDB_SIGNAL_0; + (*the_target->resume) (&resume_info, 1); +} + +/* See target/target.h. */ + +void +target_continue (ptid_t ptid, enum gdb_signal signal) +{ + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_continue; + resume_info.sig = gdb_signal_to_host (signal); + (*the_target->resume) (&resume_info, 1); +} + +/* See target/target.h. */ + +int +target_supports_multi_process (void) +{ + return (the_target->supports_multi_process != NULL ? + (*the_target->supports_multi_process) () : 0); +} + +int +start_non_stop (int nonstop) +{ + if (the_target->start_non_stop == NULL) + { + if (nonstop) + return -1; + else + return 0; + } + + return (*the_target->start_non_stop) (nonstop); +} + +void +set_target_ops (process_stratum_target *target) +{ + the_target = XNEW (process_stratum_target); + memcpy (the_target, target, sizeof (*the_target)); +} + +/* Convert pid to printable format. */ + +const char * +target_pid_to_str (ptid_t ptid) +{ + static char buf[80]; + + if (ptid == minus_one_ptid) + xsnprintf (buf, sizeof (buf), ""); + else if (ptid == null_ptid) + xsnprintf (buf, sizeof (buf), ""); + else if (ptid.tid () != 0) + xsnprintf (buf, sizeof (buf), "Thread %d.0x%lx", + ptid.pid (), ptid.tid ()); + else if (ptid.lwp () != 0) + xsnprintf (buf, sizeof (buf), "LWP %d.%ld", + ptid.pid (), ptid.lwp ()); + else + xsnprintf (buf, sizeof (buf), "Process %d", + ptid.pid ()); + + return buf; +} + +int +kill_inferior (process_info *proc) +{ + gdb_agent_about_to_close (proc->pid); + + return (*the_target->kill) (proc); +} + +/* Target can do hardware single step. */ + +int +target_can_do_hardware_single_step (void) +{ + return 1; +} + +/* Default implementation for breakpoint_kind_for_pc. + + The default behavior for targets that don't implement breakpoint_kind_for_pc + is to use the size of a breakpoint as the kind. */ + +int +default_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + int size = 0; + + gdb_assert (the_target->sw_breakpoint_from_kind != NULL); + + (*the_target->sw_breakpoint_from_kind) (0, &size); + return size; +} + +/* Define it. */ + +target_terminal_state target_terminal::m_terminal_state + = target_terminal_state::is_ours; + +/* See target/target.h. */ + +void +target_terminal::init () +{ + /* Placeholder needed because of fork_inferior. Not necessary on + GDBserver. */ +} + +/* See target/target.h. */ + +void +target_terminal::inferior () +{ + /* Placeholder needed because of fork_inferior. Not necessary on + GDBserver. */ +} + +/* See target/target.h. */ + +void +target_terminal::ours () +{ + /* Placeholder needed because of fork_inferior. Not necessary on + GDBserver. */ +} + +/* See target/target.h. */ + +void +target_terminal::ours_for_output (void) +{ + /* Placeholder. */ +} + +/* See target/target.h. */ + +void +target_terminal::info (const char *arg, int from_tty) +{ + /* Placeholder. */ +} diff --git a/gdbserver/target.h b/gdbserver/target.h new file mode 100644 index 00000000000..1b0810ba049 --- /dev/null +++ b/gdbserver/target.h @@ -0,0 +1,736 @@ +/* Target operations for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#ifndef GDBSERVER_TARGET_H +#define GDBSERVER_TARGET_H + +#include /* for mode_t */ +#include "target/target.h" +#include "target/resume.h" +#include "target/wait.h" +#include "target/waitstatus.h" +#include "mem-break.h" +#include "gdbsupport/btrace-common.h" +#include + +struct emit_ops; +struct buffer; +struct process_info; + +/* This structure describes how to resume a particular thread (or all + threads) based on the client's request. If thread is -1, then this + entry applies to all threads. These are passed around as an + array. */ + +struct thread_resume +{ + ptid_t thread; + + /* How to "resume". */ + enum resume_kind kind; + + /* If non-zero, send this signal when we resume, or to stop the + thread. If stopping a thread, and this is 0, the target should + stop the thread however it best decides to (e.g., SIGSTOP on + linux; SuspendThread on win32). This is a host signal value (not + enum gdb_signal). */ + int sig; + + /* Range to single step within. Valid only iff KIND is resume_step. + + Single-step once, and then continuing stepping as long as the + thread stops in this range. (If the range is empty + [STEP_RANGE_START == STEP_RANGE_END], then this is a single-step + request.) */ + CORE_ADDR step_range_start; /* Inclusive */ + CORE_ADDR step_range_end; /* Exclusive */ +}; + +/* GDBserver doesn't have a concept of strata like GDB, but we call + its target vector "process_stratum" anyway for the benefit of + shared code. */ +struct process_stratum_target +{ + /* Start a new process. + + PROGRAM is a path to the program to execute. + PROGRAM_ARGS is a standard NULL-terminated array of arguments, + to be passed to the inferior as ``argv'' (along with PROGRAM). + + Returns the new PID on success, -1 on failure. Registers the new + process with the process list. */ + int (*create_inferior) (const char *program, + const std::vector &program_args); + + /* Do additional setup after a new process is created, including + exec-wrapper completion. */ + void (*post_create_inferior) (void); + + /* Attach to a running process. + + PID is the process ID to attach to, specified by the user + or a higher layer. + + Returns -1 if attaching is unsupported, 0 on success, and calls + error() otherwise. */ + + int (*attach) (unsigned long pid); + + /* Kill process PROC. Return -1 on failure, and 0 on success. */ + + int (*kill) (process_info *proc); + + /* Detach from process PROC. Return -1 on failure, and 0 on + success. */ + + int (*detach) (process_info *proc); + + /* The inferior process has died. Do what is right. */ + + void (*mourn) (struct process_info *proc); + + /* Wait for process PID to exit. */ + + void (*join) (int pid); + + /* Return 1 iff the thread with process ID PID is alive. */ + + int (*thread_alive) (ptid_t pid); + + /* Resume the inferior process. */ + + void (*resume) (struct thread_resume *resume_info, size_t n); + + /* Wait for the inferior process or thread to change state. Store + status through argument pointer STATUS. + + PTID = -1 to wait for any pid to do something, PTID(pid,0,0) to + wait for any thread of process pid to do something. Return ptid + of child, or -1 in case of error; store status through argument + pointer STATUS. OPTIONS is a bit set of options defined as + TARGET_W* above. If options contains TARGET_WNOHANG and there's + no child stop to report, return is + null_ptid/TARGET_WAITKIND_IGNORE. */ + + ptid_t (*wait) (ptid_t ptid, struct target_waitstatus *status, int options); + + /* Fetch registers from the inferior process. + + If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */ + + void (*fetch_registers) (struct regcache *regcache, int regno); + + /* Store registers to the inferior process. + + If REGNO is -1, store all registers; otherwise, store at least REGNO. */ + + void (*store_registers) (struct regcache *regcache, int regno); + + /* Prepare to read or write memory from the inferior process. + Targets use this to do what is necessary to get the state of the + inferior such that it is possible to access memory. + + This should generally only be called from client facing routines, + such as gdb_read_memory/gdb_write_memory, or the GDB breakpoint + insertion routine. + + Like `read_memory' and `write_memory' below, returns 0 on success + and errno on failure. */ + + int (*prepare_to_access_memory) (void); + + /* Undo the effects of prepare_to_access_memory. */ + + void (*done_accessing_memory) (void); + + /* Read memory from the inferior process. This should generally be + called through read_inferior_memory, which handles breakpoint shadowing. + + Read LEN bytes at MEMADDR into a buffer at MYADDR. + + Returns 0 on success and errno on failure. */ + + int (*read_memory) (CORE_ADDR memaddr, unsigned char *myaddr, int len); + + /* Write memory to the inferior process. This should generally be + called through target_write_memory, which handles breakpoint shadowing. + + Write LEN bytes from the buffer at MYADDR to MEMADDR. + + Returns 0 on success and errno on failure. */ + + int (*write_memory) (CORE_ADDR memaddr, const unsigned char *myaddr, + int len); + + /* Query GDB for the values of any symbols we're interested in. + This function is called whenever we receive a "qSymbols::" + query, which corresponds to every time more symbols (might) + become available. NULL if we aren't interested in any + symbols. */ + + void (*look_up_symbols) (void); + + /* Send an interrupt request to the inferior process, + however is appropriate. */ + + void (*request_interrupt) (void); + + /* Read auxiliary vector data from the inferior process. + + Read LEN bytes at OFFSET into a buffer at MYADDR. */ + + int (*read_auxv) (CORE_ADDR offset, unsigned char *myaddr, + unsigned int len); + + /* Returns true if GDB Z breakpoint type TYPE is supported, false + otherwise. The type is coded as follows: + '0' - software-breakpoint + '1' - hardware-breakpoint + '2' - write watchpoint + '3' - read watchpoint + '4' - access watchpoint + */ + int (*supports_z_point_type) (char z_type); + + /* Insert and remove a break or watchpoint. + Returns 0 on success, -1 on failure and 1 on unsupported. */ + + int (*insert_point) (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp); + int (*remove_point) (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp); + + /* Returns 1 if the target stopped because it executed a software + breakpoint instruction, 0 otherwise. */ + int (*stopped_by_sw_breakpoint) (void); + + /* Returns true if the target knows whether a trap was caused by a + SW breakpoint triggering. */ + int (*supports_stopped_by_sw_breakpoint) (void); + + /* Returns 1 if the target stopped for a hardware breakpoint. */ + int (*stopped_by_hw_breakpoint) (void); + + /* Returns true if the target knows whether a trap was caused by a + HW breakpoint triggering. */ + int (*supports_stopped_by_hw_breakpoint) (void); + + /* Returns true if the target can do hardware single step. */ + int (*supports_hardware_single_step) (void); + + /* Returns 1 if target was stopped due to a watchpoint hit, 0 otherwise. */ + + int (*stopped_by_watchpoint) (void); + + /* Returns the address associated with the watchpoint that hit, if any; + returns 0 otherwise. */ + + CORE_ADDR (*stopped_data_address) (void); + + /* Reports the text, data offsets of the executable. This is + needed for uclinux where the executable is relocated during load + time. */ + + int (*read_offsets) (CORE_ADDR *text, CORE_ADDR *data); + + /* Fetch the address associated with a specific thread local storage + area, determined by the specified THREAD, OFFSET, and LOAD_MODULE. + Stores it in *ADDRESS and returns zero on success; otherwise returns + an error code. A return value of -1 means this system does not + support the operation. */ + + int (*get_tls_address) (struct thread_info *thread, CORE_ADDR offset, + CORE_ADDR load_module, CORE_ADDR *address); + + /* Fill BUF with an hostio error packet representing the last hostio + error. */ + void (*hostio_last_error) (char *buf); + + /* Read/Write OS data using qXfer packets. */ + int (*qxfer_osdata) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, CORE_ADDR offset, + int len); + + /* Read/Write extra signal info. */ + int (*qxfer_siginfo) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len); + + int (*supports_non_stop) (void); + + /* Enables async target events. Returns the previous enable + state. */ + int (*async) (int enable); + + /* Switch to non-stop (1) or all-stop (0) mode. Return 0 on + success, -1 otherwise. */ + int (*start_non_stop) (int); + + /* Returns true if the target supports multi-process debugging. */ + int (*supports_multi_process) (void); + + /* Returns true if fork events are supported. */ + int (*supports_fork_events) (void); + + /* Returns true if vfork events are supported. */ + int (*supports_vfork_events) (void); + + /* Returns true if exec events are supported. */ + int (*supports_exec_events) (void); + + /* Allows target to re-initialize connection-specific settings. */ + void (*handle_new_gdb_connection) (void); + + /* If not NULL, target-specific routine to process monitor command. + Returns 1 if handled, or 0 to perform default processing. */ + int (*handle_monitor_command) (char *); + + /* Returns the core given a thread, or -1 if not known. */ + int (*core_of_thread) (ptid_t); + + /* Read loadmaps. Read LEN bytes at OFFSET into a buffer at MYADDR. */ + int (*read_loadmap) (const char *annex, CORE_ADDR offset, + unsigned char *myaddr, unsigned int len); + + /* Target specific qSupported support. FEATURES is an array of + features with COUNT elements. */ + void (*process_qsupported) (char **features, int count); + + /* Return 1 if the target supports tracepoints, 0 (or leave the + callback NULL) otherwise. */ + int (*supports_tracepoints) (void); + + /* Read PC from REGCACHE. */ + CORE_ADDR (*read_pc) (struct regcache *regcache); + + /* Write PC to REGCACHE. */ + void (*write_pc) (struct regcache *regcache, CORE_ADDR pc); + + /* Return true if THREAD is known to be stopped now. */ + int (*thread_stopped) (struct thread_info *thread); + + /* Read Thread Information Block address. */ + int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address); + + /* Pause all threads. If FREEZE, arrange for any resume attempt to + be ignored until an unpause_all call unfreezes threads again. + There can be nested calls to pause_all, so a freeze counter + should be maintained. */ + void (*pause_all) (int freeze); + + /* Unpause all threads. Threads that hadn't been resumed by the + client should be left stopped. Basically a pause/unpause call + pair should not end up resuming threads that were stopped before + the pause call. */ + void (*unpause_all) (int unfreeze); + + /* Stabilize all threads. That is, force them out of jump pads. */ + void (*stabilize_threads) (void); + + /* Install a fast tracepoint jump pad. TPOINT is the address of the + tracepoint internal object as used by the IPA agent. TPADDR is + the address of tracepoint. COLLECTOR is address of the function + the jump pad redirects to. LOCKADDR is the address of the jump + pad lock object. ORIG_SIZE is the size in bytes of the + instruction at TPADDR. JUMP_ENTRY points to the address of the + jump pad entry, and on return holds the address past the end of + the created jump pad. If a trampoline is created by the function, + then TRAMPOLINE and TRAMPOLINE_SIZE return the address and size of + the trampoline, else they remain unchanged. JJUMP_PAD_INSN is a + buffer containing a copy of the instruction at TPADDR. + ADJUST_INSN_ADDR and ADJUST_INSN_ADDR_END are output parameters that + return the address range where the instruction at TPADDR was relocated + to. If an error occurs, the ERR may be used to pass on an error + message. */ + int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err); + + /* Return the bytecode operations vector for the current inferior. + Returns NULL if bytecode compilation is not supported. */ + struct emit_ops *(*emit_ops) (void); + + /* Returns true if the target supports disabling randomization. */ + int (*supports_disable_randomization) (void); + + /* Return the minimum length of an instruction that can be safely overwritten + for use as a fast tracepoint. */ + int (*get_min_fast_tracepoint_insn_len) (void); + + /* Read solib info on SVR4 platforms. */ + int (*qxfer_libraries_svr4) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len); + + /* Return true if target supports debugging agent. */ + int (*supports_agent) (void); + + /* Enable branch tracing for PTID based on CONF and allocate a branch trace + target information struct for reading and for disabling branch trace. */ + struct btrace_target_info *(*enable_btrace) + (ptid_t ptid, const struct btrace_config *conf); + + /* Disable branch tracing. + Returns zero on success, non-zero otherwise. */ + int (*disable_btrace) (struct btrace_target_info *tinfo); + + /* Read branch trace data into buffer. + Return 0 on success; print an error message into BUFFER and return -1, + otherwise. */ + int (*read_btrace) (struct btrace_target_info *, struct buffer *, + enum btrace_read_type type); + + /* Read the branch trace configuration into BUFFER. + Return 0 on success; print an error message into BUFFER and return -1 + otherwise. */ + int (*read_btrace_conf) (const struct btrace_target_info *, struct buffer *); + + /* Return true if target supports range stepping. */ + int (*supports_range_stepping) (void); + + /* Return the full absolute name of the executable file that was + run to create the process PID. If the executable file cannot + be determined, NULL is returned. Otherwise, a pointer to a + character string containing the pathname is returned. This + string should be copied into a buffer by the client if the string + will not be immediately used, or if it must persist. */ + char *(*pid_to_exec_file) (int pid); + + /* Multiple-filesystem-aware open. Like open(2), but operating in + the filesystem as it appears to process PID. Systems where all + processes share a common filesystem should set this to NULL. + If NULL, the caller should fall back to open(2). */ + int (*multifs_open) (int pid, const char *filename, + int flags, mode_t mode); + + /* Multiple-filesystem-aware unlink. Like unlink(2), but operates + in the filesystem as it appears to process PID. Systems where + all processes share a common filesystem should set this to NULL. + If NULL, the caller should fall back to unlink(2). */ + int (*multifs_unlink) (int pid, const char *filename); + + /* Multiple-filesystem-aware readlink. Like readlink(2), but + operating in the filesystem as it appears to process PID. + Systems where all processes share a common filesystem should + set this to NULL. If NULL, the caller should fall back to + readlink(2). */ + ssize_t (*multifs_readlink) (int pid, const char *filename, + char *buf, size_t bufsiz); + + /* Return the breakpoint kind for this target based on PC. The PCPTR is + adjusted to the real memory location in case a flag (e.g., the Thumb bit on + ARM) was present in the PC. */ + int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr); + + /* Return the software breakpoint from KIND. KIND can have target + specific meaning like the Z0 kind parameter. + SIZE is set to the software breakpoint's length in memory. */ + const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size); + + /* Return the thread's name, or NULL if the target is unable to determine it. + The returned value must not be freed by the caller. */ + const char *(*thread_name) (ptid_t thread); + + /* Return the breakpoint kind for this target based on the current + processor state (e.g. the current instruction mode on ARM) and the + PC. The PCPTR is adjusted to the real memory location in case a flag + (e.g., the Thumb bit on ARM) is present in the PC. */ + int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr); + + /* Returns true if the target can software single step. */ + int (*supports_software_single_step) (void); + + /* Return 1 if the target supports catch syscall, 0 (or leave the + callback NULL) otherwise. */ + int (*supports_catch_syscall) (void); + + /* Return tdesc index for IPA. */ + int (*get_ipa_tdesc_idx) (void); + + /* Thread ID to (numeric) thread handle: Return true on success and + false for failure. Return pointer to thread handle via HANDLE + and the handle's length via HANDLE_LEN. */ + bool (*thread_handle) (ptid_t ptid, gdb_byte **handle, int *handle_len); +}; + +extern process_stratum_target *the_target; + +void set_target_ops (process_stratum_target *); + +#define create_inferior(program, program_args) \ + (*the_target->create_inferior) (program, program_args) + +#define target_post_create_inferior() \ + do \ + { \ + if (the_target->post_create_inferior != NULL) \ + (*the_target->post_create_inferior) (); \ + } while (0) + +#define myattach(pid) \ + (*the_target->attach) (pid) + +int kill_inferior (process_info *proc); + +#define target_supports_fork_events() \ + (the_target->supports_fork_events ? \ + (*the_target->supports_fork_events) () : 0) + +#define target_supports_vfork_events() \ + (the_target->supports_vfork_events ? \ + (*the_target->supports_vfork_events) () : 0) + +#define target_supports_exec_events() \ + (the_target->supports_exec_events ? \ + (*the_target->supports_exec_events) () : 0) + +#define target_handle_new_gdb_connection() \ + do \ + { \ + if (the_target->handle_new_gdb_connection != NULL) \ + (*the_target->handle_new_gdb_connection) (); \ + } while (0) + +#define detach_inferior(proc) \ + (*the_target->detach) (proc) + +#define mythread_alive(pid) \ + (*the_target->thread_alive) (pid) + +#define fetch_inferior_registers(regcache, regno) \ + (*the_target->fetch_registers) (regcache, regno) + +#define store_inferior_registers(regcache, regno) \ + (*the_target->store_registers) (regcache, regno) + +#define join_inferior(pid) \ + (*the_target->join) (pid) + +#define target_supports_non_stop() \ + (the_target->supports_non_stop ? (*the_target->supports_non_stop ) () : 0) + +#define target_async(enable) \ + (the_target->async ? (*the_target->async) (enable) : 0) + +#define target_process_qsupported(features, count) \ + do \ + { \ + if (the_target->process_qsupported) \ + the_target->process_qsupported (features, count); \ + } while (0) + +#define target_supports_catch_syscall() \ + (the_target->supports_catch_syscall ? \ + (*the_target->supports_catch_syscall) () : 0) + +#define target_get_ipa_tdesc_idx() \ + (the_target->get_ipa_tdesc_idx \ + ? (*the_target->get_ipa_tdesc_idx) () : 0) + +#define target_supports_tracepoints() \ + (the_target->supports_tracepoints \ + ? (*the_target->supports_tracepoints) () : 0) + +#define target_supports_fast_tracepoints() \ + (the_target->install_fast_tracepoint_jump_pad != NULL) + +#define target_get_min_fast_tracepoint_insn_len() \ + (the_target->get_min_fast_tracepoint_insn_len \ + ? (*the_target->get_min_fast_tracepoint_insn_len) () : 0) + +#define thread_stopped(thread) \ + (*the_target->thread_stopped) (thread) + +#define pause_all(freeze) \ + do \ + { \ + if (the_target->pause_all) \ + (*the_target->pause_all) (freeze); \ + } while (0) + +#define unpause_all(unfreeze) \ + do \ + { \ + if (the_target->unpause_all) \ + (*the_target->unpause_all) (unfreeze); \ + } while (0) + +#define stabilize_threads() \ + do \ + { \ + if (the_target->stabilize_threads) \ + (*the_target->stabilize_threads) (); \ + } while (0) + +#define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \ + collector, lockaddr, \ + orig_size, \ + jump_entry, \ + trampoline, trampoline_size, \ + jjump_pad_insn, \ + jjump_pad_insn_size, \ + adjusted_insn_addr, \ + adjusted_insn_addr_end, \ + err) \ + (*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr, \ + collector,lockaddr, \ + orig_size, jump_entry, \ + trampoline, \ + trampoline_size, \ + jjump_pad_insn, \ + jjump_pad_insn_size, \ + adjusted_insn_addr, \ + adjusted_insn_addr_end, \ + err) + +#define target_emit_ops() \ + (the_target->emit_ops ? (*the_target->emit_ops) () : NULL) + +#define target_supports_disable_randomization() \ + (the_target->supports_disable_randomization ? \ + (*the_target->supports_disable_randomization) () : 0) + +#define target_supports_agent() \ + (the_target->supports_agent ? \ + (*the_target->supports_agent) () : 0) + +static inline struct btrace_target_info * +target_enable_btrace (ptid_t ptid, const struct btrace_config *conf) +{ + if (the_target->enable_btrace == nullptr) + error (_("Target does not support branch tracing.")); + + return (*the_target->enable_btrace) (ptid, conf); +} + +static inline int +target_disable_btrace (struct btrace_target_info *tinfo) +{ + if (the_target->disable_btrace == nullptr) + error (_("Target does not support branch tracing.")); + + return (*the_target->disable_btrace) (tinfo); +} + +static inline int +target_read_btrace (struct btrace_target_info *tinfo, + struct buffer *buffer, + enum btrace_read_type type) +{ + if (the_target->read_btrace == nullptr) + error (_("Target does not support branch tracing.")); + + return (*the_target->read_btrace) (tinfo, buffer, type); +} + +static inline int +target_read_btrace_conf (struct btrace_target_info *tinfo, + struct buffer *buffer) +{ + if (the_target->read_btrace_conf == nullptr) + error (_("Target does not support branch tracing.")); + + return (*the_target->read_btrace_conf) (tinfo, buffer); +} + +#define target_supports_range_stepping() \ + (the_target->supports_range_stepping ? \ + (*the_target->supports_range_stepping) () : 0) + +#define target_supports_stopped_by_sw_breakpoint() \ + (the_target->supports_stopped_by_sw_breakpoint ? \ + (*the_target->supports_stopped_by_sw_breakpoint) () : 0) + +#define target_stopped_by_sw_breakpoint() \ + (the_target->stopped_by_sw_breakpoint ? \ + (*the_target->stopped_by_sw_breakpoint) () : 0) + +#define target_supports_stopped_by_hw_breakpoint() \ + (the_target->supports_stopped_by_hw_breakpoint ? \ + (*the_target->supports_stopped_by_hw_breakpoint) () : 0) + +#define target_supports_hardware_single_step() \ + (the_target->supports_hardware_single_step ? \ + (*the_target->supports_hardware_single_step) () : 0) + +#define target_stopped_by_hw_breakpoint() \ + (the_target->stopped_by_hw_breakpoint ? \ + (*the_target->stopped_by_hw_breakpoint) () : 0) + +#define target_breakpoint_kind_from_pc(pcptr) \ + (the_target->breakpoint_kind_from_pc \ + ? (*the_target->breakpoint_kind_from_pc) (pcptr) \ + : default_breakpoint_kind_from_pc (pcptr)) + +#define target_breakpoint_kind_from_current_state(pcptr) \ + (the_target->breakpoint_kind_from_current_state \ + ? (*the_target->breakpoint_kind_from_current_state) (pcptr) \ + : target_breakpoint_kind_from_pc (pcptr)) + +#define target_supports_software_single_step() \ + (the_target->supports_software_single_step ? \ + (*the_target->supports_software_single_step) () : 0) + +/* Start non-stop mode, returns 0 on success, -1 on failure. */ + +int start_non_stop (int nonstop); + +ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, + int connected_wait); + +/* Prepare to read or write memory from the inferior process. See the + corresponding process_stratum_target methods for more details. */ + +int prepare_to_access_memory (void); +void done_accessing_memory (void); + +#define target_core_of_thread(ptid) \ + (the_target->core_of_thread ? (*the_target->core_of_thread) (ptid) \ + : -1) + +#define target_thread_name(ptid) \ + (the_target->thread_name ? (*the_target->thread_name) (ptid) \ + : NULL) + +#define target_thread_handle(ptid, handle, handle_len) \ + (the_target->thread_handle ? (*the_target->thread_handle) \ + (ptid, handle, handle_len) \ + : false) + +int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); + +int set_desired_thread (); + +const char *target_pid_to_str (ptid_t); + +int target_can_do_hardware_single_step (void); + +int default_breakpoint_kind_from_pc (CORE_ADDR *pcptr); + +#endif /* GDBSERVER_TARGET_H */ diff --git a/gdbserver/tdesc.c b/gdbserver/tdesc.c new file mode 100644 index 00000000000..de25e7cfb46 --- /dev/null +++ b/gdbserver/tdesc.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2012-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "tdesc.h" +#include "regdef.h" + +#ifndef IN_PROCESS_AGENT + +target_desc::~target_desc () +{ + xfree ((char *) arch); + xfree ((char *) osabi); +} + +bool target_desc::operator== (const target_desc &other) const +{ + if (reg_defs != other.reg_defs) + return false; + + /* Compare expedite_regs. */ + int i = 0; + for (; expedite_regs[i] != NULL; i++) + { + if (strcmp (expedite_regs[i], other.expedite_regs[i]) != 0) + return false; + } + if (other.expedite_regs[i] != NULL) + return false; + + return true; +} + +#endif + +void target_desc::accept (tdesc_element_visitor &v) const +{ +#ifndef IN_PROCESS_AGENT + v.visit_pre (this); + + for (const tdesc_feature_up &feature : features) + feature->accept (v); + + v.visit_post (this); +#endif +} + +void +init_target_desc (struct target_desc *tdesc, + const char **expedite_regs) +{ + int offset = 0; + + /* Go through all the features and populate reg_defs. */ + for (const tdesc_feature_up &feature : tdesc->features) + for (const tdesc_reg_up &treg : feature->registers) + { + int regnum = treg->target_regnum; + + /* Register number will increase (possibly with gaps) or be zero. */ + gdb_assert (regnum == 0 || regnum >= tdesc->reg_defs.size ()); + + if (regnum != 0) + tdesc->reg_defs.resize (regnum, reg (offset)); + + tdesc->reg_defs.emplace_back (treg->name.c_str (), offset, + treg->bitsize); + offset += treg->bitsize; + } + + tdesc->registers_size = offset / 8; + + /* Make sure PBUFSIZ is large enough to hold a full register + packet. */ + gdb_assert (2 * tdesc->registers_size + 32 <= PBUFSIZ); + +#ifndef IN_PROCESS_AGENT + tdesc->expedite_regs = expedite_regs; +#endif +} + +struct target_desc * +allocate_target_description (void) +{ + return new target_desc (); +} + +#ifndef IN_PROCESS_AGENT + +static const struct target_desc default_description {}; + +void +copy_target_description (struct target_desc *dest, + const struct target_desc *src) +{ + dest->reg_defs = src->reg_defs; + dest->expedite_regs = src->expedite_regs; + dest->registers_size = src->registers_size; + dest->xmltarget = src->xmltarget; +} + +const struct target_desc * +current_target_desc (void) +{ + if (current_thread == NULL) + return &default_description; + + return current_process ()->tdesc; +} + +/* See gdbsupport/tdesc.h. */ + +const char * +tdesc_architecture_name (const struct target_desc *target_desc) +{ + return target_desc->arch; +} + +/* See gdbsupport/tdesc.h. */ + +void +set_tdesc_architecture (struct target_desc *target_desc, + const char *name) +{ + target_desc->arch = xstrdup (name); +} + +/* See gdbsupport/tdesc.h. */ + +const char * +tdesc_osabi_name (const struct target_desc *target_desc) +{ + return target_desc->osabi; +} + +/* See gdbsupport/tdesc.h. */ + +void +set_tdesc_osabi (struct target_desc *target_desc, const char *name) +{ + target_desc->osabi = xstrdup (name); +} + +/* See gdbsupport/tdesc.h. */ + +const char * +tdesc_get_features_xml (const target_desc *tdesc) +{ + /* Either .xmltarget or .features is not NULL. */ + gdb_assert (tdesc->xmltarget != NULL + || (!tdesc->features.empty () + && tdesc->arch != NULL)); + + if (tdesc->xmltarget == NULL) + { + std::string buffer ("@"); + print_xml_feature v (&buffer); + tdesc->accept (v); + tdesc->xmltarget = xstrdup (buffer.c_str ()); + } + + return tdesc->xmltarget; +} +#endif + +/* See gdbsupport/tdesc.h. */ + +struct tdesc_feature * +tdesc_create_feature (struct target_desc *tdesc, const char *name) +{ + struct tdesc_feature *new_feature = new tdesc_feature (name); + tdesc->features.emplace_back (new_feature); + return new_feature; +} + +/* See gdbsupport/tdesc.h. */ + +bool +tdesc_contains_feature (const target_desc *tdesc, const std::string &feature) +{ + gdb_assert (tdesc != nullptr); + + for (const tdesc_feature_up &f : tdesc->features) + { + if (f->name == feature) + return true; + } + + return false; +} diff --git a/gdbserver/tdesc.h b/gdbserver/tdesc.h new file mode 100644 index 00000000000..5e0df85cea8 --- /dev/null +++ b/gdbserver/tdesc.h @@ -0,0 +1,101 @@ +/* Target description definitions for remote server for GDB. + Copyright (C) 2012-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_TDESC_H +#define GDBSERVER_TDESC_H + +#include "gdbsupport/tdesc.h" + +#include "regdef.h" +#include + +/* A target description. Inherit from tdesc_feature so that target_desc + can be used as tdesc_feature. */ + +struct target_desc : tdesc_element +{ + /* A vector of elements of register definitions that + describe the inferior's register set. */ + std::vector reg_defs; + + /* The register cache size, in bytes. */ + int registers_size; + + /* XML features in this target description. */ + std::vector features; + +#ifndef IN_PROCESS_AGENT + /* An array of register names. These are the "expedite" registers: + registers whose values are sent along with stop replies. */ + const char **expedite_regs = NULL; + + /* Defines what to return when looking for the "target.xml" file in + response to qXfer:features:read. Its contents can either be + verbatim XML code (prefixed with a '@') or else the name of the + actual XML file to be used in place of "target.xml". + + If NULL then its content will be generated by parsing the target + description into xml. */ + mutable const char *xmltarget = NULL; + + /* The value of element in the XML, replying GDB. */ + const char *arch = NULL; + + /* The value of element in the XML, replying GDB. */ + const char *osabi = NULL; + +public: + target_desc () + : registers_size (0) + {} + + ~target_desc (); + + bool operator== (const target_desc &other) const; + + bool operator!= (const target_desc &other) const + { + return !(*this == other); + } +#endif + + void accept (tdesc_element_visitor &v) const override; +}; + +/* Copy target description SRC to DEST. */ + +void copy_target_description (struct target_desc *dest, + const struct target_desc *src); + +/* Initialize TDESC, and then set its expedite_regs field to + EXPEDITE_REGS. */ + +void init_target_desc (struct target_desc *tdesc, + const char **expedite_regs); + +/* Return the current inferior's target description. Never returns + NULL. */ + +const struct target_desc *current_target_desc (void); + +/* Return true if TDESC contains the feature described by string FEATURE. + Return false otherwise. */ +bool tdesc_contains_feature (const target_desc *tdesc, + const std::string &feature); + +#endif /* GDBSERVER_TDESC_H */ diff --git a/gdbserver/thread-db.c b/gdbserver/thread-db.c new file mode 100644 index 00000000000..2bb6d28820e --- /dev/null +++ b/gdbserver/thread-db.c @@ -0,0 +1,910 @@ +/* Thread management interface, for the remote server for GDB. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + + Contributed by MontaVista Software. + + 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 3 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, see . */ + +#include "server.h" + +#include "linux-low.h" + +#include "debug.h" +#include "gdb_proc_service.h" +#include "nat/gdb_thread_db.h" +#include "gdbsupport/gdb_vecs.h" +#include "nat/linux-procfs.h" +#include "gdbsupport/scoped_restore.h" + +#ifndef USE_LIBTHREAD_DB_DIRECTLY +#include +#endif +#include +#include + +struct thread_db +{ + /* Structure that identifies the child process for the + interface. */ + struct ps_prochandle proc_handle; + + /* Connection to the libthread_db library. */ + td_thragent_t *thread_agent; + + /* If this flag has been set, we've already asked GDB for all + symbols we might need; assume symbol cache misses are + failures. */ + int all_symbols_looked_up; + +#ifndef USE_LIBTHREAD_DB_DIRECTLY + /* Handle of the libthread_db from dlopen. */ + void *handle; +#endif + + /* Addresses of libthread_db functions. */ + td_ta_new_ftype *td_ta_new_p; + td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p; + td_thr_get_info_ftype *td_thr_get_info_p; + td_ta_thr_iter_ftype *td_ta_thr_iter_p; + td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p; + td_thr_tlsbase_ftype *td_thr_tlsbase_p; + td_symbol_list_ftype *td_symbol_list_p; +}; + +static char *libthread_db_search_path; + +static int find_one_thread (ptid_t); +static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); + +static const char * +thread_db_err_str (td_err_e err) +{ + static char buf[64]; + + switch (err) + { + case TD_OK: + return "generic 'call succeeded'"; + case TD_ERR: + return "generic error"; + case TD_NOTHR: + return "no thread to satisfy query"; + case TD_NOSV: + return "no sync handle to satisfy query"; + case TD_NOLWP: + return "no LWP to satisfy query"; + case TD_BADPH: + return "invalid process handle"; + case TD_BADTH: + return "invalid thread handle"; + case TD_BADSH: + return "invalid synchronization handle"; + case TD_BADTA: + return "invalid thread agent"; + case TD_BADKEY: + return "invalid key"; + case TD_NOMSG: + return "no event message for getmsg"; + case TD_NOFPREGS: + return "FPU register set not available"; + case TD_NOLIBTHREAD: + return "application not linked with libthread"; + case TD_NOEVENT: + return "requested event is not supported"; + case TD_NOCAPAB: + return "capability not available"; + case TD_DBERR: + return "debugger service failed"; + case TD_NOAPLIC: + return "operation not applicable to"; + case TD_NOTSD: + return "no thread-specific data for this thread"; + case TD_MALLOC: + return "malloc failed"; + case TD_PARTIALREG: + return "only part of register set was written/read"; + case TD_NOXREGS: + return "X register set not available for this thread"; +#ifdef HAVE_TD_VERSION + case TD_VERSION: + return "version mismatch between libthread_db and libpthread"; +#endif + default: + xsnprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err); + return buf; + } +} + +#if 0 +static char * +thread_db_state_str (td_thr_state_e state) +{ + static char buf[64]; + + switch (state) + { + case TD_THR_STOPPED: + return "stopped by debugger"; + case TD_THR_RUN: + return "runnable"; + case TD_THR_ACTIVE: + return "active"; + case TD_THR_ZOMBIE: + return "zombie"; + case TD_THR_SLEEP: + return "sleeping"; + case TD_THR_STOPPED_ASLEEP: + return "stopped by debugger AND blocked"; + default: + xsnprintf (buf, sizeof (buf), "unknown thread_db state %d", state); + return buf; + } +} +#endif + +/* Get thread info about PTID, accessing memory via the current + thread. */ + +static int +find_one_thread (ptid_t ptid) +{ + td_thrhandle_t th; + td_thrinfo_t ti; + td_err_e err; + struct lwp_info *lwp; + struct thread_db *thread_db = current_process ()->priv->thread_db; + int lwpid = ptid.lwp (); + + thread_info *thread = find_thread_ptid (ptid); + lwp = get_thread_lwp (thread); + if (lwp->thread_known) + return 1; + + /* Get information about this thread. */ + err = thread_db->td_ta_map_lwp2thr_p (thread_db->thread_agent, lwpid, &th); + if (err != TD_OK) + error ("Cannot get thread handle for LWP %d: %s", + lwpid, thread_db_err_str (err)); + + err = thread_db->td_thr_get_info_p (&th, &ti); + if (err != TD_OK) + error ("Cannot get thread info for LWP %d: %s", + lwpid, thread_db_err_str (err)); + + if (debug_threads) + debug_printf ("Found thread %ld (LWP %d)\n", + (unsigned long) ti.ti_tid, ti.ti_lid); + + if (lwpid != ti.ti_lid) + { + warning ("PID mismatch! Expected %ld, got %ld", + (long) lwpid, (long) ti.ti_lid); + return 0; + } + + /* If the new thread ID is zero, a final thread ID will be available + later. Do not enable thread debugging yet. */ + if (ti.ti_tid == 0) + return 0; + + lwp->thread_known = 1; + lwp->th = th; + lwp->thread_handle = ti.ti_tid; + + return 1; +} + +/* Attach a thread. Return true on success. */ + +static int +attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) +{ + struct process_info *proc = current_process (); + int pid = pid_of (proc); + ptid_t ptid = ptid_t (pid, ti_p->ti_lid, 0); + struct lwp_info *lwp; + int err; + + if (debug_threads) + debug_printf ("Attaching to thread %ld (LWP %d)\n", + (unsigned long) ti_p->ti_tid, ti_p->ti_lid); + err = linux_attach_lwp (ptid); + if (err != 0) + { + std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err); + + warning ("Could not attach to thread %ld (LWP %d): %s", + (unsigned long) ti_p->ti_tid, ti_p->ti_lid, reason.c_str ()); + + return 0; + } + + lwp = find_lwp_pid (ptid); + gdb_assert (lwp != NULL); + lwp->thread_known = 1; + lwp->th = *th_p; + lwp->thread_handle = ti_p->ti_tid; + + return 1; +} + +/* Attach thread if we haven't seen it yet. + Increment *COUNTER if we have attached a new thread. + Return false on failure. */ + +static int +maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p, + int *counter) +{ + struct lwp_info *lwp; + + lwp = find_lwp_pid (ptid_t (ti_p->ti_lid)); + if (lwp != NULL) + return 1; + + if (!attach_thread (th_p, ti_p)) + return 0; + + if (counter != NULL) + *counter += 1; + + return 1; +} + +static int +find_new_threads_callback (const td_thrhandle_t *th_p, void *data) +{ + td_thrinfo_t ti; + td_err_e err; + struct thread_db *thread_db = current_process ()->priv->thread_db; + + err = thread_db->td_thr_get_info_p (th_p, &ti); + if (err != TD_OK) + error ("Cannot get thread info: %s", thread_db_err_str (err)); + + if (ti.ti_lid == -1) + { + /* A thread with kernel thread ID -1 is either a thread that + exited and was joined, or a thread that is being created but + hasn't started yet, and that is reusing the tcb/stack of a + thread that previously exited and was joined. (glibc marks + terminated and joined threads with kernel thread ID -1. See + glibc PR17707. */ + if (debug_threads) + debug_printf ("thread_db: skipping exited and " + "joined thread (0x%lx)\n", + (unsigned long) ti.ti_tid); + return 0; + } + + /* Check for zombies. */ + if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) + return 0; + + if (!maybe_attach_thread (th_p, &ti, (int *) data)) + { + /* Terminate iteration early: we might be looking at stale data in + the inferior. The thread_db_find_new_threads will retry. */ + return 1; + } + + return 0; +} + +static void +thread_db_find_new_threads (void) +{ + td_err_e err; + ptid_t ptid = current_ptid; + struct thread_db *thread_db = current_process ()->priv->thread_db; + int loop, iteration; + + /* This function is only called when we first initialize thread_db. + First locate the initial thread. If it is not ready for + debugging yet, then stop. */ + if (find_one_thread (ptid) == 0) + return; + + /* Require 4 successive iterations which do not find any new threads. + The 4 is a heuristic: there is an inherent race here, and I have + seen that 2 iterations in a row are not always sufficient to + "capture" all threads. */ + for (loop = 0, iteration = 0; loop < 4; ++loop, ++iteration) + { + int new_thread_count = 0; + + /* Iterate over all user-space threads to discover new threads. */ + err = thread_db->td_ta_thr_iter_p (thread_db->thread_agent, + find_new_threads_callback, + &new_thread_count, + TD_THR_ANY_STATE, + TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); + if (debug_threads) + debug_printf ("Found %d threads in iteration %d.\n", + new_thread_count, iteration); + + if (new_thread_count != 0) + { + /* Found new threads. Restart iteration from beginning. */ + loop = -1; + } + } + if (err != TD_OK) + error ("Cannot find new threads: %s", thread_db_err_str (err)); +} + +/* Cache all future symbols that thread_db might request. We can not + request symbols at arbitrary states in the remote protocol, only + when the client tells us that new symbols are available. So when + we load the thread library, make sure to check the entire list. */ + +static void +thread_db_look_up_symbols (void) +{ + struct thread_db *thread_db = current_process ()->priv->thread_db; + const char **sym_list; + CORE_ADDR unused; + + for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++) + look_up_one_symbol (*sym_list, &unused, 1); + + /* We're not interested in any other libraries loaded after this + point, only in symbols in libpthread.so. */ + thread_db->all_symbols_looked_up = 1; +} + +int +thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp) +{ + struct thread_db *thread_db = current_process ()->priv->thread_db; + int may_ask_gdb = !thread_db->all_symbols_looked_up; + + /* If we've passed the call to thread_db_look_up_symbols, then + anything not in the cache must not exist; we're not interested + in any libraries loaded after that point, only in symbols in + libpthread.so. It might not be an appropriate time to look + up a symbol, e.g. while we're trying to fetch registers. */ + return look_up_one_symbol (name, addrp, may_ask_gdb); +} + +int +thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, + CORE_ADDR load_module, CORE_ADDR *address) +{ + psaddr_t addr; + td_err_e err; + struct lwp_info *lwp; + struct thread_info *saved_thread; + struct process_info *proc; + struct thread_db *thread_db; + + proc = get_thread_process (thread); + thread_db = proc->priv->thread_db; + + /* If the thread layer is not (yet) initialized, fail. */ + if (thread_db == NULL || !thread_db->all_symbols_looked_up) + return TD_ERR; + + /* If td_thr_tls_get_addr is missing rather do not expect td_thr_tlsbase + could work. */ + if (thread_db->td_thr_tls_get_addr_p == NULL + || (load_module == 0 && thread_db->td_thr_tlsbase_p == NULL)) + return -1; + + lwp = get_thread_lwp (thread); + if (!lwp->thread_known) + find_one_thread (thread->id); + if (!lwp->thread_known) + return TD_NOTHR; + + saved_thread = current_thread; + current_thread = thread; + + if (load_module != 0) + { + /* Note the cast through uintptr_t: this interface only works if + a target address fits in a psaddr_t, which is a host pointer. + So a 32-bit debugger can not access 64-bit TLS through this. */ + err = thread_db->td_thr_tls_get_addr_p (&lwp->th, + (psaddr_t) (uintptr_t) load_module, + offset, &addr); + } + else + { + /* This code path handles the case of -static -pthread executables: + https://sourceware.org/ml/libc-help/2014-03/msg00024.html + For older GNU libc r_debug.r_map is NULL. For GNU libc after + PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL. + The constant number 1 depends on GNU __libc_setup_tls + initialization of l_tls_modid to 1. */ + err = thread_db->td_thr_tlsbase_p (&lwp->th, 1, &addr); + addr = (char *) addr + offset; + } + + current_thread = saved_thread; + if (err == TD_OK) + { + *address = (CORE_ADDR) (uintptr_t) addr; + return 0; + } + else + return err; +} + +/* See linux-low.h. */ + +bool +thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len) +{ + struct thread_db *thread_db; + struct lwp_info *lwp; + thread_info *thread = find_thread_ptid (ptid); + + if (thread == NULL) + return false; + + thread_db = get_thread_process (thread)->priv->thread_db; + + if (thread_db == NULL) + return false; + + lwp = get_thread_lwp (thread); + + if (!lwp->thread_known && !find_one_thread (thread->id)) + return false; + + gdb_assert (lwp->thread_known); + + *handle = (gdb_byte *) &lwp->thread_handle; + *handle_len = sizeof (lwp->thread_handle); + return true; +} + +#ifdef USE_LIBTHREAD_DB_DIRECTLY + +static int +thread_db_load_search (void) +{ + td_err_e err; + struct thread_db *tdb; + struct process_info *proc = current_process (); + + gdb_assert (proc->priv->thread_db == NULL); + + tdb = XCNEW (struct thread_db); + proc->priv->thread_db = tdb; + + tdb->td_ta_new_p = &td_ta_new; + + /* Attempt to open a connection to the thread library. */ + err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); + if (err != TD_OK) + { + if (debug_threads) + debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err)); + free (tdb); + proc->priv->thread_db = NULL; + return 0; + } + + tdb->td_ta_map_lwp2thr_p = &td_ta_map_lwp2thr; + tdb->td_thr_get_info_p = &td_thr_get_info; + tdb->td_ta_thr_iter_p = &td_ta_thr_iter; + tdb->td_symbol_list_p = &td_symbol_list; + + /* These are not essential. */ + tdb->td_thr_tls_get_addr_p = &td_thr_tls_get_addr; + tdb->td_thr_tlsbase_p = &td_thr_tlsbase; + + return 1; +} + +#else + +static int +try_thread_db_load_1 (void *handle) +{ + td_err_e err; + struct thread_db *tdb; + struct process_info *proc = current_process (); + + gdb_assert (proc->priv->thread_db == NULL); + + tdb = XCNEW (struct thread_db); + proc->priv->thread_db = tdb; + + tdb->handle = handle; + + /* Initialize pointers to the dynamic library functions we will use. + Essential functions first. */ + +#define CHK(required, a) \ + do \ + { \ + if ((a) == NULL) \ + { \ + if (debug_threads) \ + debug_printf ("dlsym: %s\n", dlerror ()); \ + if (required) \ + { \ + free (tdb); \ + proc->priv->thread_db = NULL; \ + return 0; \ + } \ + } \ + } \ + while (0) + +#define TDB_DLSYM(tdb, func) \ + tdb->func ## _p = (func ## _ftype *) dlsym (tdb->handle, #func) + + CHK (1, TDB_DLSYM (tdb, td_ta_new)); + + /* Attempt to open a connection to the thread library. */ + err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); + if (err != TD_OK) + { + if (debug_threads) + debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err)); + free (tdb); + proc->priv->thread_db = NULL; + return 0; + } + + CHK (1, TDB_DLSYM (tdb, td_ta_map_lwp2thr)); + CHK (1, TDB_DLSYM (tdb, td_thr_get_info)); + CHK (1, TDB_DLSYM (tdb, td_ta_thr_iter)); + CHK (1, TDB_DLSYM (tdb, td_symbol_list)); + + /* These are not essential. */ + CHK (0, TDB_DLSYM (tdb, td_thr_tls_get_addr)); + CHK (0, TDB_DLSYM (tdb, td_thr_tlsbase)); + +#undef CHK +#undef TDB_DLSYM + + return 1; +} + +#ifdef HAVE_DLADDR + +/* Lookup a library in which given symbol resides. + Note: this is looking in the GDBSERVER process, not in the inferior. + Returns library name, or NULL. */ + +static const char * +dladdr_to_soname (const void *addr) +{ + Dl_info info; + + if (dladdr (addr, &info) != 0) + return info.dli_fname; + return NULL; +} + +#endif + +static int +try_thread_db_load (const char *library) +{ + void *handle; + + if (debug_threads) + debug_printf ("Trying host libthread_db library: %s.\n", + library); + handle = dlopen (library, RTLD_NOW); + if (handle == NULL) + { + if (debug_threads) + debug_printf ("dlopen failed: %s.\n", dlerror ()); + return 0; + } + +#ifdef HAVE_DLADDR + if (debug_threads && strchr (library, '/') == NULL) + { + void *td_init; + + td_init = dlsym (handle, "td_init"); + if (td_init != NULL) + { + const char *const libpath = dladdr_to_soname (td_init); + + if (libpath != NULL) + debug_printf ("Host %s resolved to: %s.\n", library, libpath); + } + } +#endif + + if (try_thread_db_load_1 (handle)) + return 1; + + /* This library "refused" to work on current inferior. */ + dlclose (handle); + return 0; +} + +/* Handle $sdir in libthread-db-search-path. + Look for libthread_db in the system dirs, or wherever a plain + dlopen(file_without_path) will look. + The result is true for success. */ + +static int +try_thread_db_load_from_sdir (void) +{ + return try_thread_db_load (LIBTHREAD_DB_SO); +} + +/* Try to load libthread_db from directory DIR of length DIR_LEN. + The result is true for success. */ + +static int +try_thread_db_load_from_dir (const char *dir, size_t dir_len) +{ + char path[PATH_MAX]; + + if (dir_len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path)) + { + char *cp = (char *) xmalloc (dir_len + 1); + + memcpy (cp, dir, dir_len); + cp[dir_len] = '\0'; + warning (_("libthread-db-search-path component too long," + " ignored: %s."), cp); + free (cp); + return 0; + } + + memcpy (path, dir, dir_len); + path[dir_len] = '/'; + strcpy (path + dir_len + 1, LIBTHREAD_DB_SO); + return try_thread_db_load (path); +} + +/* Search libthread_db_search_path for libthread_db which "agrees" + to work on current inferior. + The result is true for success. */ + +static int +thread_db_load_search (void) +{ + int rc = 0; + + if (libthread_db_search_path == NULL) + libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH); + + std::vector> dir_vec + = dirnames_to_char_ptr_vec (libthread_db_search_path); + + for (const gdb::unique_xmalloc_ptr &this_dir_up : dir_vec) + { + char *this_dir = this_dir_up.get (); + const int pdir_len = sizeof ("$pdir") - 1; + size_t this_dir_len; + + this_dir_len = strlen (this_dir); + + if (strncmp (this_dir, "$pdir", pdir_len) == 0 + && (this_dir[pdir_len] == '\0' + || this_dir[pdir_len] == '/')) + { + /* We don't maintain a list of loaded libraries so we don't know + where libpthread lives. We *could* fetch the info, but we don't + do that yet. Ignore it. */ + } + else if (strcmp (this_dir, "$sdir") == 0) + { + if (try_thread_db_load_from_sdir ()) + { + rc = 1; + break; + } + } + else + { + if (try_thread_db_load_from_dir (this_dir, this_dir_len)) + { + rc = 1; + break; + } + } + } + + if (debug_threads) + debug_printf ("thread_db_load_search returning %d\n", rc); + return rc; +} + +#endif /* USE_LIBTHREAD_DB_DIRECTLY */ + +int +thread_db_init (void) +{ + struct process_info *proc = current_process (); + + /* FIXME drow/2004-10-16: This is the "overall process ID", which + GNU/Linux calls tgid, "thread group ID". When we support + attaching to threads, the original thread may not be the correct + thread. We would have to get the process ID from /proc for NPTL. + + This isn't the only place in gdbserver that assumes that the first + process in the list is the thread group leader. */ + + if (thread_db_load_search ()) + { + /* It's best to avoid td_ta_thr_iter if possible. That walks + data structures in the inferior's address space that may be + corrupted, or, if the target is running, the list may change + while we walk it. In the latter case, it's possible that a + thread exits just at the exact time that causes GDBserver to + get stuck in an infinite loop. As the kernel supports clone + events and /proc/PID/task/ exists, then we already know about + all threads in the process. When we need info out of + thread_db on a given thread (e.g., for TLS), we'll use + find_one_thread then. That uses thread_db entry points that + do not walk libpthread's thread list, so should be safe, as + well as more efficient. */ + if (!linux_proc_task_list_dir_exists (pid_of (proc))) + thread_db_find_new_threads (); + thread_db_look_up_symbols (); + return 1; + } + + return 0; +} + +static void +switch_to_process (struct process_info *proc) +{ + int pid = pid_of (proc); + + current_thread = find_any_thread_of_pid (pid); +} + +/* Disconnect from libthread_db and free resources. */ + +static void +disable_thread_event_reporting (struct process_info *proc) +{ + struct thread_db *thread_db = proc->priv->thread_db; + if (thread_db) + { + td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta, + td_thr_events_t *event); + +#ifndef USE_LIBTHREAD_DB_DIRECTLY + td_ta_clear_event_p + = (td_ta_clear_event_ftype *) dlsym (thread_db->handle, + "td_ta_clear_event"); +#else + td_ta_clear_event_p = &td_ta_clear_event; +#endif + + if (td_ta_clear_event_p != NULL) + { + struct thread_info *saved_thread = current_thread; + td_thr_events_t events; + + switch_to_process (proc); + + /* Set the process wide mask saying we aren't interested + in any events anymore. */ + td_event_fillset (&events); + (*td_ta_clear_event_p) (thread_db->thread_agent, &events); + + current_thread = saved_thread; + } + } +} + +void +thread_db_detach (struct process_info *proc) +{ + struct thread_db *thread_db = proc->priv->thread_db; + + if (thread_db) + { + disable_thread_event_reporting (proc); + } +} + +/* Disconnect from libthread_db and free resources. */ + +void +thread_db_mourn (struct process_info *proc) +{ + struct thread_db *thread_db = proc->priv->thread_db; + if (thread_db) + { + td_ta_delete_ftype *td_ta_delete_p; + +#ifndef USE_LIBTHREAD_DB_DIRECTLY + td_ta_delete_p = (td_ta_delete_ftype *) dlsym (thread_db->handle, "td_ta_delete"); +#else + td_ta_delete_p = &td_ta_delete; +#endif + + if (td_ta_delete_p != NULL) + (*td_ta_delete_p) (thread_db->thread_agent); + +#ifndef USE_LIBTHREAD_DB_DIRECTLY + dlclose (thread_db->handle); +#endif /* USE_LIBTHREAD_DB_DIRECTLY */ + + free (thread_db); + proc->priv->thread_db = NULL; + } +} + +/* Handle "set libthread-db-search-path" monitor command and return 1. + For any other command, return 0. */ + +int +thread_db_handle_monitor_command (char *mon) +{ + const char *cmd = "set libthread-db-search-path"; + size_t cmd_len = strlen (cmd); + + if (strncmp (mon, cmd, cmd_len) == 0 + && (mon[cmd_len] == '\0' + || mon[cmd_len] == ' ')) + { + const char *cp = mon + cmd_len; + + if (libthread_db_search_path != NULL) + free (libthread_db_search_path); + + /* Skip leading space (if any). */ + while (isspace (*cp)) + ++cp; + + if (*cp == '\0') + cp = LIBTHREAD_DB_SEARCH_PATH; + libthread_db_search_path = xstrdup (cp); + + monitor_output ("libthread-db-search-path set to `"); + monitor_output (libthread_db_search_path); + monitor_output ("'\n"); + return 1; + } + + /* Tell server.c to perform default processing. */ + return 0; +} + +/* See linux-low.h. */ + +void +thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid) +{ + process_info *parent_proc = get_thread_process (parent_thr); + struct thread_db *thread_db = parent_proc->priv->thread_db; + + /* If the thread layer isn't initialized, return. It may just + be that the program uses clone, but does not use libthread_db. */ + if (thread_db == NULL || !thread_db->all_symbols_looked_up) + return; + + /* find_one_thread calls into libthread_db which accesses memory via + the current thread. Temporarily switch to a thread we know is + stopped. */ + scoped_restore restore_current_thread + = make_scoped_restore (¤t_thread, parent_thr); + + if (!find_one_thread (child_ptid)) + warning ("Cannot find thread after clone."); +} diff --git a/gdbserver/tracepoint.c b/gdbserver/tracepoint.c new file mode 100644 index 00000000000..bbca48b2efd --- /dev/null +++ b/gdbserver/tracepoint.c @@ -0,0 +1,7473 @@ +/* Tracepoint code for remote server for GDB. + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "tracepoint.h" +#include "gdbthread.h" +#include "gdbsupport/rsp-low.h" + +#include +#include +#include +#include +#include +#include "ax.h" +#include "tdesc.h" + +#define IPA_SYM_STRUCT_NAME ipa_sym_addresses +#include "gdbsupport/agent.h" + +#define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */ + +/* This file is built for both GDBserver, and the in-process + agent (IPA), a shared library that includes a tracing agent that is + loaded by the inferior to support fast tracepoints. Fast + tracepoints (or more accurately, jump based tracepoints) are + implemented by patching the tracepoint location with a jump into a + small trampoline function whose job is to save the register state, + call the in-process tracing agent, and then execute the original + instruction that was under the tracepoint jump (possibly adjusted, + if PC-relative, or some such). + + The current synchronization design is pull based. That means, + GDBserver does most of the work, by peeking/poking at the inferior + agent's memory directly for downloading tracepoint and associated + objects, and for uploading trace frames. Whenever the IPA needs + something from GDBserver (trace buffer is full, tracing stopped for + some reason, etc.) the IPA calls a corresponding hook function + where GDBserver has placed a breakpoint. + + Each of the agents has its own trace buffer. When browsing the + trace frames built from slow and fast tracepoints from GDB (tfind + mode), there's no guarantee the user is seeing the trace frames in + strict chronological creation order, although, GDBserver tries to + keep the order relatively reasonable, by syncing the trace buffers + at appropriate times. + +*/ + +#ifdef IN_PROCESS_AGENT + +static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2); + +static void +trace_vdebug (const char *fmt, ...) +{ + char buf[1024]; + va_list ap; + + va_start (ap, fmt); + vsprintf (buf, fmt, ap); + fprintf (stderr, PROG "/tracepoint: %s\n", buf); + va_end (ap); +} + +#define trace_debug_1(level, fmt, args...) \ + do { \ + if (level <= debug_threads) \ + trace_vdebug ((fmt), ##args); \ + } while (0) + +#else + +#define trace_debug_1(level, fmt, args...) \ + do { \ + if (level <= debug_threads) \ + { \ + debug_printf ((fmt), ##args); \ + debug_printf ("\n"); \ + } \ + } while (0) + +#endif + +#define trace_debug(FMT, args...) \ + trace_debug_1 (1, FMT, ##args) + +/* Prefix exported symbols, for good citizenship. All the symbols + that need exporting are defined in this module. Note that all + these symbols must be tagged with IP_AGENT_EXPORT_*. */ +#ifdef IN_PROCESS_AGENT +# define gdb_tp_heap_buffer IPA_SYM_EXPORTED_NAME (gdb_tp_heap_buffer) +# define gdb_jump_pad_buffer IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer) +# define gdb_jump_pad_buffer_end IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer_end) +# define gdb_trampoline_buffer IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer) +# define gdb_trampoline_buffer_end IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_end) +# define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error) +# define collecting IPA_SYM_EXPORTED_NAME (collecting) +# define gdb_collect_ptr IPA_SYM_EXPORTED_NAME (gdb_collect_ptr) +# define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing) +# define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer) +# define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space) +# define trace_buffer_is_full IPA_SYM_EXPORTED_NAME (trace_buffer_is_full) +# define stopping_tracepoint IPA_SYM_EXPORTED_NAME (stopping_tracepoint) +# define expr_eval_result IPA_SYM_EXPORTED_NAME (expr_eval_result) +# define error_tracepoint IPA_SYM_EXPORTED_NAME (error_tracepoint) +# define tracepoints IPA_SYM_EXPORTED_NAME (tracepoints) +# define tracing IPA_SYM_EXPORTED_NAME (tracing) +# define trace_buffer_ctrl IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl) +# define trace_buffer_ctrl_curr IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl_curr) +# define trace_buffer_lo IPA_SYM_EXPORTED_NAME (trace_buffer_lo) +# define trace_buffer_hi IPA_SYM_EXPORTED_NAME (trace_buffer_hi) +# define traceframe_read_count IPA_SYM_EXPORTED_NAME (traceframe_read_count) +# define traceframe_write_count IPA_SYM_EXPORTED_NAME (traceframe_write_count) +# define traceframes_created IPA_SYM_EXPORTED_NAME (traceframes_created) +# define trace_state_variables IPA_SYM_EXPORTED_NAME (trace_state_variables) +# define get_raw_reg_ptr IPA_SYM_EXPORTED_NAME (get_raw_reg_ptr) +# define get_trace_state_variable_value_ptr \ + IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value_ptr) +# define set_trace_state_variable_value_ptr \ + IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value_ptr) +# define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded) +# define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id) +# define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf) +# define ipa_tdesc_idx IPA_SYM_EXPORTED_NAME (ipa_tdesc_idx) +#endif + +#ifndef IN_PROCESS_AGENT + +/* Addresses of in-process agent's symbols GDBserver cares about. */ + +struct ipa_sym_addresses +{ + CORE_ADDR addr_gdb_tp_heap_buffer; + CORE_ADDR addr_gdb_jump_pad_buffer; + CORE_ADDR addr_gdb_jump_pad_buffer_end; + CORE_ADDR addr_gdb_trampoline_buffer; + CORE_ADDR addr_gdb_trampoline_buffer_end; + CORE_ADDR addr_gdb_trampoline_buffer_error; + CORE_ADDR addr_collecting; + CORE_ADDR addr_gdb_collect_ptr; + CORE_ADDR addr_stop_tracing; + CORE_ADDR addr_flush_trace_buffer; + CORE_ADDR addr_about_to_request_buffer_space; + CORE_ADDR addr_trace_buffer_is_full; + CORE_ADDR addr_stopping_tracepoint; + CORE_ADDR addr_expr_eval_result; + CORE_ADDR addr_error_tracepoint; + CORE_ADDR addr_tracepoints; + CORE_ADDR addr_tracing; + CORE_ADDR addr_trace_buffer_ctrl; + CORE_ADDR addr_trace_buffer_ctrl_curr; + CORE_ADDR addr_trace_buffer_lo; + CORE_ADDR addr_trace_buffer_hi; + CORE_ADDR addr_traceframe_read_count; + CORE_ADDR addr_traceframe_write_count; + CORE_ADDR addr_traceframes_created; + CORE_ADDR addr_trace_state_variables; + CORE_ADDR addr_get_raw_reg_ptr; + CORE_ADDR addr_get_trace_state_variable_value_ptr; + CORE_ADDR addr_set_trace_state_variable_value_ptr; + CORE_ADDR addr_ust_loaded; + CORE_ADDR addr_ipa_tdesc_idx; +}; + +static struct +{ + const char *name; + int offset; +} symbol_list[] = { + IPA_SYM(gdb_tp_heap_buffer), + IPA_SYM(gdb_jump_pad_buffer), + IPA_SYM(gdb_jump_pad_buffer_end), + IPA_SYM(gdb_trampoline_buffer), + IPA_SYM(gdb_trampoline_buffer_end), + IPA_SYM(gdb_trampoline_buffer_error), + IPA_SYM(collecting), + IPA_SYM(gdb_collect_ptr), + IPA_SYM(stop_tracing), + IPA_SYM(flush_trace_buffer), + IPA_SYM(about_to_request_buffer_space), + IPA_SYM(trace_buffer_is_full), + IPA_SYM(stopping_tracepoint), + IPA_SYM(expr_eval_result), + IPA_SYM(error_tracepoint), + IPA_SYM(tracepoints), + IPA_SYM(tracing), + IPA_SYM(trace_buffer_ctrl), + IPA_SYM(trace_buffer_ctrl_curr), + IPA_SYM(trace_buffer_lo), + IPA_SYM(trace_buffer_hi), + IPA_SYM(traceframe_read_count), + IPA_SYM(traceframe_write_count), + IPA_SYM(traceframes_created), + IPA_SYM(trace_state_variables), + IPA_SYM(get_raw_reg_ptr), + IPA_SYM(get_trace_state_variable_value_ptr), + IPA_SYM(set_trace_state_variable_value_ptr), + IPA_SYM(ust_loaded), + IPA_SYM(ipa_tdesc_idx), +}; + +static struct ipa_sym_addresses ipa_sym_addrs; + +static int read_inferior_integer (CORE_ADDR symaddr, int *val); + +/* Returns true if both the in-process agent library and the static + tracepoints libraries are loaded in the inferior, and agent has + capability on static tracepoints. */ + +static int +in_process_agent_supports_ust (void) +{ + int loaded = 0; + + if (!agent_loaded_p ()) + { + warning ("In-process agent not loaded"); + return 0; + } + + if (agent_capability_check (AGENT_CAPA_STATIC_TRACE)) + { + /* Agent understands static tracepoint, then check whether UST is in + fact loaded in the inferior. */ + if (read_inferior_integer (ipa_sym_addrs.addr_ust_loaded, &loaded)) + { + warning ("Error reading ust_loaded in lib"); + return 0; + } + + return loaded; + } + else + return 0; +} + +static void +write_e_ipa_not_loaded (char *buffer) +{ + sprintf (buffer, + "E.In-process agent library not loaded in process. " + "Fast and static tracepoints unavailable."); +} + +/* Write an error to BUFFER indicating that UST isn't loaded in the + inferior. */ + +static void +write_e_ust_not_loaded (char *buffer) +{ +#ifdef HAVE_UST + sprintf (buffer, + "E.UST library not loaded in process. " + "Static tracepoints unavailable."); +#else + sprintf (buffer, "E.GDBserver was built without static tracepoints support"); +#endif +} + +/* If the in-process agent library isn't loaded in the inferior, write + an error to BUFFER, and return 1. Otherwise, return 0. */ + +static int +maybe_write_ipa_not_loaded (char *buffer) +{ + if (!agent_loaded_p ()) + { + write_e_ipa_not_loaded (buffer); + return 1; + } + return 0; +} + +/* If the in-process agent library and the ust (static tracepoints) + library aren't loaded in the inferior, write an error to BUFFER, + and return 1. Otherwise, return 0. */ + +static int +maybe_write_ipa_ust_not_loaded (char *buffer) +{ + if (!agent_loaded_p ()) + { + write_e_ipa_not_loaded (buffer); + return 1; + } + else if (!in_process_agent_supports_ust ()) + { + write_e_ust_not_loaded (buffer); + return 1; + } + return 0; +} + +/* Cache all future symbols that the tracepoints module might request. + We can not request symbols at arbitrary states in the remote + protocol, only when the client tells us that new symbols are + available. So when we load the in-process library, make sure to + check the entire list. */ + +void +tracepoint_look_up_symbols (void) +{ + int i; + + if (agent_loaded_p ()) + return; + + for (i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++) + { + CORE_ADDR *addrp = + (CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset); + + if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0) + { + if (debug_threads) + debug_printf ("symbol `%s' not found\n", symbol_list[i].name); + return; + } + } + + agent_look_up_symbols (NULL); +} + +#endif + +/* GDBserver places a breakpoint on the IPA's version (which is a nop) + of the "stop_tracing" function. When this breakpoint is hit, + tracing stopped in the IPA for some reason. E.g., due to + tracepoint reaching the pass count, hitting conditional expression + evaluation error, etc. + + The IPA's trace buffer is never in circular tracing mode: instead, + GDBserver's is, and whenever the in-process buffer fills, it calls + "flush_trace_buffer", which triggers an internal breakpoint. + GDBserver reacts to this breakpoint by pulling the meanwhile + collected data. Old frames discarding is always handled on the + GDBserver side. */ + +#ifdef IN_PROCESS_AGENT +int +read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + memcpy (myaddr, (void *) (uintptr_t) memaddr, len); + return 0; +} + +/* Call this in the functions where GDBserver places a breakpoint, so + that the compiler doesn't try to be clever and skip calling the + function at all. This is necessary, even if we tell the compiler + to not inline said functions. */ + +#if defined(__GNUC__) +# define UNKNOWN_SIDE_EFFECTS() asm ("") +#else +# define UNKNOWN_SIDE_EFFECTS() do {} while (0) +#endif + +/* This is needed for -Wmissing-declarations. */ +IP_AGENT_EXPORT_FUNC void stop_tracing (void); + +IP_AGENT_EXPORT_FUNC void +stop_tracing (void) +{ + /* GDBserver places breakpoint here. */ + UNKNOWN_SIDE_EFFECTS(); +} + +/* This is needed for -Wmissing-declarations. */ +IP_AGENT_EXPORT_FUNC void flush_trace_buffer (void); + +IP_AGENT_EXPORT_FUNC void +flush_trace_buffer (void) +{ + /* GDBserver places breakpoint here. */ + UNKNOWN_SIDE_EFFECTS(); +} + +#endif + +#ifndef IN_PROCESS_AGENT +static int +tracepoint_handler (CORE_ADDR address) +{ + trace_debug ("tracepoint_handler: tracepoint at 0x%s hit", + paddress (address)); + return 0; +} + +/* Breakpoint at "stop_tracing" in the inferior lib. */ +struct breakpoint *stop_tracing_bkpt; +static int stop_tracing_handler (CORE_ADDR); + +/* Breakpoint at "flush_trace_buffer" in the inferior lib. */ +struct breakpoint *flush_trace_buffer_bkpt; +static int flush_trace_buffer_handler (CORE_ADDR); + +static void download_trace_state_variables (void); +static void upload_fast_traceframes (void); + +static int run_inferior_command (char *cmd, int len); + +static int +read_inferior_integer (CORE_ADDR symaddr, int *val) +{ + return read_inferior_memory (symaddr, (unsigned char *) val, + sizeof (*val)); +} + +struct tracepoint; +static int tracepoint_send_agent (struct tracepoint *tpoint); + +static int +read_inferior_uinteger (CORE_ADDR symaddr, unsigned int *val) +{ + return read_inferior_memory (symaddr, (unsigned char *) val, + sizeof (*val)); +} + +static int +read_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR *val) +{ + void *pval = (void *) (uintptr_t) val; + int ret; + + ret = read_inferior_memory (symaddr, (unsigned char *) &pval, sizeof (pval)); + *val = (uintptr_t) pval; + return ret; +} + +static int +write_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR val) +{ + void *pval = (void *) (uintptr_t) val; + return target_write_memory (symaddr, + (unsigned char *) &pval, sizeof (pval)); +} + +static int +write_inferior_integer (CORE_ADDR symaddr, int val) +{ + return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val)); +} + +static int +write_inferior_int8 (CORE_ADDR symaddr, int8_t val) +{ + return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val)); +} + +static int +write_inferior_uinteger (CORE_ADDR symaddr, unsigned int val) +{ + return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val)); +} + +static CORE_ADDR target_malloc (ULONGEST size); + +#define COPY_FIELD_TO_BUF(BUF, OBJ, FIELD) \ + do { \ + memcpy (BUF, &(OBJ)->FIELD, sizeof ((OBJ)->FIELD)); \ + BUF += sizeof ((OBJ)->FIELD); \ + } while (0) + +#endif + +/* Base action. Concrete actions inherit this. */ + +struct tracepoint_action +{ + char type; +}; + +/* An 'M' (collect memory) action. */ +struct collect_memory_action +{ + struct tracepoint_action base; + + ULONGEST addr; + ULONGEST len; + int32_t basereg; +}; + +/* An 'R' (collect registers) action. */ + +struct collect_registers_action +{ + struct tracepoint_action base; +}; + +/* An 'X' (evaluate expression) action. */ + +struct eval_expr_action +{ + struct tracepoint_action base; + + struct agent_expr *expr; +}; + +/* An 'L' (collect static trace data) action. */ +struct collect_static_trace_data_action +{ + struct tracepoint_action base; +}; + +#ifndef IN_PROCESS_AGENT +static CORE_ADDR +m_tracepoint_action_download (const struct tracepoint_action *action) +{ + CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_memory_action)); + + target_write_memory (ipa_action, (unsigned char *) action, + sizeof (struct collect_memory_action)); + + return ipa_action; +} +static char * +m_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) +{ + struct collect_memory_action *maction + = (struct collect_memory_action *) action; + + COPY_FIELD_TO_BUF (buffer, maction, addr); + COPY_FIELD_TO_BUF (buffer, maction, len); + COPY_FIELD_TO_BUF (buffer, maction, basereg); + + return buffer; +} + +static CORE_ADDR +r_tracepoint_action_download (const struct tracepoint_action *action) +{ + CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_registers_action)); + + target_write_memory (ipa_action, (unsigned char *) action, + sizeof (struct collect_registers_action)); + + return ipa_action; +} + +static char * +r_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) +{ + return buffer; +} + +static CORE_ADDR download_agent_expr (struct agent_expr *expr); + +static CORE_ADDR +x_tracepoint_action_download (const struct tracepoint_action *action) +{ + CORE_ADDR ipa_action = target_malloc (sizeof (struct eval_expr_action)); + CORE_ADDR expr; + + target_write_memory (ipa_action, (unsigned char *) action, + sizeof (struct eval_expr_action)); + expr = download_agent_expr (((struct eval_expr_action *) action)->expr); + write_inferior_data_pointer (ipa_action + + offsetof (struct eval_expr_action, expr), + expr); + + return ipa_action; +} + +/* Copy agent expression AEXPR to buffer pointed by P. If AEXPR is NULL, + copy 0 to P. Return updated header of buffer. */ + +static char * +agent_expr_send (char *p, const struct agent_expr *aexpr) +{ + /* Copy the length of condition first, and then copy its + content. */ + if (aexpr == NULL) + { + memset (p, 0, 4); + p += 4; + } + else + { + memcpy (p, &aexpr->length, 4); + p +=4; + + memcpy (p, aexpr->bytes, aexpr->length); + p += aexpr->length; + } + return p; +} + +static char * +x_tracepoint_action_send ( char *buffer, const struct tracepoint_action *action) +{ + struct eval_expr_action *eaction = (struct eval_expr_action *) action; + + return agent_expr_send (buffer, eaction->expr); +} + +static CORE_ADDR +l_tracepoint_action_download (const struct tracepoint_action *action) +{ + CORE_ADDR ipa_action + = target_malloc (sizeof (struct collect_static_trace_data_action)); + + target_write_memory (ipa_action, (unsigned char *) action, + sizeof (struct collect_static_trace_data_action)); + + return ipa_action; +} + +static char * +l_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) +{ + return buffer; +} + +static char * +tracepoint_action_send (char *buffer, const struct tracepoint_action *action) +{ + switch (action->type) + { + case 'M': + return m_tracepoint_action_send (buffer, action); + case 'R': + return r_tracepoint_action_send (buffer, action); + case 'X': + return x_tracepoint_action_send (buffer, action); + case 'L': + return l_tracepoint_action_send (buffer, action); + } + error ("Unknown trace action '%c'.", action->type); +} + +static CORE_ADDR +tracepoint_action_download (const struct tracepoint_action *action) +{ + switch (action->type) + { + case 'M': + return m_tracepoint_action_download (action); + case 'R': + return r_tracepoint_action_download (action); + case 'X': + return x_tracepoint_action_download (action); + case 'L': + return l_tracepoint_action_download (action); + } + error ("Unknown trace action '%c'.", action->type); +} +#endif + +/* This structure describes a piece of the source-level definition of + the tracepoint. The contents are not interpreted by the target, + but preserved verbatim for uploading upon reconnection. */ + +struct source_string +{ + /* The type of string, such as "cond" for a conditional. */ + char *type; + + /* The source-level string itself. For the sake of target + debugging, we store it in plaintext, even though it is always + transmitted in hex. */ + char *str; + + /* Link to the next one in the list. We link them in the order + received, in case some make up an ordered list of commands or + some such. */ + struct source_string *next; +}; + +enum tracepoint_type +{ + /* Trap based tracepoint. */ + trap_tracepoint, + + /* A fast tracepoint implemented with a jump instead of a trap. */ + fast_tracepoint, + + /* A static tracepoint, implemented by a program call into a tracing + library. */ + static_tracepoint +}; + +struct tracepoint_hit_ctx; + +typedef enum eval_result_type (*condfn) (unsigned char *, + ULONGEST *); + +/* The definition of a tracepoint. */ + +/* Tracepoints may have multiple locations, each at a different + address. This can occur with optimizations, template + instantiation, etc. Since the locations may be in different + scopes, the conditions and actions may be different for each + location. Our target version of tracepoints is more like GDB's + notion of "breakpoint locations", but we have almost nothing that + is not per-location, so we bother having two kinds of objects. The + key consequence is that numbers are not unique, and that it takes + both number and address to identify a tracepoint uniquely. */ + +struct tracepoint +{ + /* The number of the tracepoint, as specified by GDB. Several + tracepoint objects here may share a number. */ + uint32_t number; + + /* Address at which the tracepoint is supposed to trigger. Several + tracepoints may share an address. */ + CORE_ADDR address; + + /* Tracepoint type. */ + enum tracepoint_type type; + + /* True if the tracepoint is currently enabled. */ + int8_t enabled; + + /* The number of single steps that will be performed after each + tracepoint hit. */ + uint64_t step_count; + + /* The number of times the tracepoint may be hit before it will + terminate the entire tracing run. */ + uint64_t pass_count; + + /* Pointer to the agent expression that is the tracepoint's + conditional, or NULL if the tracepoint is unconditional. */ + struct agent_expr *cond; + + /* The list of actions to take when the tracepoint triggers. */ + uint32_t numactions; + struct tracepoint_action **actions; + + /* Count of the times we've hit this tracepoint during the run. + Note that while-stepping steps are not counted as "hits". */ + uint64_t hit_count; + + /* Cached sum of the sizes of traceframes created by this point. */ + uint64_t traceframe_usage; + + CORE_ADDR compiled_cond; + + /* Link to the next tracepoint in the list. */ + struct tracepoint *next; + +#ifndef IN_PROCESS_AGENT + /* The list of actions to take when the tracepoint triggers, in + string/packet form. */ + char **actions_str; + + /* The collection of strings that describe the tracepoint as it was + entered into GDB. These are not used by the target, but are + reported back to GDB upon reconnection. */ + struct source_string *source_strings; + + /* The number of bytes displaced by fast tracepoints. It may subsume + multiple instructions, for multi-byte fast tracepoints. This + field is only valid for fast tracepoints. */ + uint32_t orig_size; + + /* Only for fast tracepoints. */ + CORE_ADDR obj_addr_on_target; + + /* Address range where the original instruction under a fast + tracepoint was relocated to. (_end is actually one byte past + the end). */ + CORE_ADDR adjusted_insn_addr; + CORE_ADDR adjusted_insn_addr_end; + + /* The address range of the piece of the jump pad buffer that was + assigned to this fast tracepoint. (_end is actually one byte + past the end).*/ + CORE_ADDR jump_pad; + CORE_ADDR jump_pad_end; + + /* The address range of the piece of the trampoline buffer that was + assigned to this fast tracepoint. (_end is actually one byte + past the end). */ + CORE_ADDR trampoline; + CORE_ADDR trampoline_end; + + /* The list of actions to take while in a stepping loop. These + fields are only valid for patch-based tracepoints. */ + int num_step_actions; + struct tracepoint_action **step_actions; + /* Same, but in string/packet form. */ + char **step_actions_str; + + /* Handle returned by the breakpoint or tracepoint module when we + inserted the trap or jump, or hooked into a static tracepoint. + NULL if we haven't inserted it yet. */ + void *handle; +#endif + +}; + +#ifndef IN_PROCESS_AGENT + +/* Given `while-stepping', a thread may be collecting data for more + than one tracepoint simultaneously. On the other hand, the same + tracepoint with a while-stepping action may be hit by more than one + thread simultaneously (but not quite, each thread could be handling + a different step). Each thread holds a list of these objects, + representing the current step of each while-stepping action being + collected. */ + +struct wstep_state +{ + struct wstep_state *next; + + /* The tracepoint number. */ + int tp_number; + /* The tracepoint's address. */ + CORE_ADDR tp_address; + + /* The number of the current step in this 'while-stepping' + action. */ + long current_step; +}; + +#endif + +EXTERN_C_PUSH + +/* The linked list of all tracepoints. Marked explicitly as used as + the in-process library doesn't use it for the fast tracepoints + support. */ +IP_AGENT_EXPORT_VAR struct tracepoint *tracepoints; + +/* The first tracepoint to exceed its pass count. */ + +IP_AGENT_EXPORT_VAR struct tracepoint *stopping_tracepoint; + +/* True if the trace buffer is full or otherwise no longer usable. */ + +IP_AGENT_EXPORT_VAR int trace_buffer_is_full; + +/* The first error that occurred during expression evaluation. */ + +/* Stored as an int to avoid the IPA ABI being dependent on whatever + the compiler decides to use for the enum's underlying type. Holds + enum eval_result_type values. */ +IP_AGENT_EXPORT_VAR int expr_eval_result = expr_eval_no_error; + +EXTERN_C_POP + +#ifndef IN_PROCESS_AGENT + +/* Pointer to the last tracepoint in the list, new tracepoints are + linked in at the end. */ + +static struct tracepoint *last_tracepoint; + +static const char *eval_result_names[] = + { + "terror:in the attic", /* this should never be reported */ + "terror:empty expression", + "terror:empty stack", + "terror:stack overflow", + "terror:stack underflow", + "terror:unhandled opcode", + "terror:unrecognized opcode", + "terror:divide by zero" + }; + +#endif + +/* The tracepoint in which the error occurred. */ + +EXTERN_C_PUSH +IP_AGENT_EXPORT_VAR struct tracepoint *error_tracepoint; +EXTERN_C_POP + +struct trace_state_variable +{ + /* This is the name of the variable as used in GDB. The target + doesn't use the name, but needs to have it for saving and + reconnection purposes. */ + char *name; + + /* This number identifies the variable uniquely. Numbers may be + assigned either by the target (in the case of builtin variables), + or by GDB, and are presumed unique during the course of a trace + experiment. */ + int number; + + /* The variable's initial value, a 64-bit signed integer always. */ + LONGEST initial_value; + + /* The variable's value, a 64-bit signed integer always. */ + LONGEST value; + + /* Pointer to a getter function, used to supply computed values. */ + LONGEST (*getter) (void); + + /* Link to the next variable. */ + struct trace_state_variable *next; +}; + +/* Linked list of all trace state variables. */ + +#ifdef IN_PROCESS_AGENT +struct trace_state_variable *alloced_trace_state_variables; +#endif + +IP_AGENT_EXPORT_VAR struct trace_state_variable *trace_state_variables; + +/* The results of tracing go into a fixed-size space known as the + "trace buffer". Because usage follows a limited number of + patterns, we manage it ourselves rather than with malloc. Basic + rules are that we create only one trace frame at a time, each is + variable in size, they are never moved once created, and we only + discard if we are doing a circular buffer, and then only the oldest + ones. Each trace frame includes its own size, so we don't need to + link them together, and the trace frame number is relative to the + first one, so we don't need to record numbers. A trace frame also + records the number of the tracepoint that created it. The data + itself is a series of blocks, each introduced by a single character + and with a defined format. Each type of block has enough + type/length info to allow scanners to jump quickly from one block + to the next without reading each byte in the block. */ + +/* Trace buffer management would be simple - advance a free pointer + from beginning to end, then stop - were it not for the circular + buffer option, which is a useful way to prevent a trace run from + stopping prematurely because the buffer filled up. In the circular + case, the location of the first trace frame (trace_buffer_start) + moves as old trace frames are discarded. Also, since we grow trace + frames incrementally as actions are performed, we wrap around to + the beginning of the trace buffer. This is per-block, so each + block within a trace frame remains contiguous. Things get messy + when the wrapped-around trace frame is the one being discarded; the + free space ends up in two parts at opposite ends of the buffer. */ + +#ifndef ATTR_PACKED +# if defined(__GNUC__) +# define ATTR_PACKED __attribute__ ((packed)) +# else +# define ATTR_PACKED /* nothing */ +# endif +#endif + +/* The data collected at a tracepoint hit. This object should be as + small as possible, since there may be a great many of them. We do + not need to keep a frame number, because they are all sequential + and there are no deletions; so the Nth frame in the buffer is + always frame number N. */ + +struct traceframe +{ + /* Number of the tracepoint that collected this traceframe. A value + of 0 indicates the current end of the trace buffer. We make this + a 16-bit field because it's never going to happen that GDB's + numbering of tracepoints reaches 32,000. */ + int tpnum : 16; + + /* The size of the data in this trace frame. We limit this to 32 + bits, even on a 64-bit target, because it's just implausible that + one is validly going to collect 4 gigabytes of data at a single + tracepoint hit. */ + unsigned int data_size : 32; + + /* The base of the trace data, which is contiguous from this point. */ + unsigned char data[0]; + +} ATTR_PACKED; + +/* The size of the EOB marker, in bytes. A traceframe with zeroed + fields (and no data) marks the end of trace data. */ +#define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data) + +/* This flag is true if the trace buffer is circular, meaning that + when it fills, the oldest trace frames are discarded in order to + make room. */ + +#ifndef IN_PROCESS_AGENT +static int circular_trace_buffer; +#endif + +/* Size of the trace buffer. */ + +static LONGEST trace_buffer_size; + +EXTERN_C_PUSH + +/* Pointer to the block of memory that traceframes all go into. */ + +IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_lo; + +/* Pointer to the end of the trace buffer, more precisely to the byte + after the end of the buffer. */ + +IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_hi; + +EXTERN_C_POP + +/* Control structure holding the read/write/etc. pointers into the + trace buffer. We need more than one of these to implement a + transaction-like mechanism to guarantees that both GDBserver and the + in-process agent can try to change the trace buffer + simultaneously. */ + +struct trace_buffer_control +{ + /* Pointer to the first trace frame in the buffer. In the + non-circular case, this is equal to trace_buffer_lo, otherwise it + moves around in the buffer. */ + unsigned char *start; + + /* Pointer to the free part of the trace buffer. Note that we clear + several bytes at and after this pointer, so that traceframe + scans/searches terminate properly. */ + unsigned char *free; + + /* Pointer to the byte after the end of the free part. Note that + this may be smaller than trace_buffer_free in the circular case, + and means that the free part is in two pieces. Initially it is + equal to trace_buffer_hi, then is generally equivalent to + trace_buffer_start. */ + unsigned char *end_free; + + /* Pointer to the wraparound. If not equal to trace_buffer_hi, then + this is the point at which the trace data breaks, and resumes at + trace_buffer_lo. */ + unsigned char *wrap; +}; + +/* Same as above, to be used by GDBserver when updating the in-process + agent. */ +struct ipa_trace_buffer_control +{ + uintptr_t start; + uintptr_t free; + uintptr_t end_free; + uintptr_t wrap; +}; + + +/* We have possibly both GDBserver and an inferior thread accessing + the same IPA trace buffer memory. The IPA is the producer (tries + to put new frames in the buffer), while GDBserver occasionally + consumes them, that is, flushes the IPA's buffer into its own + buffer. Both sides need to update the trace buffer control + pointers (current head, tail, etc.). We can't use a global lock to + synchronize the accesses, as otherwise we could deadlock GDBserver + (if the thread holding the lock stops for a signal, say). So + instead of that, we use a transaction scheme where GDBserver writes + always prevail over the IPAs writes, and, we have the IPA detect + the commit failure/overwrite, and retry the whole attempt. This is + mainly implemented by having a global token object that represents + who wrote last to the buffer control structure. We need to freeze + any inferior writing to the buffer while GDBserver touches memory, + so that the inferior can correctly detect that GDBserver had been + there, otherwise, it could mistakingly think its commit was + successful; that's implemented by simply having GDBserver set a + breakpoint the inferior hits if it is the critical region. + + There are three cycling trace buffer control structure copies + (buffer head, tail, etc.), with the token object including an index + indicating which is current live copy. The IPA tentatively builds + an updated copy in a non-current control structure, while GDBserver + always clobbers the current version directly. The IPA then tries + to atomically "commit" its version; if GDBserver clobbered the + structure meanwhile, that will fail, and the IPA restarts the + allocation process. + + Listing the step in further detail, we have: + + In-process agent (producer): + + - passes by `about_to_request_buffer_space' breakpoint/lock + + - reads current token, extracts current trace buffer control index, + and starts tentatively updating the rightmost one (0->1, 1->2, + 2->0). Note that only one inferior thread is executing this code + at any given time, due to an outer lock in the jump pads. + + - updates counters, and tries to commit the token. + + - passes by second `about_to_request_buffer_space' breakpoint/lock, + leaving the sync region. + + - checks if the update was effective. + + - if trace buffer was found full, hits flush_trace_buffer + breakpoint, and restarts later afterwards. + + GDBserver (consumer): + + - sets `about_to_request_buffer_space' breakpoint/lock. + + - updates the token unconditionally, using the current buffer + control index, since it knows that the IP agent always writes to + the rightmost, and due to the breakpoint, at most one IP thread + can try to update the trace buffer concurrently to GDBserver, so + there will be no danger of trace buffer control index wrap making + the IPA write to the same index as GDBserver. + + - flushes the IP agent's trace buffer completely, and updates the + current trace buffer control structure. GDBserver *always* wins. + + - removes the `about_to_request_buffer_space' breakpoint. + +The token is stored in the `trace_buffer_ctrl_curr' variable. +Internally, it's bits are defined as: + + |-------------+-----+-------------+--------+-------------+--------------| + | Bit offsets | 31 | 30 - 20 | 19 | 18-8 | 7-0 | + |-------------+-----+-------------+--------+-------------+--------------| + | What | GSB | PC (11-bit) | unused | CC (11-bit) | TBCI (8-bit) | + |-------------+-----+-------------+--------+-------------+--------------| + + GSB - GDBserver Stamp Bit + PC - Previous Counter + CC - Current Counter + TBCI - Trace Buffer Control Index + + +An IPA update of `trace_buffer_ctrl_curr' does: + + - read CC from the current token, save as PC. + - updates pointers + - atomically tries to write PC+1,CC + +A GDBserver update of `trace_buffer_ctrl_curr' does: + + - reads PC and CC from the current token. + - updates pointers + - writes GSB,PC,CC +*/ + +/* These are the bits of `trace_buffer_ctrl_curr' that are reserved + for the counters described below. The cleared bits are used to + hold the index of the items of the `trace_buffer_ctrl' array that + is "current". */ +#define GDBSERVER_FLUSH_COUNT_MASK 0xfffffff0 + +/* `trace_buffer_ctrl_curr' contains two counters. The `previous' + counter, and the `current' counter. */ + +#define GDBSERVER_FLUSH_COUNT_MASK_PREV 0x7ff00000 +#define GDBSERVER_FLUSH_COUNT_MASK_CURR 0x0007ff00 + +/* When GDBserver update the IP agent's `trace_buffer_ctrl_curr', it + always stamps this bit as set. */ +#define GDBSERVER_UPDATED_FLUSH_COUNT_BIT 0x80000000 + +#ifdef IN_PROCESS_AGENT +IP_AGENT_EXPORT_VAR struct trace_buffer_control trace_buffer_ctrl[3]; +IP_AGENT_EXPORT_VAR unsigned int trace_buffer_ctrl_curr; + +# define TRACE_BUFFER_CTRL_CURR \ + (trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK) + +#else + +/* The GDBserver side agent only needs one instance of this object, as + it doesn't need to sync with itself. Define it as array anyway so + that the rest of the code base doesn't need to care for the + difference. */ +struct trace_buffer_control trace_buffer_ctrl[1]; +# define TRACE_BUFFER_CTRL_CURR 0 +#endif + +/* These are convenience macros used to access the current trace + buffer control in effect. */ +#define trace_buffer_start (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].start) +#define trace_buffer_free (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].free) +#define trace_buffer_end_free \ + (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].end_free) +#define trace_buffer_wrap (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].wrap) + + +/* Macro that returns a pointer to the first traceframe in the buffer. */ + +#define FIRST_TRACEFRAME() ((struct traceframe *) trace_buffer_start) + +/* Macro that returns a pointer to the next traceframe in the buffer. + If the computed location is beyond the wraparound point, subtract + the offset of the wraparound. */ + +#define NEXT_TRACEFRAME_1(TF) \ + (((unsigned char *) (TF)) + sizeof (struct traceframe) + (TF)->data_size) + +#define NEXT_TRACEFRAME(TF) \ + ((struct traceframe *) (NEXT_TRACEFRAME_1 (TF) \ + - ((NEXT_TRACEFRAME_1 (TF) >= trace_buffer_wrap) \ + ? (trace_buffer_wrap - trace_buffer_lo) \ + : 0))) + +/* The difference between these counters represents the total number + of complete traceframes present in the trace buffer. The IP agent + writes to the write count, GDBserver writes to read count. */ + +IP_AGENT_EXPORT_VAR unsigned int traceframe_write_count; +IP_AGENT_EXPORT_VAR unsigned int traceframe_read_count; + +/* Convenience macro. */ + +#define traceframe_count \ + ((unsigned int) (traceframe_write_count - traceframe_read_count)) + +/* The count of all traceframes created in the current run, including + ones that were discarded to make room. */ + +IP_AGENT_EXPORT_VAR int traceframes_created; + +#ifndef IN_PROCESS_AGENT + +/* Read-only regions are address ranges whose contents don't change, + and so can be read from target memory even while looking at a trace + frame. Without these, disassembly for instance will likely fail, + because the program code is not usually collected into a trace + frame. This data structure does not need to be very complicated or + particularly efficient, it's only going to be used occasionally, + and only by some commands. */ + +struct readonly_region +{ + /* The bounds of the region. */ + CORE_ADDR start, end; + + /* Link to the next one. */ + struct readonly_region *next; +}; + +/* Linked list of readonly regions. This list stays in effect from + one tstart to the next. */ + +static struct readonly_region *readonly_regions; + +#endif + +/* The global that controls tracing overall. */ + +IP_AGENT_EXPORT_VAR int tracing; + +#ifndef IN_PROCESS_AGENT + +/* Controls whether tracing should continue after GDB disconnects. */ + +int disconnected_tracing; + +/* The reason for the last tracing run to have stopped. We initialize + to a distinct string so that GDB can distinguish between "stopped + after running" and "stopped because never run" cases. */ + +static const char *tracing_stop_reason = "tnotrun"; + +static int tracing_stop_tpnum; + +/* 64-bit timestamps for the trace run's start and finish, expressed + in microseconds from the Unix epoch. */ + +LONGEST tracing_start_time; +LONGEST tracing_stop_time; + +/* The (optional) user-supplied name of the user that started the run. + This is an arbitrary string, and may be NULL. */ + +char *tracing_user_name; + +/* Optional user-supplied text describing the run. This is + an arbitrary string, and may be NULL. */ + +char *tracing_notes; + +/* Optional user-supplied text explaining a tstop command. This is an + arbitrary string, and may be NULL. */ + +char *tracing_stop_note; + +#endif + +/* Functions local to this file. */ + +/* Base "class" for tracepoint type specific data to be passed down to + collect_data_at_tracepoint. */ +struct tracepoint_hit_ctx +{ + enum tracepoint_type type; +}; + +#ifdef IN_PROCESS_AGENT + +/* Fast/jump tracepoint specific data to be passed down to + collect_data_at_tracepoint. */ +struct fast_tracepoint_ctx +{ + struct tracepoint_hit_ctx base; + + struct regcache regcache; + int regcache_initted; + unsigned char *regspace; + + unsigned char *regs; + struct tracepoint *tpoint; +}; + +/* Static tracepoint specific data to be passed down to + collect_data_at_tracepoint. */ +struct static_tracepoint_ctx +{ + struct tracepoint_hit_ctx base; + + /* The regcache corresponding to the registers state at the time of + the tracepoint hit. Initialized lazily, from REGS. */ + struct regcache regcache; + int regcache_initted; + + /* The buffer space REGCACHE above uses. We use a separate buffer + instead of letting the regcache malloc for both signal safety and + performance reasons; this is allocated on the stack instead. */ + unsigned char *regspace; + + /* The register buffer as passed on by lttng/ust. */ + struct registers *regs; + + /* The "printf" formatter and the args the user passed to the marker + call. We use this to be able to collect "static trace data" + ($_sdata). */ + const char *fmt; + va_list *args; + + /* The GDB tracepoint matching the probed marker that was "hit". */ + struct tracepoint *tpoint; +}; + +#else + +/* Static tracepoint specific data to be passed down to + collect_data_at_tracepoint. */ +struct trap_tracepoint_ctx +{ + struct tracepoint_hit_ctx base; + + struct regcache *regcache; +}; + +#endif + +#ifndef IN_PROCESS_AGENT +static CORE_ADDR traceframe_get_pc (struct traceframe *tframe); +static int traceframe_read_tsv (int num, LONGEST *val); +#endif + +static int condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx, + struct tracepoint *tpoint); + +#ifndef IN_PROCESS_AGENT +static void clear_readonly_regions (void); +static void clear_installed_tracepoints (void); +#endif + +static void collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, + CORE_ADDR stop_pc, + struct tracepoint *tpoint); +#ifndef IN_PROCESS_AGENT +static void collect_data_at_step (struct tracepoint_hit_ctx *ctx, + CORE_ADDR stop_pc, + struct tracepoint *tpoint, int current_step); +static void compile_tracepoint_condition (struct tracepoint *tpoint, + CORE_ADDR *jump_entry); +#endif +static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, + CORE_ADDR stop_pc, + struct tracepoint *tpoint, + struct traceframe *tframe, + struct tracepoint_action *taction); + +#ifndef IN_PROCESS_AGENT +static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR); + +static void install_tracepoint (struct tracepoint *, char *own_buf); +static void download_tracepoint (struct tracepoint *); +static int install_fast_tracepoint (struct tracepoint *, char *errbuf); +static void clone_fast_tracepoint (struct tracepoint *to, + const struct tracepoint *from); +#endif + +static LONGEST get_timestamp (void); + +#if defined(__GNUC__) +# define memory_barrier() asm volatile ("" : : : "memory") +#else +# define memory_barrier() do {} while (0) +#endif + +/* We only build the IPA if this builtin is supported, and there are + no uses of this in GDBserver itself, so we're safe in defining this + unconditionally. */ +#define cmpxchg(mem, oldval, newval) \ + __sync_val_compare_and_swap (mem, oldval, newval) + +/* Record that an error occurred during expression evaluation. */ + +static void +record_tracepoint_error (struct tracepoint *tpoint, const char *which, + enum eval_result_type rtype) +{ + trace_debug ("Tracepoint %d at %s %s eval reports error %d", + tpoint->number, paddress (tpoint->address), which, rtype); + +#ifdef IN_PROCESS_AGENT + /* Only record the first error we get. */ + if (cmpxchg (&expr_eval_result, + expr_eval_no_error, + rtype) != expr_eval_no_error) + return; +#else + if (expr_eval_result != expr_eval_no_error) + return; +#endif + + error_tracepoint = tpoint; +} + +/* Trace buffer management. */ + +static void +clear_trace_buffer (void) +{ + trace_buffer_start = trace_buffer_lo; + trace_buffer_free = trace_buffer_lo; + trace_buffer_end_free = trace_buffer_hi; + trace_buffer_wrap = trace_buffer_hi; + /* A traceframe with zeroed fields marks the end of trace data. */ + ((struct traceframe *) trace_buffer_free)->tpnum = 0; + ((struct traceframe *) trace_buffer_free)->data_size = 0; + traceframe_read_count = traceframe_write_count = 0; + traceframes_created = 0; +} + +#ifndef IN_PROCESS_AGENT + +static void +clear_inferior_trace_buffer (void) +{ + CORE_ADDR ipa_trace_buffer_lo; + CORE_ADDR ipa_trace_buffer_hi; + struct traceframe ipa_traceframe = { 0 }; + struct ipa_trace_buffer_control ipa_trace_buffer_ctrl; + + read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo, + &ipa_trace_buffer_lo); + read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi, + &ipa_trace_buffer_hi); + + ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo; + ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo; + ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi; + ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi; + + /* A traceframe with zeroed fields marks the end of trace data. */ + target_write_memory (ipa_sym_addrs.addr_trace_buffer_ctrl, + (unsigned char *) &ipa_trace_buffer_ctrl, + sizeof (ipa_trace_buffer_ctrl)); + + write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, 0); + + /* A traceframe with zeroed fields marks the end of trace data. */ + target_write_memory (ipa_trace_buffer_lo, + (unsigned char *) &ipa_traceframe, + sizeof (ipa_traceframe)); + + write_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, 0); + write_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, 0); + write_inferior_integer (ipa_sym_addrs.addr_traceframes_created, 0); +} + +#endif + +static void +init_trace_buffer (LONGEST bufsize) +{ + size_t alloc_size; + + trace_buffer_size = bufsize; + + /* Make sure to internally allocate at least space for the EOB + marker. */ + alloc_size = (bufsize < TRACEFRAME_EOB_MARKER_SIZE + ? TRACEFRAME_EOB_MARKER_SIZE : bufsize); + trace_buffer_lo = (unsigned char *) xrealloc (trace_buffer_lo, alloc_size); + + trace_buffer_hi = trace_buffer_lo + trace_buffer_size; + + clear_trace_buffer (); +} + +#ifdef IN_PROCESS_AGENT + +/* This is needed for -Wmissing-declarations. */ +IP_AGENT_EXPORT_FUNC void about_to_request_buffer_space (void); + +IP_AGENT_EXPORT_FUNC void +about_to_request_buffer_space (void) +{ + /* GDBserver places breakpoint here while it goes about to flush + data at random times. */ + UNKNOWN_SIDE_EFFECTS(); +} + +#endif + +/* Carve out a piece of the trace buffer, returning NULL in case of + failure. */ + +static void * +trace_buffer_alloc (size_t amt) +{ + unsigned char *rslt; + struct trace_buffer_control *tbctrl; + unsigned int curr; +#ifdef IN_PROCESS_AGENT + unsigned int prev, prev_filtered; + unsigned int commit_count; + unsigned int commit; + unsigned int readout; +#else + struct traceframe *oldest; + unsigned char *new_start; +#endif + + trace_debug ("Want to allocate %ld+%ld bytes in trace buffer", + (long) amt, (long) sizeof (struct traceframe)); + + /* Account for the EOB marker. */ + amt += TRACEFRAME_EOB_MARKER_SIZE; + +#ifdef IN_PROCESS_AGENT + again: + memory_barrier (); + + /* Read the current token and extract the index to try to write to, + storing it in CURR. */ + prev = trace_buffer_ctrl_curr; + prev_filtered = prev & ~GDBSERVER_FLUSH_COUNT_MASK; + curr = prev_filtered + 1; + if (curr > 2) + curr = 0; + + about_to_request_buffer_space (); + + /* Start out with a copy of the current state. GDBserver may be + midway writing to the PREV_FILTERED TBC, but, that's OK, we won't + be able to commit anyway if that happens. */ + trace_buffer_ctrl[curr] + = trace_buffer_ctrl[prev_filtered]; + trace_debug ("trying curr=%u", curr); +#else + /* The GDBserver's agent doesn't need all that syncing, and always + updates TCB 0 (there's only one, mind you). */ + curr = 0; +#endif + tbctrl = &trace_buffer_ctrl[curr]; + + /* Offsets are easier to grok for debugging than raw addresses, + especially for the small trace buffer sizes that are useful for + testing. */ + trace_debug ("Trace buffer [%d] start=%d free=%d endfree=%d wrap=%d hi=%d", + curr, + (int) (tbctrl->start - trace_buffer_lo), + (int) (tbctrl->free - trace_buffer_lo), + (int) (tbctrl->end_free - trace_buffer_lo), + (int) (tbctrl->wrap - trace_buffer_lo), + (int) (trace_buffer_hi - trace_buffer_lo)); + + /* The algorithm here is to keep trying to get a contiguous block of + the requested size, possibly discarding older traceframes to free + up space. Since free space might come in one or two pieces, + depending on whether discarded traceframes wrapped around at the + high end of the buffer, we test both pieces after each + discard. */ + while (1) + { + /* First, if we have two free parts, try the upper one first. */ + if (tbctrl->end_free < tbctrl->free) + { + if (tbctrl->free + amt <= trace_buffer_hi) + /* We have enough in the upper part. */ + break; + else + { + /* Our high part of free space wasn't enough. Give up + on it for now, set wraparound. We will recover the + space later, if/when the wrapped-around traceframe is + discarded. */ + trace_debug ("Upper part too small, setting wraparound"); + tbctrl->wrap = tbctrl->free; + tbctrl->free = trace_buffer_lo; + } + } + + /* The normal case. */ + if (tbctrl->free + amt <= tbctrl->end_free) + break; + +#ifdef IN_PROCESS_AGENT + /* The IP Agent's buffer is always circular. It isn't used + currently, but `circular_trace_buffer' could represent + GDBserver's mode. If we didn't find space, ask GDBserver to + flush. */ + + flush_trace_buffer (); + memory_barrier (); + if (tracing) + { + trace_debug ("gdbserver flushed buffer, retrying"); + goto again; + } + + /* GDBserver cancelled the tracing. Bail out as well. */ + return NULL; +#else + /* If we're here, then neither part is big enough, and + non-circular trace buffers are now full. */ + if (!circular_trace_buffer) + { + trace_debug ("Not enough space in the trace buffer"); + return NULL; + } + + trace_debug ("Need more space in the trace buffer"); + + /* If we have a circular buffer, we can try discarding the + oldest traceframe and see if that helps. */ + oldest = FIRST_TRACEFRAME (); + if (oldest->tpnum == 0) + { + /* Not good; we have no traceframes to free. Perhaps we're + asking for a block that is larger than the buffer? In + any case, give up. */ + trace_debug ("No traceframes to discard"); + return NULL; + } + + /* We don't run this code in the in-process agent currently. + E.g., we could leave the in-process agent in autonomous + circular mode if we only have fast tracepoints. If we do + that, then this bit becomes racy with GDBserver, which also + writes to this counter. */ + --traceframe_write_count; + + new_start = (unsigned char *) NEXT_TRACEFRAME (oldest); + /* If we freed the traceframe that wrapped around, go back + to the non-wrap case. */ + if (new_start < tbctrl->start) + { + trace_debug ("Discarding past the wraparound"); + tbctrl->wrap = trace_buffer_hi; + } + tbctrl->start = new_start; + tbctrl->end_free = tbctrl->start; + + trace_debug ("Discarded a traceframe\n" + "Trace buffer [%d], start=%d free=%d " + "endfree=%d wrap=%d hi=%d", + curr, + (int) (tbctrl->start - trace_buffer_lo), + (int) (tbctrl->free - trace_buffer_lo), + (int) (tbctrl->end_free - trace_buffer_lo), + (int) (tbctrl->wrap - trace_buffer_lo), + (int) (trace_buffer_hi - trace_buffer_lo)); + + /* Now go back around the loop. The discard might have resulted + in either one or two pieces of free space, so we want to try + both before freeing any more traceframes. */ +#endif + } + + /* If we get here, we know we can provide the asked-for space. */ + + rslt = tbctrl->free; + + /* Adjust the request back down, now that we know we have space for + the marker, but don't commit to AMT yet, we may still need to + restart the operation if GDBserver touches the trace buffer + (obviously only important in the in-process agent's version). */ + tbctrl->free += (amt - sizeof (struct traceframe)); + + /* Or not. If GDBserver changed the trace buffer behind our back, + we get to restart a new allocation attempt. */ + +#ifdef IN_PROCESS_AGENT + /* Build the tentative token. */ + commit_count = (((prev & GDBSERVER_FLUSH_COUNT_MASK_CURR) + 0x100) + & GDBSERVER_FLUSH_COUNT_MASK_CURR); + commit = (((prev & GDBSERVER_FLUSH_COUNT_MASK_CURR) << 12) + | commit_count + | curr); + + /* Try to commit it. */ + readout = cmpxchg (&trace_buffer_ctrl_curr, prev, commit); + if (readout != prev) + { + trace_debug ("GDBserver has touched the trace buffer, restarting." + " (prev=%08x, commit=%08x, readout=%08x)", + prev, commit, readout); + goto again; + } + + /* Hold your horses here. Even if that change was committed, + GDBserver could come in, and clobber it. We need to hold to be + able to tell if GDBserver clobbers before or after we committed + the change. Whenever GDBserver goes about touching the IPA + buffer, it sets a breakpoint in this routine, so we have a sync + point here. */ + about_to_request_buffer_space (); + + /* Check if the change has been effective, even if GDBserver stopped + us at the breakpoint. */ + + { + unsigned int refetch; + + memory_barrier (); + + refetch = trace_buffer_ctrl_curr; + + if (refetch == commit + || ((refetch & GDBSERVER_FLUSH_COUNT_MASK_PREV) >> 12) == commit_count) + { + /* effective */ + trace_debug ("change is effective: (prev=%08x, commit=%08x, " + "readout=%08x, refetch=%08x)", + prev, commit, readout, refetch); + } + else + { + trace_debug ("GDBserver has touched the trace buffer, not effective." + " (prev=%08x, commit=%08x, readout=%08x, refetch=%08x)", + prev, commit, readout, refetch); + goto again; + } + } +#endif + + /* We have a new piece of the trace buffer. Hurray! */ + + /* Add an EOB marker just past this allocation. */ + ((struct traceframe *) tbctrl->free)->tpnum = 0; + ((struct traceframe *) tbctrl->free)->data_size = 0; + + /* Adjust the request back down, now that we know we have space for + the marker. */ + amt -= sizeof (struct traceframe); + + if (debug_threads) + { + trace_debug ("Allocated %d bytes", (int) amt); + trace_debug ("Trace buffer [%d] start=%d free=%d " + "endfree=%d wrap=%d hi=%d", + curr, + (int) (tbctrl->start - trace_buffer_lo), + (int) (tbctrl->free - trace_buffer_lo), + (int) (tbctrl->end_free - trace_buffer_lo), + (int) (tbctrl->wrap - trace_buffer_lo), + (int) (trace_buffer_hi - trace_buffer_lo)); + } + + return rslt; +} + +#ifndef IN_PROCESS_AGENT + +/* Return the total free space. This is not necessarily the largest + block we can allocate, because of the two-part case. */ + +static int +free_space (void) +{ + if (trace_buffer_free <= trace_buffer_end_free) + return trace_buffer_end_free - trace_buffer_free; + else + return ((trace_buffer_end_free - trace_buffer_lo) + + (trace_buffer_hi - trace_buffer_free)); +} + +/* An 'S' in continuation packets indicates remainder are for + while-stepping. */ + +static int seen_step_action_flag; + +/* Create a tracepoint (location) with given number and address. Add this + new tracepoint to list and sort this list. */ + +static struct tracepoint * +add_tracepoint (int num, CORE_ADDR addr) +{ + struct tracepoint *tpoint, **tp_next; + + tpoint = XNEW (struct tracepoint); + tpoint->number = num; + tpoint->address = addr; + tpoint->numactions = 0; + tpoint->actions = NULL; + tpoint->actions_str = NULL; + tpoint->cond = NULL; + tpoint->num_step_actions = 0; + tpoint->step_actions = NULL; + tpoint->step_actions_str = NULL; + /* Start all off as regular (slow) tracepoints. */ + tpoint->type = trap_tracepoint; + tpoint->orig_size = -1; + tpoint->source_strings = NULL; + tpoint->compiled_cond = 0; + tpoint->handle = NULL; + tpoint->next = NULL; + + /* Find a place to insert this tracepoint into list in order to keep + the tracepoint list still in the ascending order. There may be + multiple tracepoints at the same address as TPOINT's, and this + guarantees TPOINT is inserted after all the tracepoints which are + set at the same address. For example, fast tracepoints A, B, C are + set at the same address, and D is to be insert at the same place as + well, + + -->| A |--> | B |-->| C |->... + + One jump pad was created for tracepoint A, B, and C, and the target + address of A is referenced/used in jump pad. So jump pad will let + inferior jump to A. If D is inserted in front of A, like this, + + -->| D |-->| A |--> | B |-->| C |->... + + without updating jump pad, D is not reachable during collect, which + is wrong. As we can see, the order of B, C and D doesn't matter, but + A should always be the `first' one. */ + for (tp_next = &tracepoints; + (*tp_next) != NULL && (*tp_next)->address <= tpoint->address; + tp_next = &(*tp_next)->next) + ; + tpoint->next = *tp_next; + *tp_next = tpoint; + last_tracepoint = tpoint; + + seen_step_action_flag = 0; + + return tpoint; +} + +#ifndef IN_PROCESS_AGENT + +/* Return the tracepoint with the given number and address, or NULL. */ + +static struct tracepoint * +find_tracepoint (int id, CORE_ADDR addr) +{ + struct tracepoint *tpoint; + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + if (tpoint->number == id && tpoint->address == addr) + return tpoint; + + return NULL; +} + +/* Remove TPOINT from global list. */ + +static void +remove_tracepoint (struct tracepoint *tpoint) +{ + struct tracepoint *tp, *tp_prev; + + for (tp = tracepoints, tp_prev = NULL; tp && tp != tpoint; + tp_prev = tp, tp = tp->next) + ; + + if (tp) + { + if (tp_prev) + tp_prev->next = tp->next; + else + tracepoints = tp->next; + + xfree (tp); + } +} + +/* There may be several tracepoints with the same number (because they + are "locations", in GDB parlance); return the next one after the + given tracepoint, or search from the beginning of the list if the + first argument is NULL. */ + +static struct tracepoint * +find_next_tracepoint_by_number (struct tracepoint *prev_tp, int num) +{ + struct tracepoint *tpoint; + + if (prev_tp) + tpoint = prev_tp->next; + else + tpoint = tracepoints; + for (; tpoint; tpoint = tpoint->next) + if (tpoint->number == num) + return tpoint; + + return NULL; +} + +#endif + +/* Append another action to perform when the tracepoint triggers. */ + +static void +add_tracepoint_action (struct tracepoint *tpoint, const char *packet) +{ + const char *act; + + if (*packet == 'S') + { + seen_step_action_flag = 1; + ++packet; + } + + act = packet; + + while (*act) + { + const char *act_start = act; + struct tracepoint_action *action = NULL; + + switch (*act) + { + case 'M': + { + struct collect_memory_action *maction = + XNEW (struct collect_memory_action); + ULONGEST basereg; + int is_neg; + + maction->base.type = *act; + action = &maction->base; + + ++act; + is_neg = (*act == '-'); + if (*act == '-') + ++act; + act = unpack_varlen_hex (act, &basereg); + ++act; + act = unpack_varlen_hex (act, &maction->addr); + ++act; + act = unpack_varlen_hex (act, &maction->len); + maction->basereg = (is_neg + ? - (int) basereg + : (int) basereg); + trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)", + pulongest (maction->len), + paddress (maction->addr), maction->basereg); + break; + } + case 'R': + { + struct collect_registers_action *raction = + XNEW (struct collect_registers_action); + + raction->base.type = *act; + action = &raction->base; + + trace_debug ("Want to collect registers"); + ++act; + /* skip past hex digits of mask for now */ + while (isxdigit(*act)) + ++act; + break; + } + case 'L': + { + struct collect_static_trace_data_action *raction = + XNEW (struct collect_static_trace_data_action); + + raction->base.type = *act; + action = &raction->base; + + trace_debug ("Want to collect static trace data"); + ++act; + break; + } + case 'S': + trace_debug ("Unexpected step action, ignoring"); + ++act; + break; + case 'X': + { + struct eval_expr_action *xaction = XNEW (struct eval_expr_action); + + xaction->base.type = *act; + action = &xaction->base; + + trace_debug ("Want to evaluate expression"); + xaction->expr = gdb_parse_agent_expr (&act); + break; + } + default: + trace_debug ("unknown trace action '%c', ignoring...", *act); + break; + case '-': + break; + } + + if (action == NULL) + break; + + if (seen_step_action_flag) + { + tpoint->num_step_actions++; + + tpoint->step_actions + = XRESIZEVEC (struct tracepoint_action *, tpoint->step_actions, + tpoint->num_step_actions); + tpoint->step_actions_str + = XRESIZEVEC (char *, tpoint->step_actions_str, + tpoint->num_step_actions); + tpoint->step_actions[tpoint->num_step_actions - 1] = action; + tpoint->step_actions_str[tpoint->num_step_actions - 1] + = savestring (act_start, act - act_start); + } + else + { + tpoint->numactions++; + tpoint->actions + = XRESIZEVEC (struct tracepoint_action *, tpoint->actions, + tpoint->numactions); + tpoint->actions_str + = XRESIZEVEC (char *, tpoint->actions_str, tpoint->numactions); + tpoint->actions[tpoint->numactions - 1] = action; + tpoint->actions_str[tpoint->numactions - 1] + = savestring (act_start, act - act_start); + } + } +} + +#endif + +/* Find or create a trace state variable with the given number. */ + +static struct trace_state_variable * +get_trace_state_variable (int num) +{ + struct trace_state_variable *tsv; + +#ifdef IN_PROCESS_AGENT + /* Search for an existing variable. */ + for (tsv = alloced_trace_state_variables; tsv; tsv = tsv->next) + if (tsv->number == num) + return tsv; +#endif + + /* Search for an existing variable. */ + for (tsv = trace_state_variables; tsv; tsv = tsv->next) + if (tsv->number == num) + return tsv; + + return NULL; +} + +/* Find or create a trace state variable with the given number. */ + +static struct trace_state_variable * +create_trace_state_variable (int num, int gdb) +{ + struct trace_state_variable *tsv; + + tsv = get_trace_state_variable (num); + if (tsv != NULL) + return tsv; + + /* Create a new variable. */ + tsv = XNEW (struct trace_state_variable); + tsv->number = num; + tsv->initial_value = 0; + tsv->value = 0; + tsv->getter = NULL; + tsv->name = NULL; +#ifdef IN_PROCESS_AGENT + if (!gdb) + { + tsv->next = alloced_trace_state_variables; + alloced_trace_state_variables = tsv; + } + else +#endif + { + tsv->next = trace_state_variables; + trace_state_variables = tsv; + } + return tsv; +} + +/* This is needed for -Wmissing-declarations. */ +IP_AGENT_EXPORT_FUNC LONGEST get_trace_state_variable_value (int num); + +IP_AGENT_EXPORT_FUNC LONGEST +get_trace_state_variable_value (int num) +{ + struct trace_state_variable *tsv; + + tsv = get_trace_state_variable (num); + + if (!tsv) + { + trace_debug ("No trace state variable %d, skipping value get", num); + return 0; + } + + /* Call a getter function if we have one. While it's tempting to + set up something to only call the getter once per tracepoint hit, + it could run afoul of thread races. Better to let the getter + handle it directly, if necessary to worry about it. */ + if (tsv->getter) + tsv->value = (tsv->getter) (); + + trace_debug ("get_trace_state_variable_value(%d) ==> %s", + num, plongest (tsv->value)); + + return tsv->value; +} + +/* This is needed for -Wmissing-declarations. */ +IP_AGENT_EXPORT_FUNC void set_trace_state_variable_value (int num, + LONGEST val); + +IP_AGENT_EXPORT_FUNC void +set_trace_state_variable_value (int num, LONGEST val) +{ + struct trace_state_variable *tsv; + + tsv = get_trace_state_variable (num); + + if (!tsv) + { + trace_debug ("No trace state variable %d, skipping value set", num); + return; + } + + tsv->value = val; +} + +LONGEST +agent_get_trace_state_variable_value (int num) +{ + return get_trace_state_variable_value (num); +} + +void +agent_set_trace_state_variable_value (int num, LONGEST val) +{ + set_trace_state_variable_value (num, val); +} + +static void +set_trace_state_variable_name (int num, const char *name) +{ + struct trace_state_variable *tsv; + + tsv = get_trace_state_variable (num); + + if (!tsv) + { + trace_debug ("No trace state variable %d, skipping name set", num); + return; + } + + tsv->name = (char *) name; +} + +static void +set_trace_state_variable_getter (int num, LONGEST (*getter) (void)) +{ + struct trace_state_variable *tsv; + + tsv = get_trace_state_variable (num); + + if (!tsv) + { + trace_debug ("No trace state variable %d, skipping getter set", num); + return; + } + + tsv->getter = getter; +} + +/* Add a raw traceframe for the given tracepoint. */ + +static struct traceframe * +add_traceframe (struct tracepoint *tpoint) +{ + struct traceframe *tframe; + + tframe + = (struct traceframe *) trace_buffer_alloc (sizeof (struct traceframe)); + + if (tframe == NULL) + return NULL; + + tframe->tpnum = tpoint->number; + tframe->data_size = 0; + + return tframe; +} + +/* Add a block to the traceframe currently being worked on. */ + +static unsigned char * +add_traceframe_block (struct traceframe *tframe, + struct tracepoint *tpoint, int amt) +{ + unsigned char *block; + + if (!tframe) + return NULL; + + block = (unsigned char *) trace_buffer_alloc (amt); + + if (!block) + return NULL; + + gdb_assert (tframe->tpnum == tpoint->number); + + tframe->data_size += amt; + tpoint->traceframe_usage += amt; + + return block; +} + +/* Flag that the current traceframe is finished. */ + +static void +finish_traceframe (struct traceframe *tframe) +{ + ++traceframe_write_count; + ++traceframes_created; +} + +#ifndef IN_PROCESS_AGENT + +/* Given a traceframe number NUM, find the NUMth traceframe in the + buffer. */ + +static struct traceframe * +find_traceframe (int num) +{ + struct traceframe *tframe; + int tfnum = 0; + + for (tframe = FIRST_TRACEFRAME (); + tframe->tpnum != 0; + tframe = NEXT_TRACEFRAME (tframe)) + { + if (tfnum == num) + return tframe; + ++tfnum; + } + + return NULL; +} + +static CORE_ADDR +get_traceframe_address (struct traceframe *tframe) +{ + CORE_ADDR addr; + struct tracepoint *tpoint; + + addr = traceframe_get_pc (tframe); + + if (addr) + return addr; + + /* Fallback strategy, will be incorrect for while-stepping frames + and multi-location tracepoints. */ + tpoint = find_next_tracepoint_by_number (NULL, tframe->tpnum); + return tpoint->address; +} + +/* Search for the next traceframe whose address is inside or outside + the given range. */ + +static struct traceframe * +find_next_traceframe_in_range (CORE_ADDR lo, CORE_ADDR hi, int inside_p, + int *tfnump) +{ + client_state &cs = get_client_state (); + struct traceframe *tframe; + CORE_ADDR tfaddr; + + *tfnump = cs.current_traceframe + 1; + tframe = find_traceframe (*tfnump); + /* The search is not supposed to wrap around. */ + if (!tframe) + { + *tfnump = -1; + return NULL; + } + + for (; tframe->tpnum != 0; tframe = NEXT_TRACEFRAME (tframe)) + { + tfaddr = get_traceframe_address (tframe); + if (inside_p + ? (lo <= tfaddr && tfaddr <= hi) + : (lo > tfaddr || tfaddr > hi)) + return tframe; + ++*tfnump; + } + + *tfnump = -1; + return NULL; +} + +/* Search for the next traceframe recorded by the given tracepoint. + Note that for multi-location tracepoints, this will find whatever + location appears first. */ + +static struct traceframe * +find_next_traceframe_by_tracepoint (int num, int *tfnump) +{ + client_state &cs = get_client_state (); + struct traceframe *tframe; + + *tfnump = cs.current_traceframe + 1; + tframe = find_traceframe (*tfnump); + /* The search is not supposed to wrap around. */ + if (!tframe) + { + *tfnump = -1; + return NULL; + } + + for (; tframe->tpnum != 0; tframe = NEXT_TRACEFRAME (tframe)) + { + if (tframe->tpnum == num) + return tframe; + ++*tfnump; + } + + *tfnump = -1; + return NULL; +} + +#endif + +#ifndef IN_PROCESS_AGENT + +/* Clear all past trace state. */ + +static void +cmd_qtinit (char *packet) +{ + client_state &cs = get_client_state (); + struct trace_state_variable *tsv, *prev, *next; + + /* Can't do this command without a pid attached. */ + if (current_thread == NULL) + { + write_enn (packet); + return; + } + + /* Make sure we don't try to read from a trace frame. */ + cs.current_traceframe = -1; + + stop_tracing (); + + trace_debug ("Initializing the trace"); + + clear_installed_tracepoints (); + clear_readonly_regions (); + + tracepoints = NULL; + last_tracepoint = NULL; + + /* Clear out any leftover trace state variables. Ones with target + defined getters should be kept however. */ + prev = NULL; + tsv = trace_state_variables; + while (tsv) + { + trace_debug ("Looking at var %d", tsv->number); + if (tsv->getter == NULL) + { + next = tsv->next; + if (prev) + prev->next = next; + else + trace_state_variables = next; + trace_debug ("Deleting var %d", tsv->number); + free (tsv); + tsv = next; + } + else + { + prev = tsv; + tsv = tsv->next; + } + } + + clear_trace_buffer (); + clear_inferior_trace_buffer (); + + write_ok (packet); +} + +/* Unprobe the UST marker at ADDRESS. */ + +static void +unprobe_marker_at (CORE_ADDR address) +{ + char cmd[IPA_CMD_BUF_SIZE]; + + sprintf (cmd, "unprobe_marker_at:%s", paddress (address)); + run_inferior_command (cmd, strlen (cmd) + 1); +} + +/* Restore the program to its pre-tracing state. This routine may be called + in error situations, so it needs to be careful about only restoring + from known-valid bits. */ + +static void +clear_installed_tracepoints (void) +{ + struct tracepoint *tpoint; + struct tracepoint *prev_stpoint; + + pause_all (1); + + prev_stpoint = NULL; + + /* Restore any bytes overwritten by tracepoints. */ + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + { + /* Catch the case where we might try to remove a tracepoint that + was never actually installed. */ + if (tpoint->handle == NULL) + { + trace_debug ("Tracepoint %d at 0x%s was " + "never installed, nothing to clear", + tpoint->number, paddress (tpoint->address)); + continue; + } + + switch (tpoint->type) + { + case trap_tracepoint: + { + struct breakpoint *bp + = (struct breakpoint *) tpoint->handle; + + delete_breakpoint (bp); + } + break; + case fast_tracepoint: + { + struct fast_tracepoint_jump *jump + = (struct fast_tracepoint_jump *) tpoint->handle; + + delete_fast_tracepoint_jump (jump); + } + break; + case static_tracepoint: + if (prev_stpoint != NULL + && prev_stpoint->address == tpoint->address) + /* Nothing to do. We already unprobed a tracepoint set at + this marker address (and there can only be one probe + per marker). */ + ; + else + { + unprobe_marker_at (tpoint->address); + prev_stpoint = tpoint; + } + break; + } + + tpoint->handle = NULL; + } + + unpause_all (1); +} + +/* Parse a packet that defines a tracepoint. */ + +static void +cmd_qtdp (char *own_buf) +{ + int tppacket; + /* Whether there is a trailing hyphen at the end of the QTDP packet. */ + int trail_hyphen = 0; + ULONGEST num; + ULONGEST addr; + ULONGEST count; + struct tracepoint *tpoint; + const char *packet = own_buf; + + packet += strlen ("QTDP:"); + + /* A hyphen at the beginning marks a packet specifying actions for a + tracepoint already supplied. */ + tppacket = 1; + if (*packet == '-') + { + tppacket = 0; + ++packet; + } + packet = unpack_varlen_hex (packet, &num); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &addr); + ++packet; /* skip a colon */ + + /* See if we already have this tracepoint. */ + tpoint = find_tracepoint (num, addr); + + if (tppacket) + { + /* Duplicate tracepoints are never allowed. */ + if (tpoint) + { + trace_debug ("Tracepoint error: tracepoint %d" + " at 0x%s already exists", + (int) num, paddress (addr)); + write_enn (own_buf); + return; + } + + tpoint = add_tracepoint (num, addr); + + tpoint->enabled = (*packet == 'E'); + ++packet; /* skip 'E' */ + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &count); + tpoint->step_count = count; + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &count); + tpoint->pass_count = count; + /* See if we have any of the additional optional fields. */ + while (*packet == ':') + { + ++packet; + if (*packet == 'F') + { + tpoint->type = fast_tracepoint; + ++packet; + packet = unpack_varlen_hex (packet, &count); + tpoint->orig_size = count; + } + else if (*packet == 'S') + { + tpoint->type = static_tracepoint; + ++packet; + } + else if (*packet == 'X') + { + tpoint->cond = gdb_parse_agent_expr (&packet); + } + else if (*packet == '-') + break; + else if (*packet == '\0') + break; + else + trace_debug ("Unknown optional tracepoint field"); + } + if (*packet == '-') + { + trail_hyphen = 1; + trace_debug ("Also has actions\n"); + } + + trace_debug ("Defined %stracepoint %d at 0x%s, " + "enabled %d step %" PRIu64 " pass %" PRIu64, + tpoint->type == fast_tracepoint ? "fast " + : tpoint->type == static_tracepoint ? "static " : "", + tpoint->number, paddress (tpoint->address), tpoint->enabled, + tpoint->step_count, tpoint->pass_count); + } + else if (tpoint) + add_tracepoint_action (tpoint, packet); + else + { + trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", + (int) num, paddress (addr)); + write_enn (own_buf); + return; + } + + /* Install tracepoint during tracing only once for each tracepoint location. + For each tracepoint loc, GDB may send multiple QTDP packets, and we can + determine the last QTDP packet for one tracepoint location by checking + trailing hyphen in QTDP packet. */ + if (tracing && !trail_hyphen) + { + struct tracepoint *tp = NULL; + + /* Pause all threads temporarily while we patch tracepoints. */ + pause_all (0); + + /* download_tracepoint will update global `tracepoints' + list, so it is unsafe to leave threads in jump pad. */ + stabilize_threads (); + + /* Freeze threads. */ + pause_all (1); + + + if (tpoint->type != trap_tracepoint) + { + /* Find another fast or static tracepoint at the same address. */ + for (tp = tracepoints; tp; tp = tp->next) + { + if (tp->address == tpoint->address && tp->type == tpoint->type + && tp->number != tpoint->number) + break; + } + + /* TPOINT is installed at the same address as TP. */ + if (tp) + { + if (tpoint->type == fast_tracepoint) + clone_fast_tracepoint (tpoint, tp); + else if (tpoint->type == static_tracepoint) + tpoint->handle = (void *) -1; + } + } + + if (use_agent && tpoint->type == fast_tracepoint + && agent_capability_check (AGENT_CAPA_FAST_TRACE)) + { + /* Download and install fast tracepoint by agent. */ + if (tracepoint_send_agent (tpoint) == 0) + write_ok (own_buf); + else + { + write_enn (own_buf); + remove_tracepoint (tpoint); + } + } + else + { + download_tracepoint (tpoint); + + if (tpoint->type == trap_tracepoint || tp == NULL) + { + install_tracepoint (tpoint, own_buf); + if (strcmp (own_buf, "OK") != 0) + remove_tracepoint (tpoint); + } + else + write_ok (own_buf); + } + + unpause_all (1); + return; + } + + write_ok (own_buf); +} + +static void +cmd_qtdpsrc (char *own_buf) +{ + ULONGEST num, addr, start, slen; + struct tracepoint *tpoint; + const char *packet = own_buf; + const char *saved; + char *srctype, *src; + size_t nbytes; + struct source_string *last, *newlast; + + packet += strlen ("QTDPsrc:"); + + packet = unpack_varlen_hex (packet, &num); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &addr); + ++packet; /* skip a colon */ + + /* See if we already have this tracepoint. */ + tpoint = find_tracepoint (num, addr); + + if (!tpoint) + { + trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", + (int) num, paddress (addr)); + write_enn (own_buf); + return; + } + + saved = packet; + packet = strchr (packet, ':'); + srctype = (char *) xmalloc (packet - saved + 1); + memcpy (srctype, saved, packet - saved); + srctype[packet - saved] = '\0'; + ++packet; + packet = unpack_varlen_hex (packet, &start); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &slen); + ++packet; /* skip a colon */ + src = (char *) xmalloc (slen + 1); + nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2); + src[nbytes] = '\0'; + + newlast = XNEW (struct source_string); + newlast->type = srctype; + newlast->str = src; + newlast->next = NULL; + /* Always add a source string to the end of the list; + this keeps sequences of actions/commands in the right + order. */ + if (tpoint->source_strings) + { + for (last = tpoint->source_strings; last->next; last = last->next) + ; + last->next = newlast; + } + else + tpoint->source_strings = newlast; + + write_ok (own_buf); +} + +static void +cmd_qtdv (char *own_buf) +{ + ULONGEST num, val, builtin; + char *varname; + size_t nbytes; + struct trace_state_variable *tsv; + const char *packet = own_buf; + + packet += strlen ("QTDV:"); + + packet = unpack_varlen_hex (packet, &num); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &val); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &builtin); + ++packet; /* skip a colon */ + + nbytes = strlen (packet) / 2; + varname = (char *) xmalloc (nbytes + 1); + nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes); + varname[nbytes] = '\0'; + + tsv = create_trace_state_variable (num, 1); + tsv->initial_value = (LONGEST) val; + tsv->name = varname; + + set_trace_state_variable_value (num, (LONGEST) val); + + write_ok (own_buf); +} + +static void +cmd_qtenable_disable (char *own_buf, int enable) +{ + const char *packet = own_buf; + ULONGEST num, addr; + struct tracepoint *tp; + + packet += strlen (enable ? "QTEnable:" : "QTDisable:"); + packet = unpack_varlen_hex (packet, &num); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &addr); + + tp = find_tracepoint (num, addr); + + if (tp) + { + if ((enable && tp->enabled) || (!enable && !tp->enabled)) + { + trace_debug ("Tracepoint %d at 0x%s is already %s", + (int) num, paddress (addr), + enable ? "enabled" : "disabled"); + write_ok (own_buf); + return; + } + + trace_debug ("%s tracepoint %d at 0x%s", + enable ? "Enabling" : "Disabling", + (int) num, paddress (addr)); + + tp->enabled = enable; + + if (tp->type == fast_tracepoint || tp->type == static_tracepoint) + { + int ret; + int offset = offsetof (struct tracepoint, enabled); + CORE_ADDR obj_addr = tp->obj_addr_on_target + offset; + + ret = prepare_to_access_memory (); + if (ret) + { + trace_debug ("Failed to temporarily stop inferior threads"); + write_enn (own_buf); + return; + } + + ret = write_inferior_int8 (obj_addr, enable); + done_accessing_memory (); + + if (ret) + { + trace_debug ("Cannot write enabled flag into " + "inferior process memory"); + write_enn (own_buf); + return; + } + } + + write_ok (own_buf); + } + else + { + trace_debug ("Tracepoint %d at 0x%s not found", + (int) num, paddress (addr)); + write_enn (own_buf); + } +} + +static void +cmd_qtv (char *own_buf) +{ + client_state &cs = get_client_state (); + ULONGEST num; + LONGEST val = 0; + int err; + char *packet = own_buf; + + packet += strlen ("qTV:"); + unpack_varlen_hex (packet, &num); + + if (cs.current_traceframe >= 0) + { + err = traceframe_read_tsv ((int) num, &val); + if (err) + { + strcpy (own_buf, "U"); + return; + } + } + /* Only make tsv's be undefined before the first trace run. After a + trace run is over, the user might want to see the last value of + the tsv, and it might not be available in a traceframe. */ + else if (!tracing && strcmp (tracing_stop_reason, "tnotrun") == 0) + { + strcpy (own_buf, "U"); + return; + } + else + val = get_trace_state_variable_value (num); + + sprintf (own_buf, "V%s", phex_nz (val, 0)); +} + +/* Clear out the list of readonly regions. */ + +static void +clear_readonly_regions (void) +{ + struct readonly_region *roreg; + + while (readonly_regions) + { + roreg = readonly_regions; + readonly_regions = readonly_regions->next; + free (roreg); + } +} + +/* Parse the collection of address ranges whose contents GDB believes + to be unchanging and so can be read directly from target memory + even while looking at a traceframe. */ + +static void +cmd_qtro (char *own_buf) +{ + ULONGEST start, end; + struct readonly_region *roreg; + const char *packet = own_buf; + + trace_debug ("Want to mark readonly regions"); + + clear_readonly_regions (); + + packet += strlen ("QTro"); + + while (*packet == ':') + { + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &start); + ++packet; /* skip a comma */ + packet = unpack_varlen_hex (packet, &end); + + roreg = XNEW (struct readonly_region); + roreg->start = start; + roreg->end = end; + roreg->next = readonly_regions; + readonly_regions = roreg; + trace_debug ("Added readonly region from 0x%s to 0x%s", + paddress (roreg->start), paddress (roreg->end)); + } + + write_ok (own_buf); +} + +/* Test to see if the given range is in our list of readonly ranges. + We only test for being entirely within a range, GDB is not going to + send a single memory packet that spans multiple regions. */ + +int +in_readonly_region (CORE_ADDR addr, ULONGEST length) +{ + struct readonly_region *roreg; + + for (roreg = readonly_regions; roreg; roreg = roreg->next) + if (roreg->start <= addr && (addr + length - 1) <= roreg->end) + return 1; + + return 0; +} + +static CORE_ADDR gdb_jump_pad_head; + +/* Return the address of the next free jump space. */ + +static CORE_ADDR +get_jump_space_head (void) +{ + if (gdb_jump_pad_head == 0) + { + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer, + &gdb_jump_pad_head)) + { + internal_error (__FILE__, __LINE__, + "error extracting jump_pad_buffer"); + } + } + + return gdb_jump_pad_head; +} + +/* Reserve USED bytes from the jump space. */ + +static void +claim_jump_space (ULONGEST used) +{ + trace_debug ("claim_jump_space reserves %s bytes at %s", + pulongest (used), paddress (gdb_jump_pad_head)); + gdb_jump_pad_head += used; +} + +static CORE_ADDR trampoline_buffer_head = 0; +static CORE_ADDR trampoline_buffer_tail; + +/* Reserve USED bytes from the trampoline buffer and return the + address of the start of the reserved space in TRAMPOLINE. Returns + non-zero if the space is successfully claimed. */ + +int +claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline) +{ + if (!trampoline_buffer_head) + { + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer, + &trampoline_buffer_tail)) + { + internal_error (__FILE__, __LINE__, + "error extracting trampoline_buffer"); + } + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, + &trampoline_buffer_head)) + { + internal_error (__FILE__, __LINE__, + "error extracting trampoline_buffer_end"); + } + } + + /* Start claiming space from the top of the trampoline space. If + the space is located at the bottom of the virtual address space, + this reduces the possibility that corruption will occur if a null + pointer is used to write to memory. */ + if (trampoline_buffer_head - trampoline_buffer_tail < used) + { + trace_debug ("claim_trampoline_space failed to reserve %s bytes", + pulongest (used)); + return 0; + } + + trampoline_buffer_head -= used; + + trace_debug ("claim_trampoline_space reserves %s bytes at %s", + pulongest (used), paddress (trampoline_buffer_head)); + + *trampoline = trampoline_buffer_head; + return 1; +} + +/* Returns non-zero if there is space allocated for use in trampolines + for fast tracepoints. */ + +int +have_fast_tracepoint_trampoline_buffer (char *buf) +{ + CORE_ADDR trampoline_end, errbuf; + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, + &trampoline_end)) + { + internal_error (__FILE__, __LINE__, + "error extracting trampoline_buffer_end"); + } + + if (buf) + { + buf[0] = '\0'; + strcpy (buf, "was claiming"); + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error, + &errbuf)) + { + internal_error (__FILE__, __LINE__, + "error extracting errbuf"); + } + + read_inferior_memory (errbuf, (unsigned char *) buf, 100); + } + + return trampoline_end != 0; +} + +/* Ask the IPA to probe the marker at ADDRESS. Returns -1 if running + the command fails, or 0 otherwise. If the command ran + successfully, but probing the marker failed, ERROUT will be filled + with the error to reply to GDB, and -1 is also returned. This + allows directly passing IPA errors to GDB. */ + +static int +probe_marker_at (CORE_ADDR address, char *errout) +{ + char cmd[IPA_CMD_BUF_SIZE]; + int err; + + sprintf (cmd, "probe_marker_at:%s", paddress (address)); + err = run_inferior_command (cmd, strlen (cmd) + 1); + + if (err == 0) + { + if (*cmd == 'E') + { + strcpy (errout, cmd); + return -1; + } + } + + return err; +} + +static void +clone_fast_tracepoint (struct tracepoint *to, const struct tracepoint *from) +{ + to->jump_pad = from->jump_pad; + to->jump_pad_end = from->jump_pad_end; + to->trampoline = from->trampoline; + to->trampoline_end = from->trampoline_end; + to->adjusted_insn_addr = from->adjusted_insn_addr; + to->adjusted_insn_addr_end = from->adjusted_insn_addr_end; + to->handle = from->handle; + + gdb_assert (from->handle); + inc_ref_fast_tracepoint_jump ((struct fast_tracepoint_jump *) from->handle); +} + +#define MAX_JUMP_SIZE 20 + +/* Install fast tracepoint. Return 0 if successful, otherwise return + non-zero. */ + +static int +install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf) +{ + CORE_ADDR jentry, jump_entry; + CORE_ADDR trampoline; + CORE_ADDR collect; + ULONGEST trampoline_size; + int err = 0; + /* The jump to the jump pad of the last fast tracepoint + installed. */ + unsigned char fjump[MAX_JUMP_SIZE]; + ULONGEST fjump_size; + + if (tpoint->orig_size < target_get_min_fast_tracepoint_insn_len ()) + { + trace_debug ("Requested a fast tracepoint on an instruction " + "that is of less than the minimum length."); + return 0; + } + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_collect_ptr, + &collect)) + { + error ("error extracting gdb_collect_ptr"); + return 1; + } + + jentry = jump_entry = get_jump_space_head (); + + trampoline = 0; + trampoline_size = 0; + + /* Install the jump pad. */ + err = install_fast_tracepoint_jump_pad (tpoint->obj_addr_on_target, + tpoint->address, + collect, + ipa_sym_addrs.addr_collecting, + tpoint->orig_size, + &jentry, + &trampoline, &trampoline_size, + fjump, &fjump_size, + &tpoint->adjusted_insn_addr, + &tpoint->adjusted_insn_addr_end, + errbuf); + + if (err) + return 1; + + /* Wire it in. */ + tpoint->handle = set_fast_tracepoint_jump (tpoint->address, fjump, + fjump_size); + + if (tpoint->handle != NULL) + { + tpoint->jump_pad = jump_entry; + tpoint->jump_pad_end = jentry; + tpoint->trampoline = trampoline; + tpoint->trampoline_end = trampoline + trampoline_size; + + /* Pad to 8-byte alignment. */ + jentry = ((jentry + 7) & ~0x7); + claim_jump_space (jentry - jump_entry); + } + + return 0; +} + + +/* Install tracepoint TPOINT, and write reply message in OWN_BUF. */ + +static void +install_tracepoint (struct tracepoint *tpoint, char *own_buf) +{ + tpoint->handle = NULL; + *own_buf = '\0'; + + if (tpoint->type == trap_tracepoint) + { + /* Tracepoints are installed as memory breakpoints. Just go + ahead and install the trap. The breakpoints module + handles duplicated breakpoints, and the memory read + routine handles un-patching traps from memory reads. */ + tpoint->handle = set_breakpoint_at (tpoint->address, + tracepoint_handler); + } + else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint) + { + if (!agent_loaded_p ()) + { + trace_debug ("Requested a %s tracepoint, but fast " + "tracepoints aren't supported.", + tpoint->type == static_tracepoint ? "static" : "fast"); + write_e_ipa_not_loaded (own_buf); + return; + } + if (tpoint->type == static_tracepoint + && !in_process_agent_supports_ust ()) + { + trace_debug ("Requested a static tracepoint, but static " + "tracepoints are not supported."); + write_e_ust_not_loaded (own_buf); + return; + } + + if (tpoint->type == fast_tracepoint) + install_fast_tracepoint (tpoint, own_buf); + else + { + if (probe_marker_at (tpoint->address, own_buf) == 0) + tpoint->handle = (void *) -1; + } + + } + else + internal_error (__FILE__, __LINE__, "Unknown tracepoint type"); + + if (tpoint->handle == NULL) + { + if (*own_buf == '\0') + write_enn (own_buf); + } + else + write_ok (own_buf); +} + +static void download_tracepoint_1 (struct tracepoint *tpoint); + +static void +cmd_qtstart (char *packet) +{ + struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint; + CORE_ADDR tpptr = 0, prev_tpptr = 0; + + trace_debug ("Starting the trace"); + + /* Pause all threads temporarily while we patch tracepoints. */ + pause_all (0); + + /* Get threads out of jump pads. Safe to do here, since this is a + top level command. And, required to do here, since we're + deleting/rewriting jump pads. */ + + stabilize_threads (); + + /* Freeze threads. */ + pause_all (1); + + /* Sync the fast tracepoints list in the inferior ftlib. */ + if (agent_loaded_p ()) + download_trace_state_variables (); + + /* No previous fast tpoint yet. */ + prev_ftpoint = NULL; + + /* No previous static tpoint yet. */ + prev_stpoint = NULL; + + *packet = '\0'; + + if (agent_loaded_p ()) + { + /* Tell IPA about the correct tdesc. */ + if (write_inferior_integer (ipa_sym_addrs.addr_ipa_tdesc_idx, + target_get_ipa_tdesc_idx ())) + error ("Error setting ipa_tdesc_idx variable in lib"); + } + + /* Start out empty. */ + if (agent_loaded_p ()) + write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, 0); + + /* Download and install tracepoints. */ + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + { + /* Ensure all the hit counts start at zero. */ + tpoint->hit_count = 0; + tpoint->traceframe_usage = 0; + + if (tpoint->type == trap_tracepoint) + { + /* Tracepoints are installed as memory breakpoints. Just go + ahead and install the trap. The breakpoints module + handles duplicated breakpoints, and the memory read + routine handles un-patching traps from memory reads. */ + tpoint->handle = set_breakpoint_at (tpoint->address, + tracepoint_handler); + } + else if (tpoint->type == fast_tracepoint + || tpoint->type == static_tracepoint) + { + if (maybe_write_ipa_not_loaded (packet)) + { + trace_debug ("Requested a %s tracepoint, but fast " + "tracepoints aren't supported.", + tpoint->type == static_tracepoint + ? "static" : "fast"); + break; + } + + if (tpoint->type == fast_tracepoint) + { + int use_agent_p + = use_agent && agent_capability_check (AGENT_CAPA_FAST_TRACE); + + if (prev_ftpoint != NULL + && prev_ftpoint->address == tpoint->address) + { + if (use_agent_p) + tracepoint_send_agent (tpoint); + else + download_tracepoint_1 (tpoint); + + clone_fast_tracepoint (tpoint, prev_ftpoint); + } + else + { + /* Tracepoint is installed successfully? */ + int installed = 0; + + /* Download and install fast tracepoint by agent. */ + if (use_agent_p) + installed = !tracepoint_send_agent (tpoint); + else + { + download_tracepoint_1 (tpoint); + installed = !install_fast_tracepoint (tpoint, packet); + } + + if (installed) + prev_ftpoint = tpoint; + } + } + else + { + if (!in_process_agent_supports_ust ()) + { + trace_debug ("Requested a static tracepoint, but static " + "tracepoints are not supported."); + break; + } + + download_tracepoint_1 (tpoint); + /* Can only probe a given marker once. */ + if (prev_stpoint != NULL + && prev_stpoint->address == tpoint->address) + tpoint->handle = (void *) -1; + else + { + if (probe_marker_at (tpoint->address, packet) == 0) + { + tpoint->handle = (void *) -1; + + /* So that we can handle multiple static tracepoints + at the same address easily. */ + prev_stpoint = tpoint; + } + } + } + + prev_tpptr = tpptr; + tpptr = tpoint->obj_addr_on_target; + + if (tpoint == tracepoints) + /* First object in list, set the head pointer in the + inferior. */ + write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, tpptr); + else + write_inferior_data_pointer (prev_tpptr + + offsetof (struct tracepoint, next), + tpptr); + } + + /* Any failure in the inner loop is sufficient cause to give + up. */ + if (tpoint->handle == NULL) + break; + } + + /* Any error in tracepoint insertion is unacceptable; better to + address the problem now, than end up with a useless or misleading + trace run. */ + if (tpoint != NULL) + { + clear_installed_tracepoints (); + if (*packet == '\0') + write_enn (packet); + unpause_all (1); + return; + } + + stopping_tracepoint = NULL; + trace_buffer_is_full = 0; + expr_eval_result = expr_eval_no_error; + error_tracepoint = NULL; + tracing_start_time = get_timestamp (); + + /* Tracing is now active, hits will now start being logged. */ + tracing = 1; + + if (agent_loaded_p ()) + { + if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 1)) + { + internal_error (__FILE__, __LINE__, + "Error setting tracing variable in lib"); + } + + if (write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, + 0)) + { + internal_error (__FILE__, __LINE__, + "Error clearing stopping_tracepoint variable" + " in lib"); + } + + if (write_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full, 0)) + { + internal_error (__FILE__, __LINE__, + "Error clearing trace_buffer_is_full variable" + " in lib"); + } + + stop_tracing_bkpt = set_breakpoint_at (ipa_sym_addrs.addr_stop_tracing, + stop_tracing_handler); + if (stop_tracing_bkpt == NULL) + error ("Error setting stop_tracing breakpoint"); + + flush_trace_buffer_bkpt + = set_breakpoint_at (ipa_sym_addrs.addr_flush_trace_buffer, + flush_trace_buffer_handler); + if (flush_trace_buffer_bkpt == NULL) + error ("Error setting flush_trace_buffer breakpoint"); + } + + unpause_all (1); + + write_ok (packet); +} + +/* End a tracing run, filling in a stop reason to report back to GDB, + and removing the tracepoints from the code. */ + +void +stop_tracing (void) +{ + if (!tracing) + { + trace_debug ("Tracing is already off, ignoring"); + return; + } + + trace_debug ("Stopping the trace"); + + /* Pause all threads before removing fast jumps from memory, + breakpoints, and touching IPA state variables (inferior memory). + Some thread may hit the internal tracing breakpoints, or be + collecting this moment, but that's ok, we don't release the + tpoint object's memory or the jump pads here (we only do that + when we're sure we can move all threads out of the jump pads). + We can't now, since we may be getting here due to the inferior + agent calling us. */ + pause_all (1); + + /* Stop logging. Tracepoints can still be hit, but they will not be + recorded. */ + tracing = 0; + if (agent_loaded_p ()) + { + if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 0)) + { + internal_error (__FILE__, __LINE__, + "Error clearing tracing variable in lib"); + } + } + + tracing_stop_time = get_timestamp (); + tracing_stop_reason = "t???"; + tracing_stop_tpnum = 0; + if (stopping_tracepoint) + { + trace_debug ("Stopping the trace because " + "tracepoint %d was hit %" PRIu64 " times", + stopping_tracepoint->number, + stopping_tracepoint->pass_count); + tracing_stop_reason = "tpasscount"; + tracing_stop_tpnum = stopping_tracepoint->number; + } + else if (trace_buffer_is_full) + { + trace_debug ("Stopping the trace because the trace buffer is full"); + tracing_stop_reason = "tfull"; + } + else if (expr_eval_result != expr_eval_no_error) + { + trace_debug ("Stopping the trace because of an expression eval error"); + tracing_stop_reason = eval_result_names[expr_eval_result]; + tracing_stop_tpnum = error_tracepoint->number; + } +#ifndef IN_PROCESS_AGENT + else if (!gdb_connected ()) + { + trace_debug ("Stopping the trace because GDB disconnected"); + tracing_stop_reason = "tdisconnected"; + } +#endif + else + { + trace_debug ("Stopping the trace because of a tstop command"); + tracing_stop_reason = "tstop"; + } + + stopping_tracepoint = NULL; + error_tracepoint = NULL; + + /* Clear out the tracepoints. */ + clear_installed_tracepoints (); + + if (agent_loaded_p ()) + { + /* Pull in fast tracepoint trace frames from the inferior lib + buffer into our buffer, even if our buffer is already full, + because we want to present the full number of created frames + in addition to what fit in the trace buffer. */ + upload_fast_traceframes (); + } + + if (stop_tracing_bkpt != NULL) + { + delete_breakpoint (stop_tracing_bkpt); + stop_tracing_bkpt = NULL; + } + + if (flush_trace_buffer_bkpt != NULL) + { + delete_breakpoint (flush_trace_buffer_bkpt); + flush_trace_buffer_bkpt = NULL; + } + + unpause_all (1); +} + +static int +stop_tracing_handler (CORE_ADDR addr) +{ + trace_debug ("lib hit stop_tracing"); + + /* Don't actually handle it here. When we stop tracing we remove + breakpoints from the inferior, and that is not allowed in a + breakpoint handler (as the caller is walking the breakpoint + list). */ + return 0; +} + +static int +flush_trace_buffer_handler (CORE_ADDR addr) +{ + trace_debug ("lib hit flush_trace_buffer"); + return 0; +} + +static void +cmd_qtstop (char *packet) +{ + stop_tracing (); + write_ok (packet); +} + +static void +cmd_qtdisconnected (char *own_buf) +{ + ULONGEST setting; + char *packet = own_buf; + + packet += strlen ("QTDisconnected:"); + + unpack_varlen_hex (packet, &setting); + + write_ok (own_buf); + + disconnected_tracing = setting; +} + +static void +cmd_qtframe (char *own_buf) +{ + client_state &cs = get_client_state (); + ULONGEST frame, pc, lo, hi, num; + int tfnum, tpnum; + struct traceframe *tframe; + const char *packet = own_buf; + + packet += strlen ("QTFrame:"); + + if (startswith (packet, "pc:")) + { + packet += strlen ("pc:"); + unpack_varlen_hex (packet, &pc); + trace_debug ("Want to find next traceframe at pc=0x%s", paddress (pc)); + tframe = find_next_traceframe_in_range (pc, pc, 1, &tfnum); + } + else if (startswith (packet, "range:")) + { + packet += strlen ("range:"); + packet = unpack_varlen_hex (packet, &lo); + ++packet; + unpack_varlen_hex (packet, &hi); + trace_debug ("Want to find next traceframe in the range 0x%s to 0x%s", + paddress (lo), paddress (hi)); + tframe = find_next_traceframe_in_range (lo, hi, 1, &tfnum); + } + else if (startswith (packet, "outside:")) + { + packet += strlen ("outside:"); + packet = unpack_varlen_hex (packet, &lo); + ++packet; + unpack_varlen_hex (packet, &hi); + trace_debug ("Want to find next traceframe " + "outside the range 0x%s to 0x%s", + paddress (lo), paddress (hi)); + tframe = find_next_traceframe_in_range (lo, hi, 0, &tfnum); + } + else if (startswith (packet, "tdp:")) + { + packet += strlen ("tdp:"); + unpack_varlen_hex (packet, &num); + tpnum = (int) num; + trace_debug ("Want to find next traceframe for tracepoint %d", tpnum); + tframe = find_next_traceframe_by_tracepoint (tpnum, &tfnum); + } + else + { + unpack_varlen_hex (packet, &frame); + tfnum = (int) frame; + if (tfnum == -1) + { + trace_debug ("Want to stop looking at traceframes"); + cs.current_traceframe = -1; + write_ok (own_buf); + return; + } + trace_debug ("Want to look at traceframe %d", tfnum); + tframe = find_traceframe (tfnum); + } + + if (tframe) + { + cs.current_traceframe = tfnum; + sprintf (own_buf, "F%xT%x", tfnum, tframe->tpnum); + } + else + sprintf (own_buf, "F-1"); +} + +static void +cmd_qtstatus (char *packet) +{ + char *stop_reason_rsp = NULL; + char *buf1, *buf2, *buf3; + const char *str; + int slen; + + /* Translate the plain text of the notes back into hex for + transmission. */ + + str = (tracing_user_name ? tracing_user_name : ""); + slen = strlen (str); + buf1 = (char *) alloca (slen * 2 + 1); + bin2hex ((gdb_byte *) str, buf1, slen); + + str = (tracing_notes ? tracing_notes : ""); + slen = strlen (str); + buf2 = (char *) alloca (slen * 2 + 1); + bin2hex ((gdb_byte *) str, buf2, slen); + + str = (tracing_stop_note ? tracing_stop_note : ""); + slen = strlen (str); + buf3 = (char *) alloca (slen * 2 + 1); + bin2hex ((gdb_byte *) str, buf3, slen); + + trace_debug ("Returning trace status as %d, stop reason %s", + tracing, tracing_stop_reason); + + if (agent_loaded_p ()) + { + pause_all (1); + + upload_fast_traceframes (); + + unpause_all (1); + } + + stop_reason_rsp = (char *) tracing_stop_reason; + + /* The user visible error string in terror needs to be hex encoded. + We leave it as plain string in `tracing_stop_reason' to ease + debugging. */ + if (startswith (stop_reason_rsp, "terror:")) + { + const char *result_name; + int hexstr_len; + char *p; + + result_name = stop_reason_rsp + strlen ("terror:"); + hexstr_len = strlen (result_name) * 2; + p = stop_reason_rsp + = (char *) alloca (strlen ("terror:") + hexstr_len + 1); + strcpy (p, "terror:"); + p += strlen (p); + bin2hex ((gdb_byte *) result_name, p, strlen (result_name)); + } + + /* If this was a forced stop, include any stop note that was supplied. */ + if (strcmp (stop_reason_rsp, "tstop") == 0) + { + stop_reason_rsp = (char *) alloca (strlen ("tstop:") + strlen (buf3) + 1); + strcpy (stop_reason_rsp, "tstop:"); + strcat (stop_reason_rsp, buf3); + } + + sprintf (packet, + "T%d;" + "%s:%x;" + "tframes:%x;tcreated:%x;" + "tfree:%x;tsize:%s;" + "circular:%d;" + "disconn:%d;" + "starttime:%s;stoptime:%s;" + "username:%s;notes:%s:", + tracing ? 1 : 0, + stop_reason_rsp, tracing_stop_tpnum, + traceframe_count, traceframes_created, + free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0), + circular_trace_buffer, + disconnected_tracing, + phex_nz (tracing_start_time, sizeof (tracing_start_time)), + phex_nz (tracing_stop_time, sizeof (tracing_stop_time)), + buf1, buf2); +} + +static void +cmd_qtp (char *own_buf) +{ + ULONGEST num, addr; + struct tracepoint *tpoint; + const char *packet = own_buf; + + packet += strlen ("qTP:"); + + packet = unpack_varlen_hex (packet, &num); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &addr); + + /* See if we already have this tracepoint. */ + tpoint = find_tracepoint (num, addr); + + if (!tpoint) + { + trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", + (int) num, paddress (addr)); + write_enn (own_buf); + return; + } + + sprintf (own_buf, "V%" PRIu64 ":%" PRIu64 "", tpoint->hit_count, + tpoint->traceframe_usage); +} + +/* State variables to help return all the tracepoint bits. */ +static struct tracepoint *cur_tpoint; +static unsigned int cur_action; +static unsigned int cur_step_action; +static struct source_string *cur_source_string; +static struct trace_state_variable *cur_tsv; + +/* Compose a response that is an imitation of the syntax by which the + tracepoint was originally downloaded. */ + +static void +response_tracepoint (char *packet, struct tracepoint *tpoint) +{ + char *buf; + + sprintf (packet, "T%x:%s:%c:%" PRIx64 ":%" PRIx64, tpoint->number, + paddress (tpoint->address), + (tpoint->enabled ? 'E' : 'D'), tpoint->step_count, + tpoint->pass_count); + if (tpoint->type == fast_tracepoint) + sprintf (packet + strlen (packet), ":F%x", tpoint->orig_size); + else if (tpoint->type == static_tracepoint) + sprintf (packet + strlen (packet), ":S"); + + if (tpoint->cond) + { + buf = gdb_unparse_agent_expr (tpoint->cond); + sprintf (packet + strlen (packet), ":X%x,%s", + tpoint->cond->length, buf); + free (buf); + } +} + +/* Compose a response that is an imitation of the syntax by which the + tracepoint action was originally downloaded (with the difference + that due to the way we store the actions, this will output a packet + per action, while GDB could have combined more than one action + per-packet. */ + +static void +response_action (char *packet, struct tracepoint *tpoint, + char *taction, int step) +{ + sprintf (packet, "%c%x:%s:%s", + (step ? 'S' : 'A'), tpoint->number, paddress (tpoint->address), + taction); +} + +/* Compose a response that is an imitation of the syntax by which the + tracepoint source piece was originally downloaded. */ + +static void +response_source (char *packet, + struct tracepoint *tpoint, struct source_string *src) +{ + char *buf; + int len; + + len = strlen (src->str); + buf = (char *) alloca (len * 2 + 1); + bin2hex ((gdb_byte *) src->str, buf, len); + + sprintf (packet, "Z%x:%s:%s:%x:%x:%s", + tpoint->number, paddress (tpoint->address), + src->type, 0, len, buf); +} + +/* Return the first piece of tracepoint definition, and initialize the + state machine that will iterate through all the tracepoint + bits. */ + +static void +cmd_qtfp (char *packet) +{ + trace_debug ("Returning first tracepoint definition piece"); + + cur_tpoint = tracepoints; + cur_action = cur_step_action = 0; + cur_source_string = NULL; + + if (cur_tpoint) + response_tracepoint (packet, cur_tpoint); + else + strcpy (packet, "l"); +} + +/* Return additional pieces of tracepoint definition. Each action and + stepping action must go into its own packet, because of packet size + limits, and so we use state variables to deliver one piece at a + time. */ + +static void +cmd_qtsp (char *packet) +{ + trace_debug ("Returning subsequent tracepoint definition piece"); + + if (!cur_tpoint) + { + /* This case would normally never occur, but be prepared for + GDB misbehavior. */ + strcpy (packet, "l"); + } + else if (cur_action < cur_tpoint->numactions) + { + response_action (packet, cur_tpoint, + cur_tpoint->actions_str[cur_action], 0); + ++cur_action; + } + else if (cur_step_action < cur_tpoint->num_step_actions) + { + response_action (packet, cur_tpoint, + cur_tpoint->step_actions_str[cur_step_action], 1); + ++cur_step_action; + } + else if ((cur_source_string + ? cur_source_string->next + : cur_tpoint->source_strings)) + { + if (cur_source_string) + cur_source_string = cur_source_string->next; + else + cur_source_string = cur_tpoint->source_strings; + response_source (packet, cur_tpoint, cur_source_string); + } + else + { + cur_tpoint = cur_tpoint->next; + cur_action = cur_step_action = 0; + cur_source_string = NULL; + if (cur_tpoint) + response_tracepoint (packet, cur_tpoint); + else + strcpy (packet, "l"); + } +} + +/* Compose a response that is an imitation of the syntax by which the + trace state variable was originally downloaded. */ + +static void +response_tsv (char *packet, struct trace_state_variable *tsv) +{ + char *buf = (char *) ""; + int namelen; + + if (tsv->name) + { + namelen = strlen (tsv->name); + buf = (char *) alloca (namelen * 2 + 1); + bin2hex ((gdb_byte *) tsv->name, buf, namelen); + } + + sprintf (packet, "%x:%s:%x:%s", tsv->number, phex_nz (tsv->initial_value, 0), + tsv->getter ? 1 : 0, buf); +} + +/* Return the first trace state variable definition, and initialize + the state machine that will iterate through all the tsv bits. */ + +static void +cmd_qtfv (char *packet) +{ + trace_debug ("Returning first trace state variable definition"); + + cur_tsv = trace_state_variables; + + if (cur_tsv) + response_tsv (packet, cur_tsv); + else + strcpy (packet, "l"); +} + +/* Return additional trace state variable definitions. */ + +static void +cmd_qtsv (char *packet) +{ + trace_debug ("Returning additional trace state variable definition"); + + if (cur_tsv) + { + cur_tsv = cur_tsv->next; + if (cur_tsv) + response_tsv (packet, cur_tsv); + else + strcpy (packet, "l"); + } + else + strcpy (packet, "l"); +} + +/* Return the first static tracepoint marker, and initialize the state + machine that will iterate through all the static tracepoints + markers. */ + +static void +cmd_qtfstm (char *packet) +{ + if (!maybe_write_ipa_ust_not_loaded (packet)) + run_inferior_command (packet, strlen (packet) + 1); +} + +/* Return additional static tracepoints markers. */ + +static void +cmd_qtsstm (char *packet) +{ + if (!maybe_write_ipa_ust_not_loaded (packet)) + run_inferior_command (packet, strlen (packet) + 1); +} + +/* Return the definition of the static tracepoint at a given address. + Result packet is the same as qTsST's. */ + +static void +cmd_qtstmat (char *packet) +{ + if (!maybe_write_ipa_ust_not_loaded (packet)) + run_inferior_command (packet, strlen (packet) + 1); +} + +/* Sent the agent a command to close it. */ + +void +gdb_agent_about_to_close (int pid) +{ + char buf[IPA_CMD_BUF_SIZE]; + + if (!maybe_write_ipa_not_loaded (buf)) + { + struct thread_info *saved_thread; + + saved_thread = current_thread; + + /* Find any thread which belongs to process PID. */ + current_thread = find_any_thread_of_pid (pid); + + strcpy (buf, "close"); + + run_inferior_command (buf, strlen (buf) + 1); + + current_thread = saved_thread; + } +} + +/* Return the minimum instruction size needed for fast tracepoints as a + hexadecimal number. */ + +static void +cmd_qtminftpilen (char *packet) +{ + if (current_thread == NULL) + { + /* Indicate that the minimum length is currently unknown. */ + strcpy (packet, "0"); + return; + } + + sprintf (packet, "%x", target_get_min_fast_tracepoint_insn_len ()); +} + +/* Respond to qTBuffer packet with a block of raw data from the trace + buffer. GDB may ask for a lot, but we are allowed to reply with + only as much as will fit within packet limits or whatever. */ + +static void +cmd_qtbuffer (char *own_buf) +{ + ULONGEST offset, num, tot; + unsigned char *tbp; + const char *packet = own_buf; + + packet += strlen ("qTBuffer:"); + + packet = unpack_varlen_hex (packet, &offset); + ++packet; /* skip a comma */ + unpack_varlen_hex (packet, &num); + + trace_debug ("Want to get trace buffer, %d bytes at offset 0x%s", + (int) num, phex_nz (offset, 0)); + + tot = (trace_buffer_hi - trace_buffer_lo) - free_space (); + + /* If we're right at the end, reply specially that we're done. */ + if (offset == tot) + { + strcpy (own_buf, "l"); + return; + } + + /* Object to any other out-of-bounds request. */ + if (offset > tot) + { + write_enn (own_buf); + return; + } + + /* Compute the pointer corresponding to the given offset, accounting + for wraparound. */ + tbp = trace_buffer_start + offset; + if (tbp >= trace_buffer_wrap) + tbp -= (trace_buffer_wrap - trace_buffer_lo); + + /* Trim to the remaining bytes if we're close to the end. */ + if (num > tot - offset) + num = tot - offset; + + /* Trim to available packet size. */ + if (num >= (PBUFSIZ - 16) / 2 ) + num = (PBUFSIZ - 16) / 2; + + bin2hex (tbp, own_buf, num); +} + +static void +cmd_bigqtbuffer_circular (char *own_buf) +{ + ULONGEST val; + char *packet = own_buf; + + packet += strlen ("QTBuffer:circular:"); + + unpack_varlen_hex (packet, &val); + circular_trace_buffer = val; + trace_debug ("Trace buffer is now %s", + circular_trace_buffer ? "circular" : "linear"); + write_ok (own_buf); +} + +static void +cmd_bigqtbuffer_size (char *own_buf) +{ + ULONGEST val; + LONGEST sval; + char *packet = own_buf; + + /* Can't change the size during a tracing run. */ + if (tracing) + { + write_enn (own_buf); + return; + } + + packet += strlen ("QTBuffer:size:"); + + /* -1 is sent as literal "-1". */ + if (strcmp (packet, "-1") == 0) + sval = DEFAULT_TRACE_BUFFER_SIZE; + else + { + unpack_varlen_hex (packet, &val); + sval = (LONGEST) val; + } + + init_trace_buffer (sval); + trace_debug ("Trace buffer is now %s bytes", + plongest (trace_buffer_size)); + write_ok (own_buf); +} + +static void +cmd_qtnotes (char *own_buf) +{ + size_t nbytes; + char *saved, *user, *notes, *stopnote; + char *packet = own_buf; + + packet += strlen ("QTNotes:"); + + while (*packet) + { + if (startswith (packet, "user:")) + { + packet += strlen ("user:"); + saved = packet; + packet = strchr (packet, ';'); + nbytes = (packet - saved) / 2; + user = (char *) xmalloc (nbytes + 1); + nbytes = hex2bin (saved, (gdb_byte *) user, nbytes); + user[nbytes] = '\0'; + ++packet; /* skip the semicolon */ + trace_debug ("User is '%s'", user); + xfree (tracing_user_name); + tracing_user_name = user; + } + else if (startswith (packet, "notes:")) + { + packet += strlen ("notes:"); + saved = packet; + packet = strchr (packet, ';'); + nbytes = (packet - saved) / 2; + notes = (char *) xmalloc (nbytes + 1); + nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes); + notes[nbytes] = '\0'; + ++packet; /* skip the semicolon */ + trace_debug ("Notes is '%s'", notes); + xfree (tracing_notes); + tracing_notes = notes; + } + else if (startswith (packet, "tstop:")) + { + packet += strlen ("tstop:"); + saved = packet; + packet = strchr (packet, ';'); + nbytes = (packet - saved) / 2; + stopnote = (char *) xmalloc (nbytes + 1); + nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes); + stopnote[nbytes] = '\0'; + ++packet; /* skip the semicolon */ + trace_debug ("tstop note is '%s'", stopnote); + xfree (tracing_stop_note); + tracing_stop_note = stopnote; + } + else + break; + } + + write_ok (own_buf); +} + +int +handle_tracepoint_general_set (char *packet) +{ + if (strcmp ("QTinit", packet) == 0) + { + cmd_qtinit (packet); + return 1; + } + else if (startswith (packet, "QTDP:")) + { + cmd_qtdp (packet); + return 1; + } + else if (startswith (packet, "QTDPsrc:")) + { + cmd_qtdpsrc (packet); + return 1; + } + else if (startswith (packet, "QTEnable:")) + { + cmd_qtenable_disable (packet, 1); + return 1; + } + else if (startswith (packet, "QTDisable:")) + { + cmd_qtenable_disable (packet, 0); + return 1; + } + else if (startswith (packet, "QTDV:")) + { + cmd_qtdv (packet); + return 1; + } + else if (startswith (packet, "QTro:")) + { + cmd_qtro (packet); + return 1; + } + else if (strcmp ("QTStart", packet) == 0) + { + cmd_qtstart (packet); + return 1; + } + else if (strcmp ("QTStop", packet) == 0) + { + cmd_qtstop (packet); + return 1; + } + else if (startswith (packet, "QTDisconnected:")) + { + cmd_qtdisconnected (packet); + return 1; + } + else if (startswith (packet, "QTFrame:")) + { + cmd_qtframe (packet); + return 1; + } + else if (startswith (packet, "QTBuffer:circular:")) + { + cmd_bigqtbuffer_circular (packet); + return 1; + } + else if (startswith (packet, "QTBuffer:size:")) + { + cmd_bigqtbuffer_size (packet); + return 1; + } + else if (startswith (packet, "QTNotes:")) + { + cmd_qtnotes (packet); + return 1; + } + + return 0; +} + +int +handle_tracepoint_query (char *packet) +{ + if (strcmp ("qTStatus", packet) == 0) + { + cmd_qtstatus (packet); + return 1; + } + else if (startswith (packet, "qTP:")) + { + cmd_qtp (packet); + return 1; + } + else if (strcmp ("qTfP", packet) == 0) + { + cmd_qtfp (packet); + return 1; + } + else if (strcmp ("qTsP", packet) == 0) + { + cmd_qtsp (packet); + return 1; + } + else if (strcmp ("qTfV", packet) == 0) + { + cmd_qtfv (packet); + return 1; + } + else if (strcmp ("qTsV", packet) == 0) + { + cmd_qtsv (packet); + return 1; + } + else if (startswith (packet, "qTV:")) + { + cmd_qtv (packet); + return 1; + } + else if (startswith (packet, "qTBuffer:")) + { + cmd_qtbuffer (packet); + return 1; + } + else if (strcmp ("qTfSTM", packet) == 0) + { + cmd_qtfstm (packet); + return 1; + } + else if (strcmp ("qTsSTM", packet) == 0) + { + cmd_qtsstm (packet); + return 1; + } + else if (startswith (packet, "qTSTMat:")) + { + cmd_qtstmat (packet); + return 1; + } + else if (strcmp ("qTMinFTPILen", packet) == 0) + { + cmd_qtminftpilen (packet); + return 1; + } + + return 0; +} + +#endif +#ifndef IN_PROCESS_AGENT + +/* Call this when thread TINFO has hit the tracepoint defined by + TP_NUMBER and TP_ADDRESS, and that tracepoint has a while-stepping + action. This adds a while-stepping collecting state item to the + threads' collecting state list, so that we can keep track of + multiple simultaneous while-stepping actions being collected by the + same thread. This can happen in cases like: + + ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs + ff0002 INSN2 + ff0003 INSN3 <-- TP2, collect $regs + ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs + ff0005 INSN5 + + Notice that when instruction INSN5 is reached, the while-stepping + actions of both TP1 and TP3 are still being collected, and that TP2 + had been collected meanwhile. The whole range of ff0001-ff0005 + should be single-stepped, due to at least TP1's while-stepping + action covering the whole range. */ + +static void +add_while_stepping_state (struct thread_info *tinfo, + int tp_number, CORE_ADDR tp_address) +{ + struct wstep_state *wstep = XNEW (struct wstep_state); + + wstep->next = tinfo->while_stepping; + + wstep->tp_number = tp_number; + wstep->tp_address = tp_address; + wstep->current_step = 0; + + tinfo->while_stepping = wstep; +} + +/* Release the while-stepping collecting state WSTEP. */ + +static void +release_while_stepping_state (struct wstep_state *wstep) +{ + free (wstep); +} + +/* Release all while-stepping collecting states currently associated + with thread TINFO. */ + +void +release_while_stepping_state_list (struct thread_info *tinfo) +{ + struct wstep_state *head; + + while (tinfo->while_stepping) + { + head = tinfo->while_stepping; + tinfo->while_stepping = head->next; + release_while_stepping_state (head); + } +} + +/* If TINFO was handling a 'while-stepping' action, the step has + finished, so collect any step data needed, and check if any more + steps are required. Return true if the thread was indeed + collecting tracepoint data, false otherwise. */ + +int +tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc) +{ + struct tracepoint *tpoint; + struct wstep_state *wstep; + struct wstep_state **wstep_link; + struct trap_tracepoint_ctx ctx; + + /* Pull in fast tracepoint trace frames from the inferior lib buffer into + our buffer. */ + if (agent_loaded_p ()) + upload_fast_traceframes (); + + /* Check if we were indeed collecting data for one of more + tracepoints with a 'while-stepping' count. */ + if (tinfo->while_stepping == NULL) + return 0; + + if (!tracing) + { + /* We're not even tracing anymore. Stop this thread from + collecting. */ + release_while_stepping_state_list (tinfo); + + /* The thread had stopped due to a single-step request indeed + explained by a tracepoint. */ + return 1; + } + + wstep = tinfo->while_stepping; + wstep_link = &tinfo->while_stepping; + + trace_debug ("Thread %s finished a single-step for tracepoint %d at 0x%s", + target_pid_to_str (tinfo->id), + wstep->tp_number, paddress (wstep->tp_address)); + + ctx.base.type = trap_tracepoint; + ctx.regcache = get_thread_regcache (tinfo, 1); + + while (wstep != NULL) + { + tpoint = find_tracepoint (wstep->tp_number, wstep->tp_address); + if (tpoint == NULL) + { + trace_debug ("NO TRACEPOINT %d at 0x%s FOR THREAD %s!", + wstep->tp_number, paddress (wstep->tp_address), + target_pid_to_str (tinfo->id)); + + /* Unlink. */ + *wstep_link = wstep->next; + release_while_stepping_state (wstep); + wstep = *wstep_link; + continue; + } + + /* We've just finished one step. */ + ++wstep->current_step; + + /* Collect data. */ + collect_data_at_step ((struct tracepoint_hit_ctx *) &ctx, + stop_pc, tpoint, wstep->current_step); + + if (wstep->current_step >= tpoint->step_count) + { + /* The requested numbers of steps have occurred. */ + trace_debug ("Thread %s done stepping for tracepoint %d at 0x%s", + target_pid_to_str (tinfo->id), + wstep->tp_number, paddress (wstep->tp_address)); + + /* Unlink the wstep. */ + *wstep_link = wstep->next; + release_while_stepping_state (wstep); + wstep = *wstep_link; + + /* Only check the hit count now, which ensure that we do all + our stepping before stopping the run. */ + if (tpoint->pass_count > 0 + && tpoint->hit_count >= tpoint->pass_count + && stopping_tracepoint == NULL) + stopping_tracepoint = tpoint; + } + else + { + /* Keep single-stepping until the requested numbers of steps + have occurred. */ + wstep_link = &wstep->next; + wstep = *wstep_link; + } + + if (stopping_tracepoint + || trace_buffer_is_full + || expr_eval_result != expr_eval_no_error) + { + stop_tracing (); + break; + } + } + + return 1; +} + +/* Handle any internal tracing control breakpoint hits. That means, + pull traceframes from the IPA to our buffer, and syncing both + tracing agents when the IPA's tracing stops for some reason. */ + +int +handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc) +{ + /* Pull in fast tracepoint trace frames from the inferior in-process + agent's buffer into our buffer. */ + + if (!agent_loaded_p ()) + return 0; + + upload_fast_traceframes (); + + /* Check if the in-process agent had decided we should stop + tracing. */ + if (stop_pc == ipa_sym_addrs.addr_stop_tracing) + { + int ipa_trace_buffer_is_full; + CORE_ADDR ipa_stopping_tracepoint; + int ipa_expr_eval_result; + CORE_ADDR ipa_error_tracepoint; + + trace_debug ("lib stopped at stop_tracing"); + + read_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full, + &ipa_trace_buffer_is_full); + + read_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, + &ipa_stopping_tracepoint); + write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, 0); + + read_inferior_data_pointer (ipa_sym_addrs.addr_error_tracepoint, + &ipa_error_tracepoint); + write_inferior_data_pointer (ipa_sym_addrs.addr_error_tracepoint, 0); + + read_inferior_integer (ipa_sym_addrs.addr_expr_eval_result, + &ipa_expr_eval_result); + write_inferior_integer (ipa_sym_addrs.addr_expr_eval_result, 0); + + trace_debug ("lib: trace_buffer_is_full: %d, " + "stopping_tracepoint: %s, " + "ipa_expr_eval_result: %d, " + "error_tracepoint: %s, ", + ipa_trace_buffer_is_full, + paddress (ipa_stopping_tracepoint), + ipa_expr_eval_result, + paddress (ipa_error_tracepoint)); + + if (debug_threads) + { + if (ipa_trace_buffer_is_full) + trace_debug ("lib stopped due to full buffer."); + if (ipa_stopping_tracepoint) + trace_debug ("lib stopped due to tpoint"); + if (ipa_error_tracepoint) + trace_debug ("lib stopped due to error"); + } + + if (ipa_stopping_tracepoint != 0) + { + stopping_tracepoint + = fast_tracepoint_from_ipa_tpoint_address (ipa_stopping_tracepoint); + } + else if (ipa_expr_eval_result != expr_eval_no_error) + { + expr_eval_result = ipa_expr_eval_result; + error_tracepoint + = fast_tracepoint_from_ipa_tpoint_address (ipa_error_tracepoint); + } + stop_tracing (); + return 1; + } + else if (stop_pc == ipa_sym_addrs.addr_flush_trace_buffer) + { + trace_debug ("lib stopped at flush_trace_buffer"); + return 1; + } + + return 0; +} + +/* Return true if TINFO just hit a tracepoint. Collect data if + so. */ + +int +tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc) +{ + struct tracepoint *tpoint; + int ret = 0; + struct trap_tracepoint_ctx ctx; + + /* Not tracing, don't handle. */ + if (!tracing) + return 0; + + ctx.base.type = trap_tracepoint; + ctx.regcache = get_thread_regcache (tinfo, 1); + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + { + /* Note that we collect fast tracepoints here as well. We'll + step over the fast tracepoint jump later, which avoids the + double collect. However, we don't collect for static + tracepoints here, because UST markers are compiled in program, + and probes will be executed in program. So static tracepoints + are collected there. */ + if (tpoint->enabled && stop_pc == tpoint->address + && tpoint->type != static_tracepoint) + { + trace_debug ("Thread %s at address of tracepoint %d at 0x%s", + target_pid_to_str (tinfo->id), + tpoint->number, paddress (tpoint->address)); + + /* Test the condition if present, and collect if true. */ + if (!tpoint->cond + || (condition_true_at_tracepoint + ((struct tracepoint_hit_ctx *) &ctx, tpoint))) + collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, + stop_pc, tpoint); + + if (stopping_tracepoint + || trace_buffer_is_full + || expr_eval_result != expr_eval_no_error) + { + stop_tracing (); + } + /* If the tracepoint had a 'while-stepping' action, then set + the thread to collect this tracepoint on the following + single-steps. */ + else if (tpoint->step_count > 0) + { + add_while_stepping_state (tinfo, + tpoint->number, tpoint->address); + } + + ret = 1; + } + } + + return ret; +} + +#endif + +#if defined IN_PROCESS_AGENT && defined HAVE_UST +struct ust_marker_data; +static void collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, + struct traceframe *tframe); +#endif + +/* Create a trace frame for the hit of the given tracepoint in the + given thread. */ + +static void +collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, CORE_ADDR stop_pc, + struct tracepoint *tpoint) +{ + struct traceframe *tframe; + int acti; + + /* Only count it as a hit when we actually collect data. */ + tpoint->hit_count++; + + /* If we've exceeded a defined pass count, record the event for + later, and finish the collection for this hit. This test is only + for nonstepping tracepoints, stepping tracepoints test at the end + of their while-stepping loop. */ + if (tpoint->pass_count > 0 + && tpoint->hit_count >= tpoint->pass_count + && tpoint->step_count == 0 + && stopping_tracepoint == NULL) + stopping_tracepoint = tpoint; + + trace_debug ("Making new traceframe for tracepoint %d at 0x%s, hit %" PRIu64, + tpoint->number, paddress (tpoint->address), tpoint->hit_count); + + tframe = add_traceframe (tpoint); + + if (tframe) + { + for (acti = 0; acti < tpoint->numactions; ++acti) + { +#ifndef IN_PROCESS_AGENT + trace_debug ("Tracepoint %d at 0x%s about to do action '%s'", + tpoint->number, paddress (tpoint->address), + tpoint->actions_str[acti]); +#endif + + do_action_at_tracepoint (ctx, stop_pc, tpoint, tframe, + tpoint->actions[acti]); + } + + finish_traceframe (tframe); + } + + if (tframe == NULL && tracing) + trace_buffer_is_full = 1; +} + +#ifndef IN_PROCESS_AGENT + +static void +collect_data_at_step (struct tracepoint_hit_ctx *ctx, + CORE_ADDR stop_pc, + struct tracepoint *tpoint, int current_step) +{ + struct traceframe *tframe; + int acti; + + trace_debug ("Making new step traceframe for " + "tracepoint %d at 0x%s, step %d of %" PRIu64 ", hit %" PRIu64, + tpoint->number, paddress (tpoint->address), + current_step, tpoint->step_count, + tpoint->hit_count); + + tframe = add_traceframe (tpoint); + + if (tframe) + { + for (acti = 0; acti < tpoint->num_step_actions; ++acti) + { + trace_debug ("Tracepoint %d at 0x%s about to do step action '%s'", + tpoint->number, paddress (tpoint->address), + tpoint->step_actions_str[acti]); + + do_action_at_tracepoint (ctx, stop_pc, tpoint, tframe, + tpoint->step_actions[acti]); + } + + finish_traceframe (tframe); + } + + if (tframe == NULL && tracing) + trace_buffer_is_full = 1; +} + +#endif + +#ifdef IN_PROCESS_AGENT +/* The target description index for IPA. Passed from gdbserver, used + to select ipa_tdesc. */ +EXTERN_C_PUSH +IP_AGENT_EXPORT_VAR int ipa_tdesc_idx; +EXTERN_C_POP +#endif + +static struct regcache * +get_context_regcache (struct tracepoint_hit_ctx *ctx) +{ + struct regcache *regcache = NULL; +#ifdef IN_PROCESS_AGENT + const struct target_desc *ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx); + + if (ctx->type == fast_tracepoint) + { + struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx; + if (!fctx->regcache_initted) + { + fctx->regcache_initted = 1; + init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace); + supply_regblock (&fctx->regcache, NULL); + supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs); + } + regcache = &fctx->regcache; + } +#ifdef HAVE_UST + if (ctx->type == static_tracepoint) + { + struct static_tracepoint_ctx *sctx + = (struct static_tracepoint_ctx *) ctx; + + if (!sctx->regcache_initted) + { + sctx->regcache_initted = 1; + init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace); + supply_regblock (&sctx->regcache, NULL); + /* Pass down the tracepoint address, because REGS doesn't + include the PC, but we know what it must have been. */ + supply_static_tracepoint_registers (&sctx->regcache, + (const unsigned char *) + sctx->regs, + sctx->tpoint->address); + } + regcache = &sctx->regcache; + } +#endif +#else + if (ctx->type == trap_tracepoint) + { + struct trap_tracepoint_ctx *tctx = (struct trap_tracepoint_ctx *) ctx; + regcache = tctx->regcache; + } +#endif + + gdb_assert (regcache != NULL); + + return regcache; +} + +static void +do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, + CORE_ADDR stop_pc, + struct tracepoint *tpoint, + struct traceframe *tframe, + struct tracepoint_action *taction) +{ + enum eval_result_type err; + + switch (taction->type) + { + case 'M': + { + struct collect_memory_action *maction; + struct eval_agent_expr_context ax_ctx; + + maction = (struct collect_memory_action *) taction; + ax_ctx.regcache = NULL; + ax_ctx.tframe = tframe; + ax_ctx.tpoint = tpoint; + + trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)", + pulongest (maction->len), + paddress (maction->addr), maction->basereg); + /* (should use basereg) */ + agent_mem_read (&ax_ctx, NULL, (CORE_ADDR) maction->addr, + maction->len); + break; + } + case 'R': + { + unsigned char *regspace; + struct regcache tregcache; + struct regcache *context_regcache; + int regcache_size; + + trace_debug ("Want to collect registers"); + + context_regcache = get_context_regcache (ctx); + regcache_size = register_cache_size (context_regcache->tdesc); + + /* Collect all registers for now. */ + regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size); + if (regspace == NULL) + { + trace_debug ("Trace buffer block allocation failed, skipping"); + break; + } + /* Identify a register block. */ + *regspace = 'R'; + + /* Wrap the regblock in a register cache (in the stack, we + don't want to malloc here). */ + init_register_cache (&tregcache, context_regcache->tdesc, + regspace + 1); + + /* Copy the register data to the regblock. */ + regcache_cpy (&tregcache, context_regcache); + +#ifndef IN_PROCESS_AGENT + /* On some platforms, trap-based tracepoints will have the PC + pointing to the next instruction after the trap, but we + don't want the user or GDB trying to guess whether the + saved PC needs adjusting; so always record the adjusted + stop_pc. Note that we can't use tpoint->address instead, + since it will be wrong for while-stepping actions. This + adjustment is a nop for fast tracepoints collected from the + in-process lib (but not if GDBserver is collecting one + preemptively), since the PC had already been adjusted to + contain the tracepoint's address by the jump pad. */ + trace_debug ("Storing stop pc (0x%s) in regblock", + paddress (stop_pc)); + + /* This changes the regblock, not the thread's + regcache. */ + regcache_write_pc (&tregcache, stop_pc); +#endif + } + break; + case 'X': + { + struct eval_expr_action *eaction; + struct eval_agent_expr_context ax_ctx; + + eaction = (struct eval_expr_action *) taction; + ax_ctx.regcache = get_context_regcache (ctx); + ax_ctx.tframe = tframe; + ax_ctx.tpoint = tpoint; + + trace_debug ("Want to evaluate expression"); + + err = gdb_eval_agent_expr (&ax_ctx, eaction->expr, NULL); + + if (err != expr_eval_no_error) + { + record_tracepoint_error (tpoint, "action expression", err); + return; + } + } + break; + case 'L': + { +#if defined IN_PROCESS_AGENT && defined HAVE_UST + trace_debug ("Want to collect static trace data"); + collect_ust_data_at_tracepoint (ctx, tframe); +#else + trace_debug ("warning: collecting static trace data, " + "but static tracepoints are not supported"); +#endif + } + break; + default: + trace_debug ("unknown trace action '%c', ignoring", taction->type); + break; + } +} + +static int +condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx, + struct tracepoint *tpoint) +{ + ULONGEST value = 0; + enum eval_result_type err; + + /* Presently, gdbserver doesn't run compiled conditions, only the + IPA does. If the program stops at a fast tracepoint's address + (e.g., due to a breakpoint, trap tracepoint, or stepping), + gdbserver preemptively collect the fast tracepoint. Later, on + resume, gdbserver steps over the fast tracepoint like it steps + over breakpoints, so that the IPA doesn't see that fast + tracepoint. This avoids double collects of fast tracepoints in + that stopping scenario. Having gdbserver itself handle the fast + tracepoint gives the user a consistent view of when fast or trap + tracepoints are collected, compared to an alternative where only + trap tracepoints are collected on stop, and fast tracepoints on + resume. When a fast tracepoint is being processed by gdbserver, + it is always the non-compiled condition expression that is + used. */ +#ifdef IN_PROCESS_AGENT + if (tpoint->compiled_cond) + { + struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx; + err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (fctx->regs, &value); + } + else +#endif + { + struct eval_agent_expr_context ax_ctx; + + ax_ctx.regcache = get_context_regcache (ctx); + ax_ctx.tframe = NULL; + ax_ctx.tpoint = tpoint; + + err = gdb_eval_agent_expr (&ax_ctx, tpoint->cond, &value); + } + if (err != expr_eval_no_error) + { + record_tracepoint_error (tpoint, "condition", err); + /* The error case must return false. */ + return 0; + } + + trace_debug ("Tracepoint %d at 0x%s condition evals to %s", + tpoint->number, paddress (tpoint->address), + pulongest (value)); + return (value ? 1 : 0); +} + +/* Do memory copies for bytecodes. */ +/* Do the recording of memory blocks for actions and bytecodes. */ + +int +agent_mem_read (struct eval_agent_expr_context *ctx, + unsigned char *to, CORE_ADDR from, ULONGEST len) +{ + unsigned char *mspace; + ULONGEST remaining = len; + unsigned short blocklen; + + /* If a 'to' buffer is specified, use it. */ + if (to != NULL) + { + read_inferior_memory (from, to, len); + return 0; + } + + /* Otherwise, create a new memory block in the trace buffer. */ + while (remaining > 0) + { + size_t sp; + + blocklen = (remaining > 65535 ? 65535 : remaining); + sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen; + mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp); + if (mspace == NULL) + return 1; + /* Identify block as a memory block. */ + *mspace = 'M'; + ++mspace; + /* Record address and size. */ + memcpy (mspace, &from, sizeof (from)); + mspace += sizeof (from); + memcpy (mspace, &blocklen, sizeof (blocklen)); + mspace += sizeof (blocklen); + /* Record the memory block proper. */ + read_inferior_memory (from, mspace, blocklen); + trace_debug ("%d bytes recorded", blocklen); + remaining -= blocklen; + from += blocklen; + } + return 0; +} + +int +agent_mem_read_string (struct eval_agent_expr_context *ctx, + unsigned char *to, CORE_ADDR from, ULONGEST len) +{ + unsigned char *buf, *mspace; + ULONGEST remaining = len; + unsigned short blocklen, i; + + /* To save a bit of space, block lengths are 16-bit, so break large + requests into multiple blocks. Bordering on overkill for strings, + but it could happen that someone specifies a large max length. */ + while (remaining > 0) + { + size_t sp; + + blocklen = (remaining > 65535 ? 65535 : remaining); + /* We want working space to accumulate nonzero bytes, since + traceframes must have a predecided size (otherwise it gets + harder to wrap correctly for the circular case, etc). */ + buf = (unsigned char *) xmalloc (blocklen + 1); + for (i = 0; i < blocklen; ++i) + { + /* Read the string one byte at a time, in case the string is + at the end of a valid memory area - we don't want a + correctly-terminated string to engender segvio + complaints. */ + read_inferior_memory (from + i, buf + i, 1); + + if (buf[i] == '\0') + { + blocklen = i + 1; + /* Make sure outer loop stops now too. */ + remaining = blocklen; + break; + } + } + sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen; + mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp); + if (mspace == NULL) + { + xfree (buf); + return 1; + } + /* Identify block as a memory block. */ + *mspace = 'M'; + ++mspace; + /* Record address and size. */ + memcpy ((void *) mspace, (void *) &from, sizeof (from)); + mspace += sizeof (from); + memcpy ((void *) mspace, (void *) &blocklen, sizeof (blocklen)); + mspace += sizeof (blocklen); + /* Copy the string contents. */ + memcpy ((void *) mspace, (void *) buf, blocklen); + remaining -= blocklen; + from += blocklen; + xfree (buf); + } + return 0; +} + +/* Record the value of a trace state variable. */ + +int +agent_tsv_read (struct eval_agent_expr_context *ctx, int n) +{ + unsigned char *vspace; + LONGEST val; + + vspace = add_traceframe_block (ctx->tframe, ctx->tpoint, + 1 + sizeof (n) + sizeof (LONGEST)); + if (vspace == NULL) + return 1; + /* Identify block as a variable. */ + *vspace = 'V'; + /* Record variable's number and value. */ + memcpy (vspace + 1, &n, sizeof (n)); + val = get_trace_state_variable_value (n); + memcpy (vspace + 1 + sizeof (n), &val, sizeof (val)); + trace_debug ("Variable %d recorded", n); + return 0; +} + +#ifndef IN_PROCESS_AGENT + +/* Callback for traceframe_walk_blocks, used to find a given block + type in a traceframe. */ + +static int +match_blocktype (char blocktype, unsigned char *dataptr, void *data) +{ + char *wantedp = (char *) data; + + if (*wantedp == blocktype) + return 1; + + return 0; +} + +/* Walk over all traceframe blocks of the traceframe buffer starting + at DATABASE, of DATASIZE bytes long, and call CALLBACK for each + block found, passing in DATA unmodified. If CALLBACK returns true, + this returns a pointer to where the block is found. Returns NULL + if no callback call returned true, indicating that all blocks have + been walked. */ + +static unsigned char * +traceframe_walk_blocks (unsigned char *database, unsigned int datasize, + int tfnum, + int (*callback) (char blocktype, + unsigned char *dataptr, + void *data), + void *data) +{ + unsigned char *dataptr; + + if (datasize == 0) + { + trace_debug ("traceframe %d has no data", tfnum); + return NULL; + } + + /* Iterate through a traceframe's blocks, looking for a block of the + requested type. */ + for (dataptr = database; + dataptr < database + datasize; + /* nothing */) + { + char blocktype; + unsigned short mlen; + + if (dataptr == trace_buffer_wrap) + { + /* Adjust to reflect wrapping part of the frame around to + the beginning. */ + datasize = dataptr - database; + dataptr = database = trace_buffer_lo; + } + + blocktype = *dataptr++; + + if ((*callback) (blocktype, dataptr, data)) + return dataptr; + + switch (blocktype) + { + case 'R': + /* Skip over the registers block. */ + dataptr += current_target_desc ()->registers_size; + break; + case 'M': + /* Skip over the memory block. */ + dataptr += sizeof (CORE_ADDR); + memcpy (&mlen, dataptr, sizeof (mlen)); + dataptr += (sizeof (mlen) + mlen); + break; + case 'V': + /* Skip over the TSV block. */ + dataptr += (sizeof (int) + sizeof (LONGEST)); + break; + case 'S': + /* Skip over the static trace data block. */ + memcpy (&mlen, dataptr, sizeof (mlen)); + dataptr += (sizeof (mlen) + mlen); + break; + default: + trace_debug ("traceframe %d has unknown block type 0x%x", + tfnum, blocktype); + return NULL; + } + } + + return NULL; +} + +/* Look for the block of type TYPE_WANTED in the traceframe starting + at DATABASE of DATASIZE bytes long. TFNUM is the traceframe + number. */ + +static unsigned char * +traceframe_find_block_type (unsigned char *database, unsigned int datasize, + int tfnum, char type_wanted) +{ + return traceframe_walk_blocks (database, datasize, tfnum, + match_blocktype, &type_wanted); +} + +static unsigned char * +traceframe_find_regblock (struct traceframe *tframe, int tfnum) +{ + unsigned char *regblock; + + regblock = traceframe_find_block_type (tframe->data, + tframe->data_size, + tfnum, 'R'); + + if (regblock == NULL) + trace_debug ("traceframe %d has no register data", tfnum); + + return regblock; +} + +/* Get registers from a traceframe. */ + +int +fetch_traceframe_registers (int tfnum, struct regcache *regcache, int regnum) +{ + unsigned char *dataptr; + struct tracepoint *tpoint; + struct traceframe *tframe; + + tframe = find_traceframe (tfnum); + + if (tframe == NULL) + { + trace_debug ("traceframe %d not found", tfnum); + return 1; + } + + dataptr = traceframe_find_regblock (tframe, tfnum); + if (dataptr == NULL) + { + /* Mark registers unavailable. */ + supply_regblock (regcache, NULL); + + /* We can generally guess at a PC, although this will be + misleading for while-stepping frames and multi-location + tracepoints. */ + tpoint = find_next_tracepoint_by_number (NULL, tframe->tpnum); + if (tpoint != NULL) + regcache_write_pc (regcache, tpoint->address); + } + else + supply_regblock (regcache, dataptr); + + return 0; +} + +static CORE_ADDR +traceframe_get_pc (struct traceframe *tframe) +{ + struct regcache regcache; + unsigned char *dataptr; + const struct target_desc *tdesc = current_target_desc (); + + dataptr = traceframe_find_regblock (tframe, -1); + if (dataptr == NULL) + return 0; + + init_register_cache (®cache, tdesc, dataptr); + return regcache_read_pc (®cache); +} + +/* Read a requested block of memory from a trace frame. */ + +int +traceframe_read_mem (int tfnum, CORE_ADDR addr, + unsigned char *buf, ULONGEST length, + ULONGEST *nbytes) +{ + struct traceframe *tframe; + unsigned char *database, *dataptr; + unsigned int datasize; + CORE_ADDR maddr; + unsigned short mlen; + + trace_debug ("traceframe_read_mem"); + + tframe = find_traceframe (tfnum); + + if (!tframe) + { + trace_debug ("traceframe %d not found", tfnum); + return 1; + } + + datasize = tframe->data_size; + database = dataptr = &tframe->data[0]; + + /* Iterate through a traceframe's blocks, looking for memory. */ + while ((dataptr = traceframe_find_block_type (dataptr, + datasize + - (dataptr - database), + tfnum, 'M')) != NULL) + { + memcpy (&maddr, dataptr, sizeof (maddr)); + dataptr += sizeof (maddr); + memcpy (&mlen, dataptr, sizeof (mlen)); + dataptr += sizeof (mlen); + trace_debug ("traceframe %d has %d bytes at %s", + tfnum, mlen, paddress (maddr)); + + /* If the block includes the first part of the desired range, + return as much it has; GDB will re-request the remainder, + which might be in a different block of this trace frame. */ + if (maddr <= addr && addr < (maddr + mlen)) + { + ULONGEST amt = (maddr + mlen) - addr; + if (amt > length) + amt = length; + + memcpy (buf, dataptr + (addr - maddr), amt); + *nbytes = amt; + return 0; + } + + /* Skip over this block. */ + dataptr += mlen; + } + + trace_debug ("traceframe %d has no memory data for the desired region", + tfnum); + + *nbytes = 0; + return 0; +} + +static int +traceframe_read_tsv (int tsvnum, LONGEST *val) +{ + client_state &cs = get_client_state (); + int tfnum; + struct traceframe *tframe; + unsigned char *database, *dataptr; + unsigned int datasize; + int vnum; + int found = 0; + + trace_debug ("traceframe_read_tsv"); + + tfnum = cs.current_traceframe; + + if (tfnum < 0) + { + trace_debug ("no current traceframe"); + return 1; + } + + tframe = find_traceframe (tfnum); + + if (tframe == NULL) + { + trace_debug ("traceframe %d not found", tfnum); + return 1; + } + + datasize = tframe->data_size; + database = dataptr = &tframe->data[0]; + + /* Iterate through a traceframe's blocks, looking for the last + matched tsv. */ + while ((dataptr = traceframe_find_block_type (dataptr, + datasize + - (dataptr - database), + tfnum, 'V')) != NULL) + { + memcpy (&vnum, dataptr, sizeof (vnum)); + dataptr += sizeof (vnum); + + trace_debug ("traceframe %d has variable %d", tfnum, vnum); + + /* Check that this is the variable we want. */ + if (tsvnum == vnum) + { + memcpy (val, dataptr, sizeof (*val)); + found = 1; + } + + /* Skip over this block. */ + dataptr += sizeof (LONGEST); + } + + if (!found) + trace_debug ("traceframe %d has no data for variable %d", + tfnum, tsvnum); + return !found; +} + +/* Read a requested block of static tracepoint data from a trace + frame. */ + +int +traceframe_read_sdata (int tfnum, ULONGEST offset, + unsigned char *buf, ULONGEST length, + ULONGEST *nbytes) +{ + struct traceframe *tframe; + unsigned char *database, *dataptr; + unsigned int datasize; + unsigned short mlen; + + trace_debug ("traceframe_read_sdata"); + + tframe = find_traceframe (tfnum); + + if (!tframe) + { + trace_debug ("traceframe %d not found", tfnum); + return 1; + } + + datasize = tframe->data_size; + database = &tframe->data[0]; + + /* Iterate through a traceframe's blocks, looking for static + tracepoint data. */ + dataptr = traceframe_find_block_type (database, datasize, + tfnum, 'S'); + if (dataptr != NULL) + { + memcpy (&mlen, dataptr, sizeof (mlen)); + dataptr += sizeof (mlen); + if (offset < mlen) + { + if (offset + length > mlen) + length = mlen - offset; + + memcpy (buf, dataptr, length); + *nbytes = length; + } + else + *nbytes = 0; + return 0; + } + + trace_debug ("traceframe %d has no static trace data", tfnum); + + *nbytes = 0; + return 0; +} + +/* Callback for traceframe_walk_blocks. Builds a traceframe-info + object. DATA is pointer to a struct buffer holding the + traceframe-info object being built. */ + +static int +build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data) +{ + struct buffer *buffer = (struct buffer *) data; + + switch (blocktype) + { + case 'M': + { + unsigned short mlen; + CORE_ADDR maddr; + + memcpy (&maddr, dataptr, sizeof (maddr)); + dataptr += sizeof (maddr); + memcpy (&mlen, dataptr, sizeof (mlen)); + dataptr += sizeof (mlen); + buffer_xml_printf (buffer, + "\n", + paddress (maddr), phex_nz (mlen, sizeof (mlen))); + break; + } + case 'V': + { + int vnum; + + memcpy (&vnum, dataptr, sizeof (vnum)); + buffer_xml_printf (buffer, "\n", vnum); + break; + } + case 'R': + case 'S': + { + break; + } + default: + warning ("Unhandled trace block type (%d) '%c ' " + "while building trace frame info.", + blocktype, blocktype); + break; + } + + return 0; +} + +/* Build a traceframe-info object for traceframe number TFNUM into + BUFFER. */ + +int +traceframe_read_info (int tfnum, struct buffer *buffer) +{ + struct traceframe *tframe; + + trace_debug ("traceframe_read_info"); + + tframe = find_traceframe (tfnum); + + if (!tframe) + { + trace_debug ("traceframe %d not found", tfnum); + return 1; + } + + buffer_grow_str (buffer, "\n"); + traceframe_walk_blocks (tframe->data, tframe->data_size, + tfnum, build_traceframe_info_xml, buffer); + buffer_grow_str0 (buffer, "\n"); + return 0; +} + +/* Return the first fast tracepoint whose jump pad contains PC. */ + +static struct tracepoint * +fast_tracepoint_from_jump_pad_address (CORE_ADDR pc) +{ + struct tracepoint *tpoint; + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + if (tpoint->type == fast_tracepoint) + if (tpoint->jump_pad <= pc && pc < tpoint->jump_pad_end) + return tpoint; + + return NULL; +} + +/* Return the first fast tracepoint whose trampoline contains PC. */ + +static struct tracepoint * +fast_tracepoint_from_trampoline_address (CORE_ADDR pc) +{ + struct tracepoint *tpoint; + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + { + if (tpoint->type == fast_tracepoint + && tpoint->trampoline <= pc && pc < tpoint->trampoline_end) + return tpoint; + } + + return NULL; +} + +/* Return GDBserver's tracepoint that matches the IP Agent's + tracepoint object that lives at IPA_TPOINT_OBJ in the IP Agent's + address space. */ + +static struct tracepoint * +fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR ipa_tpoint_obj) +{ + struct tracepoint *tpoint; + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + if (tpoint->type == fast_tracepoint) + if (tpoint->obj_addr_on_target == ipa_tpoint_obj) + return tpoint; + + return NULL; +} + +#endif + +/* The type of the object that is used to synchronize fast tracepoint + collection. */ + +typedef struct collecting_t +{ + /* The fast tracepoint number currently collecting. */ + uintptr_t tpoint; + + /* A number that GDBserver can use to identify the thread that is + presently holding the collect lock. This need not (and usually + is not) the thread id, as getting the current thread ID usually + requires a system call, which we want to avoid like the plague. + Usually this is thread's TCB, found in the TLS (pseudo-) + register, which is readable with a single insn on several + architectures. */ + uintptr_t thread_area; +} collecting_t; + +#ifndef IN_PROCESS_AGENT + +void +force_unlock_trace_buffer (void) +{ + write_inferior_data_pointer (ipa_sym_addrs.addr_collecting, 0); +} + +/* Check if the thread identified by THREAD_AREA which is stopped at + STOP_PC, is presently locking the fast tracepoint collection, and + if so, gather some status of said collection. Returns 0 if the + thread isn't collecting or in the jump pad at all. 1, if in the + jump pad (or within gdb_collect) and hasn't executed the adjusted + original insn yet (can set a breakpoint there and run to it). 2, + if presently executing the adjusted original insn --- in which + case, if we want to move the thread out of the jump pad, we need to + single-step it until this function returns 0. */ + +fast_tpoint_collect_result +fast_tracepoint_collecting (CORE_ADDR thread_area, + CORE_ADDR stop_pc, + struct fast_tpoint_collect_status *status) +{ + CORE_ADDR ipa_collecting; + CORE_ADDR ipa_gdb_jump_pad_buffer, ipa_gdb_jump_pad_buffer_end; + CORE_ADDR ipa_gdb_trampoline_buffer; + CORE_ADDR ipa_gdb_trampoline_buffer_end; + struct tracepoint *tpoint; + int needs_breakpoint; + + /* The thread THREAD_AREA is either: + + 0. not collecting at all, not within the jump pad, or within + gdb_collect or one of its callees. + + 1. in the jump pad and haven't reached gdb_collect + + 2. within gdb_collect (out of the jump pad) (collect is set) + + 3. we're in the jump pad, after gdb_collect having returned, + possibly executing the adjusted insns. + + For cases 1 and 3, `collecting' may or not be set. The jump pad + doesn't have any complicated jump logic, so we can tell if the + thread is executing the adjust original insn or not by just + matching STOP_PC with known jump pad addresses. If we it isn't + yet executing the original insn, set a breakpoint there, and let + the thread run to it, so to quickly step over a possible (many + insns) gdb_collect call. Otherwise, or when the breakpoint is + hit, only a few (small number of) insns are left to be executed + in the jump pad. Single-step the thread until it leaves the + jump pad. */ + + again: + tpoint = NULL; + needs_breakpoint = 0; + trace_debug ("fast_tracepoint_collecting"); + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer, + &ipa_gdb_jump_pad_buffer)) + { + internal_error (__FILE__, __LINE__, + "error extracting `gdb_jump_pad_buffer'"); + } + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer_end, + &ipa_gdb_jump_pad_buffer_end)) + { + internal_error (__FILE__, __LINE__, + "error extracting `gdb_jump_pad_buffer_end'"); + } + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer, + &ipa_gdb_trampoline_buffer)) + { + internal_error (__FILE__, __LINE__, + "error extracting `gdb_trampoline_buffer'"); + } + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, + &ipa_gdb_trampoline_buffer_end)) + { + internal_error (__FILE__, __LINE__, + "error extracting `gdb_trampoline_buffer_end'"); + } + + if (ipa_gdb_jump_pad_buffer <= stop_pc + && stop_pc < ipa_gdb_jump_pad_buffer_end) + { + /* We can tell which tracepoint(s) the thread is collecting by + matching the jump pad address back to the tracepoint. */ + tpoint = fast_tracepoint_from_jump_pad_address (stop_pc); + if (tpoint == NULL) + { + warning ("in jump pad, but no matching tpoint?"); + return fast_tpoint_collect_result::not_collecting; + } + else + { + trace_debug ("in jump pad of tpoint (%d, %s); jump_pad(%s, %s); " + "adj_insn(%s, %s)", + tpoint->number, paddress (tpoint->address), + paddress (tpoint->jump_pad), + paddress (tpoint->jump_pad_end), + paddress (tpoint->adjusted_insn_addr), + paddress (tpoint->adjusted_insn_addr_end)); + } + + /* Definitely in the jump pad. May or may not need + fast-exit-jump-pad breakpoint. */ + if (tpoint->jump_pad <= stop_pc + && stop_pc < tpoint->adjusted_insn_addr) + needs_breakpoint = 1; + } + else if (ipa_gdb_trampoline_buffer <= stop_pc + && stop_pc < ipa_gdb_trampoline_buffer_end) + { + /* We can tell which tracepoint(s) the thread is collecting by + matching the trampoline address back to the tracepoint. */ + tpoint = fast_tracepoint_from_trampoline_address (stop_pc); + if (tpoint == NULL) + { + warning ("in trampoline, but no matching tpoint?"); + return fast_tpoint_collect_result::not_collecting; + } + else + { + trace_debug ("in trampoline of tpoint (%d, %s); trampoline(%s, %s)", + tpoint->number, paddress (tpoint->address), + paddress (tpoint->trampoline), + paddress (tpoint->trampoline_end)); + } + + /* Have not reached jump pad yet, but treat the trampoline as a + part of the jump pad that is before the adjusted original + instruction. */ + needs_breakpoint = 1; + } + else + { + collecting_t ipa_collecting_obj; + + /* If `collecting' is set/locked, then the THREAD_AREA thread + may or not be the one holding the lock. We have to read the + lock to find out. */ + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_collecting, + &ipa_collecting)) + { + trace_debug ("fast_tracepoint_collecting:" + " failed reading 'collecting' in the inferior"); + return fast_tpoint_collect_result::not_collecting; + } + + if (!ipa_collecting) + { + trace_debug ("fast_tracepoint_collecting: not collecting" + " (and nobody is)."); + return fast_tpoint_collect_result::not_collecting; + } + + /* Some thread is collecting. Check which. */ + if (read_inferior_memory (ipa_collecting, + (unsigned char *) &ipa_collecting_obj, + sizeof (ipa_collecting_obj)) != 0) + goto again; + + if (ipa_collecting_obj.thread_area != thread_area) + { + trace_debug ("fast_tracepoint_collecting: not collecting " + "(another thread is)"); + return fast_tpoint_collect_result::not_collecting; + } + + tpoint + = fast_tracepoint_from_ipa_tpoint_address (ipa_collecting_obj.tpoint); + if (tpoint == NULL) + { + warning ("fast_tracepoint_collecting: collecting, " + "but tpoint %s not found?", + paddress ((CORE_ADDR) ipa_collecting_obj.tpoint)); + return fast_tpoint_collect_result::not_collecting; + } + + /* The thread is within `gdb_collect', skip over the rest of + fast tracepoint collection quickly using a breakpoint. */ + needs_breakpoint = 1; + } + + /* The caller wants a bit of status detail. */ + if (status != NULL) + { + status->tpoint_num = tpoint->number; + status->tpoint_addr = tpoint->address; + status->adjusted_insn_addr = tpoint->adjusted_insn_addr; + status->adjusted_insn_addr_end = tpoint->adjusted_insn_addr_end; + } + + if (needs_breakpoint) + { + /* Hasn't executed the original instruction yet. Set breakpoint + there, and wait till it's hit, then single-step until exiting + the jump pad. */ + + trace_debug ("\ +fast_tracepoint_collecting, returning continue-until-break at %s", + paddress (tpoint->adjusted_insn_addr)); + + return fast_tpoint_collect_result::before_insn; /* continue */ + } + else + { + /* Just single-step until exiting the jump pad. */ + + trace_debug ("fast_tracepoint_collecting, returning " + "need-single-step (%s-%s)", + paddress (tpoint->adjusted_insn_addr), + paddress (tpoint->adjusted_insn_addr_end)); + + return fast_tpoint_collect_result::at_insn; /* single-step */ + } +} + +#endif + +#ifdef IN_PROCESS_AGENT + +/* The global fast tracepoint collect lock. Points to a collecting_t + object built on the stack by the jump pad, if presently locked; + NULL if it isn't locked. Note that this lock *must* be set while + executing any *function other than the jump pad. See + fast_tracepoint_collecting. */ +EXTERN_C_PUSH +IP_AGENT_EXPORT_VAR collecting_t *collecting; +EXTERN_C_POP + +/* This is needed for -Wmissing-declarations. */ +IP_AGENT_EXPORT_FUNC void gdb_collect (struct tracepoint *tpoint, + unsigned char *regs); + +/* This routine, called from the jump pad (in asm) is designed to be + called from the jump pads of fast tracepoints, thus it is on the + critical path. */ + +IP_AGENT_EXPORT_FUNC void +gdb_collect (struct tracepoint *tpoint, unsigned char *regs) +{ + struct fast_tracepoint_ctx ctx; + const struct target_desc *ipa_tdesc; + + /* Don't do anything until the trace run is completely set up. */ + if (!tracing) + return; + + ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx); + ctx.base.type = fast_tracepoint; + ctx.regs = regs; + ctx.regcache_initted = 0; + /* Wrap the regblock in a register cache (in the stack, we don't + want to malloc here). */ + ctx.regspace = (unsigned char *) alloca (ipa_tdesc->registers_size); + if (ctx.regspace == NULL) + { + trace_debug ("Trace buffer block allocation failed, skipping"); + return; + } + + for (ctx.tpoint = tpoint; + ctx.tpoint != NULL && ctx.tpoint->address == tpoint->address; + ctx.tpoint = ctx.tpoint->next) + { + if (!ctx.tpoint->enabled) + continue; + + /* Multiple tracepoints of different types, such as fast tracepoint and + static tracepoint, can be set at the same address. */ + if (ctx.tpoint->type != tpoint->type) + continue; + + /* Test the condition if present, and collect if true. */ + if (ctx.tpoint->cond == NULL + || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, + ctx.tpoint)) + { + collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, + ctx.tpoint->address, ctx.tpoint); + + /* Note that this will cause original insns to be written back + to where we jumped from, but that's OK because we're jumping + back to the next whole instruction. This will go badly if + instruction restoration is not atomic though. */ + if (stopping_tracepoint + || trace_buffer_is_full + || expr_eval_result != expr_eval_no_error) + { + stop_tracing (); + break; + } + } + else + { + /* If there was a condition and it evaluated to false, the only + way we would stop tracing is if there was an error during + condition expression evaluation. */ + if (expr_eval_result != expr_eval_no_error) + { + stop_tracing (); + break; + } + } + } +} + +/* These global variables points to the corresponding functions. This is + necessary on powerpc64, where asking for function symbol address from gdb + results in returning the actual code pointer, instead of the descriptor + pointer. */ + +typedef void (*gdb_collect_ptr_type) (struct tracepoint *, unsigned char *); +typedef ULONGEST (*get_raw_reg_ptr_type) (const unsigned char *, int); +typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int); +typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST); + +EXTERN_C_PUSH +IP_AGENT_EXPORT_VAR gdb_collect_ptr_type gdb_collect_ptr = gdb_collect; +IP_AGENT_EXPORT_VAR get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg; +IP_AGENT_EXPORT_VAR get_trace_state_variable_value_ptr_type + get_trace_state_variable_value_ptr = get_trace_state_variable_value; +IP_AGENT_EXPORT_VAR set_trace_state_variable_value_ptr_type + set_trace_state_variable_value_ptr = set_trace_state_variable_value; +EXTERN_C_POP + +#endif + +#ifndef IN_PROCESS_AGENT + +CORE_ADDR +get_raw_reg_func_addr (void) +{ + CORE_ADDR res; + if (read_inferior_data_pointer (ipa_sym_addrs.addr_get_raw_reg_ptr, &res)) + { + error ("error extracting get_raw_reg_ptr"); + return 0; + } + return res; +} + +CORE_ADDR +get_get_tsv_func_addr (void) +{ + CORE_ADDR res; + if (read_inferior_data_pointer ( + ipa_sym_addrs.addr_get_trace_state_variable_value_ptr, &res)) + { + error ("error extracting get_trace_state_variable_value_ptr"); + return 0; + } + return res; +} + +CORE_ADDR +get_set_tsv_func_addr (void) +{ + CORE_ADDR res; + if (read_inferior_data_pointer ( + ipa_sym_addrs.addr_set_trace_state_variable_value_ptr, &res)) + { + error ("error extracting set_trace_state_variable_value_ptr"); + return 0; + } + return res; +} + +static void +compile_tracepoint_condition (struct tracepoint *tpoint, + CORE_ADDR *jump_entry) +{ + CORE_ADDR entry_point = *jump_entry; + enum eval_result_type err; + + trace_debug ("Starting condition compilation for tracepoint %d\n", + tpoint->number); + + /* Initialize the global pointer to the code being built. */ + current_insn_ptr = *jump_entry; + + emit_prologue (); + + err = compile_bytecodes (tpoint->cond); + + if (err == expr_eval_no_error) + { + emit_epilogue (); + + /* Record the beginning of the compiled code. */ + tpoint->compiled_cond = entry_point; + + trace_debug ("Condition compilation for tracepoint %d complete\n", + tpoint->number); + } + else + { + /* Leave the unfinished code in situ, but don't point to it. */ + + tpoint->compiled_cond = 0; + + trace_debug ("Condition compilation for tracepoint %d failed, " + "error code %d", + tpoint->number, err); + } + + /* Update the code pointer passed in. Note that we do this even if + the compile fails, so that we can look at the partial results + instead of letting them be overwritten. */ + *jump_entry = current_insn_ptr; + + /* Leave a gap, to aid dump decipherment. */ + *jump_entry += 16; +} + +/* The base pointer of the IPA's heap. This is the only memory the + IPA is allowed to use. The IPA should _not_ call the inferior's + `malloc' during operation. That'd be slow, and, most importantly, + it may not be safe. We may be collecting a tracepoint in a signal + handler, for example. */ +static CORE_ADDR target_tp_heap; + +/* Allocate at least SIZE bytes of memory from the IPA heap, aligned + to 8 bytes. */ + +static CORE_ADDR +target_malloc (ULONGEST size) +{ + CORE_ADDR ptr; + + if (target_tp_heap == 0) + { + /* We have the pointer *address*, need what it points to. */ + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_tp_heap_buffer, + &target_tp_heap)) + { + internal_error (__FILE__, __LINE__, + "couldn't get target heap head pointer"); + } + } + + ptr = target_tp_heap; + target_tp_heap += size; + + /* Pad to 8-byte alignment. */ + target_tp_heap = ((target_tp_heap + 7) & ~0x7); + + return ptr; +} + +static CORE_ADDR +download_agent_expr (struct agent_expr *expr) +{ + CORE_ADDR expr_addr; + CORE_ADDR expr_bytes; + + expr_addr = target_malloc (sizeof (*expr)); + target_write_memory (expr_addr, (unsigned char *) expr, sizeof (*expr)); + + expr_bytes = target_malloc (expr->length); + write_inferior_data_pointer (expr_addr + offsetof (struct agent_expr, bytes), + expr_bytes); + target_write_memory (expr_bytes, expr->bytes, expr->length); + + return expr_addr; +} + +/* Align V up to N bits. */ +#define UALIGN(V, N) (((V) + ((N) - 1)) & ~((N) - 1)) + +/* Sync tracepoint with IPA, but leave maintenance of linked list to caller. */ + +static void +download_tracepoint_1 (struct tracepoint *tpoint) +{ + struct tracepoint target_tracepoint; + CORE_ADDR tpptr = 0; + + gdb_assert (tpoint->type == fast_tracepoint + || tpoint->type == static_tracepoint); + + if (tpoint->cond != NULL && target_emit_ops () != NULL) + { + CORE_ADDR jentry, jump_entry; + + jentry = jump_entry = get_jump_space_head (); + + if (tpoint->cond != NULL) + { + /* Pad to 8-byte alignment. (needed?) */ + /* Actually this should be left for the target to + decide. */ + jentry = UALIGN (jentry, 8); + + compile_tracepoint_condition (tpoint, &jentry); + } + + /* Pad to 8-byte alignment. */ + jentry = UALIGN (jentry, 8); + claim_jump_space (jentry - jump_entry); + } + + target_tracepoint = *tpoint; + + tpptr = target_malloc (sizeof (*tpoint)); + tpoint->obj_addr_on_target = tpptr; + + /* Write the whole object. We'll fix up its pointers in a bit. + Assume no next for now. This is fixed up above on the next + iteration, if there's any. */ + target_tracepoint.next = NULL; + /* Need to clear this here too, since we're downloading the + tracepoints before clearing our own copy. */ + target_tracepoint.hit_count = 0; + + target_write_memory (tpptr, (unsigned char *) &target_tracepoint, + sizeof (target_tracepoint)); + + if (tpoint->cond) + write_inferior_data_pointer (tpptr + + offsetof (struct tracepoint, cond), + download_agent_expr (tpoint->cond)); + + if (tpoint->numactions) + { + int i; + CORE_ADDR actions_array; + + /* The pointers array. */ + actions_array + = target_malloc (sizeof (*tpoint->actions) * tpoint->numactions); + write_inferior_data_pointer (tpptr + offsetof (struct tracepoint, + actions), + actions_array); + + /* Now for each pointer, download the action. */ + for (i = 0; i < tpoint->numactions; i++) + { + struct tracepoint_action *action = tpoint->actions[i]; + CORE_ADDR ipa_action = tracepoint_action_download (action); + + if (ipa_action != 0) + write_inferior_data_pointer (actions_array + + i * sizeof (*tpoint->actions), + ipa_action); + } + } +} + +#define IPA_PROTO_FAST_TRACE_FLAG 0 +#define IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET 2 +#define IPA_PROTO_FAST_TRACE_JUMP_PAD 10 +#define IPA_PROTO_FAST_TRACE_FJUMP_SIZE 18 +#define IPA_PROTO_FAST_TRACE_FJUMP_INSN 22 + +/* Send a command to agent to download and install tracepoint TPOINT. */ + +static int +tracepoint_send_agent (struct tracepoint *tpoint) +{ + char buf[IPA_CMD_BUF_SIZE]; + char *p; + int i, ret; + + p = buf; + strcpy (p, "FastTrace:"); + p += 10; + + COPY_FIELD_TO_BUF (p, tpoint, number); + COPY_FIELD_TO_BUF (p, tpoint, address); + COPY_FIELD_TO_BUF (p, tpoint, type); + COPY_FIELD_TO_BUF (p, tpoint, enabled); + COPY_FIELD_TO_BUF (p, tpoint, step_count); + COPY_FIELD_TO_BUF (p, tpoint, pass_count); + COPY_FIELD_TO_BUF (p, tpoint, numactions); + COPY_FIELD_TO_BUF (p, tpoint, hit_count); + COPY_FIELD_TO_BUF (p, tpoint, traceframe_usage); + COPY_FIELD_TO_BUF (p, tpoint, compiled_cond); + COPY_FIELD_TO_BUF (p, tpoint, orig_size); + + /* condition */ + p = agent_expr_send (p, tpoint->cond); + + /* tracepoint_action */ + for (i = 0; i < tpoint->numactions; i++) + { + struct tracepoint_action *action = tpoint->actions[i]; + + p[0] = action->type; + p = tracepoint_action_send (&p[1], action); + } + + get_jump_space_head (); + /* Copy the value of GDB_JUMP_PAD_HEAD to command buffer, so that + agent can use jump pad from it. */ + if (tpoint->type == fast_tracepoint) + { + memcpy (p, &gdb_jump_pad_head, 8); + p += 8; + } + + ret = run_inferior_command (buf, (int) (ptrdiff_t) (p - buf)); + if (ret) + return ret; + + if (!startswith (buf, "OK")) + return 1; + + /* The value of tracepoint's target address is stored in BUF. */ + memcpy (&tpoint->obj_addr_on_target, + &buf[IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET], 8); + + if (tpoint->type == fast_tracepoint) + { + unsigned char *insn + = (unsigned char *) &buf[IPA_PROTO_FAST_TRACE_FJUMP_INSN]; + int fjump_size; + + trace_debug ("agent: read from cmd_buf 0x%x 0x%x\n", + (unsigned int) tpoint->obj_addr_on_target, + (unsigned int) gdb_jump_pad_head); + + memcpy (&gdb_jump_pad_head, &buf[IPA_PROTO_FAST_TRACE_JUMP_PAD], 8); + + /* This has been done in agent. We should also set up record for it. */ + memcpy (&fjump_size, &buf[IPA_PROTO_FAST_TRACE_FJUMP_SIZE], 4); + /* Wire it in. */ + tpoint->handle + = set_fast_tracepoint_jump (tpoint->address, insn, fjump_size); + } + + return 0; +} + +static void +download_tracepoint (struct tracepoint *tpoint) +{ + struct tracepoint *tp, *tp_prev; + + if (tpoint->type != fast_tracepoint + && tpoint->type != static_tracepoint) + return; + + download_tracepoint_1 (tpoint); + + /* Find the previous entry of TPOINT, which is fast tracepoint or + static tracepoint. */ + tp_prev = NULL; + for (tp = tracepoints; tp != tpoint; tp = tp->next) + { + if (tp->type == fast_tracepoint || tp->type == static_tracepoint) + tp_prev = tp; + } + + if (tp_prev) + { + CORE_ADDR tp_prev_target_next_addr; + + /* Insert TPOINT after TP_PREV in IPA. */ + if (read_inferior_data_pointer (tp_prev->obj_addr_on_target + + offsetof (struct tracepoint, next), + &tp_prev_target_next_addr)) + { + internal_error (__FILE__, __LINE__, + "error reading `tp_prev->next'"); + } + + /* tpoint->next = tp_prev->next */ + write_inferior_data_pointer (tpoint->obj_addr_on_target + + offsetof (struct tracepoint, next), + tp_prev_target_next_addr); + /* tp_prev->next = tpoint */ + write_inferior_data_pointer (tp_prev->obj_addr_on_target + + offsetof (struct tracepoint, next), + tpoint->obj_addr_on_target); + } + else + /* First object in list, set the head pointer in the + inferior. */ + write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, + tpoint->obj_addr_on_target); + +} + +static void +download_trace_state_variables (void) +{ + CORE_ADDR ptr = 0, prev_ptr = 0; + struct trace_state_variable *tsv; + + /* Start out empty. */ + write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables, 0); + + for (tsv = trace_state_variables; tsv != NULL; tsv = tsv->next) + { + struct trace_state_variable target_tsv; + + /* TSV's with a getter have been initialized equally in both the + inferior and GDBserver. Skip them. */ + if (tsv->getter != NULL) + continue; + + target_tsv = *tsv; + + prev_ptr = ptr; + ptr = target_malloc (sizeof (*tsv)); + + if (tsv == trace_state_variables) + { + /* First object in list, set the head pointer in the + inferior. */ + + write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables, + ptr); + } + else + { + write_inferior_data_pointer (prev_ptr + + offsetof (struct trace_state_variable, + next), + ptr); + } + + /* Write the whole object. We'll fix up its pointers in a bit. + Assume no next, fixup when needed. */ + target_tsv.next = NULL; + + target_write_memory (ptr, (unsigned char *) &target_tsv, + sizeof (target_tsv)); + + if (tsv->name != NULL) + { + size_t size = strlen (tsv->name) + 1; + CORE_ADDR name_addr = target_malloc (size); + target_write_memory (name_addr, + (unsigned char *) tsv->name, size); + write_inferior_data_pointer (ptr + + offsetof (struct trace_state_variable, + name), + name_addr); + } + + gdb_assert (tsv->getter == NULL); + } + + if (prev_ptr != 0) + { + /* Fixup the next pointer in the last item in the list. */ + write_inferior_data_pointer (prev_ptr + + offsetof (struct trace_state_variable, + next), 0); + } +} + +/* Upload complete trace frames out of the IP Agent's trace buffer + into GDBserver's trace buffer. This always uploads either all or + no trace frames. This is the counter part of + `trace_alloc_trace_buffer'. See its description of the atomic + syncing mechanism. */ + +static void +upload_fast_traceframes (void) +{ + unsigned int ipa_traceframe_read_count, ipa_traceframe_write_count; + unsigned int ipa_traceframe_read_count_racy, ipa_traceframe_write_count_racy; + CORE_ADDR tf; + struct ipa_trace_buffer_control ipa_trace_buffer_ctrl; + unsigned int curr_tbctrl_idx; + unsigned int ipa_trace_buffer_ctrl_curr; + unsigned int ipa_trace_buffer_ctrl_curr_old; + CORE_ADDR ipa_trace_buffer_ctrl_addr; + struct breakpoint *about_to_request_buffer_space_bkpt; + CORE_ADDR ipa_trace_buffer_lo; + CORE_ADDR ipa_trace_buffer_hi; + + if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, + &ipa_traceframe_read_count_racy)) + { + /* This will happen in most targets if the current thread is + running. */ + return; + } + + if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, + &ipa_traceframe_write_count_racy)) + return; + + trace_debug ("ipa_traceframe_count (racy area): %d (w=%d, r=%d)", + ipa_traceframe_write_count_racy + - ipa_traceframe_read_count_racy, + ipa_traceframe_write_count_racy, + ipa_traceframe_read_count_racy); + + if (ipa_traceframe_write_count_racy == ipa_traceframe_read_count_racy) + return; + + about_to_request_buffer_space_bkpt + = set_breakpoint_at (ipa_sym_addrs.addr_about_to_request_buffer_space, + NULL); + + if (read_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, + &ipa_trace_buffer_ctrl_curr)) + return; + + ipa_trace_buffer_ctrl_curr_old = ipa_trace_buffer_ctrl_curr; + + curr_tbctrl_idx = ipa_trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK; + + { + unsigned int prev, counter; + + /* Update the token, with new counters, and the GDBserver stamp + bit. Alway reuse the current TBC index. */ + prev = ipa_trace_buffer_ctrl_curr & GDBSERVER_FLUSH_COUNT_MASK_CURR; + counter = (prev + 0x100) & GDBSERVER_FLUSH_COUNT_MASK_CURR; + + ipa_trace_buffer_ctrl_curr = (GDBSERVER_UPDATED_FLUSH_COUNT_BIT + | (prev << 12) + | counter + | curr_tbctrl_idx); + } + + if (write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, + ipa_trace_buffer_ctrl_curr)) + return; + + trace_debug ("Lib: Committed %08x -> %08x", + ipa_trace_buffer_ctrl_curr_old, + ipa_trace_buffer_ctrl_curr); + + /* Re-read these, now that we've installed the + `about_to_request_buffer_space' breakpoint/lock. A thread could + have finished a traceframe between the last read of these + counters and setting the breakpoint above. If we start + uploading, we never want to leave this function with + traceframe_read_count != 0, otherwise, GDBserver could end up + incrementing the counter tokens more than once (due to event loop + nesting), which would break the IP agent's "effective" detection + (see trace_alloc_trace_buffer). */ + if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, + &ipa_traceframe_read_count)) + return; + if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, + &ipa_traceframe_write_count)) + return; + + if (debug_threads) + { + trace_debug ("ipa_traceframe_count (blocked area): %d (w=%d, r=%d)", + ipa_traceframe_write_count - ipa_traceframe_read_count, + ipa_traceframe_write_count, ipa_traceframe_read_count); + + if (ipa_traceframe_write_count != ipa_traceframe_write_count_racy + || ipa_traceframe_read_count != ipa_traceframe_read_count_racy) + trace_debug ("note that ipa_traceframe_count's parts changed"); + } + + /* Get the address of the current TBC object (the IP agent has an + array of 3 such objects). The index is stored in the TBC + token. */ + ipa_trace_buffer_ctrl_addr = ipa_sym_addrs.addr_trace_buffer_ctrl; + ipa_trace_buffer_ctrl_addr + += sizeof (struct ipa_trace_buffer_control) * curr_tbctrl_idx; + + if (read_inferior_memory (ipa_trace_buffer_ctrl_addr, + (unsigned char *) &ipa_trace_buffer_ctrl, + sizeof (struct ipa_trace_buffer_control))) + return; + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo, + &ipa_trace_buffer_lo)) + return; + if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi, + &ipa_trace_buffer_hi)) + return; + + /* Offsets are easier to grok for debugging than raw addresses, + especially for the small trace buffer sizes that are useful for + testing. */ + trace_debug ("Lib: Trace buffer [%d] start=%d free=%d " + "endfree=%d wrap=%d hi=%d", + curr_tbctrl_idx, + (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo)); + + /* Note that the IPA's buffer is always circular. */ + +#define IPA_FIRST_TRACEFRAME() (ipa_trace_buffer_ctrl.start) + +#define IPA_NEXT_TRACEFRAME_1(TF, TFOBJ) \ + ((TF) + sizeof (struct traceframe) + (TFOBJ)->data_size) + +#define IPA_NEXT_TRACEFRAME(TF, TFOBJ) \ + (IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) \ + - ((IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) >= ipa_trace_buffer_ctrl.wrap) \ + ? (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo) \ + : 0)) + + tf = IPA_FIRST_TRACEFRAME (); + + while (ipa_traceframe_write_count - ipa_traceframe_read_count) + { + struct tracepoint *tpoint; + struct traceframe *tframe; + unsigned char *block; + struct traceframe ipa_tframe; + + if (read_inferior_memory (tf, (unsigned char *) &ipa_tframe, + offsetof (struct traceframe, data))) + error ("Uploading: couldn't read traceframe at %s\n", paddress (tf)); + + if (ipa_tframe.tpnum == 0) + { + internal_error (__FILE__, __LINE__, + "Uploading: No (more) fast traceframes, but" + " ipa_traceframe_count == %u??\n", + ipa_traceframe_write_count + - ipa_traceframe_read_count); + } + + /* Note that this will be incorrect for multi-location + tracepoints... */ + tpoint = find_next_tracepoint_by_number (NULL, ipa_tframe.tpnum); + + tframe = add_traceframe (tpoint); + if (tframe == NULL) + { + trace_buffer_is_full = 1; + trace_debug ("Uploading: trace buffer is full"); + } + else + { + /* Copy the whole set of blocks in one go for now. FIXME: + split this in smaller blocks. */ + block = add_traceframe_block (tframe, tpoint, + ipa_tframe.data_size); + if (block != NULL) + { + if (read_inferior_memory (tf + + offsetof (struct traceframe, data), + block, ipa_tframe.data_size)) + error ("Uploading: Couldn't read traceframe data at %s\n", + paddress (tf + offsetof (struct traceframe, data))); + } + + trace_debug ("Uploading: traceframe didn't fit"); + finish_traceframe (tframe); + } + + tf = IPA_NEXT_TRACEFRAME (tf, &ipa_tframe); + + /* If we freed the traceframe that wrapped around, go back + to the non-wrap case. */ + if (tf < ipa_trace_buffer_ctrl.start) + { + trace_debug ("Lib: Discarding past the wraparound"); + ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi; + } + ipa_trace_buffer_ctrl.start = tf; + ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_ctrl.start; + ++ipa_traceframe_read_count; + + if (ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.free + && ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.end_free) + { + trace_debug ("Lib: buffer is fully empty. " + "Trace buffer [%d] start=%d free=%d endfree=%d", + curr_tbctrl_idx, + (int) (ipa_trace_buffer_ctrl.start + - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.free + - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.end_free + - ipa_trace_buffer_lo)); + + ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo; + ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo; + ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi; + ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi; + } + + trace_debug ("Uploaded a traceframe\n" + "Lib: Trace buffer [%d] start=%d free=%d " + "endfree=%d wrap=%d hi=%d", + curr_tbctrl_idx, + (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.end_free + - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo), + (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo)); + } + + if (target_write_memory (ipa_trace_buffer_ctrl_addr, + (unsigned char *) &ipa_trace_buffer_ctrl, + sizeof (struct ipa_trace_buffer_control))) + return; + + write_inferior_integer (ipa_sym_addrs.addr_traceframe_read_count, + ipa_traceframe_read_count); + + trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx); + + pause_all (1); + + delete_breakpoint (about_to_request_buffer_space_bkpt); + about_to_request_buffer_space_bkpt = NULL; + + unpause_all (1); + + if (trace_buffer_is_full) + stop_tracing (); +} +#endif + +#ifdef IN_PROCESS_AGENT + +IP_AGENT_EXPORT_VAR int ust_loaded; +IP_AGENT_EXPORT_VAR char cmd_buf[IPA_CMD_BUF_SIZE]; + +#ifdef HAVE_UST + +/* Static tracepoints. */ + +/* UST puts a "struct tracepoint" in the global namespace, which + conflicts with our tracepoint. Arguably, being a library, it + shouldn't take ownership of such a generic name. We work around it + here. */ +#define tracepoint ust_tracepoint +#include +#undef tracepoint + +extern int serialize_to_text (char *outbuf, int bufsize, + const char *fmt, va_list ap); + +#define GDB_PROBE_NAME "gdb" + +/* We dynamically search for the UST symbols instead of linking them + in. This lets the user decide if the application uses static + tracepoints, instead of always pulling libust.so in. This vector + holds pointers to all functions we care about. */ + +static struct +{ + int (*serialize_to_text) (char *outbuf, int bufsize, + const char *fmt, va_list ap); + + int (*ltt_probe_register) (struct ltt_available_probe *pdata); + int (*ltt_probe_unregister) (struct ltt_available_probe *pdata); + + int (*ltt_marker_connect) (const char *channel, const char *mname, + const char *pname); + int (*ltt_marker_disconnect) (const char *channel, const char *mname, + const char *pname); + + void (*marker_iter_start) (struct marker_iter *iter); + void (*marker_iter_next) (struct marker_iter *iter); + void (*marker_iter_stop) (struct marker_iter *iter); + void (*marker_iter_reset) (struct marker_iter *iter); +} ust_ops; + +#include + +/* Cast through typeof to catch incompatible API changes. Since UST + only builds with gcc, we can freely use gcc extensions here + too. */ +#define GET_UST_SYM(SYM) \ + do \ + { \ + if (ust_ops.SYM == NULL) \ + ust_ops.SYM = (typeof (&SYM)) dlsym (RTLD_DEFAULT, #SYM); \ + if (ust_ops.SYM == NULL) \ + return 0; \ + } while (0) + +#define USTF(SYM) ust_ops.SYM + +/* Get pointers to all libust.so functions we care about. */ + +static int +dlsym_ust (void) +{ + GET_UST_SYM (serialize_to_text); + + GET_UST_SYM (ltt_probe_register); + GET_UST_SYM (ltt_probe_unregister); + GET_UST_SYM (ltt_marker_connect); + GET_UST_SYM (ltt_marker_disconnect); + + GET_UST_SYM (marker_iter_start); + GET_UST_SYM (marker_iter_next); + GET_UST_SYM (marker_iter_stop); + GET_UST_SYM (marker_iter_reset); + + ust_loaded = 1; + return 1; +} + +/* Given an UST marker, return the matching gdb static tracepoint. + The match is done by address. */ + +static struct tracepoint * +ust_marker_to_static_tracepoint (const struct marker *mdata) +{ + struct tracepoint *tpoint; + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + { + if (tpoint->type != static_tracepoint) + continue; + + if (tpoint->address == (uintptr_t) mdata->location) + return tpoint; + } + + return NULL; +} + +/* The probe function we install on lttng/ust markers. Whenever a + probed ust marker is hit, this function is called. This is similar + to gdb_collect, only for static tracepoints, instead of fast + tracepoints. */ + +static void +gdb_probe (const struct marker *mdata, void *probe_private, + struct registers *regs, void *call_private, + const char *fmt, va_list *args) +{ + struct tracepoint *tpoint; + struct static_tracepoint_ctx ctx; + const struct target_desc *ipa_tdesc; + + /* Don't do anything until the trace run is completely set up. */ + if (!tracing) + { + trace_debug ("gdb_probe: not tracing\n"); + return; + } + + ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx); + ctx.base.type = static_tracepoint; + ctx.regcache_initted = 0; + ctx.regs = regs; + ctx.fmt = fmt; + ctx.args = args; + + /* Wrap the regblock in a register cache (in the stack, we don't + want to malloc here). */ + ctx.regspace = alloca (ipa_tdesc->registers_size); + if (ctx.regspace == NULL) + { + trace_debug ("Trace buffer block allocation failed, skipping"); + return; + } + + tpoint = ust_marker_to_static_tracepoint (mdata); + if (tpoint == NULL) + { + trace_debug ("gdb_probe: marker not known: " + "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"", + mdata->location, mdata->channel, + mdata->name, mdata->format); + return; + } + + if (!tpoint->enabled) + { + trace_debug ("gdb_probe: tracepoint disabled"); + return; + } + + ctx.tpoint = tpoint; + + trace_debug ("gdb_probe: collecting marker: " + "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"", + mdata->location, mdata->channel, + mdata->name, mdata->format); + + /* Test the condition if present, and collect if true. */ + if (tpoint->cond == NULL + || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, + tpoint)) + { + collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx, + tpoint->address, tpoint); + + if (stopping_tracepoint + || trace_buffer_is_full + || expr_eval_result != expr_eval_no_error) + stop_tracing (); + } + else + { + /* If there was a condition and it evaluated to false, the only + way we would stop tracing is if there was an error during + condition expression evaluation. */ + if (expr_eval_result != expr_eval_no_error) + stop_tracing (); + } +} + +/* Called if the gdb static tracepoint requested collecting "$_sdata", + static tracepoint string data. This is a string passed to the + tracing library by the user, at the time of the tracepoint marker + call. E.g., in the UST marker call: + + trace_mark (ust, bar33, "str %s", "FOOBAZ"); + + the collected data is "str FOOBAZ". +*/ + +static void +collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, + struct traceframe *tframe) +{ + struct static_tracepoint_ctx *umd = (struct static_tracepoint_ctx *) ctx; + unsigned char *bufspace; + int size; + va_list copy; + unsigned short blocklen; + + if (umd == NULL) + { + trace_debug ("Wanted to collect static trace data, " + "but there's no static trace data"); + return; + } + + va_copy (copy, *umd->args); + size = USTF(serialize_to_text) (NULL, 0, umd->fmt, copy); + va_end (copy); + + trace_debug ("Want to collect ust data"); + + /* 'S' + size + string */ + bufspace = add_traceframe_block (tframe, umd->tpoint, + 1 + sizeof (blocklen) + size + 1); + if (bufspace == NULL) + { + trace_debug ("Trace buffer block allocation failed, skipping"); + return; + } + + /* Identify a static trace data block. */ + *bufspace = 'S'; + + blocklen = size + 1; + memcpy (bufspace + 1, &blocklen, sizeof (blocklen)); + + va_copy (copy, *umd->args); + USTF(serialize_to_text) ((char *) bufspace + 1 + sizeof (blocklen), + size + 1, umd->fmt, copy); + va_end (copy); + + trace_debug ("Storing static tracepoint data in regblock: %s", + bufspace + 1 + sizeof (blocklen)); +} + +/* The probe to register with lttng/ust. */ +static struct ltt_available_probe gdb_ust_probe = + { + GDB_PROBE_NAME, + NULL, + gdb_probe, + }; + +#endif /* HAVE_UST */ +#endif /* IN_PROCESS_AGENT */ + +#ifndef IN_PROCESS_AGENT + +/* Ask the in-process agent to run a command. Since we don't want to + have to handle the IPA hitting breakpoints while running the + command, we pause all threads, remove all breakpoints, and then set + the helper thread re-running. We communicate with the helper + thread by means of direct memory xfering, and a socket for + synchronization. */ + +static int +run_inferior_command (char *cmd, int len) +{ + int err = -1; + int pid = current_ptid.pid (); + + trace_debug ("run_inferior_command: running: %s", cmd); + + pause_all (0); + uninsert_all_breakpoints (); + + err = agent_run_command (pid, (const char *) cmd, len); + + reinsert_all_breakpoints (); + unpause_all (0); + + return err; +} + +#else /* !IN_PROCESS_AGENT */ + +#include +#include + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) +#endif + +/* Where we put the socked used for synchronization. */ +#define SOCK_DIR P_tmpdir + +/* Thread ID of the helper thread. GDBserver reads this to know which + is the help thread. This is an LWP id on Linux. */ +EXTERN_C_PUSH +IP_AGENT_EXPORT_VAR int helper_thread_id; +EXTERN_C_POP + +static int +init_named_socket (const char *name) +{ + int result, fd; + struct sockaddr_un addr; + + result = fd = socket (PF_UNIX, SOCK_STREAM, 0); + if (result == -1) + { + warning ("socket creation failed: %s", safe_strerror (errno)); + return -1; + } + + addr.sun_family = AF_UNIX; + + strncpy (addr.sun_path, name, UNIX_PATH_MAX); + addr.sun_path[UNIX_PATH_MAX - 1] = '\0'; + + result = access (name, F_OK); + if (result == 0) + { + /* File exists. */ + result = unlink (name); + if (result == -1) + { + warning ("unlink failed: %s", safe_strerror (errno)); + close (fd); + return -1; + } + warning ("socket %s already exists; overwriting", name); + } + + result = bind (fd, (struct sockaddr *) &addr, sizeof (addr)); + if (result == -1) + { + warning ("bind failed: %s", safe_strerror (errno)); + close (fd); + return -1; + } + + result = listen (fd, 1); + if (result == -1) + { + warning ("listen: %s", safe_strerror (errno)); + close (fd); + return -1; + } + + return fd; +} + +static char agent_socket_name[UNIX_PATH_MAX]; + +static int +gdb_agent_socket_init (void) +{ + int result, fd; + + result = xsnprintf (agent_socket_name, UNIX_PATH_MAX, "%s/gdb_ust%d", + SOCK_DIR, getpid ()); + if (result >= UNIX_PATH_MAX) + { + trace_debug ("string overflow allocating socket name"); + return -1; + } + + fd = init_named_socket (agent_socket_name); + if (fd < 0) + warning ("Error initializing named socket (%s) for communication with the " + "ust helper thread. Check that directory exists and that it " + "is writable.", agent_socket_name); + + return fd; +} + +#ifdef HAVE_UST + +/* The next marker to be returned on a qTsSTM command. */ +static const struct marker *next_st; + +/* Returns the first known marker. */ + +struct marker * +first_marker (void) +{ + struct marker_iter iter; + + USTF(marker_iter_reset) (&iter); + USTF(marker_iter_start) (&iter); + + return iter.marker; +} + +/* Returns the marker following M. */ + +const struct marker * +next_marker (const struct marker *m) +{ + struct marker_iter iter; + + USTF(marker_iter_reset) (&iter); + USTF(marker_iter_start) (&iter); + + for (; iter.marker != NULL; USTF(marker_iter_next) (&iter)) + { + if (iter.marker == m) + { + USTF(marker_iter_next) (&iter); + return iter.marker; + } + } + + return NULL; +} + +/* Return an hexstr version of the STR C string, fit for sending to + GDB. */ + +static char * +cstr_to_hexstr (const char *str) +{ + int len = strlen (str); + char *hexstr = xmalloc (len * 2 + 1); + bin2hex ((gdb_byte *) str, hexstr, len); + return hexstr; +} + +/* Compose packet that is the response to the qTsSTM/qTfSTM/qTSTMat + packets. */ + +static void +response_ust_marker (char *packet, const struct marker *st) +{ + char *strid, *format, *tmp; + + next_st = next_marker (st); + + tmp = xmalloc (strlen (st->channel) + 1 + + strlen (st->name) + 1); + sprintf (tmp, "%s/%s", st->channel, st->name); + + strid = cstr_to_hexstr (tmp); + free (tmp); + + format = cstr_to_hexstr (st->format); + + sprintf (packet, "m%s:%s:%s", + paddress ((uintptr_t) st->location), + strid, + format); + + free (strid); + free (format); +} + +/* Return the first static tracepoint, and initialize the state + machine that will iterate through all the static tracepoints. */ + +static void +cmd_qtfstm (char *packet) +{ + trace_debug ("Returning first trace state variable definition"); + + if (first_marker ()) + response_ust_marker (packet, first_marker ()); + else + strcpy (packet, "l"); +} + +/* Return additional trace state variable definitions. */ + +static void +cmd_qtsstm (char *packet) +{ + trace_debug ("Returning static tracepoint"); + + if (next_st) + response_ust_marker (packet, next_st); + else + strcpy (packet, "l"); +} + +/* Disconnect the GDB probe from a marker at a given address. */ + +static void +unprobe_marker_at (char *packet) +{ + char *p = packet; + ULONGEST address; + struct marker_iter iter; + + p += sizeof ("unprobe_marker_at:") - 1; + + p = unpack_varlen_hex (p, &address); + + USTF(marker_iter_reset) (&iter); + USTF(marker_iter_start) (&iter); + for (; iter.marker != NULL; USTF(marker_iter_next) (&iter)) + if ((uintptr_t ) iter.marker->location == address) + { + int result; + + result = USTF(ltt_marker_disconnect) (iter.marker->channel, + iter.marker->name, + GDB_PROBE_NAME); + if (result < 0) + warning ("could not disable marker %s/%s", + iter.marker->channel, iter.marker->name); + break; + } +} + +/* Connect the GDB probe to a marker at a given address. */ + +static int +probe_marker_at (char *packet) +{ + char *p = packet; + ULONGEST address; + struct marker_iter iter; + struct marker *m; + + p += sizeof ("probe_marker_at:") - 1; + + p = unpack_varlen_hex (p, &address); + + USTF(marker_iter_reset) (&iter); + + for (USTF(marker_iter_start) (&iter), m = iter.marker; + m != NULL; + USTF(marker_iter_next) (&iter), m = iter.marker) + if ((uintptr_t ) m->location == address) + { + int result; + + trace_debug ("found marker for address. " + "ltt_marker_connect (marker = %s/%s)", + m->channel, m->name); + + result = USTF(ltt_marker_connect) (m->channel, m->name, + GDB_PROBE_NAME); + if (result && result != -EEXIST) + trace_debug ("ltt_marker_connect (marker = %s/%s, errno = %d)", + m->channel, m->name, -result); + + if (result < 0) + { + sprintf (packet, "E.could not connect marker: channel=%s, name=%s", + m->channel, m->name); + return -1; + } + + strcpy (packet, "OK"); + return 0; + } + + sprintf (packet, "E.no marker found at 0x%s", paddress (address)); + return -1; +} + +static int +cmd_qtstmat (char *packet) +{ + char *p = packet; + ULONGEST address; + struct marker_iter iter; + struct marker *m; + + p += sizeof ("qTSTMat:") - 1; + + p = unpack_varlen_hex (p, &address); + + USTF(marker_iter_reset) (&iter); + + for (USTF(marker_iter_start) (&iter), m = iter.marker; + m != NULL; + USTF(marker_iter_next) (&iter), m = iter.marker) + if ((uintptr_t ) m->location == address) + { + response_ust_marker (packet, m); + return 0; + } + + strcpy (packet, "l"); + return -1; +} + +static void +gdb_ust_init (void) +{ + if (!dlsym_ust ()) + return; + + USTF(ltt_probe_register) (&gdb_ust_probe); +} + +#endif /* HAVE_UST */ + +#include + +static void +gdb_agent_remove_socket (void) +{ + unlink (agent_socket_name); +} + +/* Helper thread of agent. */ + +static void * +gdb_agent_helper_thread (void *arg) +{ + int listen_fd; + + atexit (gdb_agent_remove_socket); + + while (1) + { + listen_fd = gdb_agent_socket_init (); + + if (helper_thread_id == 0) + helper_thread_id = syscall (SYS_gettid); + + if (listen_fd == -1) + { + warning ("could not create sync socket"); + break; + } + + while (1) + { + socklen_t tmp; + struct sockaddr_un sockaddr; + int fd; + char buf[1]; + int ret; + int stop_loop = 0; + + tmp = sizeof (sockaddr); + + do + { + fd = accept (listen_fd, (struct sockaddr *) &sockaddr, &tmp); + } + /* It seems an ERESTARTSYS can escape out of accept. */ + while (fd == -512 || (fd == -1 && errno == EINTR)); + + if (fd < 0) + { + warning ("Accept returned %d, error: %s", + fd, safe_strerror (errno)); + break; + } + + do + { + ret = read (fd, buf, 1); + } while (ret == -1 && errno == EINTR); + + if (ret == -1) + { + warning ("reading socket (fd=%d) failed with %s", + fd, safe_strerror (errno)); + close (fd); + break; + } + + if (cmd_buf[0]) + { + if (startswith (cmd_buf, "close")) + { + stop_loop = 1; + } +#ifdef HAVE_UST + else if (strcmp ("qTfSTM", cmd_buf) == 0) + { + cmd_qtfstm (cmd_buf); + } + else if (strcmp ("qTsSTM", cmd_buf) == 0) + { + cmd_qtsstm (cmd_buf); + } + else if (startswith (cmd_buf, "unprobe_marker_at:")) + { + unprobe_marker_at (cmd_buf); + } + else if (startswith (cmd_buf, "probe_marker_at:")) + { + probe_marker_at (cmd_buf); + } + else if (startswith (cmd_buf, "qTSTMat:")) + { + cmd_qtstmat (cmd_buf); + } +#endif /* HAVE_UST */ + } + + /* Fix compiler's warning: ignoring return value of 'write'. */ + ret = write (fd, buf, 1); + close (fd); + + if (stop_loop) + { + close (listen_fd); + unlink (agent_socket_name); + + /* Sleep endlessly to wait the whole inferior stops. This + thread can not exit because GDB or GDBserver may still need + 'current_thread' (representing this thread) to access + inferior memory. Otherwise, this thread exits earlier than + other threads, and 'current_thread' is set to NULL. */ + while (1) + sleep (10); + } + } + } + + return NULL; +} + +#include +#include + +EXTERN_C_PUSH +IP_AGENT_EXPORT_VAR int gdb_agent_capability = AGENT_CAPA_STATIC_TRACE; +EXTERN_C_POP + +static void +gdb_agent_init (void) +{ + int res; + pthread_t thread; + sigset_t new_mask; + sigset_t orig_mask; + + /* We want the helper thread to be as transparent as possible, so + have it inherit an all-signals-blocked mask. */ + + sigfillset (&new_mask); + res = pthread_sigmask (SIG_SETMASK, &new_mask, &orig_mask); + if (res) + perror_with_name ("pthread_sigmask (1)"); + + res = pthread_create (&thread, + NULL, + gdb_agent_helper_thread, + NULL); + + res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL); + if (res) + perror_with_name ("pthread_sigmask (2)"); + + while (helper_thread_id == 0) + usleep (1); + +#ifdef HAVE_UST + gdb_ust_init (); +#endif +} + +#include + +IP_AGENT_EXPORT_VAR char *gdb_tp_heap_buffer; +IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer; +IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer_end; +IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer; +IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_end; +IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_error; + +/* Record the result of getting buffer space for fast tracepoint + trampolines. Any error message is copied, since caller may not be + using persistent storage. */ + +void +set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, char *errmsg) +{ + gdb_trampoline_buffer = (char *) (uintptr_t) begin; + gdb_trampoline_buffer_end = (char *) (uintptr_t) end; + if (errmsg) + strncpy (gdb_trampoline_buffer_error, errmsg, 99); + else + strcpy (gdb_trampoline_buffer_error, "no buffer passed"); +} + +static void __attribute__ ((constructor)) +initialize_tracepoint_ftlib (void) +{ + initialize_tracepoint (); + + gdb_agent_init (); +} + +#ifndef HAVE_GETAUXVAL +/* Retrieve the value of TYPE from the auxiliary vector. If TYPE is not + found, 0 is returned. This function is provided if glibc is too old. */ + +unsigned long +getauxval (unsigned long type) +{ + unsigned long data[2]; + FILE *f = fopen ("/proc/self/auxv", "r"); + unsigned long value = 0; + + if (f == NULL) + return 0; + + while (fread (data, sizeof (data), 1, f) > 0) + { + if (data[0] == type) + { + value = data[1]; + break; + } + } + + fclose (f); + return value; +} +#endif + +#endif /* IN_PROCESS_AGENT */ + +/* Return a timestamp, expressed as microseconds of the usual Unix + time. (As the result is a 64-bit number, it will not overflow any + time soon.) */ + +static LONGEST +get_timestamp (void) +{ + using namespace std::chrono; + + steady_clock::time_point now = steady_clock::now (); + return duration_cast (now.time_since_epoch ()).count (); +} + +void +initialize_tracepoint (void) +{ + /* Start with the default size. */ + init_trace_buffer (DEFAULT_TRACE_BUFFER_SIZE); + + /* Wire trace state variable 1 to be the timestamp. This will be + uploaded to GDB upon connection and become one of its trace state + variables. (In case you're wondering, if GDB already has a trace + variable numbered 1, it will be renumbered.) */ + create_trace_state_variable (1, 0); + set_trace_state_variable_name (1, "trace_timestamp"); + set_trace_state_variable_getter (1, get_timestamp); + +#ifdef IN_PROCESS_AGENT + { + int pagesize; + size_t jump_pad_size; + + pagesize = sysconf (_SC_PAGE_SIZE); + if (pagesize == -1) + perror_with_name ("sysconf"); + +#define SCRATCH_BUFFER_NPAGES 20 + + jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES; + + gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024); + gdb_jump_pad_buffer = (char *) alloc_jump_pad_buffer (jump_pad_size); + if (gdb_jump_pad_buffer == NULL) + perror_with_name ("mmap"); + gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size; + } + + gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0; + + /* It's not a fatal error for something to go wrong with trampoline + buffer setup, but it can be mysterious, so create a channel to + report back on what went wrong, using a fixed size since we may + not be able to allocate space later when the problem occurs. */ + gdb_trampoline_buffer_error = (char *) xmalloc (IPA_BUFSIZ); + + strcpy (gdb_trampoline_buffer_error, "No errors reported"); + + initialize_low_tracepoint (); +#endif +} diff --git a/gdbserver/tracepoint.h b/gdbserver/tracepoint.h new file mode 100644 index 00000000000..030b2a92344 --- /dev/null +++ b/gdbserver/tracepoint.h @@ -0,0 +1,195 @@ +/* Tracepoint code for remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_TRACEPOINT_H +#define GDBSERVER_TRACEPOINT_H + +/* Size for a small buffer to report problems from the in-process + agent back to GDBserver. */ +#define IPA_BUFSIZ 100 + +void initialize_tracepoint (void); + +#if defined(__GNUC__) +# define ATTR_USED __attribute__((used)) +# define ATTR_NOINLINE __attribute__((noinline)) +#else +# define ATTR_USED +# define ATTR_NOINLINE +#endif + +/* How to make symbol public/exported. */ + +#if defined _WIN32 || defined __CYGWIN__ +# define EXPORTED_SYMBOL __declspec (dllexport) +#else +# if __GNUC__ >= 4 +# define EXPORTED_SYMBOL __attribute__ ((visibility ("default"))) +# else +# define EXPORTED_SYMBOL +# endif +#endif + +/* Use these to make sure the functions and variables the IPA needs to + export (symbols GDBserver needs to query GDB about) are visible and + have C linkage. + + Tag exported functions with IP_AGENT_EXPORT_FUNC, tag the + definitions of exported variables with IP_AGENT_EXPORT_VAR, and + variable declarations with IP_AGENT_EXPORT_VAR_DECL. Variables + must also be exported with C linkage. As we can't both use extern + "C" and initialize a variable in the same statement, variables that + don't have a separate declaration must use + EXTERN_C_PUSH/EXTERN_C_POP around their definition. */ + +#ifdef IN_PROCESS_AGENT +# define IP_AGENT_EXPORT_FUNC EXTERN_C EXPORTED_SYMBOL ATTR_NOINLINE ATTR_USED +# define IP_AGENT_EXPORT_VAR EXPORTED_SYMBOL ATTR_USED +# define IP_AGENT_EXPORT_VAR_DECL EXTERN_C EXPORTED_SYMBOL +#else +# define IP_AGENT_EXPORT_FUNC static +# define IP_AGENT_EXPORT_VAR +# define IP_AGENT_EXPORT_VAR_DECL extern +#endif + +IP_AGENT_EXPORT_VAR_DECL int tracing; + +extern int disconnected_tracing; + +void tracepoint_look_up_symbols (void); + +void stop_tracing (void); + +int handle_tracepoint_general_set (char *own_buf); +int handle_tracepoint_query (char *own_buf); + +int tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc); +int tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc); + +void release_while_stepping_state_list (struct thread_info *tinfo); + +int in_readonly_region (CORE_ADDR addr, ULONGEST length); +int traceframe_read_mem (int tfnum, CORE_ADDR addr, + unsigned char *buf, ULONGEST length, + ULONGEST *nbytes); +int fetch_traceframe_registers (int tfnum, + struct regcache *regcache, + int regnum); + +int traceframe_read_sdata (int tfnum, ULONGEST offset, + unsigned char *buf, ULONGEST length, + ULONGEST *nbytes); + +int traceframe_read_info (int tfnum, struct buffer *buffer); + +/* If a thread is determined to be collecting a fast tracepoint, this + structure holds the collect status. */ + +struct fast_tpoint_collect_status +{ + /* The tracepoint that is presently being collected. */ + int tpoint_num; + CORE_ADDR tpoint_addr; + + /* The address range in the jump pad of where the original + instruction the tracepoint jump was inserted was relocated + to. */ + CORE_ADDR adjusted_insn_addr; + CORE_ADDR adjusted_insn_addr_end; +}; + +/* The possible states a thread can be in, related to the collection of fast + tracepoint. */ + +enum class fast_tpoint_collect_result +{ + /* Not collecting a fast tracepoint. */ + not_collecting, + + /* In the jump pad, but before the relocated instruction. */ + before_insn, + + /* In the jump pad, but at (or after) the relocated instruction. */ + at_insn, +}; + +fast_tpoint_collect_result fast_tracepoint_collecting + (CORE_ADDR thread_area, CORE_ADDR stop_pc, + struct fast_tpoint_collect_status *status); + +void force_unlock_trace_buffer (void); + +int handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc); + +#ifdef IN_PROCESS_AGENT +void initialize_low_tracepoint (void); +const struct target_desc *get_ipa_tdesc (int idx); +void supply_fast_tracepoint_registers (struct regcache *regcache, + const unsigned char *regs); +void supply_static_tracepoint_registers (struct regcache *regcache, + const unsigned char *regs, + CORE_ADDR pc); +void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, + char *errmsg); +void *alloc_jump_pad_buffer (size_t size); +#ifndef HAVE_GETAUXVAL +unsigned long getauxval (unsigned long type); +#endif +#else +void stop_tracing (void); + +int claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline); +int have_fast_tracepoint_trampoline_buffer (char *msgbuf); +void gdb_agent_about_to_close (int pid); +#endif + +struct traceframe; +struct eval_agent_expr_context; + +/* Do memory copies for bytecodes. */ +/* Do the recording of memory blocks for actions and bytecodes. */ + +int agent_mem_read (struct eval_agent_expr_context *ctx, + unsigned char *to, CORE_ADDR from, + ULONGEST len); + +LONGEST agent_get_trace_state_variable_value (int num); +void agent_set_trace_state_variable_value (int num, LONGEST val); + +/* Record the value of a trace state variable. */ + +int agent_tsv_read (struct eval_agent_expr_context *ctx, int n); +int agent_mem_read_string (struct eval_agent_expr_context *ctx, + unsigned char *to, + CORE_ADDR from, + ULONGEST len); + +/* The prototype the get_raw_reg function in the IPA. Each arch's + bytecode compiler emits calls to this function. */ +ULONGEST get_raw_reg (const unsigned char *raw_regs, int regnum); + +/* Returns the address of the get_raw_reg function in the IPA. */ +CORE_ADDR get_raw_reg_func_addr (void); +/* Returns the address of the get_trace_state_variable_value + function in the IPA. */ +CORE_ADDR get_get_tsv_func_addr (void); +/* Returns the address of the set_trace_state_variable_value + function in the IPA. */ +CORE_ADDR get_set_tsv_func_addr (void); + +#endif /* GDBSERVER_TRACEPOINT_H */ diff --git a/gdbserver/utils.c b/gdbserver/utils.c new file mode 100644 index 00000000000..d88f4ac5ca7 --- /dev/null +++ b/gdbserver/utils.c @@ -0,0 +1,127 @@ +/* General utility routines for the remote server for GDB. + Copyright (C) 1986-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" + +#ifdef IN_PROCESS_AGENT +# define PREFIX "ipa: " +# define TOOLNAME "GDBserver in-process agent" +#else +# define PREFIX "gdbserver: " +# define TOOLNAME "GDBserver" +#endif + +/* Generally useful subroutines used throughout the program. */ + +void +malloc_failure (long size) +{ + fprintf (stderr, + PREFIX "ran out of memory while trying to allocate %lu bytes\n", + (unsigned long) size); + exit (1); +} + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (const char *string) +{ + const char *err; + char *combined; + + err = safe_strerror (errno); + if (err == NULL) + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print an error message and return to top level. */ + +void +verror (const char *string, va_list args) +{ +#ifdef IN_PROCESS_AGENT + fflush (stdout); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + exit (1); +#else + throw_verror (GENERIC_ERROR, string, args); +#endif +} + +void +vwarning (const char *string, va_list args) +{ + fprintf (stderr, PREFIX); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); +} + +/* Report a problem internal to GDBserver, and exit. */ + +void +internal_verror (const char *file, int line, const char *fmt, va_list args) +{ + fprintf (stderr, "\ +%s:%d: A problem internal to " TOOLNAME " has been detected.\n", file, line); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + exit (1); +} + +/* Report a problem internal to GDBserver. */ + +void +internal_vwarning (const char *file, int line, const char *fmt, va_list args) +{ + fprintf (stderr, "\ +%s:%d: A problem internal to " TOOLNAME " has been detected.\n", file, line); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); +} + +/* Convert a CORE_ADDR into a HEX string, like %lx. + The result is stored in a circular static buffer, NUMCELLS deep. */ + +char * +paddress (CORE_ADDR addr) +{ + return phex_nz (addr, sizeof (CORE_ADDR)); +} + +/* Convert a file descriptor into a printable string. */ + +char * +pfildes (gdb_fildes_t fd) +{ +#if USE_WIN32API + return phex_nz (fd, sizeof (gdb_fildes_t)); +#else + return plongest (fd); +#endif +} diff --git a/gdbserver/utils.h b/gdbserver/utils.h new file mode 100644 index 00000000000..fa3ca9bb945 --- /dev/null +++ b/gdbserver/utils.h @@ -0,0 +1,25 @@ +/* General utility routines for the remote server for GDB. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_UTILS_H +#define GDBSERVER_UTILS_H + +char *paddress (CORE_ADDR addr); +char *pfildes (gdb_fildes_t fd); + +#endif /* GDBSERVER_UTILS_H */ diff --git a/gdbserver/win32-arm-low.c b/gdbserver/win32-arm-low.c new file mode 100644 index 00000000000..619847d10fc --- /dev/null +++ b/gdbserver/win32-arm-low.c @@ -0,0 +1,134 @@ +/* Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "win32-low.h" + +#ifndef CONTEXT_FLOATING_POINT +#define CONTEXT_FLOATING_POINT 0 +#endif + +/* Defined in auto-generated file reg-arm.c. */ +void init_registers_arm (void); +extern const struct target_desc *tdesc_arm; + +static void +arm_get_thread_context (win32_thread_info *th) +{ + th->context.ContextFlags = \ + CONTEXT_FULL | \ + CONTEXT_FLOATING_POINT; + + GetThreadContext (th->h, &th->context); +} + +#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) +static const int mappings[] = { + context_offset (R0), + context_offset (R1), + context_offset (R2), + context_offset (R3), + context_offset (R4), + context_offset (R5), + context_offset (R6), + context_offset (R7), + context_offset (R8), + context_offset (R9), + context_offset (R10), + context_offset (R11), + context_offset (R12), + context_offset (Sp), + context_offset (Lr), + context_offset (Pc), + -1, /* f0 */ + -1, /* f1 */ + -1, /* f2 */ + -1, /* f3 */ + -1, /* f4 */ + -1, /* f5 */ + -1, /* f6 */ + -1, /* f7 */ + -1, /* fps */ + context_offset (Psr), +}; +#undef context_offset + +/* Return a pointer into a CONTEXT field indexed by gdb register number. + Return a pointer to an dummy register holding zero if there is no + corresponding CONTEXT field for the given register number. */ +static char * +regptr (CONTEXT* c, int r) +{ + if (mappings[r] < 0) + { + static ULONG zero; + /* Always force value to zero, in case the user tried to write + to this register before. */ + zero = 0; + return (char *) &zero; + } + else + return (char *) c + mappings[r]; +} + +/* Fetch register from gdbserver regcache data. */ +static void +arm_fetch_inferior_register (struct regcache *regcache, + win32_thread_info *th, int r) +{ + char *context_offset = regptr (&th->context, r); + supply_register (regcache, r, context_offset); +} + +/* Store a new register value into the thread context of TH. */ +static void +arm_store_inferior_register (struct regcache *regcache, + win32_thread_info *th, int r) +{ + collect_register (regcache, r, regptr (&th->context, r)); +} + +static void +arm_arch_setup (void) +{ + init_registers_arm (); + win32_tdesc = tdesc_arm; +} + +/* Correct in either endianness. We do not support Thumb yet. */ +static const unsigned long arm_wince_breakpoint = 0xe6000010; +#define arm_wince_breakpoint_len 4 + +struct win32_target_ops the_low_target = { + arm_arch_setup, + sizeof (mappings) / sizeof (mappings[0]), + NULL, /* initial_stuff */ + arm_get_thread_context, + NULL, /* prepare_to_resume */ + NULL, /* thread_added */ + arm_fetch_inferior_register, + arm_store_inferior_register, + NULL, /* single_step */ + (const unsigned char *) &arm_wince_breakpoint, + arm_wince_breakpoint_len, + /* Watchpoint related functions. See target.h for comments. */ + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL /* stopped_data_address */ +}; diff --git a/gdbserver/win32-i386-low.c b/gdbserver/win32-i386-low.c new file mode 100644 index 00000000000..f5f09e96a57 --- /dev/null +++ b/gdbserver/win32-i386-low.c @@ -0,0 +1,468 @@ +/* Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "win32-low.h" +#include "x86-low.h" +#include "gdbsupport/x86-xstate.h" +#ifdef __x86_64__ +#include "arch/amd64.h" +#endif +#include "arch/i386.h" +#include "tdesc.h" +#include "x86-tdesc.h" + +#ifndef CONTEXT_EXTENDED_REGISTERS +#define CONTEXT_EXTENDED_REGISTERS 0 +#endif + +#define FCS_REGNUM 27 +#define FOP_REGNUM 31 + +#define FLAG_TRACE_BIT 0x100 + +static struct x86_debug_reg_state debug_reg_state; + +static void +update_debug_registers (thread_info *thread) +{ + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + + /* The actual update is done later just before resuming the lwp, + we just mark that the registers need updating. */ + th->debug_registers_changed = 1; +} + +/* Update the inferior's debug register REGNUM from STATE. */ + +static void +x86_dr_low_set_addr (int regnum, CORE_ADDR addr) +{ + gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); + + /* Only update the threads of this process. */ + for_each_thread (current_thread->id.pid (), update_debug_registers); +} + +/* Update the inferior's DR7 debug control register from STATE. */ + +static void +x86_dr_low_set_control (unsigned long control) +{ + /* Only update the threads of this process. */ + for_each_thread (current_thread->id.pid (), update_debug_registers); +} + +/* Return the current value of a DR register of the current thread's + context. */ + +static DWORD64 +win32_get_current_dr (int dr) +{ + win32_thread_info *th + = (win32_thread_info *) thread_target_data (current_thread); + + win32_require_context (th); + +#define RET_DR(DR) \ + case DR: \ + return th->context.Dr ## DR + + switch (dr) + { + RET_DR (0); + RET_DR (1); + RET_DR (2); + RET_DR (3); + RET_DR (6); + RET_DR (7); + } + +#undef RET_DR + + gdb_assert_not_reached ("unhandled dr"); +} + +static CORE_ADDR +x86_dr_low_get_addr (int regnum) +{ + gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); + + return win32_get_current_dr (regnum - DR_FIRSTADDR); +} + +static unsigned long +x86_dr_low_get_control (void) +{ + return win32_get_current_dr (7); +} + +/* Get the value of the DR6 debug status register from the inferior + and record it in STATE. */ + +static unsigned long +x86_dr_low_get_status (void) +{ + return win32_get_current_dr (6); +} + +/* Low-level function vector. */ +struct x86_dr_low_type x86_dr_low = + { + x86_dr_low_set_control, + x86_dr_low_set_addr, + x86_dr_low_get_addr, + x86_dr_low_get_status, + x86_dr_low_get_control, + sizeof (void *), + }; + +/* Breakpoint/watchpoint support. */ + +static int +i386_supports_z_point_type (char z_type) +{ + switch (z_type) + { + case Z_PACKET_WRITE_WP: + case Z_PACKET_ACCESS_WP: + return 1; + default: + return 0; + } +} + +static int +i386_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + switch (type) + { + case raw_bkpt_type_write_wp: + case raw_bkpt_type_access_wp: + { + enum target_hw_bp_type hw_type + = raw_bkpt_type_to_target_hw_bp_type (type); + + return x86_dr_insert_watchpoint (&debug_reg_state, + hw_type, addr, size); + } + default: + /* Unsupported. */ + return 1; + } +} + +static int +i386_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + switch (type) + { + case raw_bkpt_type_write_wp: + case raw_bkpt_type_access_wp: + { + enum target_hw_bp_type hw_type + = raw_bkpt_type_to_target_hw_bp_type (type); + + return x86_dr_remove_watchpoint (&debug_reg_state, + hw_type, addr, size); + } + default: + /* Unsupported. */ + return 1; + } +} + +static int +x86_stopped_by_watchpoint (void) +{ + return x86_dr_stopped_by_watchpoint (&debug_reg_state); +} + +static CORE_ADDR +x86_stopped_data_address (void) +{ + CORE_ADDR addr; + if (x86_dr_stopped_data_address (&debug_reg_state, &addr)) + return addr; + return 0; +} + +static void +i386_initial_stuff (void) +{ + x86_low_init_dregs (&debug_reg_state); +} + +static void +i386_get_thread_context (win32_thread_info *th) +{ + /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if + the system doesn't support extended registers. */ + static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS; + + again: + th->context.ContextFlags = (CONTEXT_FULL + | CONTEXT_FLOATING_POINT + | CONTEXT_DEBUG_REGISTERS + | extended_registers); + + if (!GetThreadContext (th->h, &th->context)) + { + DWORD e = GetLastError (); + + if (extended_registers && e == ERROR_INVALID_PARAMETER) + { + extended_registers = 0; + goto again; + } + + error ("GetThreadContext failure %ld\n", (long) e); + } +} + +static void +i386_prepare_to_resume (win32_thread_info *th) +{ + if (th->debug_registers_changed) + { + struct x86_debug_reg_state *dr = &debug_reg_state; + + win32_require_context (th); + + th->context.Dr0 = dr->dr_mirror[0]; + th->context.Dr1 = dr->dr_mirror[1]; + th->context.Dr2 = dr->dr_mirror[2]; + th->context.Dr3 = dr->dr_mirror[3]; + /* th->context.Dr6 = dr->dr_status_mirror; + FIXME: should we set dr6 also ?? */ + th->context.Dr7 = dr->dr_control_mirror; + + th->debug_registers_changed = 0; + } +} + +static void +i386_thread_added (win32_thread_info *th) +{ + th->debug_registers_changed = 1; +} + +static void +i386_single_step (win32_thread_info *th) +{ + th->context.EFlags |= FLAG_TRACE_BIT; +} + +#ifndef __x86_64__ + +/* An array of offset mappings into a Win32 Context structure. + This is a one-to-one mapping which is indexed by gdb's register + numbers. It retrieves an offset into the context structure where + the 4 byte register is located. + An offset value of -1 indicates that Win32 does not provide this + register in it's CONTEXT structure. In this case regptr will return + a pointer into a dummy register. */ +#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) +static const int mappings[] = { + context_offset (Eax), + context_offset (Ecx), + context_offset (Edx), + context_offset (Ebx), + context_offset (Esp), + context_offset (Ebp), + context_offset (Esi), + context_offset (Edi), + context_offset (Eip), + context_offset (EFlags), + context_offset (SegCs), + context_offset (SegSs), + context_offset (SegDs), + context_offset (SegEs), + context_offset (SegFs), + context_offset (SegGs), + context_offset (FloatSave.RegisterArea[0 * 10]), + context_offset (FloatSave.RegisterArea[1 * 10]), + context_offset (FloatSave.RegisterArea[2 * 10]), + context_offset (FloatSave.RegisterArea[3 * 10]), + context_offset (FloatSave.RegisterArea[4 * 10]), + context_offset (FloatSave.RegisterArea[5 * 10]), + context_offset (FloatSave.RegisterArea[6 * 10]), + context_offset (FloatSave.RegisterArea[7 * 10]), + context_offset (FloatSave.ControlWord), + context_offset (FloatSave.StatusWord), + context_offset (FloatSave.TagWord), + context_offset (FloatSave.ErrorSelector), + context_offset (FloatSave.ErrorOffset), + context_offset (FloatSave.DataSelector), + context_offset (FloatSave.DataOffset), + context_offset (FloatSave.ErrorSelector), + /* XMM0-7 */ + context_offset (ExtendedRegisters[10 * 16]), + context_offset (ExtendedRegisters[11 * 16]), + context_offset (ExtendedRegisters[12 * 16]), + context_offset (ExtendedRegisters[13 * 16]), + context_offset (ExtendedRegisters[14 * 16]), + context_offset (ExtendedRegisters[15 * 16]), + context_offset (ExtendedRegisters[16 * 16]), + context_offset (ExtendedRegisters[17 * 16]), + /* MXCSR */ + context_offset (ExtendedRegisters[24]) +}; +#undef context_offset + +#else /* __x86_64__ */ + +#define context_offset(x) (offsetof (CONTEXT, x)) +static const int mappings[] = +{ + context_offset (Rax), + context_offset (Rbx), + context_offset (Rcx), + context_offset (Rdx), + context_offset (Rsi), + context_offset (Rdi), + context_offset (Rbp), + context_offset (Rsp), + context_offset (R8), + context_offset (R9), + context_offset (R10), + context_offset (R11), + context_offset (R12), + context_offset (R13), + context_offset (R14), + context_offset (R15), + context_offset (Rip), + context_offset (EFlags), + context_offset (SegCs), + context_offset (SegSs), + context_offset (SegDs), + context_offset (SegEs), + context_offset (SegFs), + context_offset (SegGs), + context_offset (FloatSave.FloatRegisters[0]), + context_offset (FloatSave.FloatRegisters[1]), + context_offset (FloatSave.FloatRegisters[2]), + context_offset (FloatSave.FloatRegisters[3]), + context_offset (FloatSave.FloatRegisters[4]), + context_offset (FloatSave.FloatRegisters[5]), + context_offset (FloatSave.FloatRegisters[6]), + context_offset (FloatSave.FloatRegisters[7]), + context_offset (FloatSave.ControlWord), + context_offset (FloatSave.StatusWord), + context_offset (FloatSave.TagWord), + context_offset (FloatSave.ErrorSelector), + context_offset (FloatSave.ErrorOffset), + context_offset (FloatSave.DataSelector), + context_offset (FloatSave.DataOffset), + context_offset (FloatSave.ErrorSelector) + /* XMM0-7 */ , + context_offset (Xmm0), + context_offset (Xmm1), + context_offset (Xmm2), + context_offset (Xmm3), + context_offset (Xmm4), + context_offset (Xmm5), + context_offset (Xmm6), + context_offset (Xmm7), + context_offset (Xmm8), + context_offset (Xmm9), + context_offset (Xmm10), + context_offset (Xmm11), + context_offset (Xmm12), + context_offset (Xmm13), + context_offset (Xmm14), + context_offset (Xmm15), + /* MXCSR */ + context_offset (FloatSave.MxCsr) +}; +#undef context_offset + +#endif /* __x86_64__ */ + +/* Fetch register from gdbserver regcache data. */ +static void +i386_fetch_inferior_register (struct regcache *regcache, + win32_thread_info *th, int r) +{ + char *context_offset = (char *) &th->context + mappings[r]; + + long l; + if (r == FCS_REGNUM) + { + l = *((long *) context_offset) & 0xffff; + supply_register (regcache, r, (char *) &l); + } + else if (r == FOP_REGNUM) + { + l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); + supply_register (regcache, r, (char *) &l); + } + else + supply_register (regcache, r, context_offset); +} + +/* Store a new register value into the thread context of TH. */ +static void +i386_store_inferior_register (struct regcache *regcache, + win32_thread_info *th, int r) +{ + char *context_offset = (char *) &th->context + mappings[r]; + collect_register (regcache, r, context_offset); +} + +static const unsigned char i386_win32_breakpoint = 0xcc; +#define i386_win32_breakpoint_len 1 + +static void +i386_arch_setup (void) +{ + struct target_desc *tdesc; + +#ifdef __x86_64__ + tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false, + false, false); + const char **expedite_regs = amd64_expedite_regs; +#else + tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); + const char **expedite_regs = i386_expedite_regs; +#endif + + init_target_desc (tdesc, expedite_regs); + + win32_tdesc = tdesc; +} + +struct win32_target_ops the_low_target = { + i386_arch_setup, + sizeof (mappings) / sizeof (mappings[0]), + i386_initial_stuff, + i386_get_thread_context, + i386_prepare_to_resume, + i386_thread_added, + i386_fetch_inferior_register, + i386_store_inferior_register, + i386_single_step, + &i386_win32_breakpoint, + i386_win32_breakpoint_len, + i386_supports_z_point_type, + i386_insert_point, + i386_remove_point, + x86_stopped_by_watchpoint, + x86_stopped_data_address +}; diff --git a/gdbserver/win32-low.c b/gdbserver/win32-low.c new file mode 100644 index 00000000000..2c4a9b1074b --- /dev/null +++ b/gdbserver/win32-low.c @@ -0,0 +1,1882 @@ +/* Low level interface to Windows debugging, for gdbserver. + Copyright (C) 2006-2020 Free Software Foundation, Inc. + + Contributed by Leo Zayas. Based on "win32-nat.c" from GDB. + + 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 3 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, see . */ + +#include "server.h" +#include "regcache.h" +#include "gdb/fileio.h" +#include "mem-break.h" +#include "win32-low.h" +#include "gdbthread.h" +#include "dll.h" +#include "hostio.h" +#include +#include +#include +#include +#include +#include +#include "gdbsupport/gdb_tilde_expand.h" +#include "gdbsupport/common-inferior.h" +#include "gdbsupport/gdb_wait.h" + +#ifndef USE_WIN32API +#include +#endif + +#define OUTMSG(X) do { printf X; fflush (stderr); } while (0) + +#define OUTMSG2(X) \ + do \ + { \ + if (debug_threads) \ + { \ + printf X; \ + fflush (stderr); \ + } \ + } while (0) + +#ifndef _T +#define _T(x) TEXT (x) +#endif + +#ifndef COUNTOF +#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0])) +#endif + +#ifdef _WIN32_WCE +# define GETPROCADDRESS(DLL, PROC) \ + ((winapi_ ## PROC) GetProcAddress (DLL, TEXT (#PROC))) +#else +# define GETPROCADDRESS(DLL, PROC) \ + ((winapi_ ## PROC) GetProcAddress (DLL, #PROC)) +#endif + +int using_threads = 1; + +/* Globals. */ +static int attaching = 0; +static HANDLE current_process_handle = NULL; +static DWORD current_process_id = 0; +static DWORD main_thread_id = 0; +static enum gdb_signal last_sig = GDB_SIGNAL_0; + +/* The current debug event from WaitForDebugEvent. */ +static DEBUG_EVENT current_event; + +/* A status that hasn't been reported to the core yet, and so + win32_wait should return it next, instead of fetching the next + debug event off the win32 API. */ +static struct target_waitstatus cached_status; + +/* Non zero if an interrupt request is to be satisfied by suspending + all threads. */ +static int soft_interrupt_requested = 0; + +/* Non zero if the inferior is stopped in a simulated breakpoint done + by suspending all the threads. */ +static int faked_breakpoint = 0; + +const struct target_desc *win32_tdesc; + +#define NUM_REGS (the_low_target.num_regs) + +typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId); +typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit); +typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE); +typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD); + +static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, + int options); +static void win32_resume (struct thread_resume *resume_info, size_t n); +#ifndef _WIN32_WCE +static void win32_add_all_dlls (void); +#endif + +/* Get the thread ID from the current selected inferior (the current + thread). */ +static ptid_t +current_thread_ptid (void) +{ + return current_ptid; +} + +/* The current debug event from WaitForDebugEvent. */ +static ptid_t +debug_event_ptid (DEBUG_EVENT *event) +{ + return ptid_t (event->dwProcessId, event->dwThreadId, 0); +} + +/* Get the thread context of the thread associated with TH. */ + +static void +win32_get_thread_context (win32_thread_info *th) +{ + memset (&th->context, 0, sizeof (CONTEXT)); + (*the_low_target.get_thread_context) (th); +#ifdef _WIN32_WCE + memcpy (&th->base_context, &th->context, sizeof (CONTEXT)); +#endif +} + +/* Set the thread context of the thread associated with TH. */ + +static void +win32_set_thread_context (win32_thread_info *th) +{ +#ifdef _WIN32_WCE + /* Calling SuspendThread on a thread that is running kernel code + will report that the suspending was successful, but in fact, that + will often not be true. In those cases, the context returned by + GetThreadContext will not be correct by the time the thread + stops, hence we can't set that context back into the thread when + resuming - it will most likely crash the inferior. + Unfortunately, there is no way to know when the thread will + really stop. To work around it, we'll only write the context + back to the thread when either the user or GDB explicitly change + it between stopping and resuming. */ + if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0) +#endif + SetThreadContext (th->h, &th->context); +} + +/* Set the thread context of the thread associated with TH. */ + +static void +win32_prepare_to_resume (win32_thread_info *th) +{ + if (the_low_target.prepare_to_resume != NULL) + (*the_low_target.prepare_to_resume) (th); +} + +/* See win32-low.h. */ + +void +win32_require_context (win32_thread_info *th) +{ + if (th->context.ContextFlags == 0) + { + if (!th->suspended) + { + if (SuspendThread (th->h) == (DWORD) -1) + { + DWORD err = GetLastError (); + OUTMSG (("warning: SuspendThread failed in thread_rec, " + "(error %d): %s\n", (int) err, strwinerror (err))); + } + else + th->suspended = 1; + } + + win32_get_thread_context (th); + } +} + +/* Find a thread record given a thread id. If GET_CONTEXT is set then + also retrieve the context for this thread. */ +static win32_thread_info * +thread_rec (ptid_t ptid, int get_context) +{ + thread_info *thread = find_thread_ptid (ptid); + if (thread == NULL) + return NULL; + + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + if (get_context) + win32_require_context (th); + return th; +} + +/* Add a thread to the thread list. */ +static win32_thread_info * +child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) +{ + win32_thread_info *th; + ptid_t ptid = ptid_t (pid, tid, 0); + + if ((th = thread_rec (ptid, FALSE))) + return th; + + th = XCNEW (win32_thread_info); + th->tid = tid; + th->h = h; + th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; + + add_thread (ptid, th); + + if (the_low_target.thread_added != NULL) + (*the_low_target.thread_added) (th); + + return th; +} + +/* Delete a thread from the list of threads. */ +static void +delete_thread_info (thread_info *thread) +{ + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + + remove_thread (thread); + CloseHandle (th->h); + free (th); +} + +/* Delete a thread from the list of threads. */ +static void +child_delete_thread (DWORD pid, DWORD tid) +{ + /* If the last thread is exiting, just return. */ + if (all_threads.size () == 1) + return; + + thread_info *thread = find_thread_ptid (ptid_t (pid, tid)); + if (thread == NULL) + return; + + delete_thread_info (thread); +} + +/* These watchpoint related wrapper functions simply pass on the function call + if the low target has registered a corresponding function. */ + +static int +win32_supports_z_point_type (char z_type) +{ + return (the_low_target.supports_z_point_type != NULL + && the_low_target.supports_z_point_type (z_type)); +} + +static int +win32_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + if (the_low_target.insert_point != NULL) + return the_low_target.insert_point (type, addr, size, bp); + else + /* Unsupported (see target.h). */ + return 1; +} + +static int +win32_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp) +{ + if (the_low_target.remove_point != NULL) + return the_low_target.remove_point (type, addr, size, bp); + else + /* Unsupported (see target.h). */ + return 1; +} + +static int +win32_stopped_by_watchpoint (void) +{ + if (the_low_target.stopped_by_watchpoint != NULL) + return the_low_target.stopped_by_watchpoint (); + else + return 0; +} + +static CORE_ADDR +win32_stopped_data_address (void) +{ + if (the_low_target.stopped_data_address != NULL) + return the_low_target.stopped_data_address (); + else + return 0; +} + + +/* Transfer memory from/to the debugged process. */ +static int +child_xfer_memory (CORE_ADDR memaddr, char *our, int len, + int write, process_stratum_target *target) +{ + BOOL success; + SIZE_T done = 0; + DWORD lasterror = 0; + uintptr_t addr = (uintptr_t) memaddr; + + if (write) + { + success = WriteProcessMemory (current_process_handle, (LPVOID) addr, + (LPCVOID) our, len, &done); + if (!success) + lasterror = GetLastError (); + FlushInstructionCache (current_process_handle, (LPCVOID) addr, len); + } + else + { + success = ReadProcessMemory (current_process_handle, (LPCVOID) addr, + (LPVOID) our, len, &done); + if (!success) + lasterror = GetLastError (); + } + if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) + return done; + else + return success ? done : -1; +} + +/* Clear out any old thread list and reinitialize it to a pristine + state. */ +static void +child_init_thread_list (void) +{ + for_each_thread (delete_thread_info); +} + +/* Zero during the child initialization phase, and nonzero otherwise. */ + +static int child_initialization_done = 0; + +static void +do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) +{ + struct process_info *proc; + + last_sig = GDB_SIGNAL_0; + + current_process_handle = proch; + current_process_id = pid; + main_thread_id = 0; + + soft_interrupt_requested = 0; + faked_breakpoint = 0; + + memset (¤t_event, 0, sizeof (current_event)); + + proc = add_process (pid, attached); + proc->tdesc = win32_tdesc; + child_init_thread_list (); + child_initialization_done = 0; + + if (the_low_target.initial_stuff != NULL) + (*the_low_target.initial_stuff) (); + + cached_status.kind = TARGET_WAITKIND_IGNORE; + + /* Flush all currently pending debug events (thread and dll list) up + to the initial breakpoint. */ + while (1) + { + struct target_waitstatus status; + + win32_wait (minus_one_ptid, &status, 0); + + /* Note win32_wait doesn't return thread events. */ + if (status.kind != TARGET_WAITKIND_LOADED) + { + cached_status = status; + break; + } + + { + struct thread_resume resume; + + resume.thread = minus_one_ptid; + resume.kind = resume_continue; + resume.sig = 0; + + win32_resume (&resume, 1); + } + } + +#ifndef _WIN32_WCE + /* Now that the inferior has been started and all DLLs have been mapped, + we can iterate over all DLLs and load them in. + + We avoid doing it any earlier because, on certain versions of Windows, + LOAD_DLL_DEBUG_EVENTs are sometimes not complete. In particular, + we have seen on Windows 8.1 that the ntdll.dll load event does not + include the DLL name, preventing us from creating an associated SO. + A possible explanation is that ntdll.dll might be mapped before + the SO info gets created by the Windows system -- ntdll.dll is + the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs + do not seem to suffer from that problem. + + Rather than try to work around this sort of issue, it is much + simpler to just ignore DLL load/unload events during the startup + phase, and then process them all in one batch now. */ + win32_add_all_dlls (); +#endif + + child_initialization_done = 1; +} + +/* Resume all artificially suspended threads if we are continuing + execution. */ +static void +continue_one_thread (thread_info *thread, int thread_id) +{ + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + + if (thread_id == -1 || thread_id == th->tid) + { + win32_prepare_to_resume (th); + + if (th->suspended) + { + if (th->context.ContextFlags) + { + win32_set_thread_context (th); + th->context.ContextFlags = 0; + } + + if (ResumeThread (th->h) == (DWORD) -1) + { + DWORD err = GetLastError (); + OUTMSG (("warning: ResumeThread failed in continue_one_thread, " + "(error %d): %s\n", (int) err, strwinerror (err))); + } + th->suspended = 0; + } + } +} + +static BOOL +child_continue (DWORD continue_status, int thread_id) +{ + /* The inferior will only continue after the ContinueDebugEvent + call. */ + for_each_thread ([&] (thread_info *thread) + { + continue_one_thread (thread, thread_id); + }); + faked_breakpoint = 0; + + if (!ContinueDebugEvent (current_event.dwProcessId, + current_event.dwThreadId, + continue_status)) + return FALSE; + + return TRUE; +} + +/* Fetch register(s) from the current thread context. */ +static void +child_fetch_inferior_registers (struct regcache *regcache, int r) +{ + int regno; + win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE); + if (r == -1 || r > NUM_REGS) + child_fetch_inferior_registers (regcache, NUM_REGS); + else + for (regno = 0; regno < r; regno++) + (*the_low_target.fetch_inferior_register) (regcache, th, regno); +} + +/* Store a new register value into the current thread context. We don't + change the program's context until later, when we resume it. */ +static void +child_store_inferior_registers (struct regcache *regcache, int r) +{ + int regno; + win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE); + if (r == -1 || r == 0 || r > NUM_REGS) + child_store_inferior_registers (regcache, NUM_REGS); + else + for (regno = 0; regno < r; regno++) + (*the_low_target.store_inferior_register) (regcache, th, regno); +} + +/* Map the Windows error number in ERROR to a locale-dependent error + message string and return a pointer to it. Typically, the values + for ERROR come from GetLastError. + + The string pointed to shall not be modified by the application, + but may be overwritten by a subsequent call to strwinerror + + The strwinerror function does not change the current setting + of GetLastError. */ + +char * +strwinerror (DWORD error) +{ + static char buf[1024]; + TCHAR *msgbuf; + DWORD lasterr = GetLastError (); + DWORD chars = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPTSTR) &msgbuf, + 0, + NULL); + if (chars != 0) + { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' + && msgbuf[chars - 1] == '\n') + { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > ((COUNTOF (buf)) - 1)) + { + chars = COUNTOF (buf) - 1; + msgbuf [chars] = 0; + } + +#ifdef UNICODE + wcstombs (buf, msgbuf, chars + 1); +#else + strncpy (buf, msgbuf, chars + 1); +#endif + LocalFree (msgbuf); + } + else + sprintf (buf, "unknown win32 error (%u)", (unsigned) error); + + SetLastError (lasterr); + return buf; +} + +static BOOL +create_process (const char *program, char *args, + DWORD flags, PROCESS_INFORMATION *pi) +{ + const char *inferior_cwd = get_inferior_cwd (); + BOOL ret; + +#ifdef _WIN32_WCE + wchar_t *p, *wprogram, *wargs, *wcwd = NULL; + size_t argslen; + + wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t)); + mbstowcs (wprogram, program, strlen (program) + 1); + + for (p = wprogram; *p; ++p) + if (L'/' == *p) + *p = L'\\'; + + argslen = strlen (args); + wargs = alloca ((argslen + 1) * sizeof (wchar_t)); + mbstowcs (wargs, args, argslen + 1); + + if (inferior_cwd != NULL) + { + std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd); + std::replace (expanded_infcwd.begin (), expanded_infcwd.end (), + '/', '\\'); + wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t)); + if (mbstowcs (wcwd, expanded_infcwd.c_str (), + expanded_infcwd.size () + 1) == NULL) + { + error (_("\ +Could not convert the expanded inferior cwd to wide-char.")); + } + } + + ret = CreateProcessW (wprogram, /* image name */ + wargs, /* command line */ + NULL, /* security, not supported */ + NULL, /* thread, not supported */ + FALSE, /* inherit handles, not supported */ + flags, /* start flags */ + NULL, /* environment, not supported */ + wcwd, /* current directory */ + NULL, /* start info, not supported */ + pi); /* proc info */ +#else + STARTUPINFOA si = { sizeof (STARTUPINFOA) }; + + ret = CreateProcessA (program, /* image name */ + args, /* command line */ + NULL, /* security */ + NULL, /* thread */ + TRUE, /* inherit handles */ + flags, /* start flags */ + NULL, /* environment */ + /* current directory */ + (inferior_cwd == NULL + ? NULL + : gdb_tilde_expand (inferior_cwd).c_str()), + &si, /* start info */ + pi); /* proc info */ +#endif + + return ret; +} + +/* Start a new process. + PROGRAM is the program name. + PROGRAM_ARGS is the vector containing the inferior's args. + Returns the new PID on success, -1 on failure. Registers the new + process with the process list. */ +static int +win32_create_inferior (const char *program, + const std::vector &program_args) +{ + client_state &cs = get_client_state (); +#ifndef USE_WIN32API + char real_path[PATH_MAX]; + char *orig_path, *new_path, *path_ptr; +#endif + BOOL ret; + DWORD flags; + PROCESS_INFORMATION pi; + DWORD err; + std::string str_program_args = stringify_argv (program_args); + char *args = (char *) str_program_args.c_str (); + + /* win32_wait needs to know we're not attaching. */ + attaching = 0; + + if (!program) + error ("No executable specified, specify executable to debug.\n"); + + flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; + +#ifndef USE_WIN32API + orig_path = NULL; + path_ptr = getenv ("PATH"); + if (path_ptr) + { + int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0); + orig_path = (char *) alloca (strlen (path_ptr) + 1); + new_path = (char *) alloca (size); + strcpy (orig_path, path_ptr); + cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size); + setenv ("PATH", new_path, 1); + } + cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX); + program = real_path; +#endif + + OUTMSG2 (("Command line is \"%s\"\n", args)); + +#ifdef CREATE_NEW_PROCESS_GROUP + flags |= CREATE_NEW_PROCESS_GROUP; +#endif + + ret = create_process (program, args, flags, &pi); + err = GetLastError (); + if (!ret && err == ERROR_FILE_NOT_FOUND) + { + char *exename = (char *) alloca (strlen (program) + 5); + strcat (strcpy (exename, program), ".exe"); + ret = create_process (exename, args, flags, &pi); + err = GetLastError (); + } + +#ifndef USE_WIN32API + if (orig_path) + setenv ("PATH", orig_path, 1); +#endif + + if (!ret) + { + error ("Error creating process \"%s%s\", (error %d): %s\n", + program, args, (int) err, strwinerror (err)); + } + else + { + OUTMSG2 (("Process created: %s\n", (char *) args)); + } + +#ifndef _WIN32_WCE + /* On Windows CE this handle can't be closed. The OS reuses + it in the debug events, while the 9x/NT versions of Windows + probably use a DuplicateHandle'd one. */ + CloseHandle (pi.hThread); +#endif + + do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0); + + /* Wait till we are at 1st instruction in program, return new pid + (assuming success). */ + cs.last_ptid = win32_wait (ptid_t (current_process_id), &cs.last_status, 0); + + return current_process_id; +} + +/* Attach to a running process. + PID is the process ID to attach to, specified by the user + or a higher layer. */ +static int +win32_attach (unsigned long pid) +{ + HANDLE h; + winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; + DWORD err; +#ifdef _WIN32_WCE + HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); +#else + HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); +#endif + DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit); + + h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); + if (h != NULL) + { + if (DebugActiveProcess (pid)) + { + if (DebugSetProcessKillOnExit != NULL) + DebugSetProcessKillOnExit (FALSE); + + /* win32_wait needs to know we're attaching. */ + attaching = 1; + do_initial_child_stuff (h, pid, 1); + return 0; + } + + CloseHandle (h); + } + + err = GetLastError (); + error ("Attach to process failed (error %d): %s\n", + (int) err, strwinerror (err)); +} + +/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */ +static void +handle_output_debug_string (void) +{ +#define READ_BUFFER_LEN 1024 + CORE_ADDR addr; + char s[READ_BUFFER_LEN + 1] = { 0 }; + DWORD nbytes = current_event.u.DebugString.nDebugStringLength; + + if (nbytes == 0) + return; + + if (nbytes > READ_BUFFER_LEN) + nbytes = READ_BUFFER_LEN; + + addr = (CORE_ADDR) (size_t) current_event.u.DebugString.lpDebugStringData; + + if (current_event.u.DebugString.fUnicode) + { + /* The event tells us how many bytes, not chars, even + in Unicode. */ + WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 }; + if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0) + return; + wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR)); + } + else + { + if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0) + return; + } + + if (!startswith (s, "cYg")) + { + if (!server_waiting) + { + OUTMSG2(("%s", s)); + return; + } + + monitor_output (s); + } +#undef READ_BUFFER_LEN +} + +static void +win32_clear_inferiors (void) +{ + if (current_process_handle != NULL) + CloseHandle (current_process_handle); + + for_each_thread (delete_thread_info); + clear_inferiors (); +} + +/* Implementation of target_ops::kill. */ + +static int +win32_kill (process_info *process) +{ + TerminateProcess (current_process_handle, 0); + for (;;) + { + if (!child_continue (DBG_CONTINUE, -1)) + break; + if (!WaitForDebugEvent (¤t_event, INFINITE)) + break; + if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) + break; + else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) + handle_output_debug_string (); + } + + win32_clear_inferiors (); + + remove_process (process); + return 0; +} + +/* Implementation of target_ops::detach. */ + +static int +win32_detach (process_info *process) +{ + winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL; + winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; +#ifdef _WIN32_WCE + HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); +#else + HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); +#endif + DebugActiveProcessStop = GETPROCADDRESS (dll, DebugActiveProcessStop); + DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit); + + if (DebugSetProcessKillOnExit == NULL + || DebugActiveProcessStop == NULL) + return -1; + + { + struct thread_resume resume; + resume.thread = minus_one_ptid; + resume.kind = resume_continue; + resume.sig = 0; + win32_resume (&resume, 1); + } + + if (!DebugActiveProcessStop (current_process_id)) + return -1; + + DebugSetProcessKillOnExit (FALSE); + remove_process (process); + + win32_clear_inferiors (); + return 0; +} + +static void +win32_mourn (struct process_info *process) +{ + remove_process (process); +} + +/* Implementation of target_ops::join. */ + +static void +win32_join (int pid) +{ + HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); + if (h != NULL) + { + WaitForSingleObject (h, INFINITE); + CloseHandle (h); + } +} + +/* Return 1 iff the thread with thread ID TID is alive. */ +static int +win32_thread_alive (ptid_t ptid) +{ + /* Our thread list is reliable; don't bother to poll target + threads. */ + return find_thread_ptid (ptid) != NULL; +} + +/* Resume the inferior process. RESUME_INFO describes how we want + to resume. */ +static void +win32_resume (struct thread_resume *resume_info, size_t n) +{ + DWORD tid; + enum gdb_signal sig; + int step; + win32_thread_info *th; + DWORD continue_status = DBG_CONTINUE; + ptid_t ptid; + + /* This handles the very limited set of resume packets that GDB can + currently produce. */ + + if (n == 1 && resume_info[0].thread == minus_one_ptid) + tid = -1; + else if (n > 1) + tid = -1; + else + /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make + the Windows resume code do the right thing for thread switching. */ + tid = current_event.dwThreadId; + + if (resume_info[0].thread != minus_one_ptid) + { + sig = gdb_signal_from_host (resume_info[0].sig); + step = resume_info[0].kind == resume_step; + } + else + { + sig = GDB_SIGNAL_0; + step = 0; + } + + if (sig != GDB_SIGNAL_0) + { + if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) + { + OUTMSG (("Cannot continue with signal %s here.\n", + gdb_signal_to_string (sig))); + } + else if (sig == last_sig) + continue_status = DBG_EXCEPTION_NOT_HANDLED; + else + OUTMSG (("Can only continue with received signal %s.\n", + gdb_signal_to_string (last_sig))); + } + + last_sig = GDB_SIGNAL_0; + + /* Get context for the currently selected thread. */ + ptid = debug_event_ptid (¤t_event); + th = thread_rec (ptid, FALSE); + if (th) + { + win32_prepare_to_resume (th); + + if (th->context.ContextFlags) + { + /* Move register values from the inferior into the thread + context structure. */ + regcache_invalidate (); + + if (step) + { + if (the_low_target.single_step != NULL) + (*the_low_target.single_step) (th); + else + error ("Single stepping is not supported " + "in this configuration.\n"); + } + + win32_set_thread_context (th); + th->context.ContextFlags = 0; + } + } + + /* Allow continuing with the same signal that interrupted us. + Otherwise complain. */ + + child_continue (continue_status, tid); +} + +static void +win32_add_one_solib (const char *name, CORE_ADDR load_addr) +{ + char buf[MAX_PATH + 1]; + char buf2[MAX_PATH + 1]; + +#ifdef _WIN32_WCE + WIN32_FIND_DATA w32_fd; + WCHAR wname[MAX_PATH + 1]; + mbstowcs (wname, name, MAX_PATH); + HANDLE h = FindFirstFile (wname, &w32_fd); +#else + WIN32_FIND_DATAA w32_fd; + HANDLE h = FindFirstFileA (name, &w32_fd); +#endif + + /* The symbols in a dll are offset by 0x1000, which is the + offset from 0 of the first byte in an image - because + of the file header and the section alignment. */ + load_addr += 0x1000; + + if (h == INVALID_HANDLE_VALUE) + strcpy (buf, name); + else + { + FindClose (h); + strcpy (buf, name); +#ifndef _WIN32_WCE + { + char cwd[MAX_PATH + 1]; + char *p; + if (GetCurrentDirectoryA (MAX_PATH + 1, cwd)) + { + p = strrchr (buf, '\\'); + if (p) + p[1] = '\0'; + SetCurrentDirectoryA (buf); + GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p); + SetCurrentDirectoryA (cwd); + } + } +#endif + } + +#ifndef _WIN32_WCE + if (strcasecmp (buf, "ntdll.dll") == 0) + { + GetSystemDirectoryA (buf, sizeof (buf)); + strcat (buf, "\\ntdll.dll"); + } +#endif + +#ifdef __CYGWIN__ + cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2)); +#else + strcpy (buf2, buf); +#endif + + loaded_dll (buf2, load_addr); +} + +static char * +get_image_name (HANDLE h, void *address, int unicode) +{ + static char buf[(2 * MAX_PATH) + 1]; + DWORD size = unicode ? sizeof (WCHAR) : sizeof (char); + char *address_ptr; + int len = 0; + char b[2]; + SIZE_T done; + + /* Attempt to read the name of the dll that was detected. + This is documented to work only when actively debugging + a program. It will not work for attached processes. */ + if (address == NULL) + return NULL; + +#ifdef _WIN32_WCE + /* Windows CE reports the address of the image name, + instead of an address of a pointer into the image name. */ + address_ptr = address; +#else + /* See if we could read the address of a string, and that the + address isn't null. */ + if (!ReadProcessMemory (h, address, &address_ptr, + sizeof (address_ptr), &done) + || done != sizeof (address_ptr) + || !address_ptr) + return NULL; +#endif + + /* Find the length of the string */ + while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done) + && (b[0] != 0 || b[size - 1] != 0) && done == size) + continue; + + if (!unicode) + ReadProcessMemory (h, address_ptr, buf, len, &done); + else + { + WCHAR *unicode_address = XALLOCAVEC (WCHAR, len); + ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR), + &done); + + WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0); + } + + return buf; +} + +typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *, + DWORD, LPDWORD); +typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE, + LPMODULEINFO, DWORD); +typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE, + LPSTR, DWORD); + +static winapi_EnumProcessModules win32_EnumProcessModules; +static winapi_GetModuleInformation win32_GetModuleInformation; +static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA; + +static BOOL +load_psapi (void) +{ + static int psapi_loaded = 0; + static HMODULE dll = NULL; + + if (!psapi_loaded) + { + psapi_loaded = 1; + dll = LoadLibrary (TEXT("psapi.dll")); + if (!dll) + return FALSE; + win32_EnumProcessModules = + GETPROCADDRESS (dll, EnumProcessModules); + win32_GetModuleInformation = + GETPROCADDRESS (dll, GetModuleInformation); + win32_GetModuleFileNameExA = + GETPROCADDRESS (dll, GetModuleFileNameExA); + } + + return (win32_EnumProcessModules != NULL + && win32_GetModuleInformation != NULL + && win32_GetModuleFileNameExA != NULL); +} + +#ifndef _WIN32_WCE + +/* Iterate over all DLLs currently mapped by our inferior, and + add them to our list of solibs. */ + +static void +win32_add_all_dlls (void) +{ + size_t i; + HMODULE dh_buf[1]; + HMODULE *DllHandle = dh_buf; + DWORD cbNeeded; + BOOL ok; + + if (!load_psapi ()) + return; + + cbNeeded = 0; + ok = (*win32_EnumProcessModules) (current_process_handle, + DllHandle, + sizeof (HMODULE), + &cbNeeded); + + if (!ok || !cbNeeded) + return; + + DllHandle = (HMODULE *) alloca (cbNeeded); + if (!DllHandle) + return; + + ok = (*win32_EnumProcessModules) (current_process_handle, + DllHandle, + cbNeeded, + &cbNeeded); + if (!ok) + return; + + for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++) + { + MODULEINFO mi; + char dll_name[MAX_PATH]; + + if (!(*win32_GetModuleInformation) (current_process_handle, + DllHandle[i], + &mi, + sizeof (mi))) + continue; + if ((*win32_GetModuleFileNameExA) (current_process_handle, + DllHandle[i], + dll_name, + MAX_PATH) == 0) + continue; + win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll); + } +} +#endif + +typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD); +typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32); +typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32); + +/* Handle a DLL load event. + + This function assumes that this event did not occur during inferior + initialization, where their event info may be incomplete (see + do_initial_child_stuff and win32_add_all_dlls for more info on + how we handle DLL loading during that phase). */ + +static void +handle_load_dll (void) +{ + LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; + char *dll_name; + + dll_name = get_image_name (current_process_handle, + event->lpImageName, event->fUnicode); + if (!dll_name) + return; + + win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll); +} + +/* Handle a DLL unload event. + + This function assumes that this event did not occur during inferior + initialization, where their event info may be incomplete (see + do_initial_child_stuff and win32_add_one_solib for more info + on how we handle DLL loading during that phase). */ + +static void +handle_unload_dll (void) +{ + CORE_ADDR load_addr = + (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; + + /* The symbols in a dll are offset by 0x1000, which is the + offset from 0 of the first byte in an image - because + of the file header and the section alignment. */ + load_addr += 0x1000; + unloaded_dll (NULL, load_addr); +} + +static void +handle_exception (struct target_waitstatus *ourstatus) +{ + DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; + + ourstatus->kind = TARGET_WAITKIND_STOPPED; + + switch (code) + { + case EXCEPTION_ACCESS_VIOLATION: + OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION")); + ourstatus->value.sig = GDB_SIGNAL_SEGV; + break; + case STATUS_STACK_OVERFLOW: + OUTMSG2 (("STATUS_STACK_OVERFLOW")); + ourstatus->value.sig = GDB_SIGNAL_SEGV; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_INEXACT_RESULT: + OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_INVALID_OPERATION: + OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_OVERFLOW: + OUTMSG2 (("STATUS_FLOAT_OVERFLOW")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_STACK_CHECK: + OUTMSG2 (("STATUS_FLOAT_STACK_CHECK")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_UNDERFLOW: + OUTMSG2 (("STATUS_FLOAT_UNDERFLOW")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_DIVIDE_BY_ZERO: + OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_INTEGER_DIVIDE_BY_ZERO: + OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_INTEGER_OVERFLOW: + OUTMSG2 (("STATUS_INTEGER_OVERFLOW")); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case EXCEPTION_BREAKPOINT: + OUTMSG2 (("EXCEPTION_BREAKPOINT")); + ourstatus->value.sig = GDB_SIGNAL_TRAP; +#ifdef _WIN32_WCE + /* Remove the initial breakpoint. */ + check_breakpoints ((CORE_ADDR) (long) current_event + .u.Exception.ExceptionRecord.ExceptionAddress); +#endif + break; + case DBG_CONTROL_C: + OUTMSG2 (("DBG_CONTROL_C")); + ourstatus->value.sig = GDB_SIGNAL_INT; + break; + case DBG_CONTROL_BREAK: + OUTMSG2 (("DBG_CONTROL_BREAK")); + ourstatus->value.sig = GDB_SIGNAL_INT; + break; + case EXCEPTION_SINGLE_STEP: + OUTMSG2 (("EXCEPTION_SINGLE_STEP")); + ourstatus->value.sig = GDB_SIGNAL_TRAP; + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION")); + ourstatus->value.sig = GDB_SIGNAL_ILL; + break; + case EXCEPTION_PRIV_INSTRUCTION: + OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION")); + ourstatus->value.sig = GDB_SIGNAL_ILL; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION")); + ourstatus->value.sig = GDB_SIGNAL_ILL; + break; + default: + if (current_event.u.Exception.dwFirstChance) + { + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + return; + } + OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s", + (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, + phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord. + ExceptionAddress, sizeof (uintptr_t)))); + ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; + break; + } + OUTMSG2 (("\n")); + last_sig = ourstatus->value.sig; +} + + +static void +suspend_one_thread (thread_info *thread) +{ + win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + + if (!th->suspended) + { + if (SuspendThread (th->h) == (DWORD) -1) + { + DWORD err = GetLastError (); + OUTMSG (("warning: SuspendThread failed in suspend_one_thread, " + "(error %d): %s\n", (int) err, strwinerror (err))); + } + else + th->suspended = 1; + } +} + +static void +fake_breakpoint_event (void) +{ + OUTMSG2(("fake_breakpoint_event\n")); + + faked_breakpoint = 1; + + memset (¤t_event, 0, sizeof (current_event)); + current_event.dwThreadId = main_thread_id; + current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT; + current_event.u.Exception.ExceptionRecord.ExceptionCode + = EXCEPTION_BREAKPOINT; + + for_each_thread (suspend_one_thread); +} + +#ifdef _WIN32_WCE +static int +auto_delete_breakpoint (CORE_ADDR stop_pc) +{ + return 1; +} +#endif + +/* Get the next event from the child. */ + +static int +get_child_debug_event (struct target_waitstatus *ourstatus) +{ + ptid_t ptid; + + last_sig = GDB_SIGNAL_0; + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + + /* Check if GDB sent us an interrupt request. */ + check_remote_input_interrupt_request (); + + if (soft_interrupt_requested) + { + soft_interrupt_requested = 0; + fake_breakpoint_event (); + goto gotevent; + } + +#ifndef _WIN32_WCE + attaching = 0; +#else + if (attaching) + { + /* WinCE doesn't set an initial breakpoint automatically. To + stop the inferior, we flush all currently pending debug + events -- the thread list and the dll list are always + reported immediatelly without delay, then, we suspend all + threads and pretend we saw a trap at the current PC of the + main thread. + + Contrary to desktop Windows, Windows CE *does* report the dll + names on LOAD_DLL_DEBUG_EVENTs resulting from a + DebugActiveProcess call. This limits the way we can detect + if all the dlls have already been reported. If we get a real + debug event before leaving attaching, the worst that will + happen is the user will see a spurious breakpoint. */ + + current_event.dwDebugEventCode = 0; + if (!WaitForDebugEvent (¤t_event, 0)) + { + OUTMSG2(("no attach events left\n")); + fake_breakpoint_event (); + attaching = 0; + } + else + OUTMSG2(("got attach event\n")); + } + else +#endif + { + /* Keep the wait time low enough for comfortable remote + interruption, but high enough so gdbserver doesn't become a + bottleneck. */ + if (!WaitForDebugEvent (¤t_event, 250)) + { + DWORD e = GetLastError(); + + if (e == ERROR_PIPE_NOT_CONNECTED) + { + /* This will happen if the loader fails to succesfully + load the application, e.g., if the main executable + tries to pull in a non-existing export from a + DLL. */ + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = 1; + return 1; + } + + return 0; + } + } + + gotevent: + + switch (current_event.dwDebugEventCode) + { + case CREATE_THREAD_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT " + "for pid=%u tid=%x)\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + + /* Record the existence of this thread. */ + child_add_thread (current_event.dwProcessId, + current_event.dwThreadId, + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase); + break; + + case EXIT_THREAD_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + child_delete_thread (current_event.dwProcessId, + current_event.dwThreadId); + + current_thread = get_first_thread (); + return 1; + + case CREATE_PROCESS_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + CloseHandle (current_event.u.CreateProcessInfo.hFile); + + current_process_handle = current_event.u.CreateProcessInfo.hProcess; + main_thread_id = current_event.dwThreadId; + + /* Add the main thread. */ + child_add_thread (current_event.dwProcessId, + main_thread_id, + current_event.u.CreateProcessInfo.hThread, + current_event.u.CreateProcessInfo.lpThreadLocalBase); + +#ifdef _WIN32_WCE + if (!attaching) + { + /* Windows CE doesn't set the initial breakpoint + automatically like the desktop versions of Windows do. + We add it explicitly here. It will be removed as soon as + it is hit. */ + set_breakpoint_at ((CORE_ADDR) (long) current_event.u + .CreateProcessInfo.lpStartAddress, + auto_delete_breakpoint); + } +#endif + break; + + case EXIT_PROCESS_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + { + DWORD exit_status = current_event.u.ExitProcess.dwExitCode; + /* If the exit status looks like a fatal exception, but we + don't recognize the exception's code, make the original + exit status value available, to avoid losing information. */ + int exit_signal + = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1; + if (exit_signal == -1) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = exit_status; + } + else + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = gdb_signal_from_host (exit_signal); + } + } + child_continue (DBG_CONTINUE, -1); + CloseHandle (current_process_handle); + current_process_handle = NULL; + break; + + case LOAD_DLL_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + CloseHandle (current_event.u.LoadDll.hFile); + if (! child_initialization_done) + break; + handle_load_dll (); + + ourstatus->kind = TARGET_WAITKIND_LOADED; + ourstatus->value.sig = GDB_SIGNAL_TRAP; + break; + + case UNLOAD_DLL_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + if (! child_initialization_done) + break; + handle_unload_dll (); + ourstatus->kind = TARGET_WAITKIND_LOADED; + ourstatus->value.sig = GDB_SIGNAL_TRAP; + break; + + case EXCEPTION_DEBUG_EVENT: + OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + handle_exception (ourstatus); + break; + + case OUTPUT_DEBUG_STRING_EVENT: + /* A message from the kernel (or Cygwin). */ + OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT " + "for pid=%u tid=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId)); + handle_output_debug_string (); + break; + + default: + OUTMSG2 (("gdbserver: kernel event unknown " + "for pid=%u tid=%x code=%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, + (unsigned) current_event.dwDebugEventCode)); + break; + } + + ptid = debug_event_ptid (¤t_event); + current_thread = find_thread_ptid (ptid); + return 1; +} + +/* Wait for the inferior process to change state. + STATUS will be filled in with a response code to send to GDB. + Returns the signal which caused the process to stop. */ +static ptid_t +win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) +{ + struct regcache *regcache; + + if (cached_status.kind != TARGET_WAITKIND_IGNORE) + { + /* The core always does a wait after creating the inferior, and + do_initial_child_stuff already ran the inferior to the + initial breakpoint (or an exit, if creating the process + fails). Report it now. */ + *ourstatus = cached_status; + cached_status.kind = TARGET_WAITKIND_IGNORE; + return debug_event_ptid (¤t_event); + } + + while (1) + { + if (!get_child_debug_event (ourstatus)) + continue; + + switch (ourstatus->kind) + { + case TARGET_WAITKIND_EXITED: + OUTMSG2 (("Child exited with retcode = %x\n", + ourstatus->value.integer)); + win32_clear_inferiors (); + return ptid_t (current_event.dwProcessId); + case TARGET_WAITKIND_STOPPED: + case TARGET_WAITKIND_SIGNALLED: + case TARGET_WAITKIND_LOADED: + OUTMSG2 (("Child Stopped with signal = %d \n", + ourstatus->value.sig)); + + regcache = get_thread_regcache (current_thread, 1); + child_fetch_inferior_registers (regcache, -1); + return debug_event_ptid (¤t_event); + default: + OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind)); + /* fall-through */ + case TARGET_WAITKIND_SPURIOUS: + /* do nothing, just continue */ + child_continue (DBG_CONTINUE, -1); + break; + } + } +} + +/* Fetch registers from the inferior process. + If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */ +static void +win32_fetch_inferior_registers (struct regcache *regcache, int regno) +{ + child_fetch_inferior_registers (regcache, regno); +} + +/* Store registers to the inferior process. + If REGNO is -1, store all registers; otherwise, store at least REGNO. */ +static void +win32_store_inferior_registers (struct regcache *regcache, int regno) +{ + child_store_inferior_registers (regcache, regno); +} + +/* Read memory from the inferior process. This should generally be + called through read_inferior_memory, which handles breakpoint shadowing. + Read LEN bytes at MEMADDR into a buffer at MYADDR. */ +static int +win32_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + return child_xfer_memory (memaddr, (char *) myaddr, len, 0, 0) != len; +} + +/* Write memory to the inferior process. This should generally be + called through write_inferior_memory, which handles breakpoint shadowing. + Write LEN bytes from the buffer at MYADDR to MEMADDR. + Returns 0 on success and errno on failure. */ +static int +win32_write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, + int len) +{ + return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len; +} + +/* Send an interrupt request to the inferior process. */ +static void +win32_request_interrupt (void) +{ + winapi_DebugBreakProcess DebugBreakProcess; + winapi_GenerateConsoleCtrlEvent GenerateConsoleCtrlEvent; + +#ifdef _WIN32_WCE + HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); +#else + HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); +#endif + + GenerateConsoleCtrlEvent = GETPROCADDRESS (dll, GenerateConsoleCtrlEvent); + + if (GenerateConsoleCtrlEvent != NULL + && GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id)) + return; + + /* GenerateConsoleCtrlEvent can fail if process id being debugged is + not a process group id. + Fallback to XP/Vista 'DebugBreakProcess', which generates a + breakpoint exception in the interior process. */ + + DebugBreakProcess = GETPROCADDRESS (dll, DebugBreakProcess); + + if (DebugBreakProcess != NULL + && DebugBreakProcess (current_process_handle)) + return; + + /* Last resort, suspend all threads manually. */ + soft_interrupt_requested = 1; +} + +#ifdef _WIN32_WCE +int +win32_error_to_fileio_error (DWORD err) +{ + switch (err) + { + case ERROR_BAD_PATHNAME: + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_NAME: + case ERROR_PATH_NOT_FOUND: + return FILEIO_ENOENT; + case ERROR_CRC: + case ERROR_IO_DEVICE: + case ERROR_OPEN_FAILED: + return FILEIO_EIO; + case ERROR_INVALID_HANDLE: + return FILEIO_EBADF; + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + return FILEIO_EACCES; + case ERROR_NOACCESS: + return FILEIO_EFAULT; + case ERROR_BUSY: + return FILEIO_EBUSY; + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + return FILEIO_EEXIST; + case ERROR_BAD_DEVICE: + return FILEIO_ENODEV; + case ERROR_DIRECTORY: + return FILEIO_ENOTDIR; + case ERROR_FILENAME_EXCED_RANGE: + case ERROR_INVALID_DATA: + case ERROR_INVALID_PARAMETER: + case ERROR_NEGATIVE_SEEK: + return FILEIO_EINVAL; + case ERROR_TOO_MANY_OPEN_FILES: + return FILEIO_EMFILE; + case ERROR_HANDLE_DISK_FULL: + case ERROR_DISK_FULL: + return FILEIO_ENOSPC; + case ERROR_WRITE_PROTECT: + return FILEIO_EROFS; + case ERROR_NOT_SUPPORTED: + return FILEIO_ENOSYS; + } + + return FILEIO_EUNKNOWN; +} + +static void +wince_hostio_last_error (char *buf) +{ + DWORD winerr = GetLastError (); + int fileio_err = win32_error_to_fileio_error (winerr); + sprintf (buf, "F-1,%x", fileio_err); +} +#endif + +/* Write Windows OS Thread Information Block address. */ + +static int +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr) +{ + win32_thread_info *th; + th = thread_rec (ptid, 0); + if (th == NULL) + return 0; + if (addr != NULL) + *addr = th->thread_local_base; + return 1; +} + +/* Implementation of the target_ops method "sw_breakpoint_from_kind". */ + +static const gdb_byte * +win32_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = the_low_target.breakpoint_len; + return the_low_target.breakpoint; +} + +static process_stratum_target win32_target_ops = { + win32_create_inferior, + NULL, /* post_create_inferior */ + win32_attach, + win32_kill, + win32_detach, + win32_mourn, + win32_join, + win32_thread_alive, + win32_resume, + win32_wait, + win32_fetch_inferior_registers, + win32_store_inferior_registers, + NULL, /* prepare_to_access_memory */ + NULL, /* done_accessing_memory */ + win32_read_inferior_memory, + win32_write_inferior_memory, + NULL, /* lookup_symbols */ + win32_request_interrupt, + NULL, /* read_auxv */ + win32_supports_z_point_type, + win32_insert_point, + win32_remove_point, + NULL, /* stopped_by_sw_breakpoint */ + NULL, /* supports_stopped_by_sw_breakpoint */ + NULL, /* stopped_by_hw_breakpoint */ + NULL, /* supports_stopped_by_hw_breakpoint */ + target_can_do_hardware_single_step, + win32_stopped_by_watchpoint, + win32_stopped_data_address, + NULL, /* read_offsets */ + NULL, /* get_tls_address */ +#ifdef _WIN32_WCE + wince_hostio_last_error, +#else + hostio_last_error_from_errno, +#endif + NULL, /* qxfer_osdata */ + NULL, /* qxfer_siginfo */ + NULL, /* supports_non_stop */ + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* supports_fork_events */ + NULL, /* supports_vfork_events */ + NULL, /* supports_exec_events */ + NULL, /* handle_new_gdb_connection */ + NULL, /* handle_monitor_command */ + NULL, /* core_of_thread */ + NULL, /* read_loadmap */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* read_pc */ + NULL, /* write_pc */ + NULL, /* thread_stopped */ + win32_get_tib_address, + NULL, /* pause_all */ + NULL, /* unpause_all */ + NULL, /* stabilize_threads */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* supports_disable_randomization */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* qxfer_libraries_svr4 */ + NULL, /* support_agent */ + NULL, /* enable_btrace */ + NULL, /* disable_btrace */ + NULL, /* read_btrace */ + NULL, /* read_btrace_conf */ + NULL, /* supports_range_stepping */ + NULL, /* pid_to_exec_file */ + NULL, /* multifs_open */ + NULL, /* multifs_unlink */ + NULL, /* multifs_readlink */ + NULL, /* breakpoint_kind_from_pc */ + win32_sw_breakpoint_from_kind, +}; + +/* Initialize the Win32 backend. */ +void +initialize_low (void) +{ + set_target_ops (&win32_target_ops); + the_low_target.arch_setup (); +} diff --git a/gdbserver/win32-low.h b/gdbserver/win32-low.h new file mode 100644 index 00000000000..7a3eeda6e24 --- /dev/null +++ b/gdbserver/win32-low.h @@ -0,0 +1,122 @@ +/* Internal interfaces for the Win32 specific target code for gdbserver. + Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_WIN32_LOW_H +#define GDBSERVER_WIN32_LOW_H + +#include + +struct target_desc; + +/* The inferior's target description. This is a global because the + Windows ports support neither bi-arch nor multi-process. */ +extern const struct target_desc *win32_tdesc; + +/* Thread information structure used to track extra information about + each thread. */ +typedef struct win32_thread_info +{ + /* The Win32 thread identifier. */ + DWORD tid; + + /* The handle to the thread. */ + HANDLE h; + + /* Thread Information Block address. */ + CORE_ADDR thread_local_base; + + /* Non zero if SuspendThread was called on this thread. */ + int suspended; + +#ifdef _WIN32_WCE + /* The context as retrieved right after suspending the thread. */ + CONTEXT base_context; +#endif + + /* The context of the thread, including any manipulations. */ + CONTEXT context; + + /* Whether debug registers changed since we last set CONTEXT back to + the thread. */ + int debug_registers_changed; +} win32_thread_info; + +struct win32_target_ops +{ + /* Architecture-specific setup. */ + void (*arch_setup) (void); + + /* The number of target registers. */ + int num_regs; + + /* Perform initializations on startup. */ + void (*initial_stuff) (void); + + /* Fetch the context from the inferior. */ + void (*get_thread_context) (win32_thread_info *th); + + /* Called just before resuming the thread. */ + void (*prepare_to_resume) (win32_thread_info *th); + + /* Called when a thread was added. */ + void (*thread_added) (win32_thread_info *th); + + /* Fetch register from gdbserver regcache data. */ + void (*fetch_inferior_register) (struct regcache *regcache, + win32_thread_info *th, int r); + + /* Store a new register value into the thread context of TH. */ + void (*store_inferior_register) (struct regcache *regcache, + win32_thread_info *th, int r); + + void (*single_step) (win32_thread_info *th); + + const unsigned char *breakpoint; + int breakpoint_len; + + /* Breakpoint/Watchpoint related functions. See target.h for comments. */ + int (*supports_z_point_type) (char z_type); + int (*insert_point) (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp); + int (*remove_point) (enum raw_bkpt_type type, CORE_ADDR addr, + int size, struct raw_breakpoint *bp); + int (*stopped_by_watchpoint) (void); + CORE_ADDR (*stopped_data_address) (void); +}; + +extern struct win32_target_ops the_low_target; + +/* Retrieve the context for this thread, if not already retrieved. */ +extern void win32_require_context (win32_thread_info *th); + +/* Map the Windows error number in ERROR to a locale-dependent error + message string and return a pointer to it. Typically, the values + for ERROR come from GetLastError. + + The string pointed to shall not be modified by the application, + but may be overwritten by a subsequent call to strwinerror + + The strwinerror function does not change the current setting + of GetLastError. */ +extern char * strwinerror (DWORD error); + +/* in wincecompat.c */ + +extern void to_back_slashes (char *); + +#endif /* GDBSERVER_WIN32_LOW_H */ diff --git a/gdbserver/wincecompat.c b/gdbserver/wincecompat.c new file mode 100644 index 00000000000..46eece17e55 --- /dev/null +++ b/gdbserver/wincecompat.c @@ -0,0 +1,38 @@ +/* Compatibility routines for Windows CE. + Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" + +#include + +void +perror (const char *s) +{ + if (s && *s) + fprintf (stderr, "%s: %s\n", s, strwinerror (GetLastError ())); + else + fprintf (stderr, "%s\n", strwinerror (GetLastError ())); +} + +void +to_back_slashes (char *path) +{ + for (; *path; ++path) + if ('/' == *path) + *path = '\\'; +} diff --git a/gdbserver/wincecompat.h b/gdbserver/wincecompat.h new file mode 100644 index 00000000000..34705c3d66c --- /dev/null +++ b/gdbserver/wincecompat.h @@ -0,0 +1,30 @@ +/* Compatibility routines for Windows CE. + Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_WINCECOMPAT_H +#define GDBSERVER_WINCECOMPAT_H + +#include + +#define errno (GetLastError ()) + +/* in win32-low.c */ +extern char * strwinerror (DWORD error); +#define strerror strwinerror + +#endif /* GDBSERVER_WINCECOMPAT_H */ diff --git a/gdbserver/x86-low.c b/gdbserver/x86-low.c new file mode 100644 index 00000000000..611e60b0137 --- /dev/null +++ b/gdbserver/x86-low.c @@ -0,0 +1,38 @@ +/* Low level support for x86 (i386 and x86-64). + + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#include "server.h" +#include "x86-low.h" + +/* Clear the reference counts and forget everything we knew about the + debug registers. */ + +void +x86_low_init_dregs (struct x86_debug_reg_state *state) +{ + int i; + + ALL_DEBUG_ADDRESS_REGISTERS (i) + { + state->dr_mirror[i] = 0; + state->dr_ref_count[i] = 0; + } + state->dr_control_mirror = 0; + state->dr_status_mirror = 0; +} diff --git a/gdbserver/x86-low.h b/gdbserver/x86-low.h new file mode 100644 index 00000000000..a797fc737fc --- /dev/null +++ b/gdbserver/x86-low.h @@ -0,0 +1,28 @@ +/* Low level support for x86 (i386 and x86-64). + + Copyright (C) 2009-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_X86_LOW_H +#define GDBSERVER_X86_LOW_H + +#include "nat/x86-dregs.h" + +/* Initialize STATE. */ +extern void x86_low_init_dregs (struct x86_debug_reg_state *state); + +#endif /* GDBSERVER_X86_LOW_H */ diff --git a/gdbserver/x86-tdesc.h b/gdbserver/x86-tdesc.h new file mode 100644 index 00000000000..8398cfdb836 --- /dev/null +++ b/gdbserver/x86-tdesc.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2018-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +#ifndef GDBSERVER_X86_TDESC_H +#define GDBSERVER_X86_TDESC_H + +/* The "expedite" registers for x86 targets. Since whether the + variable is used depends on host/configuration, we mark it + ATTRIBUTE_UNUSED to keep it simple here. */ +static const char *i386_expedite_regs[] ATTRIBUTE_UNUSED + = {"ebp", "esp", "eip", NULL}; + +#ifdef __x86_64__ +/* The "expedite" registers for x86_64 targets. */ +static const char *amd64_expedite_regs[] = {"rbp", "rsp", "rip", NULL}; +#endif + +#endif /* GDBSERVER_X86_TDESC_H */ diff --git a/gdbserver/xtensa-xtregs.c b/gdbserver/xtensa-xtregs.c new file mode 100644 index 00000000000..bd14679ff80 --- /dev/null +++ b/gdbserver/xtensa-xtregs.c @@ -0,0 +1,37 @@ +/* Table mapping between kernel xtregset and GDB register cache. + Copyright (C) 2007-2020 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3 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, see . */ + + +typedef struct { + int gdb_regnum; + int gdb_offset; + int ptrace_cp_offset; + int ptrace_offset; + int size; + int coproc; + int dbnum; + char* name +;} xtensa_regtable_t; + +#define XTENSA_ELF_XTREG_SIZE 4 + +const xtensa_regtable_t xtensa_regmap_table[] = { + /* gnum,gofs,cpofs,ofs,siz,cp, dbnum, name */ + { 44, 176, 0, 0, 4, -1, 0x020c, "scompare1" }, + { 0 } +}; diff --git a/src-release.sh b/src-release.sh index 1de971eb01a..1f69deeb0e6 100755 --- a/src-release.sh +++ b/src-release.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright (C) 1990-2019 Free Software Foundation +# Copyright (C) 1990-2020 Free Software Foundation # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -315,7 +315,7 @@ gas_release() tar_compress $package $tool "$GAS_SUPPORT_DIRS" "$compressors" } -GDB_SUPPORT_DIRS="bfd include libiberty libctf opcodes readline sim intl libdecnumber cpu zlib contrib gnulib gdbsupport" +GDB_SUPPORT_DIRS="bfd include libiberty libctf opcodes readline sim intl libdecnumber cpu zlib contrib gnulib gdbsupport gdbserver" gdb_release() { compressors=$1