Implement a GDB server in Valgrind. See #214909.
authorsewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Fri, 6 May 2011 21:02:55 +0000 (21:02 +0000)
committersewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Fri, 6 May 2011 21:02:55 +0000 (21:02 +0000)
(Philippe Waroquiers, philippe.waroquiers@skynet.be)

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11727 a5019735-40e9-0310-863c-91ae7b9d1cf9

193 files changed:
Makefile.am
callgrind/docs/cl-manual.xml
callgrind/main.c
configure.in
coregrind/Makefile.am
coregrind/m_aspacemgr/aspacemgr-linux.c
coregrind/m_errormgr.c
coregrind/m_gdbserver/32bit-core-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-core-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-core.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-linux-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-linux-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-linux.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-sse-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-sse-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/32bit-sse.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-core-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-core-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-core.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-linux-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-linux-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-linux.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-sse-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-sse-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/64bit-sse.xml [new file with mode: 0644]
coregrind/m_gdbserver/README_DEVELOPERS [new file with mode: 0644]
coregrind/m_gdbserver/amd64-coresse-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/amd64-linux-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-core-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-core-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-core.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-vfpv3-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-vfpv3-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-vfpv3.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-with-vfpv3-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/arm-with-vfpv3.xml [new file with mode: 0644]
coregrind/m_gdbserver/gdb/signals.h [new file with mode: 0644]
coregrind/m_gdbserver/i386-coresse-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/i386-linux-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/inferiors.c [new file with mode: 0644]
coregrind/m_gdbserver/m_gdbserver.c [new file with mode: 0644]
coregrind/m_gdbserver/power-altivec-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-altivec-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-altivec.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-core.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-fpu-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-fpu-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-fpu.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-linux-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-linux-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/power-linux.xml [new file with mode: 0644]
coregrind/m_gdbserver/power64-core-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/power64-core-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/power64-core.xml [new file with mode: 0644]
coregrind/m_gdbserver/power64-linux-valgrind-s1.xml [new file with mode: 0644]
coregrind/m_gdbserver/power64-linux-valgrind-s2.xml [new file with mode: 0644]
coregrind/m_gdbserver/power64-linux.xml [new file with mode: 0644]
coregrind/m_gdbserver/powerpc-altivec32l-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/powerpc-altivec32l.xml [new file with mode: 0644]
coregrind/m_gdbserver/powerpc-altivec64l-valgrind.xml [new file with mode: 0644]
coregrind/m_gdbserver/powerpc-altivec64l.xml [new file with mode: 0644]
coregrind/m_gdbserver/regcache.c [new file with mode: 0644]
coregrind/m_gdbserver/regcache.h [new file with mode: 0644]
coregrind/m_gdbserver/regdef.h [new file with mode: 0644]
coregrind/m_gdbserver/remote-utils.c [new file with mode: 0644]
coregrind/m_gdbserver/server.c [new file with mode: 0644]
coregrind/m_gdbserver/server.h [new file with mode: 0644]
coregrind/m_gdbserver/signals.c [new file with mode: 0644]
coregrind/m_gdbserver/target.c [new file with mode: 0644]
coregrind/m_gdbserver/target.h [new file with mode: 0644]
coregrind/m_gdbserver/utils.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low-amd64.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low-arm.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low-ppc32.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low-ppc64.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low-s390x.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low-x86.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind-low.c [new file with mode: 0644]
coregrind/m_gdbserver/valgrind_low.h [new file with mode: 0644]
coregrind/m_gdbserver/version.c [new file with mode: 0644]
coregrind/m_libcbase.c
coregrind/m_libcfile.c
coregrind/m_libcprint.c
coregrind/m_libcproc.c
coregrind/m_main.c
coregrind/m_options.c
coregrind/m_scheduler/scheduler.c
coregrind/m_signals.c
coregrind/m_translate.c
coregrind/pub_core_aspacemgr.h
coregrind/pub_core_errormgr.h
coregrind/pub_core_gdbserver.h [new file with mode: 0644]
coregrind/pub_core_options.h
coregrind/pub_core_scheduler.h
coregrind/vgdb.c [new file with mode: 0644]
docs/xml/manual-core.xml
gdbserver_tests/Makefile.am [new file with mode: 0644]
gdbserver_tests/README_DEVELOPPERS [new file with mode: 0644]
gdbserver_tests/clean_after_fork.c [new file with mode: 0644]
gdbserver_tests/filter_gdb [new file with mode: 0755]
gdbserver_tests/filter_make_empty [new file with mode: 0755]
gdbserver_tests/filter_memcheck_monitor [new file with mode: 0755]
gdbserver_tests/filter_stderr [new file with mode: 0755]
gdbserver_tests/filter_vgdb [new file with mode: 0755]
gdbserver_tests/invoker [new file with mode: 0755]
gdbserver_tests/make_local_links [new file with mode: 0755]
gdbserver_tests/mcbreak.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcbreak.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcbreak.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcbreak.stdout.exp [new file with mode: 0644]
gdbserver_tests/mcbreak.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcbreak.vgtest [new file with mode: 0644]
gdbserver_tests/mcclean_after_fork.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcclean_after_fork.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcclean_after_fork.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcclean_after_fork.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcclean_after_fork.vgtest [new file with mode: 0644]
gdbserver_tests/mchelp.stderr.exp [new file with mode: 0644]
gdbserver_tests/mchelp.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mchelp.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mchelp.vgtest [new file with mode: 0644]
gdbserver_tests/mcinfcallRU.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcinfcallRU.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcinfcallRU.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcinfcallRU.vgtest [new file with mode: 0644]
gdbserver_tests/mcinfcallWSRU.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcinfcallWSRU.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcinfcallWSRU.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcinfcallWSRU.vgtest [new file with mode: 0644]
gdbserver_tests/mcinvokeRU.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcinvokeRU.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcinvokeRU.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcinvokeRU.vgtest [new file with mode: 0644]
gdbserver_tests/mcinvokeWS.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcinvokeWS.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcinvokeWS.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcinvokeWS.vgtest [new file with mode: 0644]
gdbserver_tests/mcleak.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcleak.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcleak.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcleak.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcleak.vgtest [new file with mode: 0644]
gdbserver_tests/mcsignopass.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcsignopass.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcsignopass.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcsignopass.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcsignopass.vgtest [new file with mode: 0644]
gdbserver_tests/mcsigpass.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcsigpass.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcsigpass.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcsigpass.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcsigpass.vgtest [new file with mode: 0644]
gdbserver_tests/mcvabits.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcvabits.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcvabits.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcvabits.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcvabits.vgtest [new file with mode: 0644]
gdbserver_tests/mcwatchpoints.stderr.exp [new file with mode: 0644]
gdbserver_tests/mcwatchpoints.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mcwatchpoints.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mcwatchpoints.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mcwatchpoints.vgtest [new file with mode: 0644]
gdbserver_tests/mssnapshot.stderr.exp [new file with mode: 0644]
gdbserver_tests/mssnapshot.stderrB.exp [new file with mode: 0644]
gdbserver_tests/mssnapshot.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/mssnapshot.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/mssnapshot.vgtest [new file with mode: 0644]
gdbserver_tests/nlcontrolc.stderr.exp [new file with mode: 0644]
gdbserver_tests/nlcontrolc.stderrB.exp [new file with mode: 0644]
gdbserver_tests/nlcontrolc.stdinB.gdb [new file with mode: 0644]
gdbserver_tests/nlcontrolc.stdoutB.exp [new file with mode: 0644]
gdbserver_tests/nlcontrolc.vgtest [new file with mode: 0644]
gdbserver_tests/simulate_control_c [new file with mode: 0755]
gdbserver_tests/sleepers.c [new file with mode: 0644]
gdbserver_tests/t.c [new file with mode: 0644]
gdbserver_tests/watchpoints.c [new file with mode: 0644]
include/pub_tool_gdbserver.h [new file with mode: 0644]
include/pub_tool_libcbase.h
include/pub_tool_libcfile.h
include/pub_tool_libcproc.h
include/pub_tool_options.h
include/valgrind.h
include/vki/vki-s390x-linux.h
massif/docs/ms-manual.xml
massif/ms_main.c
memcheck/docs/mc-manual.xml
memcheck/mc_errors.c
memcheck/mc_include.h
memcheck/mc_main.c
none/tests/cmdline1.stdout.exp
none/tests/cmdline2.stdout.exp
none/tests/valgrind_cpp_test.cpp
tests/vg_regtest.in

index 61fddf5345ced219b2b8b3ff5d63d7e83f49110b..be6e8b765df749b40337ebb07c76a91cc31ecbef 100644 (file)
@@ -25,6 +25,7 @@ else
   TEST_EXP_TOOLS = exp-bbv
 endif
 
+
 # Put docs last because building the HTML is slow and we want to get
 # everything else working before we try it.
 SUBDIRS = \
@@ -36,6 +37,7 @@ SUBDIRS = \
        $(EXP_TOOLS) \
        tests \
        perf \
+       gdbserver_tests \
        auxprogs \
        mpi \
        docs
@@ -72,11 +74,15 @@ default.supp: $(DEFAULT_SUPP_FILES)
 
 ## Preprend @PERL@ because tests/vg_regtest isn't executable
 regtest: check
-       @PERL@ tests/vg_regtest $(TEST_TOOLS) $(TEST_EXP_TOOLS)
+       gdbserver_tests/make_local_links $(GDB)
+       @PERL@ tests/vg_regtest gdbserver_tests $(TEST_TOOLS) $(TEST_EXP_TOOLS)
 nonexp-regtest: check
        @PERL@ tests/vg_regtest $(TEST_TOOLS)
 exp-regtest: check
-       @PERL@ tests/vg_regtest $(TEST_EXP_TOOLS)
+       @PERL@ tests/vg_regtest gdbserver_tests $(TEST_EXP_TOOLS)
+# Nb: gdbserver_tests are put in exp-regtest rather than nonexp-regtest
+# because they are tested with various valgrind tools, so might be using
+# an experimental tool.
 
 ## Preprend @PERL@ because tests/vg_perf isn't executable
 perf: check
index 3f8330eafe29f2a43fa5d8b6c3cae6f4d11942b0..cb79bdc6b9751063720dd0cb153c8abfb8807b90 100644 (file)
@@ -1075,6 +1075,32 @@ Also see <xref linkend="cl-manual.cycles"/>.</para>
 
 </sect1>
 
+<sect1 id="cl-manual.monitor-commands" xreflabel="Callgrind Monitor Commands">
+<title>Callgrind Monitor Commands</title>
+<para>The Callgrind tool provides monitor commands handled by the Valgrind
+gdbserver (see <xref linkend="manual-core.gdbserver-commandhandling"/>).
+</para>
+
+<itemizedlist>
+  <listitem>
+    <para><varname>ct.dump [&lt;dump_hint&gt;]</varname> requests to dump the
+    profile data. </para>
+  </listitem>
+
+  <listitem>
+    <para><varname>ct.zero</varname> requests to zero the profile data
+    counters. </para>
+  </listitem>
+
+  <listitem>
+    <para>It would be nice to have some more callgrind monitor
+    commands such as e.g. toggle collect and start instrumentation.
+    </para>
+  </listitem>
+
+</itemizedlist>
+</sect1>
+
 <sect1 id="cl-manual.clientrequests" xreflabel="Client request reference">
 <title>Callgrind specific client requests</title>
 
index a07c453c2fa75d0e5bf4fe7ff2c59553b7f216c5..7de26557e73146631a36aaa55fd311ea43046e92 100644 (file)
@@ -36,6 +36,7 @@
 #include "global.h"
 
 #include "pub_tool_threadstate.h"
+#include "pub_tool_gdbserver.h"
 
 #include "cg_branchpred.c"
 
@@ -1355,11 +1356,56 @@ void CLG_(set_instrument_state)(Char* reason, Bool state)
                 reason, state ? "ON" : "OFF");
 }
   
+static void print_monitor_help ( void )
+{
+   VG_(gdb_printf) ("\n");
+   VG_(gdb_printf) ("callgrind monitor commands:\n");
+   VG_(gdb_printf) ("  ct.dump [<dump_hint>]\n");
+   VG_(gdb_printf) ("        dump counters\n");
+   VG_(gdb_printf) ("  ct.zero\n");
+   VG_(gdb_printf) ("        zero counters\n");
+   VG_(gdb_printf) ("\n");
+}
+
+/* return True if request recognised, False otherwise */
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
+{
+   Char* wcmd;
+   Char s[VG_(strlen(req))]; /* copy for strtok_r */
+   Char *ssaveptr;
+
+   VG_(strcpy) (s, req);
+
+   wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
+   switch (VG_(keyword_id) ("help ct.dump ct.zero", 
+                            wcmd, kwd_report_duplicated_matches)) {
+   case -2: /* multiple matches */
+      return True;
+   case -1: /* not found */
+      return False;
+   case  0: /* help */
+      print_monitor_help();
+      return True;
+   case  1: { /* ct.dump */
+      CLG_(dump_profile)(req, False);
+      return True;
+   }
+   case  2: { /* ct.zero */
+      CLG_(zero_all_cost)(False);
+      return True;
+   }
+
+   default: 
+      tl_assert(0);
+      return False;
+   }
+}
 
 static
 Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
 {
-   if (!VG_IS_TOOL_USERREQ('C','T',args[0]))
+   if (!VG_IS_TOOL_USERREQ('C','T',args[0])
+       && VG_USERREQ__GDB_MONITOR_COMMAND   != args[0])
       return False;
 
    switch(args[0]) {
@@ -1399,6 +1445,14 @@ Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
      *ret = 0;                 /* meaningless */
      break;
 
+   case VG_USERREQ__GDB_MONITOR_COMMAND: {
+      Bool handled = handle_gdb_monitor_command (tid, (Char*)args[1]);
+      if (handled)
+         *ret = 1;
+      else
+         *ret = 0;
+      return handled;
+   }
    default:
       return False;
    }
index 667064e1329d84ce6bd4e652ba48c44c926f0af1..a0df0633513a118181fd021b5466554fec054032 100644 (file)
@@ -1907,6 +1907,7 @@ AC_CONFIG_FILES([
    tests/vg_regtest 
    perf/Makefile 
    perf/vg_perf
+   gdbserver_tests/Makefile
    include/Makefile 
    auxprogs/Makefile
    mpi/Makefile
index 57fa59358311a962aa74602963834cb9a047752b..43d8683a76da9620567351c9a082782d59888452 100644 (file)
@@ -31,6 +31,7 @@ EXTRA_DIST = \
 
 bin_PROGRAMS = \
        valgrind \
+       vgdb \
        no_op_client_for_valgrind
 
 if VGCONF_OS_IS_LINUX
@@ -58,6 +59,12 @@ if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
 valgrind_LDFLAGS   += -Wl,-read_only_relocs -Wl,suppress
 endif
 
+vgdb_SOURCES = vgdb.c
+vgdb_CPPFLAGS  = $(AM_CPPFLAGS_PRI)
+vgdb_CFLAGS    = $(AM_CFLAGS_PRI)
+vgdb_CCASFLAGS = $(AM_CCASFLAGS_PRI)
+vgdb_LDFLAGS   = $(AM_CFLAGS_PRI) -lpthread
+
 no_op_client_for_valgrind_SOURCES = no_op_client_for_valgrind.c
 no_op_client_for_valgrind_CPPFLAGS  = $(AM_CPPFLAGS_PRI)
 no_op_client_for_valgrind_CFLAGS    = $(AM_CFLAGS_PRI)
@@ -147,6 +154,7 @@ noinst_HEADERS = \
        pub_core_dispatch_asm.h \
        pub_core_errormgr.h     \
        pub_core_execontext.h   \
+       pub_core_gdbserver.h    \
        pub_core_hashtable.h    \
        pub_core_initimg.h      \
        pub_core_libcbase.h     \
@@ -202,6 +210,12 @@ noinst_HEADERS = \
        m_demangle/demangle.h   \
        m_demangle/safe-ctype.h \
        m_demangle/vg_libciface.h \
+       m_gdbserver/regcache.h \
+       m_gdbserver/regdef.h \
+       m_gdbserver/server.h \
+       m_gdbserver/target.h \
+       m_gdbserver/valgrind_low.h \
+       m_gdbserver/gdb/signals.h \
        m_initimg/priv_initimg_pathscan.h \
        m_initimg/simple_huffman.c \
        m_scheduler/priv_sema.h \
@@ -291,12 +305,29 @@ COREGRIND_SOURCES_COMMON = \
        m_dispatch/dispatch-amd64-linux.S \
        m_dispatch/dispatch-ppc32-linux.S \
        m_dispatch/dispatch-ppc64-linux.S \
-       m_dispatch/dispatch-arm-linux.S \
+       m_dispatch/dispatch-arm-linux.S \
        m_dispatch/dispatch-s390x-linux.S \
        m_dispatch/dispatch-ppc32-aix5.S \
        m_dispatch/dispatch-ppc64-aix5.S \
        m_dispatch/dispatch-x86-darwin.S \
        m_dispatch/dispatch-amd64-darwin.S \
+       m_gdbserver/m_gdbserver.c \
+       m_gdbserver/inferiors.c \
+       m_gdbserver/m_gdbserver.c \
+       m_gdbserver/regcache.c \
+       m_gdbserver/remote-utils.c \
+       m_gdbserver/server.c \
+       m_gdbserver/signals.c \
+       m_gdbserver/target.c \
+       m_gdbserver/utils.c \
+       m_gdbserver/valgrind-low.c \
+       m_gdbserver/valgrind-low-x86.c \
+       m_gdbserver/valgrind-low-amd64.c \
+       m_gdbserver/valgrind-low-arm.c \
+       m_gdbserver/valgrind-low-ppc32.c \
+       m_gdbserver/valgrind-low-ppc64.c \
+       m_gdbserver/valgrind-low-s390x.c \
+       m_gdbserver/version.c \
        m_initimg/initimg-linux.c \
        m_initimg/initimg-aix5.c \
        m_initimg/initimg-darwin.c \
@@ -312,7 +343,7 @@ COREGRIND_SOURCES_COMMON = \
        m_sigframe/sigframe-amd64-linux.c \
        m_sigframe/sigframe-ppc32-linux.c \
        m_sigframe/sigframe-ppc64-linux.c \
-       m_sigframe/sigframe-arm-linux.c \
+       m_sigframe/sigframe-arm-linux.c \
        m_sigframe/sigframe-s390x-linux.c \
        m_sigframe/sigframe-ppc32-aix5.c \
        m_sigframe/sigframe-ppc64-aix5.c \
@@ -322,7 +353,7 @@ COREGRIND_SOURCES_COMMON = \
        m_syswrap/syscall-amd64-linux.S \
        m_syswrap/syscall-ppc32-linux.S \
        m_syswrap/syscall-ppc64-linux.S \
-       m_syswrap/syscall-arm-linux.S \
+       m_syswrap/syscall-arm-linux.S \
        m_syswrap/syscall-s390x-linux.S \
        m_syswrap/syscall-ppc32-aix5.S \
        m_syswrap/syscall-ppc64-aix5.S \
@@ -338,7 +369,7 @@ COREGRIND_SOURCES_COMMON = \
        m_syswrap/syswrap-amd64-linux.c \
        m_syswrap/syswrap-ppc32-linux.c \
        m_syswrap/syswrap-ppc64-linux.c \
-       m_syswrap/syswrap-arm-linux.c \
+       m_syswrap/syswrap-arm-linux.c \
        m_syswrap/syswrap-s390x-linux.c \
        m_syswrap/syswrap-ppc32-aix5.c \
        m_syswrap/syswrap-ppc64-aix5.c \
@@ -433,11 +464,104 @@ vgpreload_core_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS = \
        $(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
 endif
 
+#----------------------------------------------------------------------------
+# gdbserver xml target descriptions
+#----------------------------------------------------------------------------
+pkglib_DATA =
+
+if VGCONF_ARCHS_INCLUDE_ARM
+pkglib_DATA +=         m_gdbserver/arm-core-valgrind-s1.xml \
+               m_gdbserver/arm-core-valgrind-s2.xml \
+               m_gdbserver/arm-core.xml \
+               m_gdbserver/arm-vfpv3-valgrind-s1.xml \
+               m_gdbserver/arm-vfpv3-valgrind-s2.xml \
+               m_gdbserver/arm-vfpv3.xml \
+               m_gdbserver/arm-with-vfpv3-valgrind.xml \
+               m_gdbserver/arm-with-vfpv3.xml
+endif
+
+if VGCONF_ARCHS_INCLUDE_X86
+pkglib_DATA +=         m_gdbserver/32bit-core-valgrind-s1.xml \
+               m_gdbserver/32bit-core-valgrind-s2.xml \
+               m_gdbserver/32bit-core.xml \
+               m_gdbserver/32bit-sse-valgrind-s1.xml \
+               m_gdbserver/32bit-sse-valgrind-s2.xml \
+               m_gdbserver/32bit-sse.xml
+if VGCONF_OS_IS_LINUX
+pkglib_DATA += m_gdbserver/32bit-linux-valgrind-s1.xml \
+               m_gdbserver/32bit-linux-valgrind-s2.xml \
+               m_gdbserver/32bit-linux.xml \
+               m_gdbserver/i386-linux-valgrind.xml
+endif
+if VGCONF_OS_IS_DARWIN
+pkglib_DATA += m_gdbserver/i386-coresse-valgrind.xml
+endif
+endif
+
+if VGCONF_ARCHS_INCLUDE_AMD64
+pkglib_DATA += m_gdbserver/64bit-core-valgrind-s1.xml \
+               m_gdbserver/64bit-core-valgrind-s2.xml \
+               m_gdbserver/64bit-core.xml \
+               m_gdbserver/64bit-sse-valgrind-s1.xml \
+               m_gdbserver/64bit-sse-valgrind-s2.xml \
+               m_gdbserver/64bit-sse.xml
+
+if VGCONF_OS_IS_LINUX
+pkglib_DATA += m_gdbserver/64bit-linux-valgrind-s1.xml \
+               m_gdbserver/64bit-linux-valgrind-s2.xml \
+               m_gdbserver/64bit-linux.xml \
+               m_gdbserver/amd64-linux-valgrind.xml
+endif
+if VGCONF_OS_IS_DARWIN
+pkglib_DATA += m_gdbserver/amd64-coresse-valgrind.xml
+endif
+endif
+
+if VGCONF_ARCHS_INCLUDE_PPC32
+pkglib_DATA += m_gdbserver/power-altivec-valgrind-s1.xml \
+               m_gdbserver/power-altivec-valgrind-s2.xml \
+               m_gdbserver/power-altivec.xml \
+               m_gdbserver/power-core.xml \
+               m_gdbserver/power-fpu-valgrind-s1.xml \
+               m_gdbserver/power-fpu-valgrind-s2.xml \
+               m_gdbserver/power-fpu.xml \
+               m_gdbserver/power-linux-valgrind-s1.xml \
+               m_gdbserver/power-linux-valgrind-s2.xml \
+               m_gdbserver/power-linux.xml \
+               m_gdbserver/powerpc-altivec32l-valgrind.xml \
+               m_gdbserver/powerpc-altivec32l.xml
+endif
+
+if VGCONF_ARCHS_INCLUDE_PPC64
+pkglib_DATA += m_gdbserver/power64-core-valgrind-s1.xml \
+               m_gdbserver/power64-core-valgrind-s2.xml \
+               m_gdbserver/power64-core.xml \
+               m_gdbserver/power64-linux-valgrind-s1.xml \
+               m_gdbserver/power64-linux-valgrind-s2.xml \
+               m_gdbserver/power64-linux.xml \
+               m_gdbserver/powerpc-altivec64l-valgrind.xml \
+               m_gdbserver/powerpc-altivec64l.xml
+if ! VGCONF_ARCHS_INCLUDE_PPC32
+pkglib_DATA += m_gdbserver/power-altivec-valgrind-s1.xml \
+               m_gdbserver/power-altivec-valgrind-s2.xml \
+               m_gdbserver/power-altivec.xml \
+               m_gdbserver/power-fpu-valgrind-s1.xml \
+               m_gdbserver/power-fpu-valgrind-s2.xml \
+               m_gdbserver/power-fpu.xml
+endif
+endif
+
+
 #----------------------------------------------------------------------------
 # General stuff
 #----------------------------------------------------------------------------
 
 all-local: inplace-noinst_PROGRAMS inplace-noinst_DSYMS
+       mkdir -p $(inplacedir); \
+       for f in $(pkglib_DATA); do \
+         rm -f $(inplacedir)/$$f; \
+         ln -f -s ../$(subdir)/$$f $(inplacedir); \
+       done
 
 clean-local: clean-noinst_DSYMS
 
index cc092cec474d1062662a2fe520c34d463653db6e..9765ba8dd79ea2d3b123226ae1eb6d45bb007bfd 100644 (file)
@@ -2488,11 +2488,11 @@ SysRes VG_(am_sbrk_anon_float_valgrind)( SizeT cszB )
 
 
 /* Map a file at an unconstrained address for V, and update the
-   segment array accordingly.  This is used by V for transiently
-   mapping in object files to read their debug info.  */
+   segment array accordingly. Use the provided flags */
 
-SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot, 
-                                          Int fd, Off64T offset )
+static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot,
+                                                       UInt flags,
+                                                       Int fd, Off64T offset )
 {
    SysRes     sres;
    NSegment   seg;
@@ -2520,7 +2520,7 @@ SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
       any resulting failure immediately. */
    sres = VG_(am_do_mmap_NO_NOTIFY)( 
              advised, length, prot, 
-             VKI_MAP_FIXED|VKI_MAP_PRIVATE, 
+             flags,
              fd, offset 
           );
    if (sr_isError(sres))
@@ -2556,7 +2556,25 @@ SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot,
    AM_SANITY_CHECK;
    return sres;
 }
+/* Map privately a file at an unconstrained address for V, and update the
+   segment array accordingly.  This is used by V for transiently
+   mapping in object files to read their debug info.  */
+
+SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot, 
+                                          Int fd, Off64T offset )
+{
+   return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
+                                                  VKI_MAP_FIXED|VKI_MAP_PRIVATE,
+                                                  fd, offset );
+}
 
+extern SysRes VG_(am_shared_mmap_file_float_valgrind)
+   ( SizeT length, UInt prot, Int fd, Off64T offset )
+{
+   return VG_(am_mmap_file_float_valgrind_flags) (length, prot,
+                                                  VKI_MAP_FIXED|VKI_MAP_SHARED,
+                                                  fd, offset );
+}
 
 /* --- --- munmap helper --- --- */
 
index bb3247a85048746944eb5dc88a17130a17c8aef6..98e9d53a6f128dfb46ea5d09077a7bfc6afa4ff1 100644 (file)
@@ -36,6 +36,7 @@
 #include "pub_core_debuginfo.h"
 #include "pub_core_errormgr.h"
 #include "pub_core_execontext.h"
+#include "pub_core_gdbserver.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"
@@ -494,7 +495,18 @@ void do_actions_on_error(Error* err, Bool allow_db_attach)
    /* Should be assured by caller */
    vg_assert( ! VG_(clo_xml) );
 
+   /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
+   if (VG_(clo_vgdb) != Vg_VgdbNo
+       && allow_db_attach 
+       && VG_(dyn_vgdb_error) <= n_errs_found) {
+      VG_(umsg)("(action on error) vgdb me ... \n");
+      VG_(gdbserver)( err->tid );
+      VG_(umsg)("Continuing ...\n");
+   }
+
    /* Perhaps we want a debugger attach at this point? */
+   /* GDBTD ??? maybe we should/could remove the below assuming the
+      gdbserver interface is better ??? */
    if (allow_db_attach &&
        VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_attach) ))
    {   
@@ -540,13 +552,13 @@ void do_actions_on_error(Error* err, Bool allow_db_attach)
      attach (and detach), and optionally prints a suppression; both
      of these may require user input.
 */
-static void pp_Error ( Error* err, Bool allow_db_attach )
+static void pp_Error ( Error* err, Bool allow_db_attach, Bool xml )
 {
    /* If this fails, you probably specified your tool's method
       dictionary incorrectly. */
    vg_assert(VG_(needs).tool_errors);
 
-   if (VG_(clo_xml)) {
+   if (xml) {
 
       /* Note, allow_db_attach is ignored in here. */
  
@@ -718,7 +730,8 @@ void VG_(maybe_record_error) ( ThreadId tid,
          }
 
          /* Move p to the front of the list so that future searches
-            for it are faster. */
+            for it are faster. It also allows to print the last
+            error (see VG_(show_last_error). */
          if (p_prev != NULL) {
             vg_assert(p_prev->next == p);
             p_prev->next = p->next;
@@ -780,7 +793,7 @@ void VG_(maybe_record_error) ( ThreadId tid,
       n_err_contexts++;
       n_errs_found++;
       /* Actually show the error; more complex than you might think. */
-      pp_Error( p, /*allow_db_attach*/True );
+      pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
       /* update stats */
       n_errs_shown++;
    } else {
@@ -825,7 +838,7 @@ Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
 
       if (print_error) {
          /* Actually show the error; more complex than you might think. */
-         pp_Error(&err, allow_db_attach);
+         pp_Error(&err, allow_db_attach, VG_(clo_xml));
          /* update stats */
          n_errs_shown++;
       }
@@ -881,20 +894,19 @@ static Bool show_used_suppressions ( void )
    return any_supp;
 }
 
-
 /* Show all the errors that occurred, and possibly also the
    suppressions used. */
-void VG_(show_all_errors) ( void )
+void VG_(show_all_errors) (  Int verbosity, Bool xml )
 {
    Int    i, n_min;
    Error *p, *p_min;
    Bool   any_supp;
 
-   if (VG_(clo_verbosity) == 0)
+   if (verbosity == 0)
       return;
 
    /* If we're printing XML, just show the suppressions and stop. */
-   if (VG_(clo_xml)) {
+   if (xml) {
       (void)show_used_suppressions();
       return;
    }
@@ -905,13 +917,15 @@ void VG_(show_all_errors) ( void )
              n_errs_found, n_err_contexts, 
              n_errs_suppressed, n_supp_contexts );
 
-   if (VG_(clo_verbosity) <= 1)
+   if (verbosity <= 1)
       return;
 
    // We do the following only at -v or above, and only in non-XML
    // mode
 
-   /* Print the contexts in order of increasing error count. */
+   /* Print the contexts in order of increasing error count. 
+      Once an error is shown, we add a huge value to its count to filter it
+      out. After having shown all errors, we reset count to the original value. */
    for (i = 0; i < n_err_contexts; i++) {
       n_min = (1 << 30) - 1;
       p_min = NULL;
@@ -928,10 +942,10 @@ void VG_(show_all_errors) ( void )
       VG_(umsg)("\n");
       VG_(umsg)("%d errors in context %d of %d:\n",
                 p_min->count, i+1, n_err_contexts);
-      pp_Error( p_min, False/*allow_db_attach*/ );
+      pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
 
       // We're not printing XML -- we'd have exited above if so.
-      vg_assert(! VG_(clo_xml));
+      vg_assert(! xml);
 
       if ((i+1 == VG_(clo_dump_error))) {
          StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
@@ -941,9 +955,16 @@ void VG_(show_all_errors) ( void )
                           /*allow redir?*/True);
       }
 
-      p_min->count = 1 << 30;
+      p_min->count = p_min->count + (1 << 30);
    } 
 
+   /* reset the counts, otherwise a 2nd call does not show anything anymore */ 
+   for (p = errors; p != NULL; p = p->next) {
+      if (p->count >= (1 << 30))
+         p->count = p->count - (1 << 30);
+   }
+
+
    any_supp = show_used_suppressions();
 
    if (any_supp) 
@@ -956,6 +977,16 @@ void VG_(show_all_errors) ( void )
              n_supp_contexts );
 }
 
+void VG_(show_last_error) ( void )
+{
+   if (n_err_contexts == 0) {
+      VG_(umsg)("No errors yet\n");
+      return;
+   }
+
+   pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
+}
+
 
 /* Show occurrence counts of all errors, in XML form. */
 void VG_(show_error_counts_as_XML) ( void )
diff --git a/coregrind/m_gdbserver/32bit-core-valgrind-s1.xml b/coregrind/m_gdbserver/32bit-core-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..9a0582f
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core.valgrind.s1">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="eaxs1" bitsize="32" type="int32"/>
+  <reg name="ecxs1" bitsize="32" type="int32"/>
+  <reg name="edxs1" bitsize="32" type="int32"/>
+  <reg name="ebxs1" bitsize="32" type="int32"/>
+  <reg name="esps1" bitsize="32" type="data_ptr"/>
+  <reg name="ebps1" bitsize="32" type="data_ptr"/>
+  <reg name="esis1" bitsize="32" type="int32"/>
+  <reg name="edis1" bitsize="32" type="int32"/>
+
+  <reg name="eips1" bitsize="32" type="code_ptr"/>
+  <reg name="eflagss1" bitsize="32" type="i386_eflags"/>
+  <reg name="css1" bitsize="32" type="int32"/>
+  <reg name="sss1" bitsize="32" type="int32"/>
+  <reg name="dss1" bitsize="32" type="int32"/>
+  <reg name="ess1" bitsize="32" type="int32"/>
+  <reg name="fss1" bitsize="32" type="int32"/>
+  <reg name="gss1" bitsize="32" type="int32"/>
+
+  <reg name="st0s1" bitsize="80" type="i387_ext"/>
+  <reg name="st1s1" bitsize="80" type="i387_ext"/>
+  <reg name="st2s1" bitsize="80" type="i387_ext"/>
+  <reg name="st3s1" bitsize="80" type="i387_ext"/>
+  <reg name="st4s1" bitsize="80" type="i387_ext"/>
+  <reg name="st5s1" bitsize="80" type="i387_ext"/>
+  <reg name="st6s1" bitsize="80" type="i387_ext"/>
+  <reg name="st7s1" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrls1" bitsize="32" type="int" group="float"/>
+  <reg name="fstats1" bitsize="32" type="int" group="float"/>
+  <reg name="ftags1" bitsize="32" type="int" group="float"/>
+  <reg name="fisegs1" bitsize="32" type="int" group="float"/>
+  <reg name="fioffs1" bitsize="32" type="int" group="float"/>
+  <reg name="fosegs1" bitsize="32" type="int" group="float"/>
+  <reg name="fooffs1" bitsize="32" type="int" group="float"/>
+  <reg name="fops1" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-core-valgrind-s2.xml b/coregrind/m_gdbserver/32bit-core-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..1b272c5
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core.valgrind.s2">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="eaxs2" bitsize="32" type="int32"/>
+  <reg name="ecxs2" bitsize="32" type="int32"/>
+  <reg name="edxs2" bitsize="32" type="int32"/>
+  <reg name="ebxs2" bitsize="32" type="int32"/>
+  <reg name="esps2" bitsize="32" type="data_ptr"/>
+  <reg name="ebps2" bitsize="32" type="data_ptr"/>
+  <reg name="esis2" bitsize="32" type="int32"/>
+  <reg name="edis2" bitsize="32" type="int32"/>
+
+  <reg name="eips2" bitsize="32" type="code_ptr"/>
+  <reg name="eflagss2" bitsize="32" type="i386_eflags"/>
+  <reg name="css2" bitsize="32" type="int32"/>
+  <reg name="sss2" bitsize="32" type="int32"/>
+  <reg name="dss2" bitsize="32" type="int32"/>
+  <reg name="ess2" bitsize="32" type="int32"/>
+  <reg name="fss2" bitsize="32" type="int32"/>
+  <reg name="gss2" bitsize="32" type="int32"/>
+
+  <reg name="st0s2" bitsize="80" type="i387_ext"/>
+  <reg name="st1s2" bitsize="80" type="i387_ext"/>
+  <reg name="st2s2" bitsize="80" type="i387_ext"/>
+  <reg name="st3s2" bitsize="80" type="i387_ext"/>
+  <reg name="st4s2" bitsize="80" type="i387_ext"/>
+  <reg name="st5s2" bitsize="80" type="i387_ext"/>
+  <reg name="st6s2" bitsize="80" type="i387_ext"/>
+  <reg name="st7s2" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrls2" bitsize="32" type="int" group="float"/>
+  <reg name="fstats2" bitsize="32" type="int" group="float"/>
+  <reg name="ftags2" bitsize="32" type="int" group="float"/>
+  <reg name="fisegs2" bitsize="32" type="int" group="float"/>
+  <reg name="fioffs2" bitsize="32" type="int" group="float"/>
+  <reg name="fosegs2" bitsize="32" type="int" group="float"/>
+  <reg name="fooffs2" bitsize="32" type="int" group="float"/>
+  <reg name="fops2" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-core.xml b/coregrind/m_gdbserver/32bit-core.xml
new file mode 100644 (file)
index 0000000..4d0377e
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="eax" bitsize="32" type="int32"/>
+  <reg name="ecx" bitsize="32" type="int32"/>
+  <reg name="edx" bitsize="32" type="int32"/>
+  <reg name="ebx" bitsize="32" type="int32"/>
+  <reg name="esp" bitsize="32" type="data_ptr"/>
+  <reg name="ebp" bitsize="32" type="data_ptr"/>
+  <reg name="esi" bitsize="32" type="int32"/>
+  <reg name="edi" bitsize="32" type="int32"/>
+
+  <reg name="eip" bitsize="32" type="code_ptr"/>
+  <reg name="eflags" bitsize="32" type="i386_eflags"/>
+  <reg name="cs" bitsize="32" type="int32"/>
+  <reg name="ss" bitsize="32" type="int32"/>
+  <reg name="ds" bitsize="32" type="int32"/>
+  <reg name="es" bitsize="32" type="int32"/>
+  <reg name="fs" bitsize="32" type="int32"/>
+  <reg name="gs" bitsize="32" type="int32"/>
+
+  <reg name="st0" bitsize="80" type="i387_ext"/>
+  <reg name="st1" bitsize="80" type="i387_ext"/>
+  <reg name="st2" bitsize="80" type="i387_ext"/>
+  <reg name="st3" bitsize="80" type="i387_ext"/>
+  <reg name="st4" bitsize="80" type="i387_ext"/>
+  <reg name="st5" bitsize="80" type="i387_ext"/>
+  <reg name="st6" bitsize="80" type="i387_ext"/>
+  <reg name="st7" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrl" bitsize="32" type="int" group="float"/>
+  <reg name="fstat" bitsize="32" type="int" group="float"/>
+  <reg name="ftag" bitsize="32" type="int" group="float"/>
+  <reg name="fiseg" bitsize="32" type="int" group="float"/>
+  <reg name="fioff" bitsize="32" type="int" group="float"/>
+  <reg name="foseg" bitsize="32" type="int" group="float"/>
+  <reg name="fooff" bitsize="32" type="int" group="float"/>
+  <reg name="fop" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-linux-valgrind-s1.xml b/coregrind/m_gdbserver/32bit-linux-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..fdf23f0
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux.valgrind.s1">
+  <reg name="orig_eaxs1" bitsize="32" type="int" regnum="83"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-linux-valgrind-s2.xml b/coregrind/m_gdbserver/32bit-linux-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..137e3af
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux.valgrind.s2">
+  <reg name="orig_eaxs2" bitsize="32" type="int" regnum="125"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-linux.xml b/coregrind/m_gdbserver/32bit-linux.xml
new file mode 100644 (file)
index 0000000..975daf9
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux">
+  <reg name="orig_eax" bitsize="32" type="int" regnum="41"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-sse-valgrind-s1.xml b/coregrind/m_gdbserver/32bit-sse-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..1a368c4
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.sse.valgrind.s1">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v2d" type="ieee_double" count="2"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v2i64" type="int64" count="2"/>
+  <union id="vec128">
+    <field name="v4_float" type="v4f"/>
+    <field name="v2_double" type="v2d"/>
+    <field name="v16_int8" type="v16i8"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v2_int64" type="v2i64"/>
+    <field name="uint128" type="uint128"/>
+  </union>
+  <flags id="i386_mxcsr" size="4">
+    <field name="IE" start="0" end="0"/>
+    <field name="DE" start="1" end="1"/>
+    <field name="ZE" start="2" end="2"/>
+    <field name="OE" start="3" end="3"/>
+    <field name="UE" start="4" end="4"/>
+    <field name="PE" start="5" end="5"/>
+    <field name="DAZ" start="6" end="6"/>
+    <field name="IM" start="7" end="7"/>
+    <field name="DM" start="8" end="8"/>
+    <field name="ZM" start="9" end="9"/>
+    <field name="OM" start="10" end="10"/>
+    <field name="UM" start="11" end="11"/>
+    <field name="PM" start="12" end="12"/>
+    <field name="FZ" start="15" end="15"/>
+  </flags>
+
+  <reg name="xmm0s1" bitsize="128" type="vec128"/>
+  <reg name="xmm1s1" bitsize="128" type="vec128"/>
+  <reg name="xmm2s1" bitsize="128" type="vec128"/>
+  <reg name="xmm3s1" bitsize="128" type="vec128"/>
+  <reg name="xmm4s1" bitsize="128" type="vec128"/>
+  <reg name="xmm5s1" bitsize="128" type="vec128"/>
+  <reg name="xmm6s1" bitsize="128" type="vec128"/>
+  <reg name="xmm7s1" bitsize="128" type="vec128"/>
+
+  <reg name="mxcsrs1" bitsize="32" type="i386_mxcsr" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-sse-valgrind-s2.xml b/coregrind/m_gdbserver/32bit-sse-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..c69da70
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.sse.valgrind.s2">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v2d" type="ieee_double" count="2"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v2i64" type="int64" count="2"/>
+  <union id="vec128">
+    <field name="v4_float" type="v4f"/>
+    <field name="v2_double" type="v2d"/>
+    <field name="v16_int8" type="v16i8"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v2_int64" type="v2i64"/>
+    <field name="uint128" type="uint128"/>
+  </union>
+  <flags id="i386_mxcsr" size="4">
+    <field name="IE" start="0" end="0"/>
+    <field name="DE" start="1" end="1"/>
+    <field name="ZE" start="2" end="2"/>
+    <field name="OE" start="3" end="3"/>
+    <field name="UE" start="4" end="4"/>
+    <field name="PE" start="5" end="5"/>
+    <field name="DAZ" start="6" end="6"/>
+    <field name="IM" start="7" end="7"/>
+    <field name="DM" start="8" end="8"/>
+    <field name="ZM" start="9" end="9"/>
+    <field name="OM" start="10" end="10"/>
+    <field name="UM" start="11" end="11"/>
+    <field name="PM" start="12" end="12"/>
+    <field name="FZ" start="15" end="15"/>
+  </flags>
+
+  <reg name="xmm0s2" bitsize="128" type="vec128"/>
+  <reg name="xmm1s2" bitsize="128" type="vec128"/>
+  <reg name="xmm2s2" bitsize="128" type="vec128"/>
+  <reg name="xmm3s2" bitsize="128" type="vec128"/>
+  <reg name="xmm4s2" bitsize="128" type="vec128"/>
+  <reg name="xmm5s2" bitsize="128" type="vec128"/>
+  <reg name="xmm6s2" bitsize="128" type="vec128"/>
+  <reg name="xmm7s2" bitsize="128" type="vec128"/>
+
+  <reg name="mxcsrs2" bitsize="32" type="i386_mxcsr" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/32bit-sse.xml b/coregrind/m_gdbserver/32bit-sse.xml
new file mode 100644 (file)
index 0000000..cca94b3
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.sse">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v2d" type="ieee_double" count="2"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v2i64" type="int64" count="2"/>
+  <union id="vec128">
+    <field name="v4_float" type="v4f"/>
+    <field name="v2_double" type="v2d"/>
+    <field name="v16_int8" type="v16i8"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v2_int64" type="v2i64"/>
+    <field name="uint128" type="uint128"/>
+  </union>
+  <flags id="i386_mxcsr" size="4">
+    <field name="IE" start="0" end="0"/>
+    <field name="DE" start="1" end="1"/>
+    <field name="ZE" start="2" end="2"/>
+    <field name="OE" start="3" end="3"/>
+    <field name="UE" start="4" end="4"/>
+    <field name="PE" start="5" end="5"/>
+    <field name="DAZ" start="6" end="6"/>
+    <field name="IM" start="7" end="7"/>
+    <field name="DM" start="8" end="8"/>
+    <field name="ZM" start="9" end="9"/>
+    <field name="OM" start="10" end="10"/>
+    <field name="UM" start="11" end="11"/>
+    <field name="PM" start="12" end="12"/>
+    <field name="FZ" start="15" end="15"/>
+  </flags>
+
+  <reg name="xmm0" bitsize="128" type="vec128" regnum="32"/>
+  <reg name="xmm1" bitsize="128" type="vec128"/>
+  <reg name="xmm2" bitsize="128" type="vec128"/>
+  <reg name="xmm3" bitsize="128" type="vec128"/>
+  <reg name="xmm4" bitsize="128" type="vec128"/>
+  <reg name="xmm5" bitsize="128" type="vec128"/>
+  <reg name="xmm6" bitsize="128" type="vec128"/>
+  <reg name="xmm7" bitsize="128" type="vec128"/>
+
+  <reg name="mxcsr" bitsize="32" type="i386_mxcsr" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-core-valgrind-s1.xml b/coregrind/m_gdbserver/64bit-core-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..67b497f
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core.valgrind.s1">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="raxs1" bitsize="64" type="int64"/>
+  <reg name="rbxs1" bitsize="64" type="int64"/>
+  <reg name="rcxs1" bitsize="64" type="int64"/>
+  <reg name="rdxs1" bitsize="64" type="int64"/>
+  <reg name="rsis1" bitsize="64" type="int64"/>
+  <reg name="rdis1" bitsize="64" type="int64"/>
+  <reg name="rbps1" bitsize="64" type="data_ptr"/>
+  <reg name="rsps1" bitsize="64" type="data_ptr"/>
+  <reg name="r8s1" bitsize="64" type="int64"/>
+  <reg name="r9s1" bitsize="64" type="int64"/>
+  <reg name="r10s1" bitsize="64" type="int64"/>
+  <reg name="r11s1" bitsize="64" type="int64"/>
+  <reg name="r12s1" bitsize="64" type="int64"/>
+  <reg name="r13s1" bitsize="64" type="int64"/>
+  <reg name="r14s1" bitsize="64" type="int64"/>
+  <reg name="r15s1" bitsize="64" type="int64"/>
+
+  <reg name="rips1" bitsize="64" type="code_ptr"/>
+  <reg name="eflagss1" bitsize="32" type="i386_eflags"/>
+  <reg name="css1" bitsize="32" type="int32"/>
+  <reg name="sss1" bitsize="32" type="int32"/>
+  <reg name="dss1" bitsize="32" type="int32"/>
+  <reg name="ess1" bitsize="32" type="int32"/>
+  <reg name="fss1" bitsize="32" type="int32"/>
+  <reg name="gss1" bitsize="32" type="int32"/>
+
+  <reg name="st0s1" bitsize="80" type="i387_ext"/>
+  <reg name="st1s1" bitsize="80" type="i387_ext"/>
+  <reg name="st2s1" bitsize="80" type="i387_ext"/>
+  <reg name="st3s1" bitsize="80" type="i387_ext"/>
+  <reg name="st4s1" bitsize="80" type="i387_ext"/>
+  <reg name="st5s1" bitsize="80" type="i387_ext"/>
+  <reg name="st6s1" bitsize="80" type="i387_ext"/>
+  <reg name="st7s1" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrls1" bitsize="32" type="int" group="float"/>
+  <reg name="fstats1" bitsize="32" type="int" group="float"/>
+  <reg name="ftags1" bitsize="32" type="int" group="float"/>
+  <reg name="fisegs1" bitsize="32" type="int" group="float"/>
+  <reg name="fioffs1" bitsize="32" type="int" group="float"/>
+  <reg name="fosegs1" bitsize="32" type="int" group="float"/>
+  <reg name="fooffs1" bitsize="32" type="int" group="float"/>
+  <reg name="fops1" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-core-valgrind-s2.xml b/coregrind/m_gdbserver/64bit-core-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..14f2726
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core.valgrind.s2">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="raxs2" bitsize="64" type="int64"/>
+  <reg name="rbxs2" bitsize="64" type="int64"/>
+  <reg name="rcxs2" bitsize="64" type="int64"/>
+  <reg name="rdxs2" bitsize="64" type="int64"/>
+  <reg name="rsis2" bitsize="64" type="int64"/>
+  <reg name="rdis2" bitsize="64" type="int64"/>
+  <reg name="rbps2" bitsize="64" type="data_ptr"/>
+  <reg name="rsps2" bitsize="64" type="data_ptr"/>
+  <reg name="r8s2" bitsize="64" type="int64"/>
+  <reg name="r9s2" bitsize="64" type="int64"/>
+  <reg name="r10s2" bitsize="64" type="int64"/>
+  <reg name="r11s2" bitsize="64" type="int64"/>
+  <reg name="r12s2" bitsize="64" type="int64"/>
+  <reg name="r13s2" bitsize="64" type="int64"/>
+  <reg name="r14s2" bitsize="64" type="int64"/>
+  <reg name="r15s2" bitsize="64" type="int64"/>
+
+  <reg name="rips2" bitsize="64" type="code_ptr"/>
+  <reg name="eflagss2" bitsize="32" type="i386_eflags"/>
+  <reg name="css2" bitsize="32" type="int32"/>
+  <reg name="sss2" bitsize="32" type="int32"/>
+  <reg name="dss2" bitsize="32" type="int32"/>
+  <reg name="ess2" bitsize="32" type="int32"/>
+  <reg name="fss2" bitsize="32" type="int32"/>
+  <reg name="gss2" bitsize="32" type="int32"/>
+
+  <reg name="st0s2" bitsize="80" type="i387_ext"/>
+  <reg name="st1s2" bitsize="80" type="i387_ext"/>
+  <reg name="st2s2" bitsize="80" type="i387_ext"/>
+  <reg name="st3s2" bitsize="80" type="i387_ext"/>
+  <reg name="st4s2" bitsize="80" type="i387_ext"/>
+  <reg name="st5s2" bitsize="80" type="i387_ext"/>
+  <reg name="st6s2" bitsize="80" type="i387_ext"/>
+  <reg name="st7s2" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrls2" bitsize="32" type="int" group="float"/>
+  <reg name="fstats2" bitsize="32" type="int" group="float"/>
+  <reg name="ftags2" bitsize="32" type="int" group="float"/>
+  <reg name="fisegs2" bitsize="32" type="int" group="float"/>
+  <reg name="fioffs2" bitsize="32" type="int" group="float"/>
+  <reg name="fosegs2" bitsize="32" type="int" group="float"/>
+  <reg name="fooffs2" bitsize="32" type="int" group="float"/>
+  <reg name="fops2" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-core.xml b/coregrind/m_gdbserver/64bit-core.xml
new file mode 100644 (file)
index 0000000..8cfe3fe
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="rax" bitsize="64" type="int64"/>
+  <reg name="rbx" bitsize="64" type="int64"/>
+  <reg name="rcx" bitsize="64" type="int64"/>
+  <reg name="rdx" bitsize="64" type="int64"/>
+  <reg name="rsi" bitsize="64" type="int64"/>
+  <reg name="rdi" bitsize="64" type="int64"/>
+  <reg name="rbp" bitsize="64" type="data_ptr"/>
+  <reg name="rsp" bitsize="64" type="data_ptr"/>
+  <reg name="r8" bitsize="64" type="int64"/>
+  <reg name="r9" bitsize="64" type="int64"/>
+  <reg name="r10" bitsize="64" type="int64"/>
+  <reg name="r11" bitsize="64" type="int64"/>
+  <reg name="r12" bitsize="64" type="int64"/>
+  <reg name="r13" bitsize="64" type="int64"/>
+  <reg name="r14" bitsize="64" type="int64"/>
+  <reg name="r15" bitsize="64" type="int64"/>
+
+  <reg name="rip" bitsize="64" type="code_ptr"/>
+  <reg name="eflags" bitsize="32" type="i386_eflags"/>
+  <reg name="cs" bitsize="32" type="int32"/>
+  <reg name="ss" bitsize="32" type="int32"/>
+  <reg name="ds" bitsize="32" type="int32"/>
+  <reg name="es" bitsize="32" type="int32"/>
+  <reg name="fs" bitsize="32" type="int32"/>
+  <reg name="gs" bitsize="32" type="int32"/>
+
+  <reg name="st0" bitsize="80" type="i387_ext"/>
+  <reg name="st1" bitsize="80" type="i387_ext"/>
+  <reg name="st2" bitsize="80" type="i387_ext"/>
+  <reg name="st3" bitsize="80" type="i387_ext"/>
+  <reg name="st4" bitsize="80" type="i387_ext"/>
+  <reg name="st5" bitsize="80" type="i387_ext"/>
+  <reg name="st6" bitsize="80" type="i387_ext"/>
+  <reg name="st7" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrl" bitsize="32" type="int" group="float"/>
+  <reg name="fstat" bitsize="32" type="int" group="float"/>
+  <reg name="ftag" bitsize="32" type="int" group="float"/>
+  <reg name="fiseg" bitsize="32" type="int" group="float"/>
+  <reg name="fioff" bitsize="32" type="int" group="float"/>
+  <reg name="foseg" bitsize="32" type="int" group="float"/>
+  <reg name="fooff" bitsize="32" type="int" group="float"/>
+  <reg name="fop" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-linux-valgrind-s1.xml b/coregrind/m_gdbserver/64bit-linux-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..fc1c2dd
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux.valgrind.s1">
+  <reg name="orig_raxs1" bitsize="64" type="int" regnum="115"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-linux-valgrind-s2.xml b/coregrind/m_gdbserver/64bit-linux-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..452ddec
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux.valgrind.s2">
+  <reg name="orig_raxs2" bitsize="64" type="int" regnum="173"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-linux.xml b/coregrind/m_gdbserver/64bit-linux.xml
new file mode 100644 (file)
index 0000000..8609272
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux">
+  <reg name="orig_rax" bitsize="64" type="int" regnum="57"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-sse-valgrind-s1.xml b/coregrind/m_gdbserver/64bit-sse-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..9db6c74
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.sse.valgrind.s1">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v2d" type="ieee_double" count="2"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v2i64" type="int64" count="2"/>
+  <union id="vec128">
+    <field name="v4_float" type="v4f"/>
+    <field name="v2_double" type="v2d"/>
+    <field name="v16_int8" type="v16i8"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v2_int64" type="v2i64"/>
+    <field name="uint128" type="uint128"/>
+  </union>
+  <flags id="i386_mxcsr" size="4">
+    <field name="IE" start="0" end="0"/>
+    <field name="DE" start="1" end="1"/>
+    <field name="ZE" start="2" end="2"/>
+    <field name="OE" start="3" end="3"/>
+    <field name="UE" start="4" end="4"/>
+    <field name="PE" start="5" end="5"/>
+    <field name="DAZ" start="6" end="6"/>
+    <field name="IM" start="7" end="7"/>
+    <field name="DM" start="8" end="8"/>
+    <field name="ZM" start="9" end="9"/>
+    <field name="OM" start="10" end="10"/>
+    <field name="UM" start="11" end="11"/>
+    <field name="PM" start="12" end="12"/>
+    <field name="FZ" start="15" end="15"/>
+  </flags>
+
+  <reg name="xmm0s1" bitsize="128" type="vec128"/>
+  <reg name="xmm1s1" bitsize="128" type="vec128"/>
+  <reg name="xmm2s1" bitsize="128" type="vec128"/>
+  <reg name="xmm3s1" bitsize="128" type="vec128"/>
+  <reg name="xmm4s1" bitsize="128" type="vec128"/>
+  <reg name="xmm5s1" bitsize="128" type="vec128"/>
+  <reg name="xmm6s1" bitsize="128" type="vec128"/>
+  <reg name="xmm7s1" bitsize="128" type="vec128"/>
+  <reg name="xmm8s1" bitsize="128" type="vec128"/>
+  <reg name="xmm9s1" bitsize="128" type="vec128"/>
+  <reg name="xmm10s1" bitsize="128" type="vec128"/>
+  <reg name="xmm11s1" bitsize="128" type="vec128"/>
+  <reg name="xmm12s1" bitsize="128" type="vec128"/>
+  <reg name="xmm13s1" bitsize="128" type="vec128"/>
+  <reg name="xmm14s1" bitsize="128" type="vec128"/>
+  <reg name="xmm15s1" bitsize="128" type="vec128"/>
+
+  <reg name="mxcsrs1" bitsize="32" type="i386_mxcsr" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-sse-valgrind-s2.xml b/coregrind/m_gdbserver/64bit-sse-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..189910e
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.sse.valgrind.s2">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v2d" type="ieee_double" count="2"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v2i64" type="int64" count="2"/>
+  <union id="vec128">
+    <field name="v4_float" type="v4f"/>
+    <field name="v2_double" type="v2d"/>
+    <field name="v16_int8" type="v16i8"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v2_int64" type="v2i64"/>
+    <field name="uint128" type="uint128"/>
+  </union>
+  <flags id="i386_mxcsr" size="4">
+    <field name="IE" start="0" end="0"/>
+    <field name="DE" start="1" end="1"/>
+    <field name="ZE" start="2" end="2"/>
+    <field name="OE" start="3" end="3"/>
+    <field name="UE" start="4" end="4"/>
+    <field name="PE" start="5" end="5"/>
+    <field name="DAZ" start="6" end="6"/>
+    <field name="IM" start="7" end="7"/>
+    <field name="DM" start="8" end="8"/>
+    <field name="ZM" start="9" end="9"/>
+    <field name="OM" start="10" end="10"/>
+    <field name="UM" start="11" end="11"/>
+    <field name="PM" start="12" end="12"/>
+    <field name="FZ" start="15" end="15"/>
+  </flags>
+
+  <reg name="xmm0s2" bitsize="128" type="vec128"/>
+  <reg name="xmm1s2" bitsize="128" type="vec128"/>
+  <reg name="xmm2s2" bitsize="128" type="vec128"/>
+  <reg name="xmm3s2" bitsize="128" type="vec128"/>
+  <reg name="xmm4s2" bitsize="128" type="vec128"/>
+  <reg name="xmm5s2" bitsize="128" type="vec128"/>
+  <reg name="xmm6s2" bitsize="128" type="vec128"/>
+  <reg name="xmm7s2" bitsize="128" type="vec128"/>
+  <reg name="xmm8s2" bitsize="128" type="vec128"/>
+  <reg name="xmm9s2" bitsize="128" type="vec128"/>
+  <reg name="xmm10s2" bitsize="128" type="vec128"/>
+  <reg name="xmm11s2" bitsize="128" type="vec128"/>
+  <reg name="xmm12s2" bitsize="128" type="vec128"/>
+  <reg name="xmm13s2" bitsize="128" type="vec128"/>
+  <reg name="xmm14s2" bitsize="128" type="vec128"/>
+  <reg name="xmm15s2" bitsize="128" type="vec128"/>
+
+  <reg name="mxcsrs2" bitsize="32" type="i386_mxcsr" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/64bit-sse.xml b/coregrind/m_gdbserver/64bit-sse.xml
new file mode 100644 (file)
index 0000000..d7f7925
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.sse">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v2d" type="ieee_double" count="2"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v2i64" type="int64" count="2"/>
+  <union id="vec128">
+    <field name="v4_float" type="v4f"/>
+    <field name="v2_double" type="v2d"/>
+    <field name="v16_int8" type="v16i8"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v2_int64" type="v2i64"/>
+    <field name="uint128" type="uint128"/>
+  </union>
+  <flags id="i386_mxcsr" size="4">
+    <field name="IE" start="0" end="0"/>
+    <field name="DE" start="1" end="1"/>
+    <field name="ZE" start="2" end="2"/>
+    <field name="OE" start="3" end="3"/>
+    <field name="UE" start="4" end="4"/>
+    <field name="PE" start="5" end="5"/>
+    <field name="DAZ" start="6" end="6"/>
+    <field name="IM" start="7" end="7"/>
+    <field name="DM" start="8" end="8"/>
+    <field name="ZM" start="9" end="9"/>
+    <field name="OM" start="10" end="10"/>
+    <field name="UM" start="11" end="11"/>
+    <field name="PM" start="12" end="12"/>
+    <field name="FZ" start="15" end="15"/>
+  </flags>
+
+  <reg name="xmm0" bitsize="128" type="vec128" regnum="40"/>
+  <reg name="xmm1" bitsize="128" type="vec128"/>
+  <reg name="xmm2" bitsize="128" type="vec128"/>
+  <reg name="xmm3" bitsize="128" type="vec128"/>
+  <reg name="xmm4" bitsize="128" type="vec128"/>
+  <reg name="xmm5" bitsize="128" type="vec128"/>
+  <reg name="xmm6" bitsize="128" type="vec128"/>
+  <reg name="xmm7" bitsize="128" type="vec128"/>
+  <reg name="xmm8" bitsize="128" type="vec128"/>
+  <reg name="xmm9" bitsize="128" type="vec128"/>
+  <reg name="xmm10" bitsize="128" type="vec128"/>
+  <reg name="xmm11" bitsize="128" type="vec128"/>
+  <reg name="xmm12" bitsize="128" type="vec128"/>
+  <reg name="xmm13" bitsize="128" type="vec128"/>
+  <reg name="xmm14" bitsize="128" type="vec128"/>
+  <reg name="xmm15" bitsize="128" type="vec128"/>
+
+  <reg name="mxcsr" bitsize="32" type="i386_mxcsr" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/README_DEVELOPERS b/coregrind/m_gdbserver/README_DEVELOPERS
new file mode 100644 (file)
index 0000000..2334078
--- /dev/null
@@ -0,0 +1,433 @@
+This file contains various notes/ideas/history/... related
+to gdbserver in valgrind.
+
+How to use Valgrind gdbserver ?
+-------------------------------
+This is described in the Valgrind user manual.
+Before reading the below, you better read the user manual first.
+
+What is gdbserver ?
+-------------------
+gdb debugger typically is used to debug a process running
+on the same machine : gdb uses system calls (such as ptrace) 
+to fetch data from the process being debugged
+or to change data in the process 
+or interrupt the process 
+or ...
+
+gdb can also debug processes running in a different computer
+(e.g. it can debug a process running on a small real time
+board).
+
+gdb does this by sending some commands (e.g. using tcp/ip) to a piece
+of code running on the remote computer. This piece of code (called a
+gdb stub in small boards, or gdbserver when the remote computer runs
+an OS such as GNU/linux) will provide a set of commands allowing gdb
+to remotely debug the process.  Examples of commands are: "get the
+registers", "get the list of running threads", "read xxx bytes at
+address yyyyyyyy", etc.  The definition of all these commands and the
+associated replies is the gdb remote serial protocol, which is
+documented in Appendix D of gdb user manual.
+
+The standard gdb distribution has a standalone gdbserver (a small
+executable) which implements this protocol and the needed system calls
+to allow gdb to remotely debug process running on a linux or MacOS or
+...
+
+Activation of gdbserver code inside valgrind
+--------------------------------------------
+The gdbserver code (from gdb 6.6, GPL2+) has been modified so as to
+link it with valgrind and allow the valgrind guest process to be
+debugged by a gdb speaking to this gdbserver embedded in valgrind.
+The ptrace system calls inside gdbserver have been replaced by reading
+the state of the guest.
+
+The gdbserver functionality is activated with valgrind command line
+options. If gdbserver is not enabled, then the impact on valgrind
+runtime is minimal: basically it just checks at startup the command
+line option to see that there is nothing to do for what concerns gdb
+server: there is a "if gdbserver is active" check in the translate
+function of translate.c and an "if" in the valgrind scheduler.
+If the valgrind gdbserver is activated (--vgdb=yes), the impact
+is minimal (from time to time, the valgrind scheduler checks a counter
+in memory). Option --vgdb-poll=yyyyy controls how often the scheduler
+will do a (somewhat) more heavy check to see if gdbserver needs to
+stop execution of the guest to allow debugging.
+If valgrind gdbserver is activated with --vgdb=full, then
+each instruction is instrumented with an additional call to a dirty
+helper. 
+
+How does gdbserver code interacts with valgrind ?
+-------------------------------------------------
+When an error is reported, the gdbserver code is called.  It reads
+commands from gdb using read system call on a FIFO (e.g. a command
+such as "get the registers").  It executes the command (e.g. fetches
+the registers from the guest state) and writes the reply (e.g. a
+packet containing the register data).  When gdb instructs gdbserver to
+"continue", the control is returned to valgrind, which then continues
+to execute guest code.  The FIFOs used to communication between
+valgrind and gdb are created at startup if gdbserver is activated
+according to the --vgdb=no/yes/full command line option.
+
+How are signals "handled" ?
+---------------------------
+When a signal is to be given to the guest, valgrind core first calls
+gdbserver (if a gdb is currently connected to valgrind, otherwise the
+signal is delivered immediately). If gdb instructs to give the signal
+to the process, the signal is delivered to the guest.  Otherwise, the
+signal is ignored (not given to the guest). The user can
+with gdb further decide to pass (or not pass) the signal.
+Note that some (fatal) signals cannot be ignored.
+
+How are "break/step/stepi/next/..." implemented ?
+-------------------------------------------------
+When a break is put by gdb on an instruction, a command is sent to the
+gdbserver in valgrind. This causes the basic block of this instruction
+to be discarded and then re-instrumented so as to insert calls to a
+dirty helper which calls the gdb server code.  When a block is
+instrumented for gdbserver, all the "jump targets" of this block are
+invalidated, so as to allow step/stepi/next to properly work: these
+blocks will themselves automatically be re-instrumented for gdbserver
+if they are jumped to.
+The valgrind gdbserver remembers which blocks have been instrumented
+due to this "lazy 'jump targets' debugging instrumentation" so as to
+discard these "debugging translation" when gdb instructs to continue
+the execution normally.
+The blocks in which an explicit break has been put by the user
+are kept instrumented for gdbserver.
+(but note that by default, gdb removes all breaks when the
+process is stopped, and re-inserts all breaks when the process
+is continued). This behaviour can be changed using the gdb
+command 'set breakpoint always-inserted'.
+
+How are watchpoints implemented ?
+---------------------------------
+Watchpoints implies support from the tool to detect that
+a location is read and/or written. Currently, only memcheck
+supports this : when a watchpoint is placed, memcheck changes
+the addressability bits of the watched memory zone to be unacessible.
+Before an access, memcheck then detects an error, but sees this error
+is due to a watchpoint and gives the control back to gdb.
+Stopping on the exact instruction for a write watchpoint implies
+to use --vgdb=full. This is because the error is detected by memcheck
+before modifying the value. gdb checks that the value has not changed
+and so "does not believe" the information that the write watchpoint
+was triggered, and continues the execution. At the next watchpoint
+occurence, gdb sees the value has changed. But the watchpoints are all
+reported "off by one". To avoid this, Valgrind gdbserver must
+terminate the current instruction before reporting the write watchpoint.
+Terminating precisely the current instruction implies to have
+instrumented all the instructions of the block for gdbserver even
+if there is no break in this block. This is ensured by --vgdb=full.
+See m_gdbserver.c Bool VG_(is_watched) where watchpoint handling
+is implemented.
+
+How is the Valgrind gdbserver receiving commands/packets from gdb ?
+-------------------------------------------------------------------
+The embedded gdbserver reads gdb commands on a named pipe having
+(by default) the name   /tmp/vgdb-pipe-from-vgdb-to-%d
+where %d will be replaced by the pid.
+The embedded gdbserver will reply to gdb commands on a named pipe
+/tmp/vgdb-pipe-to-vgdb-from-%d
+
+gdb does not speak directly with gdbserver in valgrind: a relay application
+called vgdb is needed between gdb and the valgrind-ified process.
+gdb writes commands on the stdin of vgdb. vgdb reads these
+commands and writes them on FIFO /tmp/vgdb-pipe-from-vgdb-to-%d.
+vgdb reads replies on FIFO /tmp/vgdb-pipe-to-vgdb-from-%d and writes
+them on its stdout. 
+
+Note: The solution of named pipes was preferred to tcp ip connections as
+it allows a discovery of which valgrind-ified processes are ready to accept
+command by looking at files starting with the /tmp/vgdb-pipe- prefix
+(changeable by a command line option).
+Also, the usual unix protections are protecting 
+the valgrind process against other users sending commands.
+The relay process also takes into account the wake up of the valgrind
+process in case all threads are blocked in a system call.
+The relay process can also be used in a shell to send commands
+without a gdb (this allows to have a standard mechanism to control
+valgrind tools from the command line, rather than specialized mechanism
+e.g. in callgrind).
+
+How is gdbserver activated if all Valgrind threads are blocked in a syscall ?
+-----------------------------------------------------------------------------
+vgdb relays characters from gdb to valgrind. The scheduler will from
+time to time check if gdbserver has to handle incoming characters.
+(the check is efficient i.e. most of the time consists in checking
+a counter in (shared) memory).
+
+However, it might be that all the threads in the valgrind process are
+blocked in a system call. In such a case, no polling will be done by
+the valgrind scheduler (as no activity takes place).  By default, vgdb
+will check after 100ms if the characters it has written have been read
+by valgrind. If not, vgdb will force the invocation of the gdbserver
+code inside the valgrind process.
+
+This forced invocation is implemented using the ptrace system call:
+using ptrace, vgdb will cause the valgrind process to call the
+gdbserver code.
+
+This wake up is *not* done using signals as this would imply to
+implement a syscall restart logic in valgrind for all system
+calls. When using ptrace as above, the linux kernel is responsible to
+restart the system call.
+
+This wakeup is also *not* implemented by having a "system thread"
+started by valgrind as this would transform all non-threaded programs
+in threaded programs when running under valgrind. Also, such a 'system
+thread' for gdbserver was tried by Greg Parker in the early MacOS
+port, and was unreliable.  
+
+So, the ptrace based solution was chosen instead.
+
+There used to be some bugs in the kernel when using ptrace on 
+a process blocked in a system call : the symptom is that the system
+call fails with an unknown errno 512. This typically happens
+with a vgdb in 64bits ptrace-ing a 32 bits process.
+A bypass for old kernels has been integrated in vgdb.c (sign extend
+register rax).
+
+At least on a fedora core 12 (kernel 2.6.32), syscall restart of read
+and select are working ok and red-hat 5.3 (an old kernel), everything
+works properly.
+
+Need to investigate if darwin and/or AIX can similarly do syscall
+restart with ptrace.
+
+The vgdb argument --max-invoke-ms=xxx allows to control the nr of
+milli-seconds after which vgdb will force the invocation of gdbserver
+code.  If xxx is 0, this disables the forced invocation.
+Also, disabling this ptrace mechanism is necessary in case you are
+debugging the valgrind code at the same time as debugging the guest
+process using gdbserver.
+
+Do not kill -9 vgdb while it has interrupted the valgrind process,
+otherwise the valgrind process will very probably stay stopped or die.
+
+
+Implementation is based on the gdbserver code from gdb 6.6
+----------------------------------------------------------
+The gdbserver implementation is derived from the gdbserver included
+in the gdb distribution.
+The files originating from gdb are : inferiors.c, regcache.[ch],
+regdef.h, remote-utils.c, server.[ch], signals.c, target.[ch], utils.c,
+version.c.
+valgrind-low-* are inspired from gdb files.
+
+This code had to be changed to integrate properly within valgrind
+(e.g. no libc usage).  Some of these changes have been ensured by
+using the preprocessor to replace calls by valgrind equivalent,
+e.g. #define memcpy(...) VG_(memcpy) (...).
+
+Some "control flow" changes are due to the fact that gdbserver inside
+valgrind must return the control to valgrind when the 'debugged'
+process has to run, while in a classical gdbserver usage, the
+gdbserver process waits for a debugged process to stop on a break or
+similar.  This has implied to have some variables to remember the
+state of gdbserver before returning to valgrind (search for
+resume_packet_needed in server.c) and "goto" the place where gdbserver
+expects a stopped process to return control to gdbserver.
+
+How does a tool need to be changed to be "debuggable" ?
+-------------------------------------------------------
+There is no need to modify a tool to have it "debuggable" via
+gdbserver : e.g. reports of errors, break etc will work "out of the
+box".  If an interactive usage of tool client requests or similar is
+desired for a tool, then simple code can be written for that via a
+specific client request VG_USERREQ__GDB_MONITOR_COMMAND code. The tool
+function "handle_client_request" must then parse the string received
+in argument and call the expected valgrind or tool code.  See
+e.g. massif ms_handle_client_request as an example.
+
+
+Automatic regression tests:
+---------------------------
+Automatic Valgrind gdbserver tests are in the directory
+$(top_srcdir)/gdbserver_tests.
+Read $(top_srcdir)/gdbserver_tests/README_DEVELOPPERS for more
+info about testing.
+
+How to integrate support for a new architecture xxx?
+----------------------------------------------------
+Let's imagine a new architecture hal9000 has to be supported.
+
+Mandatory:
+The main thing to do is to make a file valgrind-low-hal9000.c.
+Start from an existing file (e.g. valgrind-low-x86.c).
+The data structures 'struct reg regs'
+and 'const char *expedite_regs' are build from files
+in the gdb sources, e.g. for an new arch hal9000
+   cd gdb/regformats
+   ./regdat.sh reg-hal9000.dat hal9000
+
+From the generated file hal9000, you copy/paste in
+valgrind-low-hal9000.c the two needed data structures and change their
+name to 'regs' and 'expedite_regs'
+
+Then adapt the set of functions needed to initialize the structure
+'static struct valgrind_target_ops low_target'.
+
+Optional but heavily recommended:
+To have a proper wake up of a Valgrind process with all threads
+blocked in a system call, some architecture specific code
+has to be done in vgdb.c : search for PTRACEINVOKER processor symbol
+to see what has to be completed.
+
+For Linux based platforms, all the ptrace calls should be ok.
+The only thing needed is the code needed to "push a dummy call" on the stack,
+i.e. assign the relevant registers in the struct user_regs_struct, and push
+values on the stack according to the ABI.
+
+For other platforms (i.e. Macos), more work is needed as the ptrace calls
+on Macos are either different and/or incomplete (and so, 'Mach' specific
+things are needed e.g. to attach to threads etc).
+A courageous Mac aficionado is welcome on this aspect.
+
+Optional:
+To let gdb see the Valgrind shadow registers, xml description
+files have to be provided + valgrind-low-hal9000.c has
+to give the top xml file.
+Start from the xml files found in the gdb distribution directory
+gdb/features. You need to duplicate and modify these files to provide
+shadow1 and shadow2 register sets description.
+
+Modify coregrind/Makefile.am:
+    add valgrind-low-hal9000.c
+    If you have target xml description, also add them in pkglib_DATA 
+
+
+A not handled comment given by Julian at FOSDEM.
+------------------------------------------------
+* the check for vgdb-poll in scheduler.c could/should be moved to another place:
+    instead of having it in run_thread_for_a_while
+    the vgdb poll check could be in VG_(scheduler).
+  (not clear to me why one is better than the other ???)
+
+TODO and/or additional nice things to have
+------------------------------------------
+* many options can be changed on-line without problems.
+  => would be nice to have a vg.option command that would evaluate
+  its arguments like the  startup options of m_main.c and tool clo processing.
+
+* have a mc.who_points_at <address> | <loss_record_nr>
+    that would describe the addresses where a pointer is found
+    to address (or address leaked at loss_record_nr>)
+  This would allow to interactively searching who is "keeping" a piece
+  of memory.
+
+* some GDBTD in the code 
+
+(GDBTD = GDB To Do = something still to look at and/or a question)
+
+* All architectures and platforms are done.
+  But there are still some "GDBTD" to convert between gdb registers
+  and VEX registers :
+  e.g. some registers in x86 or amd64 that I could not
+  translate to VEX registers. Someone with a good knowledge
+  of these architectures might complete this 
+  (see the GDBTD in valgrind-low-*.c)
+
+* "hardware" watchpoint (read/write/access watchpoints) are implemented 
+  but can't persuade gdb to insert a hw watchpoint of what valgrind
+  supports (i.e. of whatever length).
+  The reason why gdb does not accept a hardware watch of let's say
+  10 bytes is:
+default_region_ok_for_hw_watchpoint (addr=134520360, len=10) at target.c:2738
+2738     return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
+#0  default_region_ok_for_hw_watchpoint (addr=134520360, len=10)
+    at target.c:2738
+2738     return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
+#1  0x08132e65 in can_use_hardware_watchpoint (v=0x85a8ef0)
+    at breakpoint.c:8300
+8300             if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+#2  0x0813bd17 in watch_command_1 (arg=0x84169f0 "", accessflag=2, 
+    from_tty=<value optimized out>) at breakpoint.c:8140
+  A small patch in gdb remote.c allowed to control the remote target watchpoint
+  length limit. This patch is to be submitted.
+
+* Currently, at least on recent linux kernel, vgdb can properly wake
+  up a valgrind process which is blocked in system calls. Maybe we
+  need to see till which kernel version the ptrace + syscall restart
+  is broken, and put the default value of --max-invoke-ms to 0 in this
+  case.
+
+* more client requests can be programmed in various tools.  Currently,
+  there are only a few standard valgrind or memcheck client requests
+  implemented.
+  vg.suppression [generate|add|delete] might be an interesting command: 
+     generate would output a suppression, add/delete would add a suppression
+     in memory for the last (or selected?) error.
+  vg.break on fn calls/entry/exit + commands associated to it 
+    (such as search leaks)?
+
+
+
+* currently jump(s) and inferior call(s) are somewhat dangerous
+  when called from a block not yet instrumented : instead
+  of continuing till the next Imark, where there will be a
+  debugger call that can properly jump at an instruction boundary,
+  the jump/call will quit the "middle" of an instruction.
+  We could detect if the current block is instrumented by a trick
+  like this:
+     /* Each time helperc_CallDebugger is called, we will store
+        the address from which is it called and the nr of bbs_done
+        when called. This allows to detect that gdbserver is called
+        from a block which is instrumented. */
+     static HWord CallDebugger_addr;
+     static ULong CallDebugger_bbs_done;
+
+     Bool VG_(gdbserver_current_IP_instrumented) (ThreadId tid)
+     {
+        if (VG_(get_IP) (tid) != CallDebugger_addr
+            || CallDebugger_bbs_done != VG_(bbs_done)())
+           return False;
+        return True;
+     }
+
+  Alternatively, we ensure we can re-instrument the current
+  block for gdbserver while executing it.
+  Something like:
+  keep current block till the end of the current instruction, then
+  go back to scheduler.
+  Unsure if and how this is do-able.
+
+
+* ensure that all non static symbols of gdbserver files are #define
+  xxxxx VG_(xxxxx) ???? Is this really needed ? I have tried to put in
+  a test program variables and functions with the same name as valgrind
+  stuff, and everything seems to be ok.
+  I see that all exported symbols in valgrind have a unique prefix
+  created with VG_ or MC_ or ...
+  This is not done for the "gdb gdbserver code", where I have kept
+  the original names. Is this a problem ? I could not create
+  a "symbol" collision between the user symbol and the valgrind
+  core gdbserver symbol.
+
+* currently, gdbserver can only stop/continue the whole process. It
+  might be interesting to have a fine-grained thread control (vCont
+  packet) maybe for tools such as helgrind, drd.  This would allow the
+  user to stop/resume specific threads.  Also, maybe this would solve
+  the following problem: wait for a breakpoint to be encountered,
+  switch thread, next. This sometimes causes an internal error in gdb,
+  probably because gdb believes the current thread will be continued ?
+
+* would be nice to have some more tests.
+
+* better valgrind target support in gdb (see comments of Tom Tromey).
+
+
+-------- description of how gdb invokes a function in the inferior
+to call a function in the inferior (below is for x86):
+gdb writes ESP and EBP to have some more stack space
+push a return address equal to  0x8048390 <_start>
+puts a break                at  0x8048390
+put address of the function to call (e.g. hello_world in EIP (0x8048444))
+continue
+break encountered at 0x8048391 (90 after decrement)
+  => report stop to gdb
+  => gdb restores esp/ebp/eip to what it was (eg. 0x804848C)
+  => gdb "s" => causes the EIP to go to the new EIP (i.e. 0x804848C)
+     gdbserver tells "resuming from 0x804848c"
+                     "stop pc is 0x8048491" => informed gdb of this
+
diff --git a/coregrind/m_gdbserver/amd64-coresse-valgrind.xml b/coregrind/m_gdbserver/amd64-coresse-valgrind.xml
new file mode 100644 (file)
index 0000000..3008d5f
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- AMD64 - core and sse.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>i386:x86-64</architecture>
+  <xi:include href="64bit-core.xml"/>
+  <xi:include href="64bit-sse.xml"/>
+  <xi:include href="64bit-core-valgrind-s1.xml"/>
+  <xi:include href="64bit-sse-valgrind-s1.xml"/>
+  <xi:include href="64bit-core-valgrind-s2.xml"/>
+  <xi:include href="64bit-sse-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/amd64-linux-valgrind.xml b/coregrind/m_gdbserver/amd64-linux-valgrind.xml
new file mode 100644 (file)
index 0000000..a18e557
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- AMD64 - Includes Linux-only special "register".  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>i386:x86-64</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="64bit-core.xml"/>
+  <xi:include href="64bit-sse.xml"/>
+  <xi:include href="64bit-linux.xml"/>
+  <xi:include href="64bit-core-valgrind-s1.xml"/>
+  <xi:include href="64bit-sse-valgrind-s1.xml"/>
+  <xi:include href="64bit-linux-valgrind-s1.xml"/>
+  <xi:include href="64bit-core-valgrind-s2.xml"/>
+  <xi:include href="64bit-sse-valgrind-s2.xml"/>
+  <xi:include href="64bit-linux-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/arm-core-valgrind-s1.xml b/coregrind/m_gdbserver/arm-core-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..cc033a0
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.core.valgrind.s1">
+  <reg name="r0s1" bitsize="32"/>
+  <reg name="r1s1" bitsize="32"/>
+  <reg name="r2s1" bitsize="32"/>
+  <reg name="r3s1" bitsize="32"/>
+  <reg name="r4s1" bitsize="32"/>
+  <reg name="r5s1" bitsize="32"/>
+  <reg name="r6s1" bitsize="32"/>
+  <reg name="r7s1" bitsize="32"/>
+  <reg name="r8s1" bitsize="32"/>
+  <reg name="r9s1" bitsize="32"/>
+  <reg name="r10s1" bitsize="32"/>
+  <reg name="r11s1" bitsize="32"/>
+  <reg name="r12s1" bitsize="32"/>
+  <reg name="sps1" bitsize="32" type="data_ptr"/>
+  <reg name="lrs1" bitsize="32"/>
+  <reg name="pcs1" bitsize="32" type="code_ptr"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsrs1" bitsize="32" regnum="25"/>
+</feature>
diff --git a/coregrind/m_gdbserver/arm-core-valgrind-s2.xml b/coregrind/m_gdbserver/arm-core-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..9c3aa69
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.core.valgrind.s2">
+  <reg name="r0s2" bitsize="32"/>
+  <reg name="r1s2" bitsize="32"/>
+  <reg name="r2s2" bitsize="32"/>
+  <reg name="r3s2" bitsize="32"/>
+  <reg name="r4s2" bitsize="32"/>
+  <reg name="r5s2" bitsize="32"/>
+  <reg name="r6s2" bitsize="32"/>
+  <reg name="r7s2" bitsize="32"/>
+  <reg name="r8s2" bitsize="32"/>
+  <reg name="r9s2" bitsize="32"/>
+  <reg name="r10s2" bitsize="32"/>
+  <reg name="r11s2" bitsize="32"/>
+  <reg name="r12s2" bitsize="32"/>
+  <reg name="sps2" bitsize="32" type="data_ptr"/>
+  <reg name="lrs2" bitsize="32"/>
+  <reg name="pcs2" bitsize="32" type="code_ptr"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsrs2" bitsize="32" regnum="25"/>
+</feature>
diff --git a/coregrind/m_gdbserver/arm-core.xml b/coregrind/m_gdbserver/arm-core.xml
new file mode 100644 (file)
index 0000000..1624901
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.core">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+  <reg name="lr" bitsize="32"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsr" bitsize="32" regnum="25"/>
+</feature>
diff --git a/coregrind/m_gdbserver/arm-vfpv3-valgrind-s1.xml b/coregrind/m_gdbserver/arm-vfpv3-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..619f73f
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp.valgrind.s1">
+  <reg name="d0s1" bitsize="64" type="ieee_double"/>
+  <reg name="d1s1" bitsize="64" type="ieee_double"/>
+  <reg name="d2s1" bitsize="64" type="ieee_double"/>
+  <reg name="d3s1" bitsize="64" type="ieee_double"/>
+  <reg name="d4s1" bitsize="64" type="ieee_double"/>
+  <reg name="d5s1" bitsize="64" type="ieee_double"/>
+  <reg name="d6s1" bitsize="64" type="ieee_double"/>
+  <reg name="d7s1" bitsize="64" type="ieee_double"/>
+  <reg name="d8s1" bitsize="64" type="ieee_double"/>
+  <reg name="d9s1" bitsize="64" type="ieee_double"/>
+  <reg name="d10s1" bitsize="64" type="ieee_double"/>
+  <reg name="d11s1" bitsize="64" type="ieee_double"/>
+  <reg name="d12s1" bitsize="64" type="ieee_double"/>
+  <reg name="d13s1" bitsize="64" type="ieee_double"/>
+  <reg name="d14s1" bitsize="64" type="ieee_double"/>
+  <reg name="d15s1" bitsize="64" type="ieee_double"/>
+  <reg name="d16s1" bitsize="64" type="ieee_double"/>
+  <reg name="d17s1" bitsize="64" type="ieee_double"/>
+  <reg name="d18s1" bitsize="64" type="ieee_double"/>
+  <reg name="d19s1" bitsize="64" type="ieee_double"/>
+  <reg name="d20s1" bitsize="64" type="ieee_double"/>
+  <reg name="d21s1" bitsize="64" type="ieee_double"/>
+  <reg name="d22s1" bitsize="64" type="ieee_double"/>
+  <reg name="d23s1" bitsize="64" type="ieee_double"/>
+  <reg name="d24s1" bitsize="64" type="ieee_double"/>
+  <reg name="d25s1" bitsize="64" type="ieee_double"/>
+  <reg name="d26s1" bitsize="64" type="ieee_double"/>
+  <reg name="d27s1" bitsize="64" type="ieee_double"/>
+  <reg name="d28s1" bitsize="64" type="ieee_double"/>
+  <reg name="d29s1" bitsize="64" type="ieee_double"/>
+  <reg name="d30s1" bitsize="64" type="ieee_double"/>
+  <reg name="d31s1" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscrs1" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/arm-vfpv3-valgrind-s2.xml b/coregrind/m_gdbserver/arm-vfpv3-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..c0e8677
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp.valgrind.s2">
+  <reg name="d0s2" bitsize="64" type="ieee_double"/>
+  <reg name="d1s2" bitsize="64" type="ieee_double"/>
+  <reg name="d2s2" bitsize="64" type="ieee_double"/>
+  <reg name="d3s2" bitsize="64" type="ieee_double"/>
+  <reg name="d4s2" bitsize="64" type="ieee_double"/>
+  <reg name="d5s2" bitsize="64" type="ieee_double"/>
+  <reg name="d6s2" bitsize="64" type="ieee_double"/>
+  <reg name="d7s2" bitsize="64" type="ieee_double"/>
+  <reg name="d8s2" bitsize="64" type="ieee_double"/>
+  <reg name="d9s2" bitsize="64" type="ieee_double"/>
+  <reg name="d10s2" bitsize="64" type="ieee_double"/>
+  <reg name="d11s2" bitsize="64" type="ieee_double"/>
+  <reg name="d12s2" bitsize="64" type="ieee_double"/>
+  <reg name="d13s2" bitsize="64" type="ieee_double"/>
+  <reg name="d14s2" bitsize="64" type="ieee_double"/>
+  <reg name="d15s2" bitsize="64" type="ieee_double"/>
+  <reg name="d16s2" bitsize="64" type="ieee_double"/>
+  <reg name="d17s2" bitsize="64" type="ieee_double"/>
+  <reg name="d18s2" bitsize="64" type="ieee_double"/>
+  <reg name="d19s2" bitsize="64" type="ieee_double"/>
+  <reg name="d20s2" bitsize="64" type="ieee_double"/>
+  <reg name="d21s2" bitsize="64" type="ieee_double"/>
+  <reg name="d22s2" bitsize="64" type="ieee_double"/>
+  <reg name="d23s2" bitsize="64" type="ieee_double"/>
+  <reg name="d24s2" bitsize="64" type="ieee_double"/>
+  <reg name="d25s2" bitsize="64" type="ieee_double"/>
+  <reg name="d26s2" bitsize="64" type="ieee_double"/>
+  <reg name="d27s2" bitsize="64" type="ieee_double"/>
+  <reg name="d28s2" bitsize="64" type="ieee_double"/>
+  <reg name="d29s2" bitsize="64" type="ieee_double"/>
+  <reg name="d30s2" bitsize="64" type="ieee_double"/>
+  <reg name="d31s2" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscrs2" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/arm-vfpv3.xml b/coregrind/m_gdbserver/arm-vfpv3.xml
new file mode 100644 (file)
index 0000000..d0e9a59
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="ieee_double"/>
+  <reg name="d1" bitsize="64" type="ieee_double"/>
+  <reg name="d2" bitsize="64" type="ieee_double"/>
+  <reg name="d3" bitsize="64" type="ieee_double"/>
+  <reg name="d4" bitsize="64" type="ieee_double"/>
+  <reg name="d5" bitsize="64" type="ieee_double"/>
+  <reg name="d6" bitsize="64" type="ieee_double"/>
+  <reg name="d7" bitsize="64" type="ieee_double"/>
+  <reg name="d8" bitsize="64" type="ieee_double"/>
+  <reg name="d9" bitsize="64" type="ieee_double"/>
+  <reg name="d10" bitsize="64" type="ieee_double"/>
+  <reg name="d11" bitsize="64" type="ieee_double"/>
+  <reg name="d12" bitsize="64" type="ieee_double"/>
+  <reg name="d13" bitsize="64" type="ieee_double"/>
+  <reg name="d14" bitsize="64" type="ieee_double"/>
+  <reg name="d15" bitsize="64" type="ieee_double"/>
+  <reg name="d16" bitsize="64" type="ieee_double"/>
+  <reg name="d17" bitsize="64" type="ieee_double"/>
+  <reg name="d18" bitsize="64" type="ieee_double"/>
+  <reg name="d19" bitsize="64" type="ieee_double"/>
+  <reg name="d20" bitsize="64" type="ieee_double"/>
+  <reg name="d21" bitsize="64" type="ieee_double"/>
+  <reg name="d22" bitsize="64" type="ieee_double"/>
+  <reg name="d23" bitsize="64" type="ieee_double"/>
+  <reg name="d24" bitsize="64" type="ieee_double"/>
+  <reg name="d25" bitsize="64" type="ieee_double"/>
+  <reg name="d26" bitsize="64" type="ieee_double"/>
+  <reg name="d27" bitsize="64" type="ieee_double"/>
+  <reg name="d28" bitsize="64" type="ieee_double"/>
+  <reg name="d29" bitsize="64" type="ieee_double"/>
+  <reg name="d30" bitsize="64" type="ieee_double"/>
+  <reg name="d31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/coregrind/m_gdbserver/arm-with-vfpv3-valgrind.xml b/coregrind/m_gdbserver/arm-with-vfpv3-valgrind.xml
new file mode 100644 (file)
index 0000000..6501c9b
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <xi:include href="arm-core.xml"/>
+  <xi:include href="arm-vfpv3.xml"/>
+  <xi:include href="arm-core-valgrind-s1.xml"/>
+  <xi:include href="arm-vfpv3-valgrind-s1.xml"/>
+  <xi:include href="arm-core-valgrind-s2.xml"/>
+  <xi:include href="arm-vfpv3-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/arm-with-vfpv3.xml b/coregrind/m_gdbserver/arm-with-vfpv3.xml
new file mode 100644 (file)
index 0000000..319da1a
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <xi:include href="arm-core.xml"/>
+  <xi:include href="arm-vfpv3.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/gdb/signals.h b/coregrind/m_gdbserver/gdb/signals.h
new file mode 100644 (file)
index 0000000..c240f6b
--- /dev/null
@@ -0,0 +1,238 @@
+/* Target signal numbers for GDB and the GDB remote protocol.
+   Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+   1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef GDB_SIGNALS_H
+#define GDB_SIGNALS_H
+
+/* The numbering of these signals is chosen to match traditional unix
+   signals (insofar as various unices use the same numbers, anyway).
+   It is also the numbering of the GDB remote protocol.  Other remote
+   protocols, if they use a different numbering, should make sure to
+   translate appropriately.
+
+   Since these numbers have actually made it out into other software
+   (stubs, etc.), you mustn't disturb the assigned numbering.  If you
+   need to add new signals here, add them to the end of the explicitly
+   numbered signals, at the comment marker.  Add them unconditionally,
+   not within any #if or #ifdef.
+
+   This is based strongly on Unix/POSIX signals for several reasons:
+   (1) This set of signals represents a widely-accepted attempt to
+   represent events of this sort in a portable fashion, (2) we want a
+   signal to make it from wait to child_wait to the user intact, (3) many
+   remote protocols use a similar encoding.  However, it is
+   recognized that this set of signals has limitations (such as not
+   distinguishing between various kinds of SIGSEGV, or not
+   distinguishing hitting a breakpoint from finishing a single step).
+   So in the future we may get around this either by adding additional
+   signals for breakpoint, single-step, etc., or by adding signal
+   codes; the latter seems more in the spirit of what BSD, System V,
+   etc. are doing to address these issues.  */
+
+/* For an explanation of what each signal means, see
+   signals.c.  */
+
+enum target_signal
+  {
+    /* Used some places (e.g. stop_signal) to record the concept that
+       there is no signal.  */
+    TARGET_SIGNAL_0 = 0,
+    TARGET_SIGNAL_FIRST = 0,
+    TARGET_SIGNAL_HUP = 1,
+    TARGET_SIGNAL_INT = 2,
+    TARGET_SIGNAL_QUIT = 3,
+    TARGET_SIGNAL_ILL = 4,
+    TARGET_SIGNAL_TRAP = 5,
+    TARGET_SIGNAL_ABRT = 6,
+    TARGET_SIGNAL_EMT = 7,
+    TARGET_SIGNAL_FPE = 8,
+    TARGET_SIGNAL_KILL = 9,
+    TARGET_SIGNAL_BUS = 10,
+    TARGET_SIGNAL_SEGV = 11,
+    TARGET_SIGNAL_SYS = 12,
+    TARGET_SIGNAL_PIPE = 13,
+    TARGET_SIGNAL_ALRM = 14,
+    TARGET_SIGNAL_TERM = 15,
+    TARGET_SIGNAL_URG = 16,
+    TARGET_SIGNAL_STOP = 17,
+    TARGET_SIGNAL_TSTP = 18,
+    TARGET_SIGNAL_CONT = 19,
+    TARGET_SIGNAL_CHLD = 20,
+    TARGET_SIGNAL_TTIN = 21,
+    TARGET_SIGNAL_TTOU = 22,
+    TARGET_SIGNAL_IO = 23,
+    TARGET_SIGNAL_XCPU = 24,
+    TARGET_SIGNAL_XFSZ = 25,
+    TARGET_SIGNAL_VTALRM = 26,
+    TARGET_SIGNAL_PROF = 27,
+    TARGET_SIGNAL_WINCH = 28,
+    TARGET_SIGNAL_LOST = 29,
+    TARGET_SIGNAL_USR1 = 30,
+    TARGET_SIGNAL_USR2 = 31,
+    TARGET_SIGNAL_PWR = 32,
+    /* Similar to SIGIO.  Perhaps they should have the same number.  */
+    TARGET_SIGNAL_POLL = 33,
+    TARGET_SIGNAL_WIND = 34,
+    TARGET_SIGNAL_PHONE = 35,
+    TARGET_SIGNAL_WAITING = 36,
+    TARGET_SIGNAL_LWP = 37,
+    TARGET_SIGNAL_DANGER = 38,
+    TARGET_SIGNAL_GRANT = 39,
+    TARGET_SIGNAL_RETRACT = 40,
+    TARGET_SIGNAL_MSG = 41,
+    TARGET_SIGNAL_SOUND = 42,
+    TARGET_SIGNAL_SAK = 43,
+    TARGET_SIGNAL_PRIO = 44,
+    TARGET_SIGNAL_REALTIME_33 = 45,
+    TARGET_SIGNAL_REALTIME_34 = 46,
+    TARGET_SIGNAL_REALTIME_35 = 47,
+    TARGET_SIGNAL_REALTIME_36 = 48,
+    TARGET_SIGNAL_REALTIME_37 = 49,
+    TARGET_SIGNAL_REALTIME_38 = 50,
+    TARGET_SIGNAL_REALTIME_39 = 51,
+    TARGET_SIGNAL_REALTIME_40 = 52,
+    TARGET_SIGNAL_REALTIME_41 = 53,
+    TARGET_SIGNAL_REALTIME_42 = 54,
+    TARGET_SIGNAL_REALTIME_43 = 55,
+    TARGET_SIGNAL_REALTIME_44 = 56,
+    TARGET_SIGNAL_REALTIME_45 = 57,
+    TARGET_SIGNAL_REALTIME_46 = 58,
+    TARGET_SIGNAL_REALTIME_47 = 59,
+    TARGET_SIGNAL_REALTIME_48 = 60,
+    TARGET_SIGNAL_REALTIME_49 = 61,
+    TARGET_SIGNAL_REALTIME_50 = 62,
+    TARGET_SIGNAL_REALTIME_51 = 63,
+    TARGET_SIGNAL_REALTIME_52 = 64,
+    TARGET_SIGNAL_REALTIME_53 = 65,
+    TARGET_SIGNAL_REALTIME_54 = 66,
+    TARGET_SIGNAL_REALTIME_55 = 67,
+    TARGET_SIGNAL_REALTIME_56 = 68,
+    TARGET_SIGNAL_REALTIME_57 = 69,
+    TARGET_SIGNAL_REALTIME_58 = 70,
+    TARGET_SIGNAL_REALTIME_59 = 71,
+    TARGET_SIGNAL_REALTIME_60 = 72,
+    TARGET_SIGNAL_REALTIME_61 = 73,
+    TARGET_SIGNAL_REALTIME_62 = 74,
+    TARGET_SIGNAL_REALTIME_63 = 75,
+
+    /* Used internally by Solaris threads.  See signal(5) on Solaris.  */
+    TARGET_SIGNAL_CANCEL = 76,
+
+    /* Yes, this pains me, too.  But LynxOS didn't have SIG32, and now
+       GNU/Linux does, and we can't disturb the numbering, since it's
+       part of the remote protocol.  Note that in some GDB's
+       TARGET_SIGNAL_REALTIME_32 is number 76.  */
+    TARGET_SIGNAL_REALTIME_32,
+    /* Yet another pain, IRIX 6 has SIG64. */
+    TARGET_SIGNAL_REALTIME_64,
+    /* Yet another pain, GNU/Linux MIPS might go up to 128. */
+    TARGET_SIGNAL_REALTIME_65,
+    TARGET_SIGNAL_REALTIME_66,
+    TARGET_SIGNAL_REALTIME_67,
+    TARGET_SIGNAL_REALTIME_68,
+    TARGET_SIGNAL_REALTIME_69,
+    TARGET_SIGNAL_REALTIME_70,
+    TARGET_SIGNAL_REALTIME_71,
+    TARGET_SIGNAL_REALTIME_72,
+    TARGET_SIGNAL_REALTIME_73,
+    TARGET_SIGNAL_REALTIME_74,
+    TARGET_SIGNAL_REALTIME_75,
+    TARGET_SIGNAL_REALTIME_76,
+    TARGET_SIGNAL_REALTIME_77,
+    TARGET_SIGNAL_REALTIME_78,
+    TARGET_SIGNAL_REALTIME_79,
+    TARGET_SIGNAL_REALTIME_80,
+    TARGET_SIGNAL_REALTIME_81,
+    TARGET_SIGNAL_REALTIME_82,
+    TARGET_SIGNAL_REALTIME_83,
+    TARGET_SIGNAL_REALTIME_84,
+    TARGET_SIGNAL_REALTIME_85,
+    TARGET_SIGNAL_REALTIME_86,
+    TARGET_SIGNAL_REALTIME_87,
+    TARGET_SIGNAL_REALTIME_88,
+    TARGET_SIGNAL_REALTIME_89,
+    TARGET_SIGNAL_REALTIME_90,
+    TARGET_SIGNAL_REALTIME_91,
+    TARGET_SIGNAL_REALTIME_92,
+    TARGET_SIGNAL_REALTIME_93,
+    TARGET_SIGNAL_REALTIME_94,
+    TARGET_SIGNAL_REALTIME_95,
+    TARGET_SIGNAL_REALTIME_96,
+    TARGET_SIGNAL_REALTIME_97,
+    TARGET_SIGNAL_REALTIME_98,
+    TARGET_SIGNAL_REALTIME_99,
+    TARGET_SIGNAL_REALTIME_100,
+    TARGET_SIGNAL_REALTIME_101,
+    TARGET_SIGNAL_REALTIME_102,
+    TARGET_SIGNAL_REALTIME_103,
+    TARGET_SIGNAL_REALTIME_104,
+    TARGET_SIGNAL_REALTIME_105,
+    TARGET_SIGNAL_REALTIME_106,
+    TARGET_SIGNAL_REALTIME_107,
+    TARGET_SIGNAL_REALTIME_108,
+    TARGET_SIGNAL_REALTIME_109,
+    TARGET_SIGNAL_REALTIME_110,
+    TARGET_SIGNAL_REALTIME_111,
+    TARGET_SIGNAL_REALTIME_112,
+    TARGET_SIGNAL_REALTIME_113,
+    TARGET_SIGNAL_REALTIME_114,
+    TARGET_SIGNAL_REALTIME_115,
+    TARGET_SIGNAL_REALTIME_116,
+    TARGET_SIGNAL_REALTIME_117,
+    TARGET_SIGNAL_REALTIME_118,
+    TARGET_SIGNAL_REALTIME_119,
+    TARGET_SIGNAL_REALTIME_120,
+    TARGET_SIGNAL_REALTIME_121,
+    TARGET_SIGNAL_REALTIME_122,
+    TARGET_SIGNAL_REALTIME_123,
+    TARGET_SIGNAL_REALTIME_124,
+    TARGET_SIGNAL_REALTIME_125,
+    TARGET_SIGNAL_REALTIME_126,
+    TARGET_SIGNAL_REALTIME_127,
+
+    TARGET_SIGNAL_INFO,
+
+    /* Some signal we don't know about.  */
+    TARGET_SIGNAL_UNKNOWN,
+
+    /* Use whatever signal we use when one is not specifically specified
+       (for passing to proceed and so on).  */
+    TARGET_SIGNAL_DEFAULT,
+
+    /* Mach exceptions.  In versions of GDB before 5.2, these were just before
+       TARGET_SIGNAL_INFO if you were compiling on a Mach host (and missing
+       otherwise).  */
+    TARGET_EXC_BAD_ACCESS,
+    TARGET_EXC_BAD_INSTRUCTION,
+    TARGET_EXC_ARITHMETIC,
+    TARGET_EXC_EMULATION,
+    TARGET_EXC_SOFTWARE,
+    TARGET_EXC_BREAKPOINT,
+
+    /* If you are adding a new signal, add it just above this comment.  */
+
+    /* Last and unused enum value, for sizing arrays, etc.  */
+    TARGET_SIGNAL_LAST
+  };
+
+#endif /* #ifndef GDB_SIGNALS_H */
diff --git a/coregrind/m_gdbserver/i386-coresse-valgrind.xml b/coregrind/m_gdbserver/i386-coresse-valgrind.xml
new file mode 100644 (file)
index 0000000..1ec7c9e
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- I386 with SSE -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>i386</architecture>
+  <xi:include href="32bit-core.xml"/>
+  <xi:include href="32bit-sse.xml"/>
+  <xi:include href="32bit-core-valgrind-s1.xml"/>
+  <xi:include href="32bit-sse-valgrind-s1.xml"/>
+  <xi:include href="32bit-core-valgrind-s2.xml"/>
+  <xi:include href="32bit-sse-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/i386-linux-valgrind.xml b/coregrind/m_gdbserver/i386-linux-valgrind.xml
new file mode 100644 (file)
index 0000000..8720440
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- I386 with SSE - Includes Linux-only special "register".  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>i386</architecture>
+  <osabi>GNU/Linux</osabi>
+  <xi:include href="32bit-core.xml"/>
+  <xi:include href="32bit-sse.xml"/>
+  <xi:include href="32bit-linux.xml"/>
+  <xi:include href="32bit-core-valgrind-s1.xml"/>
+  <xi:include href="32bit-sse-valgrind-s1.xml"/>
+  <xi:include href="32bit-linux-valgrind-s1.xml"/>
+  <xi:include href="32bit-core-valgrind-s2.xml"/>
+  <xi:include href="32bit-sse-valgrind-s2.xml"/>
+  <xi:include href="32bit-linux-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/inferiors.c b/coregrind/m_gdbserver/inferiors.c
new file mode 100644 (file)
index 0000000..cdfea0b
--- /dev/null
@@ -0,0 +1,227 @@
+/* Inferior process information for the remote server for GDB.
+   Copyright (C) 2002, 2005, 2011
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+
+struct thread_info
+{
+   struct inferior_list_entry entry;
+   void *target_data;
+   void *regcache_data;
+   unsigned int gdb_id;
+};
+
+struct inferior_list all_threads;
+
+struct thread_info *current_inferior;
+
+#define get_thread(inf) ((struct thread_info *)(inf))
+
+void add_inferior_to_list (struct inferior_list *list,
+                     struct inferior_list_entry *new_inferior)
+{
+   new_inferior->next = NULL;
+   if (list->tail != NULL)
+      list->tail->next = new_inferior;
+   else
+      list->head = new_inferior;
+   list->tail = new_inferior;
+}
+
+void for_each_inferior (struct inferior_list *list,
+                  void (*action) (struct inferior_list_entry *))
+{
+   struct inferior_list_entry *cur = list->head, *next;
+
+   while (cur != NULL) {
+      next = cur->next;
+      (*action) (cur);
+      cur = next;
+   }
+}
+
+void change_inferior_id (struct inferior_list *list,
+                   unsigned long new_id)
+{
+   if (list->head != list->tail)
+      error ("tried to change thread ID after multiple threads are created\n");
+
+   list->head->id = new_id;
+}
+
+void remove_inferior (struct inferior_list *list,
+                struct inferior_list_entry *entry)
+{
+   struct inferior_list_entry **cur;
+
+   if (list->head == entry) {
+      list->head = entry->next;
+      if (list->tail == entry)
+         list->tail = list->head;
+      return;
+   }
+
+   cur = &list->head;
+   while (*cur && (*cur)->next != entry)
+      cur = &(*cur)->next;
+
+   if (*cur == NULL)
+      return;
+
+   (*cur)->next = entry->next;
+
+   if (list->tail == entry)
+      list->tail = *cur;
+}
+
+void add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
+{
+   struct thread_info *new_thread
+      = (struct thread_info *) malloc (sizeof (*new_thread));
+
+   VG_(memset) (new_thread, 0, sizeof (*new_thread));
+
+   new_thread->entry.id = thread_id;
+
+   add_inferior_to_list (&all_threads, & new_thread->entry);
+  
+   if (current_inferior == NULL)
+      current_inferior = new_thread;
+
+   new_thread->target_data = target_data;
+   set_inferior_regcache_data (new_thread, new_register_cache ());
+   new_thread->gdb_id = gdb_id;
+}
+
+unsigned int thread_id_to_gdb_id (unsigned long thread_id)
+{
+   struct inferior_list_entry *inf = all_threads.head;
+
+   while (inf != NULL) {
+      struct thread_info *thread = get_thread (inf);
+      if (inf->id == thread_id)
+         return thread->gdb_id;
+      inf = inf->next;
+   }
+
+   return 0;
+}
+
+unsigned int thread_to_gdb_id (struct thread_info *thread)
+{
+   return thread->gdb_id;
+}
+
+struct thread_info * gdb_id_to_thread (unsigned int gdb_id)
+{
+   struct inferior_list_entry *inf = all_threads.head;
+
+   while (inf != NULL) {
+      struct thread_info *thread = get_thread (inf);
+      if (thread->gdb_id == gdb_id)
+         return thread;
+      inf = inf->next;
+   }
+
+   return NULL;
+}
+
+unsigned long gdb_id_to_thread_id (unsigned int gdb_id)
+{
+   struct thread_info *thread = gdb_id_to_thread (gdb_id);
+
+   return thread ? thread->entry.id : 0;
+}
+
+static
+void free_one_thread (struct inferior_list_entry *inf)
+{
+   struct thread_info *thread = get_thread (inf);
+   free_register_cache (inferior_regcache_data (thread));
+   free (thread);
+}
+
+void remove_thread (struct thread_info *thread)
+{
+   remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
+   free_one_thread (&thread->entry);
+}
+
+void clear_inferiors (void)
+{
+   for_each_inferior (&all_threads, free_one_thread);
+
+   all_threads.head = all_threads.tail = NULL;
+}
+
+struct inferior_list_entry * find_inferior (struct inferior_list *list,
+                                            int (*func) 
+                                              (struct inferior_list_entry *,
+                                               void *),
+                                            void *arg)
+{
+   struct inferior_list_entry *inf = list->head;
+
+   while (inf != NULL) {
+      if ((*func) (inf, arg))
+         return inf;
+      inf = inf->next;
+   }
+   
+   return NULL;
+}
+
+struct inferior_list_entry * find_inferior_id (struct inferior_list *list,
+                                               unsigned long id)
+{
+   struct inferior_list_entry *inf = list->head;
+
+   while (inf != NULL) {
+      if (inf->id == id)
+         return inf;
+      inf = inf->next;
+   }
+   
+   return NULL;
+}
+
+void * inferior_target_data (struct thread_info *inferior)
+{
+   return inferior->target_data;
+}
+
+void set_inferior_target_data (struct thread_info *inferior, void *data)
+{
+   inferior->target_data = data;
+}
+
+void * inferior_regcache_data (struct thread_info *inferior)
+{
+   return inferior->regcache_data;
+}
+
+void set_inferior_regcache_data (struct thread_info *inferior, void *data)
+{
+   inferior->regcache_data = data;
+}
diff --git a/coregrind/m_gdbserver/m_gdbserver.c b/coregrind/m_gdbserver/m_gdbserver.c
new file mode 100644 (file)
index 0000000..cfde922
--- /dev/null
@@ -0,0 +1,1289 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Handle remote gdb protocol.                    m_gdbserver.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011 Philippe Waroquiers
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_gdbserver.h"
+#include "pub_core_options.h"
+#include "pub_core_libcsetjmp.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_tool_hashtable.h"
+#include "pub_core_libcassert.h"
+#include "pub_tool_libcbase.h"
+#include "pub_core_libcsignal.h"
+#include "pub_tool_machine.h"     // VG_(fnptr_to_fnentry)
+#include "pub_tool_debuginfo.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_syswrap.h"
+
+#include "server.h"
+
+Int VG_(dyn_vgdb_error);
+
+/* forward declarations */
+VG_REGPARM(1)
+void VG_(helperc_CallDebugger) ( HWord iaddr );
+VG_REGPARM(1)
+void VG_(helperc_invalidate_if_not_gdbserved) ( Addr addr );
+static void invalidate_current_ip (ThreadId tid, char *who);
+
+/* reasons of call to call_gdbserver. */
+typedef
+   enum {
+      init_reason,    // initialises gdbserver resources
+      vgdb_reason,    // gdbserver invocation by vgdb doing ptrace
+      core_reason,    // gdbserver invocation by core (e.g. error encountered)
+      break_reason,   // break encountered
+      watch_reason,   // watchpoint detected by tool
+      signal_reason}  // signal encountered
+    CallReason;
+
+static char* ppCallReason(CallReason reason)
+{
+   switch (reason) {
+   case init_reason:    return "init_reason";
+   case vgdb_reason:    return "vgdb_reason";
+   case core_reason:    return "core_reason";
+   case break_reason:   return "break_reason";
+   case watch_reason:   return "watch_reason";
+   case signal_reason:  return "signal_reason";
+   default: vg_assert (0);
+   }
+}
+
+/* An instruction instrumented for gdbserver looks like this:
+    1. Ist_Mark (0x1234)
+    2. helperc_CallDebugger (0x1234)   
+         This will give control to gdb if there is a break at 0x1234
+         or if we are single stepping
+    3. ... here the real IR for the instruction at 0x1234
+
+    When there is a break at 0x1234:
+      if user does "continue" or "step" or similar, 
+        then - the call to debugger returns
+             - valgrind executes at 3. the real IR(s) for 0x1234
+
+      if as part of helperc_CallDebugger, the user calls 
+      some code in gdb e.g print hello_world()
+        then - gdb prepares a dummy stack frame with a specific 
+               return address (typically it uses _start) and
+               inserts a break at this address
+             - gdb then puts in EIP the address of hello_world()
+             - gdb then continues (so the helperc_CallDebugger
+               returns)
+             - call_gdbserver() function will then return the
+               control to the scheduler (using VG_MINIMAL_LONGJMP)
+               to allow the block of the new EIP
+               to be executed.
+             - hello_world code is executed.
+             - when hello_world() returns, it returns to
+               _start and encounters the break at _start.
+             - gdb then removes this break, put 0x1234 in EIP
+               and does a "step". This causes to jump from
+               _start to 0x1234, where the call to 
+                helperc_CallDebugger is redone.
+             - This is all ok, the user can then give new gdb 
+               commands. 
+
+    However, when continue is given, address 0x1234 is to
+    be executed: gdb gives a single step, which must not 
+    report again the break at 0x1234. To avoid a 2nd report
+    of the same break, the below tells that the next 
+    helperc_CallDebugger call must ignore a break/stop at
+    this address.
+*/
+static Addr ignore_this_break_once = 0;
+
+
+static void call_gdbserver ( ThreadId tid , CallReason reason);
+
+/* convert from CORE_ADDR to void* */
+static
+void* C2v(CORE_ADDR addr)
+{
+   return (void*) addr;
+}
+
+/* Describes the address addr (for debugging/printing purposes).
+   Last two results are kept. A third call will replace the
+   oldest result. */
+static char* sym (Addr addr, Bool is_code)
+{
+   static char buf[2][200];
+   static int w = 0;
+   PtrdiffT offset;
+   if (w == 2) w = 0;
+   if (is_code) {
+      VG_(describe_IP) (addr, buf[w], 200);
+   } else {
+      VG_(get_datasym_and_offset) (addr, buf[w], 200, &offset);
+   }
+   return buf[w++];
+}
+
+/* Each time gdbserver is called, gdbserver_called is incremented
+   gdbserver_exited is incremented when gdbserver is asked to exit */
+static int gdbserver_called = 0;
+static int gdbserver_exited = 0;
+
+typedef
+   enum {
+     GS_break,
+     GS_jump
+   }
+   GS_Kind;
+
+typedef
+   struct _GS_Address {
+      struct _GS_Address* next;
+      Addr    addr;
+      GS_Kind kind;
+   }
+   GS_Address;
+
+/* gs_addresses contains a list of all addresses that have been invalidated
+   because they have been (or must be) instrumented for gdbserver. 
+   An entry is added in this table when there is a break at this
+   address (kind == GS_break) or if this address is the jump target of an
+   exit of a block that has been instrumented for gdbserver while
+   single stepping (kind == GS_jump).
+   When gdbserver is not single stepping anymore, all GS_jump entries
+   are removed, their translations are invalidated.
+*/
+static VgHashTable gs_addresses = NULL;
+
+static void add_gs_address (Addr addr, GS_Kind kind, char* from)
+{
+   GS_Address *p;
+
+   p = VG_(arena_malloc)(VG_AR_CORE, from, sizeof(GS_Address));
+   p->addr = addr;
+   p->kind = kind;
+   VG_(HT_add_node)(gs_addresses, p);
+   VG_(discard_translations) (addr, 1, from);
+}
+
+static void remove_gs_address (GS_Address* g, char* from)
+{
+   VG_(HT_remove) (gs_addresses, g->addr);
+   VG_(discard_translations) (g->addr, 1, from);
+   VG_(arena_free) (VG_AR_CORE, g);
+}
+
+char* VG_(ppPointKind) (PointKind kind)
+{
+   switch(kind) {
+   case software_breakpoint: return "software_breakpoint";
+   case hardware_breakpoint: return "hardware_breakpoint";
+   case write_watchpoint:    return "write_watchpoint";
+   case read_watchpoint:     return "read_watchpoint";
+   case access_watchpoint:   return "access_watchpoint";
+   default: vg_assert(0);
+   }
+}
+
+typedef
+   struct _GS_Watch {
+      struct _GS_Watch* next;
+      Addr    addr;
+      SizeT   len;
+      PointKind kind;
+   }
+   GS_Watch;
+
+/* gs_watches contains a list of all addresses+len that are being watched. */
+static VgHashTable gs_watches = NULL;
+
+
+/* protocol spec tells the below must be idempotent. */
+static void breakpoint (Bool insert, CORE_ADDR addr)
+{
+   GS_Address *g;
+
+   g = VG_(HT_lookup) (gs_addresses, (UWord)addr);
+   if (insert) {
+      /* insert a breakpoint at addr or upgrade its kind */
+      if (g == NULL) {
+         add_gs_address (addr, GS_break, "m_gdbserver breakpoint insert");
+      } else {
+         /* already gdbserved. Normally, it must be because of a jump.
+            However, due to idempotent or if connection with gdb was
+            lost (kept breaks from the previous gdb), if already existing,
+            we just upgrade its kind. */
+         g->kind = GS_break;
+      }
+   } else {
+      /* delete a breakpoint at addr or downgrade its kind */
+      if (g != NULL && g->kind == GS_break) {
+         if (valgrind_single_stepping()) {
+            /* keep gdbserved instrumentation while single stepping */
+            g->kind = GS_jump;
+         } else {
+            remove_gs_address (g, "m_gdbserver breakpoint remove");
+         }
+      } else {
+         dlog (1, "remove break addr %p %s\n",
+               C2v(addr), (g == NULL ? 
+                           "NULL" : 
+                           (g->kind == GS_jump ? "GS_jump" : "GS_break")));
+      }
+   }
+}
+
+static Bool (*tool_watchpoint) (PointKind kind, 
+                                Bool insert, 
+                                Addr addr,
+                                SizeT len) = NULL;
+void VG_(needs_watchpoint) (Bool (*watchpoint) (PointKind kind, 
+                                                Bool insert, 
+                                                Addr addr,
+                                                SizeT len))
+{
+   tool_watchpoint = watchpoint;
+}
+     
+Bool VG_(gdbserver_point) (PointKind kind, Bool insert,
+                           CORE_ADDR addr, int len)
+{
+   Bool res;
+   GS_Watch *g;
+   Bool is_code = kind == software_breakpoint || kind == hardware_breakpoint;
+
+   dlog(1, "%s %s at addr %p %s\n",
+        (insert ? "insert" : "remove"), 
+        VG_(ppPointKind) (kind),
+        C2v(addr), 
+        sym(addr, is_code));
+
+   if (is_code) {
+      breakpoint (insert, addr);
+      return True;
+   }
+
+   vg_assert (kind == access_watchpoint 
+              || kind == read_watchpoint 
+              || kind == write_watchpoint);
+
+   if (tool_watchpoint == NULL)
+      return False;
+
+   res = (*tool_watchpoint) (kind, insert, addr, len);
+   if (!res) 
+      return False; /* error or unsupported */
+
+   g = VG_(HT_lookup) (gs_watches, (UWord)addr);
+   if (insert) {
+      if (g == NULL) {
+         g = VG_(arena_malloc)(VG_AR_CORE, "gdbserver_point watchpoint",
+                               sizeof(GS_Watch));
+         g->addr = addr;
+         g->len  = len;
+         g->kind = kind;
+         VG_(HT_add_node)(gs_watches, g);
+      } else {
+         g->kind = kind;
+      }
+   } else {
+      vg_assert (g != NULL);
+      VG_(HT_remove) (gs_watches, g->addr);
+      VG_(arena_free) (VG_AR_CORE, g);
+   }  
+   return True;
+}
+
+Bool VG_(is_watched)(PointKind kind, Addr addr, Int szB)
+{
+   GS_Watch* g;
+   Bool watched = False;
+   const ThreadId tid = VG_(running_tid);
+
+   if (!gdbserver_called)
+      return False;
+
+   Addr to = addr + szB; // semi-open interval [addr, to[
+
+   vg_assert (kind == access_watchpoint 
+              || kind == read_watchpoint 
+              || kind == write_watchpoint);
+   dlog(1, "tid %d VG_(is_watched) %s addr %p szB %d\n",
+        tid, VG_(ppPointKind) (kind), C2v(addr), szB);
+   VG_(HT_ResetIter) (gs_watches);
+   while ((g = VG_(HT_Next) (gs_watches))) {
+      switch (g->kind) {
+      case software_breakpoint:
+      case hardware_breakpoint:
+         break;
+      case access_watchpoint:
+      case read_watchpoint:
+      case write_watchpoint:
+         if (to <= g->addr || addr >= (g->addr + g->len))
+            /* If no overlap, examine next watchpoint: */
+            continue;
+
+         watched = True; /* We have an overlap */
+
+         /* call gdbserver if access kind reported by the tool
+            matches the watchpoint kind. */
+         if (kind == access_watchpoint
+             || g->kind == access_watchpoint
+             || g->kind == kind) {
+            /* Watchpoint encountered.
+               If this is a read watchpoint, we directly call gdbserver
+               to report it to gdb.
+               Otherwise, for a write watchpoint, we have to finish
+               the instruction so as to modify the value.
+               If we do not finish the instruction, then gdb sees no
+               value change and continues.
+               For a read watchpoint, we better call gdbserver directly:
+               in case the current block is not gdbserved, Valgrind
+               will execute instructions till the next block. */
+
+            /* set the watchpoint stop address to the first read or written. */
+            if (g->addr <= addr) {
+               VG_(set_watchpoint_stop_address) (addr);
+            } else {
+               VG_(set_watchpoint_stop_address) (g->addr);
+            }
+
+            if (kind == write_watchpoint) {
+               /* Let Valgrind stop as early as possible after this instruction
+                  by switching to Single Stepping mode. */
+               valgrind_set_single_stepping (True);
+               invalidate_current_ip (tid, "m_gdbserver write watchpoint");
+            } else {
+               call_gdbserver (tid, watch_reason);
+               VG_(set_watchpoint_stop_address) ((Addr) 0);
+            }
+            return True; // we are watched here.
+         }
+         break;
+      default:
+         vg_assert (0);
+      }
+   }
+   return watched;
+}
+
+/* Returns the reason for which gdbserver instrumentation is needed */
+static VgVgdb VG_(gdbserver_instrumentation_needed) (VexGuestExtents* vge)
+{
+   GS_Address* g;
+   int e;
+
+   if (!gdbserver_called)
+      return Vg_VgdbNo;
+
+   if (valgrind_single_stepping()) {
+      dlog(2, "gdbserver_instrumentation_needed due to single stepping\n");
+      return Vg_VgdbYes;
+   }
+
+   if (VG_(clo_vgdb) == Vg_VgdbYes && VG_(HT_count_nodes) (gs_addresses) == 0)
+      return Vg_VgdbNo;
+
+   /* We assume we do not have a huge nr of breakpoints.
+      Otherwise, we need something more efficient e.g.
+      a sorted list of breakpoints or associate extents to it or ...
+   */
+   VG_(HT_ResetIter) (gs_addresses);
+   while ((g = VG_(HT_Next) (gs_addresses))) {
+      for (e = 0; e < vge->n_used; e++) {
+         if (g->addr >= vge->base[e] && g->addr < vge->base[e] + vge->len[e]) {
+            dlog(2,
+                 "gdbserver_instrumentation_needed %p %s reason %s\n",
+                 C2v(g->addr), sym(g->addr, /* is_code */ True),
+                 (g->kind == GS_jump ? "GS_jump" : "GS_break"));
+            return Vg_VgdbYes;
+         }
+      }
+   }
+
+   if (VG_(clo_vgdb) == Vg_VgdbFull) {
+      dlog(4, "gdbserver_instrumentation_needed"
+           " due to VG_(clo_vgdb) == Vg_VgdbFull\n");
+      return Vg_VgdbFull;
+   }
+
+
+   return Vg_VgdbNo;
+}
+
+// Clear gdbserved_addresses in gs_addresses.
+// If clear_only_jumps, clears only the addresses that are served
+// for jump reasons.
+// Otherwise, clear all the addresses.
+// Cleared addresses are invalidated so as to have them re-translated.
+static void clear_gdbserved_addresses(Bool clear_only_jumps)
+{
+   GS_Address** ag;
+   UInt n_elems;
+   int i;
+
+   dlog(1,
+        "clear_gdbserved_addresses: scanning hash table nodes %d\n", 
+        VG_(HT_count_nodes) (gs_addresses));
+   ag = (GS_Address**) VG_(HT_to_array) (gs_addresses, &n_elems);
+   for (i = 0; i < n_elems; i++)
+      if (!clear_only_jumps || ag[i]->kind == GS_jump)
+         remove_gs_address (ag[i], "clear_gdbserved_addresses");
+   VG_(free) (ag);
+}
+
+// Clear watched addressed in gs_watches
+static void clear_watched_addresses(void)
+{
+   GS_Watch** ag;
+   UInt n_elems;
+   int i;
+
+   dlog(1,
+        "clear_watched_addresses: scanning hash table nodes %d\n", 
+        VG_(HT_count_nodes) (gs_watches));
+   ag = (GS_Watch**) VG_(HT_to_array) (gs_watches, &n_elems);
+   for (i = 0; i < n_elems; i++) {
+      if (!VG_(gdbserver_point) (ag[i]->kind,
+                                 /* insert */ False,
+                                 ag[i]->addr,
+                                 ag[i]->len)) {
+         vg_assert (0);
+      }
+   }
+   VG_(free) (ag);
+}
+
+static void invalidate_if_jump_not_yet_gdbserved (Addr addr, char* from)
+{
+   if (VG_(HT_lookup) (gs_addresses, (UWord)addr))
+      return;
+   add_gs_address (addr, GS_jump, from);
+}
+
+static void invalidate_current_ip (ThreadId tid, char *who)
+{
+   invalidate_if_jump_not_yet_gdbserved (VG_(get_IP) (tid), who);
+}
+
+/* when fork is done, various cleanup is needed in the child process.
+   In particular, child must have its own connection to avoid stealing 
+   data from its parent */
+static void gdbserver_cleanup_in_child_after_fork(ThreadId me)
+{
+   dlog(1, "thread %d gdbserver_cleanup_in_child_after_fork pid %d\n",
+        me, VG_(getpid) ());
+
+   /* finish connection inheritated from parent */
+   remote_finish(reset_after_fork);
+
+   /* ensure next call to gdbserver will be considered as a brand
+      new call that will initialize a fresh gdbserver. */
+   if (gdbserver_called) {
+      gdbserver_called = 0;
+      vg_assert (gs_addresses != NULL);
+      vg_assert (gs_watches != NULL);
+      clear_gdbserved_addresses(/* clear only jumps */ False);
+      VG_(HT_destruct) (gs_addresses);
+      gs_addresses = NULL;
+      clear_watched_addresses();
+      VG_(HT_destruct) (gs_watches);
+      gs_watches = NULL;
+   } else {
+      vg_assert (gs_addresses == NULL);
+      vg_assert (gs_watches == NULL);
+   }
+}
+
+/* If reason is init_reason, creates the connection resources (e.g.
+      the FIFOs) to allow a gdb connection to be detected by polling
+      using remote_desc_activity.
+   Otherwise (other reasons):
+       If connection with gdb not yet opened, opens the connection with gdb.
+       reads gdb remote protocol packets and executes the requested commands.
+*/
+static void call_gdbserver ( ThreadId tid , CallReason reason)
+{
+   ThreadState*     tst = VG_(get_ThreadState)(tid);
+   int stepping;
+   Addr saved_pc;
+
+   dlog(1, 
+        "entering call_gdbserver %s ... pid %d tid %d status %s "
+        "sched_jmpbuf_valid %d\n",
+        ppCallReason (reason),
+        VG_(getpid) (), tid, VG_(name_of_ThreadStatus)(tst->status),
+        tst->sched_jmpbuf_valid);
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   saved_pc = VG_(get_IP) (tid);
+
+   if (gdbserver_exited) {
+      dlog(0, "call_gdbserver called when gdbserver_exited %d\n",
+           gdbserver_exited);
+      return;
+   }
+
+   if (gdbserver_called == 0) {
+      vg_assert (gs_addresses == NULL);
+      vg_assert (gs_watches == NULL);
+      gs_addresses = VG_(HT_construct)( "gdbserved_addresses" );
+      gs_watches = VG_(HT_construct)( "gdbserved_watches" );
+      VG_(atfork)(NULL, NULL, gdbserver_cleanup_in_child_after_fork);
+   }
+   vg_assert (gs_addresses != NULL);
+   vg_assert (gs_watches != NULL);
+   
+   gdbserver_called++;
+
+   /* call gdbserver_init if this is the first call to gdbserver. */
+   if (gdbserver_called == 1)
+      gdbserver_init();
+
+   if (reason == init_reason || gdbserver_called == 1)
+      remote_open(VG_(clo_vgdb_prefix));
+
+   /* if the call reason is to initialize, then return control to
+      valgrind. After this initialization, gdbserver will be called
+      again either if there is an error detected by valgrind or
+      if vgdb sends data to the valgrind process. */
+   if (reason == init_reason) {
+      return;
+   }
+
+   stepping = valgrind_single_stepping();
+
+   server_main();
+
+   ignore_this_break_once = valgrind_get_ignore_break_once();
+   if (ignore_this_break_once)
+      dlog(1, "!!! will ignore_this_break_once %s\n", 
+           sym(ignore_this_break_once, /* is_code */ True));
+      
+
+   if (valgrind_single_stepping()) {
+      /* we are single stepping. If we were not stepping on entry,
+         then invalidate the current program counter so as to properly
+         do single step. In case the program counter was changed by
+         gdb, this will also invalidate the target address we will
+         jump to. */
+      if (!stepping && tid != 0) {
+         invalidate_current_ip (tid, "m_gdbserver single step");
+      }
+   } else {
+      /* We are not single stepping.  If we were stepping on entry,
+         then clear the gdbserved addresses.  This will cause all
+         these gdbserved blocks to be invalidated so that they can be
+         re-translated without being gdbserved. */
+      if (stepping)
+         clear_gdbserved_addresses(/* clear only jumps */ True);
+   }
+   
+   /* can't do sanity check at beginning. At least the stack
+      check is not yet possible. */
+   if (gdbserver_called > 1)
+      VG_(sanity_check_general) (/* force_expensive */ False);
+
+   /* If the PC has been changed by gdb, then we VG_MINIMAL_LONGJMP to
+      the scheduler to execute the block of the new PC.
+      Otherwise we just return to continue executing the
+      current block. */
+   if (VG_(get_IP) (tid) != saved_pc) {
+      dlog(1, "tid %d %s PC changed from %s to %s\n",
+           tid, VG_(name_of_ThreadStatus) (tst->status),
+           sym(saved_pc, /* is_code */ True),
+           sym(VG_(get_IP) (tid), /* is_code */ True));
+      if (tst->status == VgTs_Yielding) {
+         SysRes sres;
+         VG_(memset)(&sres, 0, sizeof(SysRes));
+         VG_(acquire_BigLock)(tid, "gdbsrv VG_MINIMAL_LONGJMP");
+      }
+      if (tst->sched_jmpbuf_valid) {
+         /* resume scheduler */
+         VG_MINIMAL_LONGJMP(tst->sched_jmpbuf);
+      }
+      /* else continue to run */
+   }
+   /* continue to run */
+}
+
+/* busy > 0 when gdbserver is currently being called.
+   busy is used to to avoid vgdb invoking gdbserver
+   while gdbserver by Valgrind. */
+static volatile int busy = 0;
+
+void VG_(gdbserver) ( ThreadId tid )
+{
+   busy++;
+   /* called by the rest of valgrind for 
+         --vgdb-error=0 reason
+      or by scheduler "poll/debug/interrupt" reason
+      or to terminate. */
+   if (tid != 0) {
+      call_gdbserver (tid, core_reason);
+   } else {
+      if (gdbserver_called == 0) {
+         dlog(1, "VG_(gdbserver) called to terminate, nothing to terminate\n");
+      } else if (gdbserver_exited) {
+         dlog(0, "VG_(gdbserver) called to terminate again %d\n",
+              gdbserver_exited);
+      } else {
+         gdbserver_terminate();
+         gdbserver_exited++;
+      }
+   }
+   busy--;
+}
+
+// nr of invoke_gdbserver while gdbserver is already executing.
+static int interrupts_while_busy = 0;
+
+// nr of invoke_gdbserver while gdbserver is not executing.
+static int interrupts_non_busy = 0;
+
+// nr of invoke_gdbserver when some threads are not interruptible.
+static int interrupts_non_interruptible = 0;
+
+/* When all threads are blocked in a system call, the Valgrind
+   scheduler cannot poll the shared memory for gdbserver activity.  In
+   such a case, vgdb will force the invokation of gdbserver using
+   ptrace. To do that, vgdb 'pushes' a call to invoke_gdbserver
+   on the stack using ptrace. invoke_gdbserver must not return.
+   Instead, it must call give_control_back_to_vgdb.
+   vgdb expects to receive a SIGTRAP, which this function generates.
+   When vgdb gets this SIGTRAP, it knows invoke_gdbserver call
+   is finished and can reset the Valgrind process in the state prior to
+   the 'pushed call' (using ptrace again).
+   This all works well. However, the user must avoid
+   'kill-9ing' vgdb during such a pushed call, otherwise
+   the SIGTRAP generated below will be seen by the Valgrind core,
+   instead of being handled by vgdb. When the Valgrind core gets
+   such a SIGTRAP, it will assert. */
+
+static void give_control_back_to_vgdb(void)
+{
+   /* cause a SIGTRAP to be sent to ourself, so that vgdb takes control.
+      vgdb will then restore the stack so as to resume the activity
+      before the ptrace (typically do_syscall_WRK). */
+   if (VG_(kill)(VG_(getpid)(), VKI_SIGTRAP) != 0)
+      vg_assert2(0, "SIGTRAP for vgdb could not be generated\n");
+
+   /* If we arrive here, it means a call was pushed on the stack
+      by vgdb, but during this call, vgdb and/or connection
+      died. Alternatively, it is a bug in the vgdb<=>Valgrind gdbserver
+      ptrace handling. */
+   vg_assert2(0, 
+              "vgdb did not took control. Did you kill vgdb ?\n"
+              "busy %d vgdb_interrupted_tid %d\n",
+              busy, vgdb_interrupted_tid);
+}
+
+/* Using ptrace calls, vgdb will force an invocation of gdbserver.
+   VG_(invoke_gdbserver) is the entry point called through the
+   vgdb ptrace technique. */
+void VG_(invoke_gdbserver) ( int check )
+{
+   /* ******* Avoid non-reentrant function call from here ..... 
+      till the ".... till here" below. */
+
+   /* We need to determine the state of the various threads to decide
+      if we directly invoke gdbserver or if we rather indicate to the
+      scheduler to invoke the gdbserver.  To decide that, it is
+      critical to avoid any "coregrind" function call as the ptrace
+      might have stopped the process in the middle of this (possibly)
+      non-rentrant function.  So, it is only when all threads are in
+      an "interruptible" state that we can safely invoke
+      gdbserver. Otherwise, we let the valgrind scheduler invoke
+      gdbserver at the next poll.  This poll will be made very soon
+      thanks to a call to VG_(force_vgdb_poll). */
+   int n_tid;
+
+   vg_assert (check == 0x8BADF00D);
+
+   if (busy) {
+      interrupts_while_busy++;
+      give_control_back_to_vgdb();
+   }
+   interrupts_non_busy++;
+
+   /* check if all threads are in an "interruptible" state.  If yes,
+      we invoke gdbserver. Otherwise, we tell the scheduler to wake up
+      asap. */
+   for (n_tid = 1; n_tid < VG_N_THREADS; n_tid++) {
+      switch (VG_(threads)[n_tid].status) {
+      /* interruptible states. */
+      case VgTs_WaitSys:
+      case VgTs_Yielding:
+         if (vgdb_interrupted_tid == 0) vgdb_interrupted_tid = n_tid;
+         break;
+
+      case VgTs_Empty:     
+      case VgTs_Zombie:
+         break;
+
+      /* non interruptible states. */
+      case VgTs_Init:
+      case VgTs_Runnable:
+         interrupts_non_interruptible++;
+         VG_(force_vgdb_poll) ();
+         give_control_back_to_vgdb();
+
+      default:             vg_assert(0);
+      }
+   }
+
+   /* .... till here.
+      From here onwards, function calls are ok: it is
+      safe to call valgrind core functions: all threads are blocked in
+      a system call or are yielding or ... */
+   dlog(1, "invoke_gdbserver running_tid %d vgdb_interrupted_tid %d\n",
+        VG_(running_tid), vgdb_interrupted_tid);
+   call_gdbserver (vgdb_interrupted_tid, vgdb_reason);
+   vgdb_interrupted_tid = 0;
+   dlog(1,
+        "exit invoke_gdbserver running_tid %d\n", VG_(running_tid));
+   give_control_back_to_vgdb();
+
+   vg_assert2(0, "end of invoke_gdbserver reached");
+
+}
+
+Bool VG_(gdbserver_activity) (ThreadId tid)
+{
+   Bool ret;
+   busy++;
+   if (!gdbserver_called)
+      call_gdbserver (tid, init_reason);
+   switch (remote_desc_activity("VG_(gdbserver_activity)")) {
+   case 0: ret = False; break;
+   case 1: ret = True; break;
+   case 2: call_gdbserver (tid, init_reason); ret = False; break;
+   default: vg_assert (0);
+   }
+   busy--;
+   return ret;
+}
+
+Bool VG_(gdbserver_report_signal) (Int sigNo, ThreadId tid)
+{
+   dlog(1, "signal %d tid %d\n", sigNo, tid);
+
+   /* if gdbserver is currently not connected, then signal
+      is to be given to the process */
+   if (!remote_connected()) {
+       dlog(1, "not connected => pass\n");
+       return True;
+   }
+   if (pass_signals[sigNo]) {
+      dlog(1, "pass_signals => pass\n");
+      return False;
+   }
+   
+   /* indicate to gdbserver that there is a signal */
+   gdbserver_signal_encountered (sigNo);
+
+   /* let gdbserver do some work, e.g. show the signal to the user */
+   call_gdbserver (tid, signal_reason);
+   
+   /* ask gdbserver what is the final decision */
+   if (gdbserver_deliver_signal (sigNo)) {
+      dlog(1, "gdbserver deliver signal\n");
+      return True;
+   } else {
+      dlog(1, "gdbserver ignore signal\n");
+      return False;
+   }
+}
+
+// Check if single_stepping or if there is a break requested at iaddr. 
+// If yes, call debugger
+VG_REGPARM(1)
+void VG_(helperc_CallDebugger) ( HWord iaddr )
+{
+   GS_Address* g;
+
+   // For Vg_VgdbFull, after a fork, we might have calls to this helper
+   // while gdbserver is not yet initialized.
+   if (!gdbserver_called)
+      return;
+
+   if (valgrind_single_stepping() ||
+       ((g = VG_(HT_lookup) (gs_addresses, (UWord)iaddr)) &&
+        (g->kind == GS_break))) {
+      if (iaddr == ignore_this_break_once) {
+         dlog(1, "ignoring ignore_this_break_once %s\n", 
+              sym(ignore_this_break_once, /* is_code */ True));
+         ignore_this_break_once = 0;
+      } else {
+         call_gdbserver (VG_(get_running_tid)(), break_reason);
+      }
+   }
+}
+
+/* software_breakpoint support --------------------------------------*/
+/* When a block is instrumented for gdbserver, single step and breaks
+   will be obeyed in this block.  However, if a jump to another block
+   is executed while single_stepping is active, we must ensure that
+   this block is also instrumented. For this, when a block is
+   instrumented for gdbserver while single_stepping, the target of all
+   the Jump instructions in this block will be checked to verify if
+   the block is already instrumented for gdbserver.  The below will
+   ensure that if not already instrumented for gdbserver, the target
+   block translation containing addr will be invalidated.  The list of
+   gdbserved Addr will also be kept so that translations can be
+   dropped automatically by gdbserver when going out of single step
+   mode.
+
+   Call the below at translation time if the jump target is a constant. 
+   Otherwise, rather use VG_(add_stmt_call_invalidate_if_not_gdbserved).
+
+   To instrument the target exit statement, you can call
+   VG_(add_stmt_call_invalidate_exit_target_if_not_gdbserved) rather
+   than check the kind of target exit. */
+static void VG_(invalidate_if_not_gdbserved) (Addr addr)
+{
+   if (valgrind_single_stepping())
+      invalidate_if_jump_not_yet_gdbserved
+         (addr, "gdbserver target jump (instrument)");
+}
+
+// same as VG_(invalidate_if_not_gdbserved) but is intended to be called 
+// at runtime (only difference is the invalidate reason which traces 
+// it is at runtime)
+VG_REGPARM(1)
+void VG_(helperc_invalidate_if_not_gdbserved) ( Addr addr )
+{
+   if (valgrind_single_stepping())
+      invalidate_if_jump_not_yet_gdbserved
+         (addr, "gdbserver target jump (runtime)");
+}
+
+static void VG_(add_stmt_call_invalidate_if_not_gdbserved)
+     ( IRSB* sb_in,
+       VexGuestLayout* layout, 
+       VexGuestExtents* vge,
+       IRTemp jmp, 
+       IRSB* irsb)
+{
+   
+   void*    fn;
+   HChar*   nm;
+   IRExpr** args;
+   Int      nargs;
+   IRDirty* di;
+
+   fn    = &VG_(helperc_invalidate_if_not_gdbserved);
+   nm    = "VG_(helperc_invalidate_if_not_gdbserved)";
+   args  = mkIRExprVec_1(IRExpr_RdTmp (jmp));
+   nargs = 1;
+   
+   di = unsafeIRDirty_0_N( nargs/*regparms*/, nm, 
+                           VG_(fnptr_to_fnentry)( fn ), args );
+
+   di->nFxState = 0;
+
+   addStmtToIRSB(irsb, IRStmt_Dirty(di));
+}
+
+/* software_breakpoint support --------------------------------------*/
+/* If a tool wants to allow gdbserver to do something at Addr, then
+   VG_(add_stmt_call_gdbserver) will add in IRSB a call to a helper
+   function.  This helper function will check if the process must be
+   stopped at the instruction Addr: either there is a break at Addr or
+   the process is being single-stepped.  Typical usage of the below is to
+   instrument an Ist_IMark to allow the debugger to interact at any
+   instruction being executed.  As soon as there is one break in a block,
+   then to allow single stepping in this block (and possible insertions
+   of other breaks in the same sb_in while the process is stopped), a
+   debugger statement will be inserted for all instructions of a block. */
+static void VG_(add_stmt_call_gdbserver) 
+     (IRSB* sb_in,                /* block being translated */
+      VexGuestLayout* layout, 
+      VexGuestExtents* vge,
+      IRType gWordTy, IRType hWordTy,
+      Addr iaddr,                 /* Addr of instruction being instrumented */
+      IRSB* irsb)                 /* irsb block to which call is added */
+{
+   void*    fn;
+   HChar*   nm;
+   IRExpr** args;
+   Int      nargs;
+   IRDirty* di;
+
+   /* first store the address in the program counter so that the check
+      done by VG_(helperc_CallDebugger) will be based on the correct
+      program counter.  We might make this more efficient by rather
+      searching for assignement to program counter and instrumenting
+      that but the below is easier and I guess that the optimiser will
+      remove the redundant store. And in any case, when debugging a
+      piece of code, the efficiency requirement is not critical: very
+      few blocks will be instrumented for debugging. */
+   
+   addStmtToIRSB(irsb, IRStmt_Put(layout->offset_IP , mkIRExpr_HWord(iaddr)));
+
+   fn    = &VG_(helperc_CallDebugger);
+   nm    = "VG_(helperc_CallDebugger)";
+   args  = mkIRExprVec_1(mkIRExpr_HWord (iaddr));
+   nargs = 1;
+   
+   di = unsafeIRDirty_0_N( nargs/*regparms*/, nm, 
+                           VG_(fnptr_to_fnentry)( fn ), args );
+
+   /* Note: in fact, a debugger call can read whatever register
+      or memory. It can also write whatever register or memory.
+      So, in theory, we have to indicate the whole universe
+      can be read and modified. It is however not critical
+      to indicate precisely what is being read/written
+      as such indications are needed for tool error detection
+      and we do not want to have errors being detected for
+      gdb interactions. */
+   
+   di->nFxState = 2;
+   di->fxState[0].fx     = Ifx_Read;
+   di->fxState[0].offset = layout->offset_SP;
+   di->fxState[0].size   = layout->sizeof_SP;
+   di->fxState[1].fx     = Ifx_Modify;
+   di->fxState[1].offset = layout->offset_IP;
+   di->fxState[1].size   = layout->sizeof_IP;
+
+   addStmtToIRSB(irsb, IRStmt_Dirty(di));
+
+}
+
+
+/* Invalidate the target of the exit if needed:
+   If target is constant, it is invalidated at translation time.
+   Otherwise, a call to a helper function is generated to invalidate
+   the translation at run time.
+   The below is thus calling either VG_(invalidate_if_not_gdbserved)
+   or VG_(add_stmt_call_invalidate_if_not_gdbserved).  */
+static void VG_(add_stmt_call_invalidate_exit_target_if_not_gdbserved)
+   (IRSB* sb_in,
+    VexGuestLayout* layout,
+    VexGuestExtents* vge,
+    IRType gWordTy,
+    IRSB* irsb)
+{
+   if (sb_in->next->tag == Iex_Const) {
+     VG_(invalidate_if_not_gdbserved) (gWordTy == Ity_I64 ?
+                                       sb_in->next->Iex.Const.con->Ico.U64 
+                                       : sb_in->next->Iex.Const.con->Ico.U32);
+   } else if (sb_in->next->tag == Iex_RdTmp) {
+     VG_(add_stmt_call_invalidate_if_not_gdbserved)
+       (sb_in, layout, vge, sb_in->next->Iex.RdTmp.tmp, irsb);
+   } else {
+     vg_assert (0); /* unexpected expression tag in exit. */
+   }
+}
+
+IRSB* VG_(instrument_for_gdbserver_if_needed)
+     (IRSB* sb_in,
+      VexGuestLayout* layout,
+      VexGuestExtents* vge,
+      IRType gWordTy, IRType hWordTy)
+{
+   IRSB* sb_out;
+   Int i;
+   const VgVgdb instr_needed = VG_(gdbserver_instrumentation_needed) (vge);
+
+   if (instr_needed == Vg_VgdbNo)
+     return sb_in;
+
+
+   /* here, we need to instrument for gdbserver */
+   sb_out = deepCopyIRSBExceptStmts(sb_in);
+
+   for (i = 0; i < sb_in->stmts_used; i++) {
+      IRStmt* st = sb_in->stmts[i];
+      
+      if (!st || st->tag == Ist_NoOp) continue;
+      
+      if (st->tag == Ist_Exit && instr_needed == Vg_VgdbYes) {
+        VG_(invalidate_if_not_gdbserved) 
+          (hWordTy == Ity_I64 ? 
+           st->Ist.Exit.dst->Ico.U64 : 
+           st->Ist.Exit.dst->Ico.U32);
+      }
+      addStmtToIRSB( sb_out, st );
+      if (st->tag == Ist_IMark) {
+         /* For an Ist_Mark, add a call to debugger. */
+         switch (instr_needed) {
+         case Vg_VgdbNo: vg_assert (0);
+         case Vg_VgdbYes:
+         case Vg_VgdbFull:
+            VG_(add_stmt_call_gdbserver) ( sb_in, layout, vge,
+                                           gWordTy, hWordTy,
+                                           st->Ist.IMark.addr,
+                                           sb_out);
+            /* There is an optimisation possible here for Vg_VgdbFull:
+               Put a guard ensuring we only call gdbserver if 'FullCallNeeded'.
+               FullCallNeeded would be set to 1 we have just switched on
+               Single Stepping or have just encountered a watchpoint
+               or have just inserted a breakpoint.
+               (as gdb by default removes and re-insert breakpoints), we would
+               need to also implement the notion of 'breakpoint pending removal'
+               to remove at the next 'continue/step' packet. */
+            break;
+         default: vg_assert (0);
+         }
+      }
+   }
+
+   if (instr_needed == Vg_VgdbYes) {
+      VG_(add_stmt_call_invalidate_exit_target_if_not_gdbserved) (sb_in,
+                                                                  layout, vge,
+                                                                  gWordTy,
+                                                                  sb_out);
+   }
+
+   return sb_out;
+}
+
+struct mon_out_buf {
+   char buf[DATASIZ+1];
+   int next;
+   UInt ret;
+};
+
+static void mon_out (HChar c, void *opaque)
+{
+   struct mon_out_buf *b = (struct mon_out_buf *) opaque;
+   b->ret++;
+   b->buf[b->next] = c;
+   b->next++;
+   if (b->next == DATASIZ) {
+      b->buf[b->next] = '\0';
+      monitor_output(b->buf);
+      b->next = 0;
+   }
+}
+UInt VG_(gdb_printf) ( const HChar *format, ... )
+{
+   struct mon_out_buf b;
+
+   b.next = 0;
+   b.ret = 0;
+   
+   va_list vargs;
+   va_start(vargs, format);
+   VG_(vcbprintf) (mon_out, &b, format, vargs);
+   va_end(vargs);
+   
+   if (b.next > 0) {
+      b.buf[b.next] = '\0';
+      monitor_output(b.buf);
+   }
+   return b.ret;
+}
+
+Int VG_(keyword_id) (Char* keywords, Char* input_word, kwd_report_error report)
+{
+   const Int il = (input_word == NULL ? 0 : VG_(strlen) (input_word));
+   Char  iw[il+1];
+   Char  kwds[VG_(strlen)(keywords)+1];
+   Char  *kwdssaveptr;
+
+   Char* kw; /* current keyword, its length, its position */
+   Int   kwl;
+   Int   kpos = -1;
+
+   Int pass; 
+   /* pass 0 = search, optional pass 1 = output message multiple matches */
+
+   Int pass1needed = 0;
+
+   Int partial_match = -1;
+   Int full_match = -1;
+
+   if (input_word == NULL) {
+      iw[0] = 0;
+      partial_match = 0; /* to force an empty string to cause an error */
+   } else {
+      VG_(strcpy) (iw, input_word);
+   }
+
+   for (pass = 0; pass < 2; pass++) {
+      VG_(strcpy) (kwds, keywords);
+      if (pass == 1)
+         VG_(gdb_printf) ("%s can match", 
+                          (il == 0 ? "<empty string>" : (char *) iw));
+      for (kw = VG_(strtok_r) (kwds, " ", &kwdssaveptr); 
+           kw != NULL; 
+           kw = VG_(strtok_r) (NULL, " ", &kwdssaveptr)) {
+         kwl = VG_(strlen) (kw);
+         kpos++;
+         
+         if (il > kwl) {
+            ; /* ishtar !~ is */
+         } else if (il == kwl) {
+            if (VG_(strcmp) (kw, iw) == 0) {
+               /* exact match */
+               if (pass == 1)
+                  VG_(gdb_printf) (" %s", kw);
+               if (full_match != -1)
+                  pass1needed++;
+               full_match = kpos;
+            }
+         } else {
+            /* il < kwl */
+            if (VG_(strncmp) (iw, kw, il) == 0) {
+               /* partial match */
+               if (pass == 1)
+                  VG_(gdb_printf) (" %s", kw);
+               if (partial_match != -1)
+                  pass1needed++;
+               partial_match = kpos;
+            }
+         }
+      }
+      /* check for success or for no match at all */
+      if (pass1needed == 0) {
+         if (full_match != -1) {
+            return full_match;
+         } else {
+            if (report == kwd_report_all && partial_match == -1) {
+               VG_(gdb_printf) ("%s does not match any of '%s'\n", 
+                                iw, keywords);
+            }
+            return partial_match;
+         }
+      }
+
+      /* here we have duplicated match error */
+      if (pass == 1 || report == kwd_report_none) {
+         if (report != kwd_report_none) {
+            VG_(gdb_printf) ("\n");
+         }
+         if (partial_match != -1 || full_match != -1)
+            return -2;
+         else
+            return -1;
+      }
+   }
+   /* UNREACHED */
+   vg_assert (0);
+}
+
+/* True if string can be a 0x number */
+static Bool is_zero_x (Char *s)
+{
+   if (strlen (s) >= 3 && s[0] == '0' && s[1] == 'x')
+      return True;
+   else
+      return False;
+}
+
+/* True if string can be a 0b number */
+static Bool is_zero_b (Char *s)
+{
+   if (strlen (s) >= 3 && s[0] == '0' && s[1] == 'b')
+      return True;
+   else
+      return False;
+}
+
+void VG_(strtok_get_address_and_size) (Addr* address, 
+                                       SizeT* szB, 
+                                       Char **ssaveptr)
+{
+   Char* wa;
+   Char* ws;
+   Char* endptr;
+   UChar *ppc;
+
+   wa = VG_(strtok_r) (NULL, " ", ssaveptr);
+   ppc = wa;
+   if (ppc == NULL || !VG_(parse_Addr) (&ppc, address)) {
+      VG_(gdb_printf) ("missing or malformed address\n");
+      *address = (Addr) 0;
+      *szB = 0;
+      return;
+   }
+   ws = VG_(strtok_r) (NULL, " ", ssaveptr);
+   if (ws == NULL) {
+      /* Do nothing, i.e. keep current value of szB. */ ;
+   } else if (is_zero_x (ws)) {
+      *szB = VG_(strtoull16) (ws, &endptr);
+   } else if (is_zero_b (ws)) {
+      Int j;
+      Char *parsews = ws;
+      Int n_bits = VG_(strlen) (ws) - 2;
+      *szB = 0;
+      ws = NULL; // assume the below loop gives a correct nr.
+      for (j = 0; j < n_bits; j++) {
+         if      ('0' == parsews[j+2]) { /* do nothing */ }
+         else if ('1' == parsews[j+2]) *szB |= (1 << (n_bits-j-1));
+         else {
+            /* report malformed binary integer */
+            ws = parsews;
+            endptr = ws + j + 2;
+            break;
+         }
+      }
+   } else {
+      *szB = VG_(strtoull10) (ws, &endptr);
+   }
+
+   if (ws != NULL && *endptr != '\0') {
+      VG_(gdb_printf) ("malformed integer, expecting "
+                       "hex 0x..... or dec ...... or binary .....b\n");
+      *address = (Addr) 0;
+      *szB = 0;
+      return;
+   }
+}
+
+void VG_(gdbserver_status_output)(void)
+{
+   const int nr_gdbserved_addresses 
+      = (gs_addresses == NULL ? -1 : VG_(HT_count_nodes) (gs_addresses));
+   const int nr_watchpoints
+      = (gs_watches == NULL ? -1 : VG_(HT_count_nodes) (gs_watches));
+   remote_utils_output_status();
+   VG_(umsg)
+      ("nr of calls to gdbserver: %d\n"
+       "single stepping %d\n"
+       "interrupts intr_tid %d gs_non_busy %d gs_busy %d tid_non_intr %d\n"
+       "gdbserved addresses %d (-1 = not initialized)\n"
+       "watchpoints %d (-1 = not initialized)\n"
+       "vgdb-error %d\n",
+       gdbserver_called,
+       valgrind_single_stepping(),
+       
+       vgdb_interrupted_tid, 
+       interrupts_non_busy, 
+       interrupts_while_busy,
+       interrupts_non_interruptible,
+       
+       nr_gdbserved_addresses,
+       nr_watchpoints,
+       VG_(dyn_vgdb_error));
+}
diff --git a/coregrind/m_gdbserver/power-altivec-valgrind-s1.xml b/coregrind/m_gdbserver/power-altivec-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..8073622
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.altivec-valgrind-s1">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <union id="vec128">
+    <field name="uint128" type="uint128"/>
+    <field name="v4_float" type="v4f"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v16_int8" type="v16i8"/>
+  </union>
+
+  <reg name="vr0s1" bitsize="128" type="vec128"/>
+  <reg name="vr1s1" bitsize="128" type="vec128"/>
+  <reg name="vr2s1" bitsize="128" type="vec128"/>
+  <reg name="vr3s1" bitsize="128" type="vec128"/>
+  <reg name="vr4s1" bitsize="128" type="vec128"/>
+  <reg name="vr5s1" bitsize="128" type="vec128"/>
+  <reg name="vr6s1" bitsize="128" type="vec128"/>
+  <reg name="vr7s1" bitsize="128" type="vec128"/>
+  <reg name="vr8s1" bitsize="128" type="vec128"/>
+  <reg name="vr9s1" bitsize="128" type="vec128"/>
+  <reg name="vr10s1" bitsize="128" type="vec128"/>
+  <reg name="vr11s1" bitsize="128" type="vec128"/>
+  <reg name="vr12s1" bitsize="128" type="vec128"/>
+  <reg name="vr13s1" bitsize="128" type="vec128"/>
+  <reg name="vr14s1" bitsize="128" type="vec128"/>
+  <reg name="vr15s1" bitsize="128" type="vec128"/>
+  <reg name="vr16s1" bitsize="128" type="vec128"/>
+  <reg name="vr17s1" bitsize="128" type="vec128"/>
+  <reg name="vr18s1" bitsize="128" type="vec128"/>
+  <reg name="vr19s1" bitsize="128" type="vec128"/>
+  <reg name="vr20s1" bitsize="128" type="vec128"/>
+  <reg name="vr21s1" bitsize="128" type="vec128"/>
+  <reg name="vr22s1" bitsize="128" type="vec128"/>
+  <reg name="vr23s1" bitsize="128" type="vec128"/>
+  <reg name="vr24s1" bitsize="128" type="vec128"/>
+  <reg name="vr25s1" bitsize="128" type="vec128"/>
+  <reg name="vr26s1" bitsize="128" type="vec128"/>
+  <reg name="vr27s1" bitsize="128" type="vec128"/>
+  <reg name="vr28s1" bitsize="128" type="vec128"/>
+  <reg name="vr29s1" bitsize="128" type="vec128"/>
+  <reg name="vr30s1" bitsize="128" type="vec128"/>
+  <reg name="vr31s1" bitsize="128" type="vec128"/>
+
+  <reg name="vscrs1" bitsize="32" group="vector"/>
+  <reg name="vrsaves1" bitsize="32" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-altivec-valgrind-s2.xml b/coregrind/m_gdbserver/power-altivec-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..fe3a427
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.altivec-valgrind-s2">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <union id="vec128">
+    <field name="uint128" type="uint128"/>
+    <field name="v4_float" type="v4f"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v16_int8" type="v16i8"/>
+  </union>
+
+  <reg name="vr0s2" bitsize="128" type="vec128"/>
+  <reg name="vr1s2" bitsize="128" type="vec128"/>
+  <reg name="vr2s2" bitsize="128" type="vec128"/>
+  <reg name="vr3s2" bitsize="128" type="vec128"/>
+  <reg name="vr4s2" bitsize="128" type="vec128"/>
+  <reg name="vr5s2" bitsize="128" type="vec128"/>
+  <reg name="vr6s2" bitsize="128" type="vec128"/>
+  <reg name="vr7s2" bitsize="128" type="vec128"/>
+  <reg name="vr8s2" bitsize="128" type="vec128"/>
+  <reg name="vr9s2" bitsize="128" type="vec128"/>
+  <reg name="vr10s2" bitsize="128" type="vec128"/>
+  <reg name="vr11s2" bitsize="128" type="vec128"/>
+  <reg name="vr12s2" bitsize="128" type="vec128"/>
+  <reg name="vr13s2" bitsize="128" type="vec128"/>
+  <reg name="vr14s2" bitsize="128" type="vec128"/>
+  <reg name="vr15s2" bitsize="128" type="vec128"/>
+  <reg name="vr16s2" bitsize="128" type="vec128"/>
+  <reg name="vr17s2" bitsize="128" type="vec128"/>
+  <reg name="vr18s2" bitsize="128" type="vec128"/>
+  <reg name="vr19s2" bitsize="128" type="vec128"/>
+  <reg name="vr20s2" bitsize="128" type="vec128"/>
+  <reg name="vr21s2" bitsize="128" type="vec128"/>
+  <reg name="vr22s2" bitsize="128" type="vec128"/>
+  <reg name="vr23s2" bitsize="128" type="vec128"/>
+  <reg name="vr24s2" bitsize="128" type="vec128"/>
+  <reg name="vr25s2" bitsize="128" type="vec128"/>
+  <reg name="vr26s2" bitsize="128" type="vec128"/>
+  <reg name="vr27s2" bitsize="128" type="vec128"/>
+  <reg name="vr28s2" bitsize="128" type="vec128"/>
+  <reg name="vr29s2" bitsize="128" type="vec128"/>
+  <reg name="vr30s2" bitsize="128" type="vec128"/>
+  <reg name="vr31s2" bitsize="128" type="vec128"/>
+
+  <reg name="vscrs2" bitsize="32" group="vector"/>
+  <reg name="vrsaves2" bitsize="32" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-altivec.xml b/coregrind/m_gdbserver/power-altivec.xml
new file mode 100644 (file)
index 0000000..45d31af
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.altivec">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <union id="vec128">
+    <field name="uint128" type="uint128"/>
+    <field name="v4_float" type="v4f"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v16_int8" type="v16i8"/>
+  </union>
+
+  <reg name="vr0" bitsize="128" type="vec128"/>
+  <reg name="vr1" bitsize="128" type="vec128"/>
+  <reg name="vr2" bitsize="128" type="vec128"/>
+  <reg name="vr3" bitsize="128" type="vec128"/>
+  <reg name="vr4" bitsize="128" type="vec128"/>
+  <reg name="vr5" bitsize="128" type="vec128"/>
+  <reg name="vr6" bitsize="128" type="vec128"/>
+  <reg name="vr7" bitsize="128" type="vec128"/>
+  <reg name="vr8" bitsize="128" type="vec128"/>
+  <reg name="vr9" bitsize="128" type="vec128"/>
+  <reg name="vr10" bitsize="128" type="vec128"/>
+  <reg name="vr11" bitsize="128" type="vec128"/>
+  <reg name="vr12" bitsize="128" type="vec128"/>
+  <reg name="vr13" bitsize="128" type="vec128"/>
+  <reg name="vr14" bitsize="128" type="vec128"/>
+  <reg name="vr15" bitsize="128" type="vec128"/>
+  <reg name="vr16" bitsize="128" type="vec128"/>
+  <reg name="vr17" bitsize="128" type="vec128"/>
+  <reg name="vr18" bitsize="128" type="vec128"/>
+  <reg name="vr19" bitsize="128" type="vec128"/>
+  <reg name="vr20" bitsize="128" type="vec128"/>
+  <reg name="vr21" bitsize="128" type="vec128"/>
+  <reg name="vr22" bitsize="128" type="vec128"/>
+  <reg name="vr23" bitsize="128" type="vec128"/>
+  <reg name="vr24" bitsize="128" type="vec128"/>
+  <reg name="vr25" bitsize="128" type="vec128"/>
+  <reg name="vr26" bitsize="128" type="vec128"/>
+  <reg name="vr27" bitsize="128" type="vec128"/>
+  <reg name="vr28" bitsize="128" type="vec128"/>
+  <reg name="vr29" bitsize="128" type="vec128"/>
+  <reg name="vr30" bitsize="128" type="vec128"/>
+  <reg name="vr31" bitsize="128" type="vec128"/>
+
+  <reg name="vscr" bitsize="32" group="vector"/>
+  <reg name="vrsave" bitsize="32" group="vector"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-core.xml b/coregrind/m_gdbserver/power-core.xml
new file mode 100644 (file)
index 0000000..9acb3ad
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+  <reg name="r0" bitsize="32" type="uint32"/>
+  <reg name="r1" bitsize="32" type="uint32"/>
+  <reg name="r2" bitsize="32" type="uint32"/>
+  <reg name="r3" bitsize="32" type="uint32"/>
+  <reg name="r4" bitsize="32" type="uint32"/>
+  <reg name="r5" bitsize="32" type="uint32"/>
+  <reg name="r6" bitsize="32" type="uint32"/>
+  <reg name="r7" bitsize="32" type="uint32"/>
+  <reg name="r8" bitsize="32" type="uint32"/>
+  <reg name="r9" bitsize="32" type="uint32"/>
+  <reg name="r10" bitsize="32" type="uint32"/>
+  <reg name="r11" bitsize="32" type="uint32"/>
+  <reg name="r12" bitsize="32" type="uint32"/>
+  <reg name="r13" bitsize="32" type="uint32"/>
+  <reg name="r14" bitsize="32" type="uint32"/>
+  <reg name="r15" bitsize="32" type="uint32"/>
+  <reg name="r16" bitsize="32" type="uint32"/>
+  <reg name="r17" bitsize="32" type="uint32"/>
+  <reg name="r18" bitsize="32" type="uint32"/>
+  <reg name="r19" bitsize="32" type="uint32"/>
+  <reg name="r20" bitsize="32" type="uint32"/>
+  <reg name="r21" bitsize="32" type="uint32"/>
+  <reg name="r22" bitsize="32" type="uint32"/>
+  <reg name="r23" bitsize="32" type="uint32"/>
+  <reg name="r24" bitsize="32" type="uint32"/>
+  <reg name="r25" bitsize="32" type="uint32"/>
+  <reg name="r26" bitsize="32" type="uint32"/>
+  <reg name="r27" bitsize="32" type="uint32"/>
+  <reg name="r28" bitsize="32" type="uint32"/>
+  <reg name="r29" bitsize="32" type="uint32"/>
+  <reg name="r30" bitsize="32" type="uint32"/>
+  <reg name="r31" bitsize="32" type="uint32"/>
+
+  <reg name="pc" bitsize="32" type="code_ptr" regnum="64"/>
+  <reg name="msr" bitsize="32" type="uint32"/>
+  <reg name="cr" bitsize="32" type="uint32"/>
+  <reg name="lr" bitsize="32" type="code_ptr"/>
+  <reg name="ctr" bitsize="32" type="uint32"/>
+  <reg name="xer" bitsize="32" type="uint32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-fpu-valgrind-s1.xml b/coregrind/m_gdbserver/power-fpu-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..01b852e
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.fpu-valgrind-s1">
+  <reg name="f0s1" bitsize="64" type="ieee_double" regnum="32"/>
+  <reg name="f1s1" bitsize="64" type="ieee_double"/>
+  <reg name="f2s1" bitsize="64" type="ieee_double"/>
+  <reg name="f3s1" bitsize="64" type="ieee_double"/>
+  <reg name="f4s1" bitsize="64" type="ieee_double"/>
+  <reg name="f5s1" bitsize="64" type="ieee_double"/>
+  <reg name="f6s1" bitsize="64" type="ieee_double"/>
+  <reg name="f7s1" bitsize="64" type="ieee_double"/>
+  <reg name="f8s1" bitsize="64" type="ieee_double"/>
+  <reg name="f9s1" bitsize="64" type="ieee_double"/>
+  <reg name="f10s1" bitsize="64" type="ieee_double"/>
+  <reg name="f11s1" bitsize="64" type="ieee_double"/>
+  <reg name="f12s1" bitsize="64" type="ieee_double"/>
+  <reg name="f13s1" bitsize="64" type="ieee_double"/>
+  <reg name="f14s1" bitsize="64" type="ieee_double"/>
+  <reg name="f15s1" bitsize="64" type="ieee_double"/>
+  <reg name="f16s1" bitsize="64" type="ieee_double"/>
+  <reg name="f17s1" bitsize="64" type="ieee_double"/>
+  <reg name="f18s1" bitsize="64" type="ieee_double"/>
+  <reg name="f19s1" bitsize="64" type="ieee_double"/>
+  <reg name="f20s1" bitsize="64" type="ieee_double"/>
+  <reg name="f21s1" bitsize="64" type="ieee_double"/>
+  <reg name="f22s1" bitsize="64" type="ieee_double"/>
+  <reg name="f23s1" bitsize="64" type="ieee_double"/>
+  <reg name="f24s1" bitsize="64" type="ieee_double"/>
+  <reg name="f25s1" bitsize="64" type="ieee_double"/>
+  <reg name="f26s1" bitsize="64" type="ieee_double"/>
+  <reg name="f27s1" bitsize="64" type="ieee_double"/>
+  <reg name="f28s1" bitsize="64" type="ieee_double"/>
+  <reg name="f29s1" bitsize="64" type="ieee_double"/>
+  <reg name="f30s1" bitsize="64" type="ieee_double"/>
+  <reg name="f31s1" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscrs1" bitsize="32" group="float" regnum="70"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-fpu-valgrind-s2.xml b/coregrind/m_gdbserver/power-fpu-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..2db1a4a
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.fpu-valgrind-s2">
+  <reg name="f0s2" bitsize="64" type="ieee_double" regnum="32"/>
+  <reg name="f1s2" bitsize="64" type="ieee_double"/>
+  <reg name="f2s2" bitsize="64" type="ieee_double"/>
+  <reg name="f3s2" bitsize="64" type="ieee_double"/>
+  <reg name="f4s2" bitsize="64" type="ieee_double"/>
+  <reg name="f5s2" bitsize="64" type="ieee_double"/>
+  <reg name="f6s2" bitsize="64" type="ieee_double"/>
+  <reg name="f7s2" bitsize="64" type="ieee_double"/>
+  <reg name="f8s2" bitsize="64" type="ieee_double"/>
+  <reg name="f9s2" bitsize="64" type="ieee_double"/>
+  <reg name="f10s2" bitsize="64" type="ieee_double"/>
+  <reg name="f11s2" bitsize="64" type="ieee_double"/>
+  <reg name="f12s2" bitsize="64" type="ieee_double"/>
+  <reg name="f13s2" bitsize="64" type="ieee_double"/>
+  <reg name="f14s2" bitsize="64" type="ieee_double"/>
+  <reg name="f15s2" bitsize="64" type="ieee_double"/>
+  <reg name="f16s2" bitsize="64" type="ieee_double"/>
+  <reg name="f17s2" bitsize="64" type="ieee_double"/>
+  <reg name="f18s2" bitsize="64" type="ieee_double"/>
+  <reg name="f19s2" bitsize="64" type="ieee_double"/>
+  <reg name="f20s2" bitsize="64" type="ieee_double"/>
+  <reg name="f21s2" bitsize="64" type="ieee_double"/>
+  <reg name="f22s2" bitsize="64" type="ieee_double"/>
+  <reg name="f23s2" bitsize="64" type="ieee_double"/>
+  <reg name="f24s2" bitsize="64" type="ieee_double"/>
+  <reg name="f25s2" bitsize="64" type="ieee_double"/>
+  <reg name="f26s2" bitsize="64" type="ieee_double"/>
+  <reg name="f27s2" bitsize="64" type="ieee_double"/>
+  <reg name="f28s2" bitsize="64" type="ieee_double"/>
+  <reg name="f29s2" bitsize="64" type="ieee_double"/>
+  <reg name="f30s2" bitsize="64" type="ieee_double"/>
+  <reg name="f31s2" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscrs2" bitsize="32" group="float" regnum="70"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-fpu.xml b/coregrind/m_gdbserver/power-fpu.xml
new file mode 100644 (file)
index 0000000..d896b47
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.fpu">
+  <reg name="f0" bitsize="64" type="ieee_double" regnum="32"/>
+  <reg name="f1" bitsize="64" type="ieee_double"/>
+  <reg name="f2" bitsize="64" type="ieee_double"/>
+  <reg name="f3" bitsize="64" type="ieee_double"/>
+  <reg name="f4" bitsize="64" type="ieee_double"/>
+  <reg name="f5" bitsize="64" type="ieee_double"/>
+  <reg name="f6" bitsize="64" type="ieee_double"/>
+  <reg name="f7" bitsize="64" type="ieee_double"/>
+  <reg name="f8" bitsize="64" type="ieee_double"/>
+  <reg name="f9" bitsize="64" type="ieee_double"/>
+  <reg name="f10" bitsize="64" type="ieee_double"/>
+  <reg name="f11" bitsize="64" type="ieee_double"/>
+  <reg name="f12" bitsize="64" type="ieee_double"/>
+  <reg name="f13" bitsize="64" type="ieee_double"/>
+  <reg name="f14" bitsize="64" type="ieee_double"/>
+  <reg name="f15" bitsize="64" type="ieee_double"/>
+  <reg name="f16" bitsize="64" type="ieee_double"/>
+  <reg name="f17" bitsize="64" type="ieee_double"/>
+  <reg name="f18" bitsize="64" type="ieee_double"/>
+  <reg name="f19" bitsize="64" type="ieee_double"/>
+  <reg name="f20" bitsize="64" type="ieee_double"/>
+  <reg name="f21" bitsize="64" type="ieee_double"/>
+  <reg name="f22" bitsize="64" type="ieee_double"/>
+  <reg name="f23" bitsize="64" type="ieee_double"/>
+  <reg name="f24" bitsize="64" type="ieee_double"/>
+  <reg name="f25" bitsize="64" type="ieee_double"/>
+  <reg name="f26" bitsize="64" type="ieee_double"/>
+  <reg name="f27" bitsize="64" type="ieee_double"/>
+  <reg name="f28" bitsize="64" type="ieee_double"/>
+  <reg name="f29" bitsize="64" type="ieee_double"/>
+  <reg name="f30" bitsize="64" type="ieee_double"/>
+  <reg name="f31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscr" bitsize="32" group="float" regnum="70"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-linux-valgrind-s1.xml b/coregrind/m_gdbserver/power-linux-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..a02dd8e
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.linux-valgrind-s1">
+  <reg name="orig_r3s1" bitsize="32" regnum="71"/>
+  <reg name="traps1" bitsize="32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-linux-valgrind-s2.xml b/coregrind/m_gdbserver/power-linux-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..59f6ee3
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.linux-valgrind-s2">
+  <reg name="orig_r3s2" bitsize="32" regnum="71"/>
+  <reg name="traps2" bitsize="32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power-linux.xml b/coregrind/m_gdbserver/power-linux.xml
new file mode 100644 (file)
index 0000000..b8b7519
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.linux">
+  <reg name="orig_r3" bitsize="32" regnum="71"/>
+  <reg name="trap" bitsize="32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power64-core-valgrind-s1.xml b/coregrind/m_gdbserver/power64-core-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..f6296bf
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core-valgrind-s1">
+  <reg name="r0s1" bitsize="64" type="uint64"/>
+  <reg name="r1s1" bitsize="64" type="uint64"/>
+  <reg name="r2s1" bitsize="64" type="uint64"/>
+  <reg name="r3s1" bitsize="64" type="uint64"/>
+  <reg name="r4s1" bitsize="64" type="uint64"/>
+  <reg name="r5s1" bitsize="64" type="uint64"/>
+  <reg name="r6s1" bitsize="64" type="uint64"/>
+  <reg name="r7s1" bitsize="64" type="uint64"/>
+  <reg name="r8s1" bitsize="64" type="uint64"/>
+  <reg name="r9s1" bitsize="64" type="uint64"/>
+  <reg name="r10s1" bitsize="64" type="uint64"/>
+  <reg name="r11s1" bitsize="64" type="uint64"/>
+  <reg name="r12s1" bitsize="64" type="uint64"/>
+  <reg name="r13s1" bitsize="64" type="uint64"/>
+  <reg name="r14s1" bitsize="64" type="uint64"/>
+  <reg name="r15s1" bitsize="64" type="uint64"/>
+  <reg name="r16s1" bitsize="64" type="uint64"/>
+  <reg name="r17s1" bitsize="64" type="uint64"/>
+  <reg name="r18s1" bitsize="64" type="uint64"/>
+  <reg name="r19s1" bitsize="64" type="uint64"/>
+  <reg name="r20s1" bitsize="64" type="uint64"/>
+  <reg name="r21s1" bitsize="64" type="uint64"/>
+  <reg name="r22s1" bitsize="64" type="uint64"/>
+  <reg name="r23s1" bitsize="64" type="uint64"/>
+  <reg name="r24s1" bitsize="64" type="uint64"/>
+  <reg name="r25s1" bitsize="64" type="uint64"/>
+  <reg name="r26s1" bitsize="64" type="uint64"/>
+  <reg name="r27s1" bitsize="64" type="uint64"/>
+  <reg name="r28s1" bitsize="64" type="uint64"/>
+  <reg name="r29s1" bitsize="64" type="uint64"/>
+  <reg name="r30s1" bitsize="64" type="uint64"/>
+  <reg name="r31s1" bitsize="64" type="uint64"/>
+
+  <reg name="pcs1" bitsize="64" type="code_ptr" regnum="64"/>
+  <reg name="msrs1" bitsize="64" type="uint64"/>
+  <reg name="crs1" bitsize="32" type="uint32"/>
+  <reg name="lrs1" bitsize="64" type="code_ptr"/>
+  <reg name="ctrs1" bitsize="64" type="uint64"/>
+  <reg name="xers1" bitsize="32" type="uint32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power64-core-valgrind-s2.xml b/coregrind/m_gdbserver/power64-core-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..663232e
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core-valgrind-s2">
+  <reg name="r0s2" bitsize="64" type="uint64"/>
+  <reg name="r1s2" bitsize="64" type="uint64"/>
+  <reg name="r2s2" bitsize="64" type="uint64"/>
+  <reg name="r3s2" bitsize="64" type="uint64"/>
+  <reg name="r4s2" bitsize="64" type="uint64"/>
+  <reg name="r5s2" bitsize="64" type="uint64"/>
+  <reg name="r6s2" bitsize="64" type="uint64"/>
+  <reg name="r7s2" bitsize="64" type="uint64"/>
+  <reg name="r8s2" bitsize="64" type="uint64"/>
+  <reg name="r9s2" bitsize="64" type="uint64"/>
+  <reg name="r10s2" bitsize="64" type="uint64"/>
+  <reg name="r11s2" bitsize="64" type="uint64"/>
+  <reg name="r12s2" bitsize="64" type="uint64"/>
+  <reg name="r13s2" bitsize="64" type="uint64"/>
+  <reg name="r14s2" bitsize="64" type="uint64"/>
+  <reg name="r15s2" bitsize="64" type="uint64"/>
+  <reg name="r16s2" bitsize="64" type="uint64"/>
+  <reg name="r17s2" bitsize="64" type="uint64"/>
+  <reg name="r18s2" bitsize="64" type="uint64"/>
+  <reg name="r19s2" bitsize="64" type="uint64"/>
+  <reg name="r20s2" bitsize="64" type="uint64"/>
+  <reg name="r21s2" bitsize="64" type="uint64"/>
+  <reg name="r22s2" bitsize="64" type="uint64"/>
+  <reg name="r23s2" bitsize="64" type="uint64"/>
+  <reg name="r24s2" bitsize="64" type="uint64"/>
+  <reg name="r25s2" bitsize="64" type="uint64"/>
+  <reg name="r26s2" bitsize="64" type="uint64"/>
+  <reg name="r27s2" bitsize="64" type="uint64"/>
+  <reg name="r28s2" bitsize="64" type="uint64"/>
+  <reg name="r29s2" bitsize="64" type="uint64"/>
+  <reg name="r30s2" bitsize="64" type="uint64"/>
+  <reg name="r31s2" bitsize="64" type="uint64"/>
+
+  <reg name="pcs2" bitsize="64" type="code_ptr" regnum="64"/>
+  <reg name="msrs2" bitsize="64" type="uint64"/>
+  <reg name="crs2" bitsize="32" type="uint32"/>
+  <reg name="lrs2" bitsize="64" type="code_ptr"/>
+  <reg name="ctrs2" bitsize="64" type="uint64"/>
+  <reg name="xers2" bitsize="32" type="uint32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power64-core.xml b/coregrind/m_gdbserver/power64-core.xml
new file mode 100644 (file)
index 0000000..e0a6ee3
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+  <reg name="r0" bitsize="64" type="uint64"/>
+  <reg name="r1" bitsize="64" type="uint64"/>
+  <reg name="r2" bitsize="64" type="uint64"/>
+  <reg name="r3" bitsize="64" type="uint64"/>
+  <reg name="r4" bitsize="64" type="uint64"/>
+  <reg name="r5" bitsize="64" type="uint64"/>
+  <reg name="r6" bitsize="64" type="uint64"/>
+  <reg name="r7" bitsize="64" type="uint64"/>
+  <reg name="r8" bitsize="64" type="uint64"/>
+  <reg name="r9" bitsize="64" type="uint64"/>
+  <reg name="r10" bitsize="64" type="uint64"/>
+  <reg name="r11" bitsize="64" type="uint64"/>
+  <reg name="r12" bitsize="64" type="uint64"/>
+  <reg name="r13" bitsize="64" type="uint64"/>
+  <reg name="r14" bitsize="64" type="uint64"/>
+  <reg name="r15" bitsize="64" type="uint64"/>
+  <reg name="r16" bitsize="64" type="uint64"/>
+  <reg name="r17" bitsize="64" type="uint64"/>
+  <reg name="r18" bitsize="64" type="uint64"/>
+  <reg name="r19" bitsize="64" type="uint64"/>
+  <reg name="r20" bitsize="64" type="uint64"/>
+  <reg name="r21" bitsize="64" type="uint64"/>
+  <reg name="r22" bitsize="64" type="uint64"/>
+  <reg name="r23" bitsize="64" type="uint64"/>
+  <reg name="r24" bitsize="64" type="uint64"/>
+  <reg name="r25" bitsize="64" type="uint64"/>
+  <reg name="r26" bitsize="64" type="uint64"/>
+  <reg name="r27" bitsize="64" type="uint64"/>
+  <reg name="r28" bitsize="64" type="uint64"/>
+  <reg name="r29" bitsize="64" type="uint64"/>
+  <reg name="r30" bitsize="64" type="uint64"/>
+  <reg name="r31" bitsize="64" type="uint64"/>
+
+  <reg name="pc" bitsize="64" type="code_ptr" regnum="64"/>
+  <reg name="msr" bitsize="64" type="uint64"/>
+  <reg name="cr" bitsize="32" type="uint32"/>
+  <reg name="lr" bitsize="64" type="code_ptr"/>
+  <reg name="ctr" bitsize="64" type="uint64"/>
+  <reg name="xer" bitsize="32" type="uint32"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power64-linux-valgrind-s1.xml b/coregrind/m_gdbserver/power64-linux-valgrind-s1.xml
new file mode 100644 (file)
index 0000000..7f1d0ac
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.linux-valgrind-s1">
+  <reg name="orig_r3s1" bitsize="64" regnum="71"/>
+  <reg name="traps1" bitsize="64"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power64-linux-valgrind-s2.xml b/coregrind/m_gdbserver/power64-linux-valgrind-s2.xml
new file mode 100644 (file)
index 0000000..007bd04
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.linux-valgrind-s2">
+  <reg name="orig_r3s2" bitsize="64" regnum="71"/>
+  <reg name="traps2" bitsize="64"/>
+</feature>
diff --git a/coregrind/m_gdbserver/power64-linux.xml b/coregrind/m_gdbserver/power64-linux.xml
new file mode 100644 (file)
index 0000000..a72a058
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.linux">
+  <reg name="orig_r3" bitsize="64" regnum="71"/>
+  <reg name="trap" bitsize="64"/>
+</feature>
diff --git a/coregrind/m_gdbserver/powerpc-altivec32l-valgrind.xml b/coregrind/m_gdbserver/powerpc-altivec32l-valgrind.xml
new file mode 100644 (file)
index 0000000..07094a4
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- PowerPC UISA - a PPC processor as viewed by user-level code.  A UISA-only
+     view of the PowerPC.  Includes Linux-only special "registers" and AltiVec
+     vector registers.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>powerpc:common</architecture>
+  <xi:include href="power-core.xml"/>
+  <xi:include href="power-fpu.xml"/>
+  <xi:include href="power-linux.xml"/>
+  <xi:include href="power-altivec.xml"/>
+  <xi:include href="power-core-valgrind-s1.xml"/>
+  <xi:include href="power-fpu-valgrind-s1.xml"/>
+  <xi:include href="power-linux-valgrind-s1.xml"/>
+  <xi:include href="power-altivec-valgrind-s1.xml"/>
+  <xi:include href="power-core-valgrind-s2.xml"/>
+  <xi:include href="power-fpu-valgrind-s2.xml"/>
+  <xi:include href="power-linux-valgrind-s2.xml"/>
+  <xi:include href="power-altivec-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/powerpc-altivec32l.xml b/coregrind/m_gdbserver/powerpc-altivec32l.xml
new file mode 100644 (file)
index 0000000..8d77e10
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- PowerPC UISA - a PPC processor as viewed by user-level code.  A UISA-only
+     view of the PowerPC.  Includes Linux-only special "registers" and AltiVec
+     vector registers.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>powerpc:common</architecture>
+  <xi:include href="power-core.xml"/>
+  <xi:include href="power-fpu.xml"/>
+  <xi:include href="power-linux.xml"/>
+  <xi:include href="power-altivec.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/powerpc-altivec64l-valgrind.xml b/coregrind/m_gdbserver/powerpc-altivec64l-valgrind.xml
new file mode 100644 (file)
index 0000000..a2cd615
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- PowerPC UISA - a PPC processor as viewed by user-level code.  A UISA-only
+     view of the PowerPC.  Includes Linux-only special "registers" and AltiVec
+     vector registers.   -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>powerpc:common64</architecture>
+  <xi:include href="power64-core.xml"/>
+  <xi:include href="power-fpu.xml"/>
+  <xi:include href="power64-linux.xml"/>
+  <xi:include href="power-altivec.xml"/>
+  <xi:include href="power64-core-valgrind-s1.xml"/>
+  <xi:include href="power-fpu-valgrind-s1.xml"/>
+  <xi:include href="power64-linux-valgrind-s1.xml"/>
+  <xi:include href="power-altivec-valgrind-s1.xml"/>
+  <xi:include href="power64-core-valgrind-s2.xml"/>
+  <xi:include href="power-fpu-valgrind-s2.xml"/>
+  <xi:include href="power64-linux-valgrind-s2.xml"/>
+  <xi:include href="power-altivec-valgrind-s2.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/powerpc-altivec64l.xml b/coregrind/m_gdbserver/powerpc-altivec64l.xml
new file mode 100644 (file)
index 0000000..d06dad9
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- PowerPC UISA - a PPC processor as viewed by user-level code.  A UISA-only
+     view of the PowerPC.  Includes Linux-only special "registers" and AltiVec
+     vector registers.   -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>powerpc:common64</architecture>
+  <xi:include href="power64-core.xml"/>
+  <xi:include href="power-fpu.xml"/>
+  <xi:include href="power64-linux.xml"/>
+  <xi:include href="power-altivec.xml"/>
+</target>
diff --git a/coregrind/m_gdbserver/regcache.c b/coregrind/m_gdbserver/regcache.c
new file mode 100644 (file)
index 0000000..a920231
--- /dev/null
@@ -0,0 +1,263 @@
+/* Register support routines for the remote server for GDB.
+   Copyright (C) 2001, 2002, 2004, 2005, 2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "regdef.h"
+
+/* The private data for the register cache.  Note that we have one
+   per inferior; this is primarily for simplicity, as the performance
+   benefit is minimal.  */
+
+struct inferior_regcache_data
+{
+   int registers_valid;
+   unsigned char *registers;
+   Bool *register_supplied; /* set to True once it has been supplied */
+};
+
+static int register_bytes;
+
+static struct reg *reg_defs;
+static int num_registers;
+
+const char **gdbserver_expedite_regs;
+
+static
+struct inferior_regcache_data * get_regcache (struct thread_info *inf,
+                                              int fetch)
+{
+   struct inferior_regcache_data *regcache;
+
+   regcache = (struct inferior_regcache_data *) inferior_regcache_data (inf);
+
+   if (regcache == NULL)
+      fatal ("no register cache\n");
+
+   /* FIXME - fetch registers for INF */
+   if (fetch && regcache->registers_valid == 0) {
+      fetch_inferior_registers (0);
+      regcache->registers_valid = 1;
+   }
+
+   return regcache;
+}
+
+void regcache_invalidate_one (struct inferior_list_entry *entry)
+{
+   struct thread_info *thread = (struct thread_info *) entry;
+   struct inferior_regcache_data *regcache;
+
+   regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
+
+   if (regcache->registers_valid) {
+      struct thread_info *saved_inferior = current_inferior;
+
+      current_inferior = thread;
+      store_inferior_registers (-1);
+      current_inferior = saved_inferior;
+   }
+
+   regcache->registers_valid = 0;
+}
+
+void regcache_invalidate ()
+{
+   for_each_inferior (&all_threads, regcache_invalidate_one);
+}
+
+int registers_length (void)
+{
+   return 2 * register_bytes;
+}
+
+void *new_register_cache (void)
+{
+   struct inferior_regcache_data *regcache;
+   
+   regcache = malloc (sizeof (*regcache));
+
+   /* 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->registers = calloc (1, register_bytes);
+   if (regcache->registers == NULL)
+      fatal ("Could not allocate register cache.\n");
+
+   regcache->register_supplied = calloc (1, num_registers);
+   if (regcache->register_supplied == NULL)
+      fatal ("Could not allocate register_supplied cache.\n");
+
+   regcache->registers_valid = 0;
+
+   return regcache;
+}
+
+void free_register_cache (void *regcache_p)
+{
+   struct inferior_regcache_data *regcache
+      = (struct inferior_regcache_data *) regcache_p;
+
+   free (regcache->registers);
+   free (regcache->register_supplied);
+   free (regcache);
+}
+
+/* if a regcache exists for entry, reallocate it.
+   This is needed if the shadow registers are added.
+   In such a case, a 2nd call to set_register_cache is done
+   which will cause the reallocation of already created caches. */
+static
+void regcache_realloc_one (struct inferior_list_entry *entry)
+{
+   struct thread_info *thread = (struct thread_info *) entry;
+   struct inferior_regcache_data *regcache;
+
+   regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
+
+   if (regcache) {
+      free_register_cache (regcache);
+      set_inferior_regcache_data (thread, new_register_cache ());
+   }
+}
+
+void set_register_cache (struct reg *regs, int n)
+{
+   int offset, i;
+  
+   reg_defs = regs;
+   num_registers = n;
+
+   offset = 0;
+   for (i = 0; i < n; i++) {
+      regs[i].offset = offset;
+      offset += regs[i].size;
+   }
+
+   register_bytes = offset / 8;
+
+   for_each_inferior (&all_threads, regcache_realloc_one);
+}
+
+void registers_to_string (char *buf)
+{
+   unsigned char *registers = get_regcache (current_inferior, 1)->registers;
+
+   convert_int_to_ascii (registers, buf, register_bytes);
+}
+
+void registers_from_string (char *buf)
+{
+   int len = strlen (buf);
+   unsigned char *registers = get_regcache (current_inferior, 1)->registers;
+
+   if (len != register_bytes * 2) {
+      warning ("Wrong sized register packet (expected %d bytes, got %d)\n",
+               2*register_bytes, len);
+      if (len > register_bytes * 2)
+         len = register_bytes * 2;
+   }
+   convert_ascii_to_int (buf, registers, len / 2);
+}
+
+int find_regno (const char *name)
+{
+   int i;
+
+   for (i = 0; i < num_registers; i++)
+      if (!strcmp (name, reg_defs[i].name))
+         return i;
+   fatal ("Unknown register %s requested\n", name);
+   return -1;
+}
+
+struct reg *find_register_by_number (int n)
+{
+   return &reg_defs[n];
+}
+
+int register_size (int n)
+{
+   return reg_defs[n].size / 8;
+}
+
+static
+unsigned char *register_data (int n, int fetch)
+{
+   unsigned char *registers
+      = get_regcache (current_inferior, fetch)->registers;
+
+   return registers + (reg_defs[n].offset / 8);
+}
+static
+unsigned char *register_data_for_supply (int n, int fetch, Bool *mod)
+{
+   struct inferior_regcache_data * cache 
+      = get_regcache (current_inferior, fetch);
+   unsigned char *registers = cache->registers;
+
+   if (cache->register_supplied[n])
+      *mod = False;
+   else
+      *mod = True;
+   cache->register_supplied[n] = True;
+   return registers + (reg_defs[n].offset / 8);
+}
+
+void supply_register (int n, const void *buf, Bool *mod)
+{
+   Bool new;
+   VG_(dmemcpy) (register_data_for_supply (n, 0, &new), 
+                 buf, register_size (n), mod);
+   if (new)
+      *mod = True;
+}
+
+void supply_register_from_string (int n, const char *buf, Bool *mod)
+{
+   Bool new;
+   unsigned char bytes_register[register_size (n)];
+   convert_ascii_to_int ((char *) buf, bytes_register, register_size (n));
+   VG_(dmemcpy) (register_data_for_supply (n, 0, &new), 
+                 bytes_register, register_size (n), mod);
+   if (new)
+      *mod = True;
+}
+
+void supply_register_by_name (const char *name, const void *buf, Bool *mod)
+{
+   supply_register (find_regno (name), buf, mod);
+}
+
+void collect_register (int n, void *buf)
+{
+   VG_(memcpy) (buf, register_data (n, 1), register_size (n));
+}
+
+void collect_register_as_string (int n, char *buf)
+{
+   convert_int_to_ascii (register_data (n, 1), buf, register_size (n));
+}
+
+void collect_register_by_name (const char *name, void *buf)
+{
+   collect_register (find_regno (name), buf);
+}
diff --git a/coregrind/m_gdbserver/regcache.h b/coregrind/m_gdbserver/regcache.h
new file mode 100644 (file)
index 0000000..2f17d0a
--- /dev/null
@@ -0,0 +1,80 @@
+/* Register support routines for the remote server for GDB.
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef REGCACHE_H
+#define REGCACHE_H
+
+struct inferior_list_entry;
+
+/* Create a new register cache for INFERIOR.  */
+
+void *new_register_cache (void);
+
+/* Release all memory associated with the register cache for INFERIOR.  */
+
+void free_register_cache (void *regcache);
+
+/* Invalidate cached registers for one or all threads.  */
+
+void regcache_invalidate_one (struct inferior_list_entry *);
+void regcache_invalidate (void);
+
+/* Convert all registers to a string in the currently specified remote
+   format.  */
+
+void registers_to_string (char *buf);
+
+/* Convert a string to register values and fill our register cache.  */
+
+void registers_from_string (char *buf);
+
+/* Return the size in bytes of a string-encoded register packet.  */
+
+int registers_length (void);
+
+/* Return a pointer to the description of register ``n''.  */
+
+struct reg *find_register_by_number (int n);
+
+int register_size (int n);
+
+int find_regno (const char *name);
+
+extern const char **gdbserver_expedite_regs;
+
+/* *mod set to True if *buf provides a new value. */
+void supply_register (int n, const void *buf, Bool *mod);
+
+/* Reads register data from buf (hex string in target byte order)
+   and stores it in the register cache.
+   *mod set to True if *buf provides a new value. */
+void supply_register_from_string (int n, const char *buf, Bool *mod);
+
+/* *mod set to True if *buf provides a new value. */
+void supply_register_by_name (const char *name, const void *buf, Bool *mod);
+
+void collect_register (int n, void *buf);
+
+void collect_register_as_string (int n, char *buf);
+
+void collect_register_by_name (const char *name, void *buf);
+
+#endif /* REGCACHE_H */
diff --git a/coregrind/m_gdbserver/regdef.h b/coregrind/m_gdbserver/regdef.h
new file mode 100644 (file)
index 0000000..60400fd
--- /dev/null
@@ -0,0 +1,47 @@
+/* Register protocol definition structures for the GNU Debugger
+   Copyright 2001, 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef REGDEF_H
+#define REGDEF_H
+
+struct reg
+{
+  /* The name of this register - NULL for pad entries.  */
+  const char *name;
+
+  /* At the moment, both of the following bit counts must be divisible
+     by eight (to match the representation as two hex digits) and divisible
+     by the size of a byte (to match the layout of each register in
+     memory).  */
+
+  /* The offset (in bits) of the value of this register in the buffer.  */
+  int offset;
+
+  /* The size (in bits) of the value of this register, as transmitted.  */
+  int size;
+};
+
+/* Set the current remote protocol and register cache according to the array
+   ``regs'', with ``n'' elements.  */
+
+void set_register_cache (struct reg *regs, int n);
+
+#endif /* REGDEF_H */
diff --git a/coregrind/m_gdbserver/remote-utils.c b/coregrind/m_gdbserver/remote-utils.c
new file mode 100644 (file)
index 0000000..eb2f011
--- /dev/null
@@ -0,0 +1,1036 @@
+/* Remote utility routines for the remote server for GDB.
+   Copyright (C) 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2006, 2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_options.h"
+
+#include "server.h"
+
+#  if defined(VGO_linux)
+#include <sys/prctl.h>
+#  endif
+
+Bool noack_mode;
+
+static int readchar (int single);
+
+void remote_utils_output_status(void);
+
+static int remote_desc;
+
+static VgdbShared *shared;
+static int  last_looked_cntr = -1;
+static struct vki_pollfd remote_desc_pollfdread_activity;
+#define INVALID_DESCRIPTOR -1
+
+/* for a gdbserver embedded in valgrind, we read from a FIFO and write
+   to another FIFO So, we need two descriptors */
+static int write_remote_desc = INVALID_DESCRIPTOR;
+static int pid_from_to_creator;
+/* only this pid will remove the FIFOs: if an exec fails, we must avoid
+   that the exiting child believes it has to remove the FIFOs of its parent */
+static int mknod_done = 0;
+
+static char *from_gdb = NULL;
+static char *to_gdb = NULL;
+static char *shared_mem = NULL;
+
+static
+int open_fifo (char *side, char *path, int flags)
+{
+  SysRes o;
+  int fd;
+  dlog(1, "Opening %s side %s\n", side, path);
+  o = VG_(open) (path, flags, 0);
+  if (sr_isError (o)) {
+     sr_perror(o, "open fifo %s\n", path);
+     fatal ("valgrind: fatal error: vgdb FIFO cannot be opened.\n");
+  } else {
+     fd = sr_Res(o);
+     dlog(1, "result fd %d\n", fd);
+  }
+  fd = VG_(safe_fd)(fd);
+  dlog(1, "result safe_fd %d\n", fd);
+  if (fd == -1)
+     fatal("safe_fd for vgdb FIFO failed\n");
+  return fd;
+}
+
+void remote_utils_output_status(void)
+{
+   if (shared == NULL)
+      VG_(umsg)("remote communication not initialized\n");
+   else
+      VG_(umsg)("shared->written_by_vgdb %d shared->seen_by_valgrind %d\n",
+                shared->written_by_vgdb, shared->seen_by_valgrind);
+}
+
+/* Returns 0 if vgdb and connection state looks good,
+   otherwise returns an int value telling which check failed. */
+static
+int vgdb_state_looks_bad(char* where)
+{
+   if (VG_(kill)(shared->vgdb_pid, 0) != 0)
+      return 1; // vgdb process does not exist anymore.
+
+   if (remote_desc_activity(where) == 2)
+      return 2; // check for error on remote desc shows a problem
+
+   if (remote_desc == INVALID_DESCRIPTOR)
+      return 3; // after check, remote_desc not ok anymore
+       
+   return 0; // all is ok.
+}
+
+/* On systems that defines PR_SET_PTRACER, verify if ptrace_scope is
+   is permissive enough for vgdb. Otherwise, call set_ptracer.
+   This is especially aimed at Ubuntu >= 10.10 which has added
+   the ptrace_scope context. */
+static
+void set_ptracer(void)
+{
+#ifdef PR_SET_PTRACER
+   SysRes o;
+   char *ptrace_scope_setting_file = "/proc/sys/kernel/yama/ptrace_scope";
+   int fd;
+   char ptrace_scope;
+   int ret;
+
+   o = VG_(open) (ptrace_scope_setting_file, VKI_O_RDONLY, 0);
+   if (sr_isError(o)) {
+      sr_perror(o, "error VG_(open) %s\n", ptrace_scope_setting_file);
+      /* can't read setting. Assuming ptrace can be called by vgdb. */
+      return;
+   }
+   fd = sr_Res(o);
+   if (VG_(read) (fd, &ptrace_scope, 1) == 1) {
+      dlog(1, "ptrace_scope %c\n", ptrace_scope);
+      if (ptrace_scope != '0') {
+         /* insufficient default ptrace_scope.
+            Indicate to the kernel that we accept to be
+            ptraced by our vgdb. */
+         ret = VG_(prctl) (PR_SET_PTRACER, shared->vgdb_pid, 0, 0, 0);
+         dlog(1, "set_ptracer to vgdb_pid %d result %d\n",
+              shared->vgdb_pid, ret);
+      }
+   } else {
+      dlog(0, "Could not read the ptrace_scope setting from %s\n",
+           ptrace_scope_setting_file);
+   }
+
+   VG_(close) (fd);
+#endif
+}
+
+/* returns 1 if one or more poll "errors" is set.
+   Errors are: VKI_POLLERR or VKI_POLLHUP or VKI_POLLNAL */
+static
+int poll_cond (short revents)
+{
+   return (revents & (VKI_POLLERR | VKI_POLLHUP | VKI_POLLNVAL));
+}
+
+/* Ensures we have a valid write file descriptor.
+   Returns 1 if we have a valid write file descriptor,
+   0 if the write fd could not be opened. */
+static
+int ensure_write_remote_desc(void)
+{
+   struct vki_pollfd write_remote_desc_ok;
+   int ret;
+   if (write_remote_desc != INVALID_DESCRIPTOR) {
+      write_remote_desc_ok.fd = write_remote_desc;
+      write_remote_desc_ok.events = VKI_POLLOUT;
+      write_remote_desc_ok.revents = 0;
+      ret = VG_(poll)(&write_remote_desc_ok, 1, 0);
+      if (ret && poll_cond(write_remote_desc_ok.revents)) {
+         dlog(1, "POLLcond %d closing write_remote_desc %d\n", 
+              write_remote_desc_ok.revents, write_remote_desc);
+         VG_(close) (write_remote_desc);
+         write_remote_desc = INVALID_DESCRIPTOR;
+      }
+   }
+   if (write_remote_desc == INVALID_DESCRIPTOR) {
+      /* open_fifo write will block if the receiving vgdb
+         process is dead.  So, let's check for vgdb state to
+         be reasonably sure someone is reading on the other
+         side of the fifo. */
+      if (!vgdb_state_looks_bad("bad?@ensure_write_remote_desc")) {
+         set_ptracer();
+         write_remote_desc = open_fifo ("write", to_gdb, VKI_O_WRONLY);
+      }
+   }
+
+   return (write_remote_desc != INVALID_DESCRIPTOR);
+}
+
+#if defined(VGO_darwin)
+#define VKI_S_IFIFO 0010000
+#endif
+static
+void safe_mknod (char *nod)
+{
+   SysRes m;
+   m = VG_(mknod) (nod, VKI_S_IFIFO|0666, 0);
+   if (sr_isError (m)) {
+      if (sr_Err (m) == VKI_EEXIST) {
+         if (VG_(clo_verbosity) > 1) {
+            VG_(umsg)("%s already created\n", nod);
+         }
+      } else {
+         sr_perror(m, "mknod %s\n", nod);
+         VG_(umsg) ("valgrind: fatal error: vgdb FIFOs cannot be created.\n");
+         VG_(exit)(1);
+      }
+   }
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  
+   For Valgrind, name is the prefix for the two read and write FIFOs
+   The two FIFOs names will be build by appending 
+   -from-vgdb-to-pid and -to-vgdb-from-pid
+   with pid being the pidnr of the valgrind process These two FIFOs
+   will be created if not existing yet. They will be removed when
+   the gdbserver connection is closed or the process exits */
+
+void remote_open (char *name)
+{
+   int save_fcntl_flags;
+   VgdbShared vgdbinit = 
+      {0, 0, 0, (Addr) VG_(invoke_gdbserver),
+       (Addr) VG_(threads), sizeof(ThreadState), 
+       offsetof(ThreadState, status),
+       offsetof(ThreadState, os_state) + offsetof(ThreadOSstate, lwpid)};
+   const int pid = VG_(getpid)();
+   const int name_default = strcmp(name, VG_CLO_VGDB_PREFIX_DEFAULT) == 0;
+   Addr addr_shared;
+   SysRes o;
+   int shared_mem_fd = INVALID_DESCRIPTOR;
+   
+   if (from_gdb != NULL) 
+      free (from_gdb);
+   from_gdb = malloc (strlen(name) + 30);
+   if (to_gdb != NULL)
+      free (to_gdb);
+   to_gdb = malloc (strlen(name) + 30);
+   if (shared_mem != NULL)
+      free (shared_mem);
+   shared_mem = malloc (strlen(name) + 30);
+   /* below 3 lines must match the equivalent in vgdb.c */
+   VG_(sprintf) (from_gdb,   "%s-from-vgdb-to-%d",    name, pid);
+   VG_(sprintf) (to_gdb,     "%s-to-vgdb-from-%d",    name, pid);
+   VG_(sprintf) (shared_mem, "%s-shared-mem-vgdb-%d", name, pid);
+   if (VG_(clo_verbosity) > 1) {
+      VG_(umsg)("embedded gdbserver: reading from %s\n", from_gdb);
+      VG_(umsg)("embedded gdbserver: writing to   %s\n", to_gdb);
+      VG_(umsg)("embedded gdbserver: shared mem   %s\n", shared_mem);
+      VG_(umsg)("CONTROL ME using: vgdb --pid=%d%s%s ...command...\n",
+                pid, (name_default ? "" : " --vgdb="),
+                (name_default ? "" : name));
+      VG_(umsg)("DEBUG ME using: (gdb) target remote | vgdb --pid=%d%s%s\n",
+                pid, (name_default ? "" : " --vgdb="), 
+                (name_default ? "" : name));
+      VG_(umsg)("   --pid optional if only one valgrind process is running\n");
+   }
+
+   if (!mknod_done) {
+      mknod_done++;
+      safe_mknod(from_gdb);
+      safe_mknod(to_gdb);
+
+      pid_from_to_creator = pid;
+      
+      o = VG_(open) (shared_mem, VKI_O_CREAT|VKI_O_RDWR, 0666);
+      if (sr_isError (o)) {
+         sr_perror(o, "cannot create shared_mem file %s\n", shared_mem);
+         fatal("");
+      } else {
+         shared_mem_fd = sr_Res(o);
+      }
+      
+      if (VG_(write)(shared_mem_fd, &vgdbinit, sizeof(VgdbShared)) 
+          != sizeof(VgdbShared)) {
+         fatal("error writing %d bytes to shared mem %s\n",
+               (int) sizeof(VgdbShared), shared_mem);
+      }
+      shared_mem_fd = VG_(safe_fd)(shared_mem_fd);
+      if (shared_mem_fd == -1) {
+         fatal("safe_fd for vgdb shared_mem %s failed\n", shared_mem);
+      }
+      {
+         SysRes res = VG_(am_shared_mmap_file_float_valgrind)
+            (sizeof(VgdbShared), VKI_PROT_READ|VKI_PROT_WRITE, 
+             shared_mem_fd, (Off64T)0);
+         if (sr_isError(res)) {
+            sr_perror(res, "error VG_(am_shared_mmap_file_float_valgrind) %s\n",
+                      shared_mem);
+            fatal("");
+         }  
+         addr_shared = sr_Res (res);
+      }
+      shared = (VgdbShared*) addr_shared;
+   }
+   
+   /* we open the read side FIFO in non blocking mode
+      We then set the fd in blocking mode.
+      Opening in non-blocking read mode always succeeds while opening
+      in non-blocking write mode succeeds only if the fifo is already
+      opened in read mode. So, we wait till we have read the first
+      character from the read side before opening the write side. */
+   remote_desc = open_fifo ("read", from_gdb, VKI_O_RDONLY|VKI_O_NONBLOCK);
+   save_fcntl_flags = VG_(fcntl) (remote_desc, VKI_F_GETFL, 0);
+   VG_(fcntl) (remote_desc, VKI_F_SETFL, save_fcntl_flags & ~VKI_O_NONBLOCK);
+   remote_desc_pollfdread_activity.fd = remote_desc;
+   remote_desc_pollfdread_activity.events = VKI_POLLIN;
+   remote_desc_pollfdread_activity.revents = 0;
+}
+
+/* sync_gdb_connection wait a time long enough to let the connection
+   be properly closed if needed when closing the connection (in case
+   of detach or error), if we reopen it too quickly, it seems there
+   are some events queued in the kernel concerning the "old"
+   connection/remote_desc which are discovered with poll or select on
+   the "new" connection/remote_desc.  We bypass this by waiting some
+   time to let a proper cleanup to be donex */
+void sync_gdb_connection(void)
+{
+   VG_(poll)(0, 0, 100);
+}
+
+static
+char * ppFinishReason (FinishReason reason)
+{
+   switch (reason) {
+   case orderly_finish:    return "orderly_finish";
+   case reset_after_error: return "reset_after_error";
+   case reset_after_fork:  return "reset_after_fork";
+   default: vg_assert (0);
+   }
+}
+
+void remote_finish (FinishReason reason)
+{
+   dlog(1, "remote_finish (reason %s) %d %d\n", 
+        ppFinishReason(reason), remote_desc, write_remote_desc);
+   reset_valgrind_sink(ppFinishReason(reason));
+   if (write_remote_desc != INVALID_DESCRIPTOR)
+      VG_(close) (write_remote_desc);
+   write_remote_desc = INVALID_DESCRIPTOR;
+   if (remote_desc != INVALID_DESCRIPTOR) {
+      remote_desc_pollfdread_activity.fd = INVALID_DESCRIPTOR;
+      remote_desc_pollfdread_activity.events = 0;
+      remote_desc_pollfdread_activity.revents = 0;
+      VG_(close) (remote_desc);
+   }
+   remote_desc = INVALID_DESCRIPTOR;
+   noack_mode = False;
+   
+   /* ensure the child will create its own FIFOs */
+   if (reason == reset_after_fork)
+      mknod_done = 0;
+   
+   if (reason == reset_after_error)
+      sync_gdb_connection();
+}
+
+/* orderly close, cleans up everything */
+void remote_close (void)
+{
+   const int pid = VG_(getpid)();
+   remote_finish(orderly_finish);
+   if (pid == pid_from_to_creator) {
+      dlog(1, "unlinking\n    %s\n    %s\n    %s\n", 
+           from_gdb, to_gdb, shared_mem);
+      if (VG_(unlink) (from_gdb) == -1)
+         warning ("could not unlink %s\n", from_gdb);
+      if (VG_(unlink) (to_gdb) == -1)
+         warning ("could not unlink %s\n", to_gdb);
+      if (VG_(unlink) (shared_mem) == -1)
+         warning ("could not unlink %s\n", shared_mem);
+   }
+   else {
+      dlog(1, "not creator => not unlinking %s and %s\n", from_gdb, to_gdb);
+   }
+   free (from_gdb);
+   free (to_gdb);
+}
+
+Bool remote_connected(void)
+{
+   return write_remote_desc != INVALID_DESCRIPTOR;
+}
+
+/* cleanup after an error detected by poll_cond */
+static
+void error_poll_cond(void)
+{
+   /* if we will close the connection, we assume either that
+      all characters have been seen or that they will be dropped. */
+   shared->seen_by_valgrind = shared->written_by_vgdb;
+   remote_finish(reset_after_error);
+}
+
+/* remote_desc_activity might be used at high frequency if the user
+   gives a small value to --vgdb-poll. So, the function avoids
+   doing repetitively system calls by rather looking at the
+   counter values maintained in shared memory by vgdb. */
+int remote_desc_activity(char *msg)
+{
+   int ret;
+   const int looking_at = shared->written_by_vgdb;
+   if (shared->seen_by_valgrind == looking_at)
+   //   if (last_looked_cntr == looking_at)
+      return 0;
+   if (remote_desc == INVALID_DESCRIPTOR)
+      return 0;
+
+   /* poll the remote desc */
+   remote_desc_pollfdread_activity.revents = 0;
+   ret = VG_(poll) (&remote_desc_pollfdread_activity, 1, 0);
+   if (ret && poll_cond(remote_desc_pollfdread_activity.revents)) {
+      dlog(1, "POLLcond %d remote_desc_pollfdread %d\n", 
+           remote_desc_pollfdread_activity.revents, remote_desc);
+      error_poll_cond();
+      ret = 2;
+   }
+   dlog(1,
+        "remote_desc_activity %s %d last_looked_cntr %d looking_at %d"
+        " shared->written_by_vgdb %d shared->seen_by_valgrind %d"
+        " ret %d\n", 
+        msg, remote_desc, last_looked_cntr, looking_at, 
+        shared->written_by_vgdb, shared->seen_by_valgrind,
+        ret);
+   /* if no error from poll, indicate we have "seen" up to looking_at */
+   if (ret != 2)
+      last_looked_cntr = looking_at;
+   return ret;
+}
+
+/* Convert hex digit A to a number.  */
+
+static
+int fromhex (int a)
+{
+   if (a >= '0' && a <= '9')
+      return a - '0';
+   else if (a >= 'a' && a <= 'f')
+      return a - 'a' + 10;
+   else
+      error ("Reply contains invalid hex digit 0x%x\n", a);
+   return 0;
+}
+
+int unhexify (char *bin, const char *hex, int count)
+{
+   int i;
+   
+   for (i = 0; i < count; i++) {
+      if (hex[0] == 0 || hex[1] == 0) {
+         /* Hex string is short, or of uneven length.
+            Return the count that has been converted so far. */
+         return i;
+      }
+      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
+      hex += 2;
+   }
+   return i;
+}
+
+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;
+}
+
+/* Convert number NIB to a hex digit.  */
+
+static
+int tohex (int nib)
+{
+   if (nib < 10)
+      return '0' + nib;
+   else
+      return 'a' + nib - 10;
+}
+
+int hexify (char *hex, const char *bin, int count)
+{
+   int i;
+
+   /* May use a length, or a nul-terminated string as input. */
+   if (count == 0)
+      count = strlen (bin);
+
+  for (i = 0; i < count; i++) {
+     *hex++ = tohex ((*bin >> 4) & 0xf);
+     *hex++ = tohex (*bin++ & 0xf);
+  }
+  *hex = 0;
+  return i;
+}
+
+/* Convert BUFFER, binary data at least LEN bytes long, into escaped
+   binary data in OUT_BUF.  Set *OUT_LEN to the length of the data
+   encoded in OUT_BUF, and return the number of bytes in OUT_BUF
+   (which may be more than *OUT_LEN due to escape characters).  The
+   total number of bytes in the output buffer will be at most
+   OUT_MAXLEN.  */
+
+int
+remote_escape_output (const gdb_byte *buffer, int len,
+                     gdb_byte *out_buf, int *out_len,
+                     int out_maxlen)
+{
+   int input_index, output_index;
+   
+   output_index = 0;
+   for (input_index = 0; input_index < len; input_index++) {
+      gdb_byte b = buffer[input_index];
+
+      if (b == '$' || b == '#' || b == '}' || b == '*') {
+         /* These must be escaped.  */
+         if (output_index + 2 > out_maxlen)
+           break;
+         out_buf[output_index++] = '}';
+         out_buf[output_index++] = b ^ 0x20;
+      } else {
+         if (output_index + 1 > out_maxlen)
+           break;
+         out_buf[output_index++] = b;
+      }
+   }
+
+   *out_len = input_index;
+   return output_index;
+}
+
+/* Convert BUFFER, escaped data LEN bytes long, into binary data
+   in OUT_BUF.  Return the number of bytes written to OUT_BUF.
+   Raise an error if the total number of bytes exceeds OUT_MAXLEN.
+
+   This function reverses remote_escape_output.  It allows more
+   escaped characters than that function does, in particular because
+   '*' must be escaped to avoid the run-length encoding processing
+   in reading packets.  */
+
+static
+int remote_unescape_input (const gdb_byte *buffer, int len,
+                      gdb_byte *out_buf, int out_maxlen)
+{
+   int input_index, output_index;
+   int escaped;
+   
+   output_index = 0;
+   escaped = 0;
+   for (input_index = 0; input_index < len; input_index++) {
+      gdb_byte b = buffer[input_index];
+
+      if (output_index + 1 > out_maxlen)
+         error ("Received too much data (len %d) from the target.\n", len);
+
+      if (escaped) {
+         out_buf[output_index++] = b ^ 0x20;
+         escaped = 0;
+      } else if (b == '}') {
+         escaped = 1;
+      } else {
+         out_buf[output_index++] = b;
+      }
+   }
+
+   if (escaped)
+      error ("Unmatched escape character in target response.\n");
+
+   return output_index;
+}
+
+/* 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;
+}
+
+/* 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.  */
+
+int putpkt_binary (char *buf, int cnt)
+{
+   int i;
+   unsigned char csum = 0;
+   char *buf2;
+   char *p;
+   int cc;
+
+   buf2 = malloc (PBUFSIZ);
+
+   /* Copy the packet into buffer BUF2, encapsulating it
+      and giving it a checksum.  */
+
+   p = buf2;
+   *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';
+
+   /* we might have to write a pkt when out FIFO not yet/anymore opened */
+   if (!ensure_write_remote_desc()) {
+      warning ("putpkt(write) error: no write_remote_desc\n");
+      return -1;
+   }
+
+   /* Send it once (noack_mode)
+      or send it over and over until we get a positive ack.  */
+
+   do {
+      if (VG_(write) (write_remote_desc, buf2, p - buf2) != p - buf2) {
+         warning ("putpkt(write) error\n");
+         return -1;
+      }
+
+      if (noack_mode)
+         dlog(1, "putpkt (\"%s\"); [no ack]\n", buf2);
+      else
+         dlog(1,"putpkt (\"%s\"); [looking for ack]\n", buf2);
+
+      if (noack_mode)
+         break;
+
+      cc = readchar (1);
+      if (cc > 0)
+         dlog(1, "[received '%c' (0x%x)]\n", cc, cc);
+
+      if (cc <= 0) {
+         if (cc == 0)
+            dlog(1, "putpkt(read): Got EOF\n");
+         else
+           warning ("putpkt(read) error\n");
+
+         free (buf2);
+         return -1;
+      }
+
+      /* Check for an input interrupt while we're here.  */
+      if (cc == '\003')
+         (*the_target->send_signal) (VKI_SIGINT);
+   }
+   while (cc != '+');
+
+   free (buf2);
+   return 1;                   /* Success! */
+}
+
+/* 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));
+}
+
+void monitor_output (char *s)
+{
+   const int len = strlen(s);
+   char *buf = malloc(1 + 2*len + 1);
+
+   buf[0] = 'O';
+   hexify(buf+1, s, len);
+   if (putpkt (buf) < 0) {
+      /* We probably have lost the connection with vgdb. */
+      reset_valgrind_sink("Error writing monitor output");
+      /* write again after reset */
+      VG_(printf) ("%s", s);
+   }
+   
+   free (buf);
+}
+
+/* Returns next char from remote GDB.  -1 if error.  */
+/* if single, only one character maximum can be read with
+   read system call. Otherwise, when reading an ack character
+   we might pile up the next gdb command in the static buf.
+   The read loop is then blocked in poll till gdb times out. */
+static
+int readchar (int single)
+{
+   static unsigned char buf[PBUFSIZ];
+   static int bufcnt = 0;
+   static unsigned char *bufp;
+   int ret;
+  
+   if (bufcnt-- > 0)
+      return *bufp++;
+
+   if (remote_desc == INVALID_DESCRIPTOR)
+      return -1;
+
+   /* No characters available in buf =>
+      wait for some characters to arrive */
+   remote_desc_pollfdread_activity.revents = 0;
+   ret = VG_(poll)(&remote_desc_pollfdread_activity, 1, -1);
+   if (ret != 1) {
+      dlog(0, "readchar: poll got %d\n", ret);
+      return -1;
+   }
+   if (single)
+      bufcnt = VG_(read) (remote_desc, buf, 1);
+   else
+      bufcnt = VG_(read) (remote_desc, buf, sizeof (buf));
+
+   if (bufcnt <= 0) {
+      if (bufcnt == 0)
+         dlog (1, "readchar: Got EOF\n");
+      else
+         warning ("readchar read error\n");
+      
+      return -1;
+   }
+
+   shared->seen_by_valgrind += bufcnt;
+   
+   /* If we have received a character and we do not yet have a
+      connection, we better open our "write" fifo to let vgdb open its
+      read fifo side */
+   if (write_remote_desc == INVALID_DESCRIPTOR 
+       && !ensure_write_remote_desc()) {
+      dlog(1, "reachar: write_remote_desc could not be created");
+   }
+
+   bufp = buf;
+   bufcnt--;
+
+   if (poll_cond(remote_desc_pollfdread_activity.revents)) {
+      dlog(1, "readchar: POLLcond got %d\n",
+           remote_desc_pollfdread_activity.revents);
+      error_poll_cond();
+   }
+
+   return *bufp++;
+}
+
+
+/* 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)
+{
+   char *bp;
+   unsigned char csum, c1, c2;
+   int c;
+  
+   while (1) {
+      csum = 0;
+      
+      while (1) {
+         c = readchar (0);
+         if (c == '$')
+           break;
+         dlog(1, "[getpkt: discarding char '%c']\n", c);
+         if (c < 0)
+           return -1;
+      }
+
+      bp = buf;
+      while (1) {
+         c = readchar (0);
+         if (c < 0)
+           return -1;
+         if (c == '#')
+           break;
+         *bp++ = c;
+         csum += c;
+      }
+      *bp = 0;
+
+      c1 = fromhex (readchar (0));
+      c2 = fromhex (readchar (0));
+
+      if (csum == (c1 << 4) + c2)
+         break;
+
+      dlog (0, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+            (c1 << 4) + c2, csum, buf);
+      if (!ensure_write_remote_desc()) {
+         dlog(1, "getpkt(write nack) no write_remote_desc");
+      }
+      VG_(write) (write_remote_desc, "-", 1);
+   }
+
+   if (noack_mode)
+      dlog(1, "getpkt (\"%s\");  [no ack] \n", buf);
+   else
+      dlog(1, "getpkt (\"%s\");  [sending ack] \n", buf);
+
+   if (!noack_mode) {
+      if (!ensure_write_remote_desc()) {
+         dlog(1, "getpkt(write ack) no write_remote_desc");
+      }
+      VG_(write) (write_remote_desc, "+", 1);
+      dlog(1, "[sent ack]\n");
+   }
+
+   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';
+}
+
+void convert_int_to_ascii (unsigned char *from, char *to, int n)
+{
+   int nib;
+   int ch;
+   while (n--) {
+      ch = *from++;
+      nib = ((ch & 0xf0) >> 4) & 0x0f;
+      *to++ = tohex (nib);
+      nib = ch & 0x0f;
+      *to++ = tohex (nib);
+   }
+   *to++ = 0;
+}
+
+
+void convert_ascii_to_int (char *from, unsigned char *to, int n)
+{
+   int nib1, nib2;
+   while (n--) {
+      nib1 = fromhex (*from++);
+      nib2 = fromhex (*from++);
+      *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f);
+   }
+}
+
+static
+char * outreg (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 (regno, buf);
+   buf += 2 * register_size (regno);
+   *buf++ = ';';
+
+   return buf;
+}
+
+void prepare_resume_reply (char *buf, char status, unsigned char sig)
+{
+   int nib;
+   
+   *buf++ = status;
+
+   nib = ((sig & 0xf0) >> 4);
+   *buf++ = tohex (nib);
+   nib = sig & 0x0f;
+   *buf++ = tohex (nib);
+
+   if (status == 'T') {
+      const char **regp = gdbserver_expedite_regs;
+      
+      if (the_target->stopped_by_watchpoint != NULL
+         && (*the_target->stopped_by_watchpoint) ()) {
+         CORE_ADDR addr;
+         int i;
+
+         strncpy (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++ = ';';
+      }
+
+      while (*regp) {
+         buf = outreg (find_regno (*regp), buf);
+         regp ++;
+      }
+
+      {
+         unsigned int gdb_id_from_wait;
+         
+         /* FIXME right place to set this? */
+         thread_from_wait = 
+            ((struct inferior_list_entry *)current_inferior)->id;
+         gdb_id_from_wait = thread_to_gdb_id (current_inferior);
+         
+         dlog(1, "Writing resume reply for %ld\n", thread_from_wait);
+         /* 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 || old_thread_from_wait != thread_from_wait) {
+            general_thread = thread_from_wait;
+            VG_(sprintf) (buf, "thread:%x;", gdb_id_from_wait);
+            buf += strlen (buf);
+            old_thread_from_wait = thread_from_wait;
+         }
+      }
+   }
+   /* For W and X, we're done.  */
+   *buf++ = 0;
+}
+
+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)
+{
+   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;
+   }
+
+   convert_ascii_to_int (&from[i++], to, *len_ptr);
+}
+
+int decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
+                unsigned int *len_ptr, unsigned char *to)
+{
+   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 (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i,
+                              to, *len_ptr) != *len_ptr)
+      return -1;
+
+   return 0;
+}
+
diff --git a/coregrind/m_gdbserver/server.c b/coregrind/m_gdbserver/server.c
new file mode 100644 (file)
index 0000000..2d3ce90
--- /dev/null
@@ -0,0 +1,971 @@
+/* Main code for remote server for GDB.
+   Copyright (C) 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003,
+   2004, 2005, 2006, 2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "regdef.h"
+#include "pub_core_options.h"
+#include "pub_core_translate.h"
+#include "pub_core_mallocfree.h"
+
+unsigned long cont_thread;
+unsigned long general_thread;
+unsigned long step_thread;
+unsigned long thread_from_wait;
+unsigned long old_thread_from_wait;
+
+/* for a gdbserver integrated in valgrind, resuming the process consists
+   in returning the control to valgrind.
+   Then at the next error or break or ..., valgrind calls gdbserver again.
+   A resume packet must then be built.
+   resume_packet_needed records the fact that the next call to gdbserver
+   must send a resume packet to gdb. */
+static Bool resume_packet_needed = False;
+
+VG_MINIMAL_JMP_BUF(toplevel);
+
+/* Decode a qXfer read request.  Return 0 if everything looks OK,
+   or -1 otherwise.  */
+
+static
+int decode_xfer_read (char *buf, char **annex, CORE_ADDR *ofs, unsigned int *len)
+{
+   /* Extract and NUL-terminate the annex.  */
+   *annex = buf;
+   while (*buf && *buf != ':')
+      buf++;
+   if (*buf == '\0')
+      return -1;
+   *buf++ = 0;
+
+   /* After the read/write marker and annex, qXfer looks like a
+      traditional 'm' packet.  */
+   decode_m_packet (buf, ofs, len);
+
+   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, unsigned char *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, (unsigned char *) buf + 1, &out_len,
+                                PBUFSIZ - POVERHSIZ - 1) + 1;
+}
+
+static Bool initial_valgrind_sink_saved = False;
+/* True <=> valgrind log sink saved in initial_valgrind_sink */
+static OutputSink initial_valgrind_sink;
+
+static Bool command_output_to_log = False;
+/* True <=> command output goes to log instead of gdb */
+
+void reset_valgrind_sink(char *info)
+{
+   if (VG_(log_output_sink).fd != initial_valgrind_sink.fd
+       && initial_valgrind_sink_saved) {
+      VG_(log_output_sink).fd = initial_valgrind_sink.fd;
+      VG_(umsg) ("Reset valgrind output to log (%s)\n",
+                 (info = NULL ? "" : info));
+   }
+}
+
+static
+void kill_request (char *msg)
+{
+   VG_(umsg) ("%s", msg);
+   remote_close();
+   VG_(exit) (0);
+}
+
+/* handle_gdb_valgrind_command handles the provided mon string command.
+   If command is recognised, return 1 else return 0.
+   Note that in case of ambiguous command, 1 is returned.
+
+   *sink_wanted_at_return is modified if one of the commands 
+   'vg.set *_output' is handled.
+*/
+static
+int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return)
+{
+   UWord ret = 0;
+   char s[strlen(mon)+1]; /* copy for strtok_r */
+   char* wcmd;
+   Char* ssaveptr;
+   char* endptr;
+   int   kwdid;
+   int int_value;
+
+   vg_assert (initial_valgrind_sink_saved);
+
+   strcpy (s, mon);
+   wcmd = strtok_r (s, " ", &ssaveptr);
+   /* NB: if possible, avoid introducing a new command below which
+      starts with the same 4 first letters as an already existing
+      command. This ensures a shorter abbreviation for the user. */
+   switch (VG_(keyword_id) ("help vg.set vg.info vg.wait vg.kill vg.translate",
+                            wcmd, kwd_report_duplicated_matches)) {
+   case -2:
+      ret = 1;
+      break;
+   case -1: 
+      break;
+   case  0: /* help */
+      ret = 1;
+      wcmd = strtok_r (NULL, " ", &ssaveptr);
+      if (wcmd == NULL) {
+         int_value = 0;
+      } else {
+         switch (VG_(keyword_id) ("debug", wcmd, kwd_report_all)) {
+         case -2: int_value = 0; break;
+         case -1: int_value = 0; break;
+         case  0: int_value = 1; break;
+         default: tl_assert (0);
+         }
+      }
+
+      VG_(gdb_printf) (
+"general valgrind monitor commands:\n"
+"  help [debug]             : monitor command help. With debug: + debugging commands\n"
+"  vg.wait [<ms>]           : sleep <ms> (default 0) then continue\n"
+"  vg.info all_errors       : show all errors found so far\n"
+"  vg.info last_error       : show last error found\n"
+"  vg.info n_errs_found     : show the nr of errors found so far\n"
+"  vg.kill                  : kill the Valgrind process\n"
+"  vg.set gdb_output        : set valgrind output to gdb\n"
+"  vg.set log_output        : set valgrind output to log\n"
+"  vg.set mixed_output      : set valgrind output to log, interactive output to gdb\n"
+"  vg.set vgdb-error <errornr> : debug me at error >= <errornr> \n");
+      if (int_value) { VG_(gdb_printf) (
+"debugging valgrind internals monitor commands:\n"
+"  vg.info gdbserver_status : show gdbserver status\n"
+"  vg.info memory           : show valgrind heap memory stats\n"
+"  vg.set debuglog <level>  : set valgrind debug log level to <level>\n"
+"  vg.translate <addr> [<traceflags>]  : debug translation of <addr> with <traceflags>\n"
+"    (default traceflags 0b00100000 : show after instrumentation)\n"
+"   An additional flag  0b100000000 allows to show gdbserver instrumentation\n");
+      }
+      break;
+   case  1: /* vg.set */
+      ret = 1;
+      wcmd = strtok_r (NULL, " ", &ssaveptr);
+      switch (kwdid = VG_(keyword_id) 
+              ("vgdb-error debuglog gdb_output log_output mixed_output",
+               wcmd, kwd_report_all)) {
+      case -2:
+      case -1: 
+         break;
+      case 0: /* vgdb-error */
+      case 1: /* debuglog */
+         wcmd = strtok_r (NULL, " ", &ssaveptr);
+         if (wcmd == NULL) {
+            int_value = 0;
+            endptr = "empty"; /* to report an error below */
+         } else {
+            int_value = strtol (wcmd, &endptr, 10);
+         }
+         if (*endptr != '\0') {
+            VG_(gdb_printf) ("missing or malformed integer value\n");
+         } else if (kwdid == 0) {
+            VG_(gdb_printf) ("vgdb-error value changed from %d to %d\n",
+                             VG_(dyn_vgdb_error), int_value);
+            VG_(dyn_vgdb_error) = int_value;
+         } else if (kwdid == 1) {
+            VG_(gdb_printf) ("debuglog value changed from %d to %d\n",
+                             VG_(debugLog_getLevel)(), int_value);
+            VG_(debugLog_startup) (int_value, "gdbsrv");
+         } else {
+            vg_assert (0);
+         }
+         break;
+      case 2: /* gdb_output */
+         (*sink_wanted_at_return).fd = -2;
+         command_output_to_log = False;
+         VG_(gdb_printf) ("valgrind output will go to gdb\n");
+         break;
+      case 3: /* log_output */
+         (*sink_wanted_at_return).fd = initial_valgrind_sink.fd;
+         command_output_to_log = True;
+         VG_(gdb_printf) ("valgrind output will go to log\n");
+         break;
+      case 4: /* mixed output */
+         (*sink_wanted_at_return).fd = initial_valgrind_sink.fd;
+         command_output_to_log = False;
+         VG_(gdb_printf)
+            ("valgrind output will go to log, interactive output will go to gdb\n");
+         break;
+      default:
+         vg_assert (0);
+      }
+      break;
+   case  2: /* vg.info */ {
+      ret = 1;
+      wcmd = strtok_r (NULL, " ", &ssaveptr);
+      switch (kwdid = VG_(keyword_id) 
+              ("all_errors n_errs_found last_error gdbserver_status memory",
+               wcmd, kwd_report_all)) {
+      case -2:
+      case -1: 
+         break;
+      case 0: // all_errors
+         // A verbosity of minimum 2 is needed to show the errors.
+         VG_(show_all_errors)(/* verbosity */ 2, /* xml */ False);
+         break;
+      case  1: // n_errs_found
+         VG_(gdb_printf) ("n_errs_found %d (vgdb-error %d)\n", 
+                          VG_(get_n_errs_found) (),
+                          VG_(dyn_vgdb_error));
+         break;
+      case 2: // last_error
+         VG_(show_last_error)();
+         break;
+      case  3: // gdbserver_status
+         VG_(gdbserver_status_output)();
+         break;
+      case  4: /* memory */
+         VG_(print_all_arena_stats) ();
+         if (VG_(clo_profile_heap))
+            VG_(print_arena_cc_analysis) ();
+         ret = 1;
+         break;
+      default:
+         vg_assert(0);
+      }
+      break;
+   }
+   case  3: /* vg.wait */
+      wcmd = strtok_r (NULL, " ", &ssaveptr);
+      if (wcmd != NULL) {
+         int_value = strtol (wcmd, &endptr, 10);
+         VG_(gdb_printf) ("gdbserver: continuing in %d ms ...\n", int_value);
+         VG_(poll)(NULL, 0, int_value);
+      }
+      VG_(gdb_printf) ("gdbserver: continuing after wait ...\n");
+      ret = 1;
+      break;
+   case  4: /* vg.kill */
+      kill_request ("monitor command request to kill this process\n");
+      break;
+   case  5: { /* vg.translate */
+      Addr address;
+      SizeT verbosity = 0x20;
+      
+      ret = 1;
+
+      VG_(strtok_get_address_and_size) (&address, &verbosity, &ssaveptr);
+      if (address != (Addr) 0 || verbosity != 0) {
+         /* we need to force the output to log for the translation trace,
+            as low level VEX tracing cannot be redirected to gdb. */
+         int saved_command_output_to_log = command_output_to_log;
+         int saved_fd = VG_(log_output_sink).fd;
+         Bool single_stepping_on_entry = valgrind_single_stepping();
+         int vex_verbosity = verbosity & 0xff;
+         VG_(log_output_sink).fd = initial_valgrind_sink.fd;
+         if ((verbosity & 0x100) && !single_stepping_on_entry) {
+            valgrind_set_single_stepping(True); 
+            // to force gdbserver instrumentation.
+         }
+         VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
+                          address,
+                          /*debugging*/True, 
+                          (Int) vex_verbosity,
+                          /*bbs_done*/0,
+                          /*allow redir?*/True);
+         if ((verbosity & 0x100) && !single_stepping_on_entry) {
+            valgrind_set_single_stepping(False);
+            // reset single stepping.
+         }
+         command_output_to_log = saved_command_output_to_log;
+         VG_(log_output_sink).fd = saved_fd;
+      }
+      break;
+   }
+
+   default:
+      vg_assert (0);
+   }
+   return ret;
+}
+
+/* handle_gdb_monitor_command handles the provided mon string command,
+   which can be either a "standard" valgrind monitor command
+   or a tool specific monitor command.
+   If command recognised, return 1 else return 0.
+   Note that in case of ambiguous command, 1 is returned.
+*/
+static
+int handle_gdb_monitor_command (char* mon)
+{
+   UWord ret = 0;
+   UWord tool_ret = 0;
+   // initially, we assume that when returning, the desired sink is the
+   // one we have when entering. It can however be changed by the standard
+   // valgrind command handling.
+   OutputSink sink_wanted_at_return = VG_(log_output_sink);
+
+   if (!initial_valgrind_sink_saved) {
+      /* first time we enter here, we save the valgrind default log sink */
+      initial_valgrind_sink = sink_wanted_at_return;
+      initial_valgrind_sink_saved = True;
+   }
+
+   if (!command_output_to_log)
+      VG_(log_output_sink).fd = -2; /* redirect to monitor_output */
+
+   ret = handle_gdb_valgrind_command (mon, &sink_wanted_at_return);
+
+   /* Even if command was recognised by valgrind core, we call the
+      tool command handler : this is needed to handle help command
+      and/or to let the tool do some additional processing of a
+      valgrind standard command. Note however that if valgrind
+      recognised the command, we will always return success. */
+   if (VG_(needs).client_requests) {
+      /* If the tool reports an error when handling a monitor command,
+         we need to avoid calling gdbserver during this command
+         handling. So, we temporarily set VG_(dyn_vgdb_error) to
+         a huge value to ensure m_errormgr.c does not call gdbserver. */
+      Int save_dyn_vgdb_error = VG_(dyn_vgdb_error);
+      UWord arg[2];
+      VG_(dyn_vgdb_error) = 999999999;
+      arg[0] = (UWord) VG_USERREQ__GDB_MONITOR_COMMAND;
+      arg[1] = (UWord) mon;
+      VG_TDICT_CALL(tool_handle_client_request, VG_(running_tid), arg,
+                    &tool_ret);
+      VG_(dyn_vgdb_error) = save_dyn_vgdb_error;
+   }
+
+   /* restore or set the desired output */
+   VG_(log_output_sink).fd = sink_wanted_at_return.fd;
+   if (ret | tool_ret)
+      return 1;
+   else
+      return 0;
+}
+
+
+/* Handle all of the extended 'Q' packets.  */
+static
+void handle_set (char *arg_own_buf, int *new_packet_len_p)
+{
+   if (strcmp ("QStartNoAckMode", arg_own_buf) == 0) {
+      noack_mode = True;
+      write_ok (arg_own_buf);
+      return;
+   }
+
+   if (strncmp ("QPassSignals:", arg_own_buf, 13) == 0) {
+      int i;
+      char *from, *to;
+      char *end = arg_own_buf + strlen(arg_own_buf);
+      CORE_ADDR sig;
+      for (i = 0; i < TARGET_SIGNAL_LAST; i++)
+         pass_signals[i] = 0;
+     
+      from = arg_own_buf + 13;
+      while (from < end) {
+         to = strchr(from, ';');
+         if (to == NULL) to = end;
+         decode_address (&sig, from, to - from);
+         pass_signals[(int)sig] = 1;
+         dlog(1, "pass_signal %d\n", (int)sig);
+         from = to;
+         if (*from == ';') from++;
+      }
+      write_ok (arg_own_buf);
+      return;
+   }
+   /* Otherwise we didn't know what packet it was.  Say we didn't
+      understand it.  */
+   arg_own_buf[0] = 0;
+}
+
+/* Handle all of the extended 'q' packets.  */
+static
+void handle_query (char *arg_own_buf, int *new_packet_len_p)
+{
+   static struct inferior_list_entry *thread_ptr;
+
+   /* qRcmd, monitor command handling.  */
+   if (strncmp ("qRcmd,", arg_own_buf, 6) == 0) {
+      char *p = arg_own_buf + 6;
+      int cmdlen = strlen(p)/2;
+      char cmd[cmdlen+1];
+      
+      if (unhexify (cmd, p, cmdlen) != cmdlen) {
+         write_enn (arg_own_buf);
+         return;
+      }
+      cmd[cmdlen] = '\0';
+       
+      if (handle_gdb_monitor_command (cmd)) {
+         /* In case the command is from a standalone vgdb,
+            connection will be closed soon => flush the output. */
+         VG_(message_flush) ();
+         write_ok (arg_own_buf);
+         return;
+      } else {
+         /* cmd not recognised */
+         VG_(gdb_printf) 
+            ("command '%s' not recognised\n"
+             "In gdb,     try 'monitor help'\n"
+             "In a shell, try 'vgdb help'\n",
+             cmd);
+         write_ok (arg_own_buf);
+         return;
+      }
+   }
+
+   /* provide some valgrind specific info in return to qThreadExtraInfo. */
+   if (strncmp ("qThreadExtraInfo,", arg_own_buf, 17) == 0) {
+      unsigned long gdb_id;
+      struct thread_info *ti;
+      ThreadState *tst;
+      char status[100];
+      
+      gdb_id = strtoul (&arg_own_buf[17], NULL, 16);
+      ti = gdb_id_to_thread (gdb_id);
+      if (ti != NULL) {
+         tst = (ThreadState *) inferior_target_data (ti);
+         /* Additional info is the tid and the thread status. */
+         VG_(snprintf) (status, sizeof(status), "tid %d %s",
+                        tst->tid, 
+                        VG_(name_of_ThreadStatus)(tst->status));
+         hexify (arg_own_buf, status, strlen(status));
+         return;
+      } else {
+         write_enn (arg_own_buf);
+         return;
+      }
+   }
+   
+   if (strcmp ("qAttached", arg_own_buf) == 0) {
+      /* tell gdb to always detach, never kill the process */
+      arg_own_buf[0] = '1';
+      arg_own_buf[1] = 0;
+      return;
+   }
+
+   if (strcmp ("qSymbol::", arg_own_buf) == 0) {
+      /* We have no symbol to read. */
+      write_ok (arg_own_buf);
+      return;
+   }
+
+   if (strcmp ("qfThreadInfo", arg_own_buf) == 0) {
+      thread_ptr = all_threads.head;
+      VG_(sprintf) (arg_own_buf, "m%x", 
+                    thread_to_gdb_id ((struct thread_info *)thread_ptr));
+      thread_ptr = thread_ptr->next;
+      return;
+   }
+
+   if (strcmp ("qsThreadInfo", arg_own_buf) == 0) {
+      if (thread_ptr != NULL) {
+         VG_(sprintf) (arg_own_buf, "m%x", 
+                       thread_to_gdb_id ((struct thread_info *)thread_ptr));
+         thread_ptr = thread_ptr->next;
+         return;
+      } else {
+         VG_(sprintf) (arg_own_buf, "l");
+         return;
+      }
+   }
+
+   if ( ((*the_target->target_xml)() != NULL 
+         || (*the_target->shadow_target_xml)() != NULL)
+        && strncmp ("qXfer:features:read:", arg_own_buf, 20) == 0) {
+      CORE_ADDR ofs;
+      unsigned int len, doc_len;
+      char *annex = NULL;
+      // First, the annex is extracted from the packet received.
+      // Then, it is replaced by the corresponding file name.
+      int fd;
+
+      /* Grab the annex, offset, and length.  */
+      if (decode_xfer_read (arg_own_buf + 20, &annex, &ofs, &len) < 0) {
+         strcpy (arg_own_buf, "E00");
+         return;
+      }
+      
+      if (strcmp (annex, "target.xml") == 0) {
+         annex = NULL; // to replace it by the corresponding filename.
+
+         /* If VG_(clo_vgdb_shadow_registers), try to use
+            shadow_target_xml. Fallback to target_xml
+            if not defined. */
+         if (VG_(clo_vgdb_shadow_registers)) {
+            annex = (*the_target->shadow_target_xml)();
+            if (annex != NULL)
+               /* Ensure the shadow registers are initialized. */
+               initialize_shadow_low(True);
+         }
+         if (annex == NULL)
+            annex = (*the_target->target_xml)();
+         if (annex == NULL) {
+            strcpy (arg_own_buf, "E00");
+            return;
+         }
+      }
+
+      {
+         char doc[VG_(strlen)(VG_(libdir)) + 1 + VG_(strlen)(annex)];
+         struct vg_stat stat_doc;
+         char toread[len];
+         int len_read;
+
+         VG_(sprintf)(doc, "%s/%s", VG_(libdir), annex);
+         fd = VG_(fd_open) (doc, VKI_O_RDONLY, 0);
+         if (fd == -1) {
+            strcpy (arg_own_buf, "E00");
+            return;
+         }
+         if (VG_(fstat) (fd, &stat_doc) != 0) {
+            VG_(close) (fd);
+            strcpy (arg_own_buf, "E00");
+            return;
+         }
+         doc_len = stat_doc.size;
+         
+         if (len > PBUFSIZ - POVERHSIZ)
+            len = PBUFSIZ - POVERHSIZ;
+
+         if (ofs > doc_len) {
+            write_enn (arg_own_buf);
+            VG_(close) (fd);
+            return;
+         }
+         VG_(lseek) (fd, ofs, VKI_SEEK_SET);
+         len_read = VG_(read) (fd, toread, len);
+         *new_packet_len_p = write_qxfer_response (arg_own_buf, toread,
+                                                   len_read, ofs + len_read < doc_len);
+         VG_(close) (fd);
+         return;
+      }
+   }
+
+   /* Protocol features query.  */
+   if (strncmp ("qSupported", arg_own_buf, 10) == 0
+       && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) {
+      VG_(sprintf) (arg_own_buf, "PacketSize=%x", PBUFSIZ - 1);
+      /* Note: max packet size including frame and checksum, but without
+         trailing null byte, which is not sent/received. */
+      
+      strcat (arg_own_buf, ";QStartNoAckMode+");
+      strcat (arg_own_buf, ";QPassSignals+");
+
+      if ((*the_target->target_xml)() != NULL
+          || (*the_target->shadow_target_xml)() != NULL) {
+         strcat (arg_own_buf, ";qXfer:features:read+");
+         /* if a new gdb connects to us, we have to reset the register
+            set to the normal register sets to allow this new gdb to
+            decide to use or not the shadow registers.
+            
+            Note that the reset is only done for gdb that are sending
+            qSupported packets. If a user first connected with a recent
+            gdb using shadow registers and then with a very old gdb
+            that does not use qSupported packet, then the old gdb will
+            not properly connect. */
+         initialize_shadow_low(False);
+      }
+      return;
+   }
+
+   /* Otherwise we didn't know what packet it was.  Say we didn't
+      understand it.  */
+   arg_own_buf[0] = 0;
+}
+
+/* Handle all of the extended 'v' packets.  */
+static
+void handle_v_requests (char *arg_own_buf, char *status, int *signal)
+{
+   /* vcont packet code from gdb 6.6 removed */
+
+   /* Otherwise we didn't know what packet it was.  Say we didn't
+      understand it.  */
+   arg_own_buf[0] = 0;
+   return;
+}
+
+static
+void myresume (int step, int sig)
+{
+   struct thread_resume resume_info[2];
+   int n = 0;
+
+   if (step || sig || (cont_thread != 0 && cont_thread != -1)) {
+      resume_info[0].thread
+         = ((struct inferior_list_entry *) current_inferior)->id;
+      resume_info[0].step = step;
+      resume_info[0].sig = sig;
+      resume_info[0].leave_stopped = 0;
+      n++;
+   }
+   resume_info[n].thread = -1;
+   resume_info[n].step = 0;
+   resume_info[n].sig = 0;
+   resume_info[n].leave_stopped = (cont_thread != 0 && cont_thread != -1);
+
+   resume_packet_needed = True;
+   (*the_target->resume) (resume_info);
+}
+
+/* server_main global variables */
+static char *own_buf;
+static unsigned char *mem_buf;
+
+void gdbserver_init (void)
+{
+   dlog(1, "gdbserver_init gdbserver embedded in valgrind: %s\n", version);
+   noack_mode = False;
+   initialize_low ();
+   own_buf = malloc (PBUFSIZ);
+   mem_buf = malloc (PBUFSIZ);
+}
+
+void gdbserver_terminate (void)
+{
+   /* last call to gdbserver is cleanup call */
+   if (VG_MINIMAL_SETJMP(toplevel)) {
+      dlog(0, "error caused VG_MINIMAL_LONGJMP to gdbserver_terminate\n");
+      return;
+   }
+   remote_close();
+}
+
+void server_main (void)
+{
+   static char status;
+   static int signal;
+
+   char ch;
+   int i = 0;
+   unsigned int len;
+   CORE_ADDR mem_addr;
+
+   signal = mywait (&status);
+   if (VG_MINIMAL_SETJMP(toplevel)) {
+      dlog(0, "error caused VG_MINIMAL_LONGJMP to server_main\n");
+   }
+   while (1) {
+      unsigned char sig;
+      int packet_len;
+      int new_packet_len = -1;
+      
+      if (resume_packet_needed) {
+         resume_packet_needed = False;
+         prepare_resume_reply (own_buf, status, signal);
+         putpkt (own_buf);
+      }
+
+      packet_len = getpkt (own_buf);
+      if (packet_len <= 0)
+         break;
+
+      i = 0;
+      ch = own_buf[i++];
+      switch (ch) {
+      case 'Q':
+         handle_set (own_buf, &new_packet_len);
+         break;
+      case 'q':
+         handle_query (own_buf, &new_packet_len);
+         break;
+      case 'd':
+         /* set/unset debugging is done through valgrind debug level. */
+         own_buf[0] = '\0';
+         break;
+      case 'D':
+         reset_valgrind_sink("gdb detaching from process");
+
+         /* When detaching or kill the process, gdb expects to get
+            an packet OK back.  Any other output will make gdb
+            believes detach did not work. */
+         write_ok (own_buf);
+         putpkt (own_buf);
+         remote_finish (reset_after_error);
+         remote_open (VG_(clo_vgdb_prefix));
+         myresume (0, 0);
+         resume_packet_needed = False;
+         return;
+      case '!':
+         /* We can not use the extended protocol with valgrind,
+            because we can not restart the running
+            program.  So return unrecognized.  */
+         own_buf[0] = '\0';
+         break;
+      case '?':
+         prepare_resume_reply (own_buf, status, signal);
+         break;
+      case 'H':
+         if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') {
+            unsigned long gdb_id, thread_id;
+            
+            gdb_id = strtoul (&own_buf[2], NULL, 16);
+            thread_id = gdb_id_to_thread_id (gdb_id);
+            if (thread_id == 0) {
+               write_enn (own_buf);
+               break;
+            }
+
+            if (own_buf[1] == 'g') {
+               general_thread = thread_id;
+               set_desired_inferior (1);
+            } else if (own_buf[1] == 'c') {
+               cont_thread = thread_id;
+            } else if (own_buf[1] == 's') {
+               step_thread = thread_id;
+            }
+            
+            write_ok (own_buf);
+         } else {
+            /* Silently ignore it so that gdb can extend the protocol
+               without compatibility headaches.  */
+            own_buf[0] = '\0';
+         }
+         break;
+      case 'g':
+         set_desired_inferior (1);
+         registers_to_string (own_buf);
+         break;
+      case 'G':
+         set_desired_inferior (1);
+         registers_from_string (&own_buf[1]);
+         write_ok (own_buf);
+         break;
+      case 'P': {
+         int regno;
+         char *regbytes;
+         Bool mod;
+         ThreadState *tst;
+         regno = strtol(&own_buf[1], NULL, 16);
+         regbytes = strchr(&own_buf[0], '=') + 1;
+         set_desired_inferior (1);
+         tst = (ThreadState *) inferior_target_data (current_inferior);
+         /* Only accept changing registers in "runnable state3.
+            In fact, it would be ok to change most of the registers
+            except a few "sensitive" registers such as the PC, SP, BP.
+            We assume we do not need to very specific here, and that we
+            can just refuse all of these. */
+         if (tst->status == VgTs_Runnable || tst->status == VgTs_Yielding) {
+            supply_register_from_string (regno, regbytes, &mod);
+            write_ok (own_buf);
+         } else {
+            /* at least from gdb 6.6 onwards, an E. error
+               reply is shown to the user. So, we do an error
+               msg which both is accepted by gdb as an error msg
+               and is readable by the user. */
+            VG_(sprintf) 
+               (own_buf,
+"E.\n"
+"ERROR changing register %s regno %d\n"
+"gdb commands changing registers (pc, sp, ...) (e.g. 'jump',\n"
+"set pc, calling from gdb a function in the debugged process, ...)\n"
+"can only be accepted if the thread is VgTs_Runnable or VgTs_Yielding state\n"
+"Thread status is %s\n",
+                find_register_by_number (regno)->name, regno,
+                VG_(name_of_ThreadStatus)(tst->status));
+            if (VG_(clo_verbosity) > 1)
+               VG_(umsg) ("%s\n", own_buf);
+         }
+         break;            
+      }
+      case 'm':
+         decode_m_packet (&own_buf[1], &mem_addr, &len);
+         if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
+            convert_int_to_ascii (mem_buf, own_buf, len);
+         else
+            write_enn (own_buf);
+         break;
+      case 'M':
+         decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
+         if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
+            write_ok (own_buf);
+         else
+            write_enn (own_buf);
+         break;
+      case 'X':
+         if (decode_X_packet (&own_buf[1], packet_len - 1,
+                              &mem_addr, &len, mem_buf) < 0
+             || write_inferior_memory (mem_addr, mem_buf, len) != 0)
+            write_enn (own_buf);
+         else
+            write_ok (own_buf);
+         break;
+      case 'C':
+         convert_ascii_to_int (own_buf + 1, &sig, 1);
+         if (target_signal_to_host_p (sig))
+            signal = target_signal_to_host (sig);
+         else
+            signal = 0;
+         set_desired_inferior (0);
+         myresume (0, signal);
+         return; // return control to valgrind
+      case 'S':
+         convert_ascii_to_int (own_buf + 1, &sig, 1);
+         if (target_signal_to_host_p (sig))
+            signal = target_signal_to_host (sig);
+         else
+            signal = 0;
+         set_desired_inferior (0);
+         myresume (1, signal);
+         return; // return control to valgrind
+      case 'c':
+         set_desired_inferior (0);
+         myresume (0, 0);
+         return; // return control to valgrind
+      case 's':
+         set_desired_inferior (0);
+         myresume (1, 0);
+         return; // return control to valgrind
+      case 'Z': {
+         char *lenptr;
+         char *dataptr;
+         CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
+         int zlen = strtol (lenptr + 1, &dataptr, 16);
+         char type = own_buf[1];
+         
+         if (the_target->insert_watchpoint == NULL
+             || (type < '0' || type > '4')) {
+            /* No watchpoint support or not a watchpoint command;
+               unrecognized either way.  */
+            own_buf[0] = '\0';
+         } else {
+            int res;
+            
+            res = (*the_target->insert_watchpoint) (type, addr, zlen);
+            if (res == 0)
+               write_ok (own_buf);
+            else if (res == 1)
+               /* Unsupported.  */
+               own_buf[0] = '\0';
+            else
+               write_enn (own_buf);
+         }
+         break;
+      }
+      case 'z': {
+         char *lenptr;
+         char *dataptr;
+         CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
+         int zlen = strtol (lenptr + 1, &dataptr, 16);
+         char type = own_buf[1];
+         
+         if (the_target->remove_watchpoint == NULL
+             || (type < '0' || type > '4')) {
+            /* No watchpoint support or not a watchpoint command;
+               unrecognized either way.  */
+            own_buf[0] = '\0';
+         } else {
+            int res;
+            
+            res = (*the_target->remove_watchpoint) (type, addr, zlen);
+            if (res == 0)
+               write_ok (own_buf);
+            else if (res == 1)
+               /* Unsupported.  */
+               own_buf[0] = '\0';
+            else
+               write_enn (own_buf);
+         }
+         break;
+      }
+      case 'k':
+         kill_request("Gdb request to kill this process\n");
+         break;
+      case 'T': {
+         unsigned long gdb_id, thread_id;
+         
+         gdb_id = strtoul (&own_buf[1], NULL, 16);
+         thread_id = gdb_id_to_thread_id (gdb_id);
+         if (thread_id == 0) {
+            write_enn (own_buf);
+            break;
+         }
+
+         if (mythread_alive (thread_id))
+            write_ok (own_buf);
+         else
+            write_enn (own_buf);
+         break;
+      }
+      case 'R':
+         /* Restarting the inferior is only supported in the
+            extended protocol.
+            => It is a request we don't understand.  Respond with an
+            empty packet so that gdb knows that we don't support this
+            request.  */
+         own_buf[0] = '\0';
+         break;
+      case 'v':
+         /* Extended (long) request.  */
+         handle_v_requests (own_buf, &status, &signal);
+         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.  */
+         own_buf[0] = '\0';
+         break;
+      }
+
+      if (new_packet_len != -1)
+         putpkt_binary (own_buf, new_packet_len);
+      else
+         putpkt (own_buf);
+      
+      if (status == 'W')
+         VG_(umsg) ("\nChild exited with status %d\n", signal);
+      if (status == 'X')
+         VG_(umsg) ("\nChild terminated with signal = 0x%x (%s)\n",
+                    target_signal_to_host (signal),
+                    target_signal_to_name (signal));
+      if (status == 'W' || status == 'X') {
+         VG_(umsg) ("Process exiting\n");
+         VG_(exit) (0);
+      }
+   }
+
+   /* We come here when getpkt fails => close the connection,
+      and re-open. Then return control to valgrind.
+      We return the control to valgrind as we assume that
+      the connection was closed due to vgdb having finished
+      to execute a command. */
+   if (VG_(clo_verbosity) > 1)
+      VG_(umsg) ("Remote side has terminated connection.  "
+                 "GDBserver will reopen the connection.\n");
+   remote_finish (reset_after_error);
+   remote_open (VG_(clo_vgdb_prefix)); 
+   myresume (0, 0);
+   resume_packet_needed = False;
+   return;
+}
diff --git a/coregrind/m_gdbserver/server.h b/coregrind/m_gdbserver/server.h
new file mode 100644 (file)
index 0000000..2b6ae0e
--- /dev/null
@@ -0,0 +1,371 @@
+/* Common definitions for remote server for GDB.
+   Copyright (C) 1993, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005,
+   2006
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef SERVER_H
+#define SERVER_H
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_errormgr.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_syscall.h"
+#include "pub_tool_libcproc.h"
+#include "pub_core_tooliface.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_libcbase.h"
+#include "pub_tool_options.h"
+#include "pub_core_gdbserver.h"
+#include "pub_tool_libcsetjmp.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_vki.h"
+#include "valgrind.h"
+
+/*------------- interface m_gdbserver <=> low level gdbserver */
+
+/* Initializes gdbserver. After a call to gdbserver_init, vgdb
+   can contact the gdbserver embedded in valgrind.
+   The rest of the low level gdbserver interface can only
+   be called */
+extern void gdbserver_init (void);
+
+extern void server_main (void);
+
+/* To be called to indicate that gdbserver usage is finished.
+   Resources (e.g. FIFOs) will be destroyed. */
+extern void gdbserver_terminate (void);
+
+
+/* Output string s to the gdb debugging this process or to vgdb.
+   Do not call this directly. Rather use VG_(monitor_print) 
+   to output something to gdb, use normal valgrind messaging
+   (e.g. VG_(umsg)) to send output that can either go
+   to gdb or to log. */
+extern void monitor_output (char *s);
+
+/* returns 0 if there is no connection or no event on the connection
+             with gdb.
+   returns 1 if there are some data which has been received from gdb
+             and that must (still) be handled.
+   returns 2 if remote_desc_activity detected the connection has been
+             lost and should be reopened.
+   msg is used for debug logging.*/
+extern int remote_desc_activity(char *msg);
+
+/* output some status of gdbserver communication */
+extern void remote_utils_output_status(void);
+
+/* True if there is a connection with gdb. */
+extern Bool remote_connected(void);
+
+/* Finish the connection with gdb and reset_valgrind_sink.
+   Keeps the FIFOs and shared mem so as to allow connection
+   to be reopened. */
+extern void remote_finish(FinishReason reason);
+
+/* If Valgrind sink was changed by gdbserver:
+      Resets the valgrind sink to before the changes done by gdbserver,
+      and does VG_(umsg). If info != NULL, info added in VG_(usmg). */
+extern void reset_valgrind_sink(char* info);
+
+   
+/* True if gdbserver is single stepping the valgrind process */
+extern Bool valgrind_single_stepping(void);
+
+/* Set Valgrind in single stepping mode or not according to Bool. */
+extern void valgrind_set_single_stepping(Bool);
+
+/* gets the addr at which a (possible) break must be ignored once.
+   If there is no such break to be ignored once, 0 is returned.
+   This is needed for the following case:
+   The user sets a break at address AAA.
+   The break is encountered. Then the user does stepi 
+   (i.e. step one instruction).
+   In such a case, the already encountered break must be ignored
+   to ensure the stepi will advance by one instruction: a "break"
+   is implemented in valgrind by some helper code just after the
+   instruction mark at which the break is set. This helper code
+   verifies if either there is a break at the current PC
+   or if we are in stepping mode. If we are in stepping mode,
+   the already encountered break must be ignored once to advance
+   to the next instruction.
+   ??? need to check if this is *really* needed. */
+extern Addr valgrind_get_ignore_break_once(void);
+
+/* When addr > 0, ensures the next stop reply packet informs
+   gdb about the encountered watchpoint.
+   Use addr 0x0 to reset. */
+extern void VG_(set_watchpoint_stop_address) (Addr addr);
+
+/* when invoked by vgdb using ptrace, contains the tid chosen
+   by vgdb (if vgdb gives a tid different of 0: a 0 tid by
+   vgdb means use the running_tid if there is one running
+   or tid 1 otherwise). */
+extern ThreadId vgdb_interrupted_tid;
+
+/*------------ end of interface to low level gdbserver */
+
+
+#define dlog(level, ...) \
+   do { if (UNLIKELY(VG_(debugLog_getLevel)() >= level))  \
+         VG_(debugLog) (level, "gdbsrv",__VA_ARGS__); }   \
+   while (0)
+
+
+/* vki only defines VKI_POLLIN but even not on all OS.
+   Below is from linux bits/poll.h */
+#ifndef VKI_POLLIN
+#define VKI_POLLIN            0x0001
+#endif
+#define VKI_POLLPRI           0x0002
+#define VKI_POLLOUT           0x0004
+#define VKI_POLLERR           0x0008
+#define VKI_POLLHUP           0x0010
+#define VKI_POLLNVAL          0x0020
+
+/* a bunch of macros to avoid libc usage in valgrind-ified gdbserver */ 
+#define strcmp(s1,s2)         VG_(strcmp) ((Char *)(s1),(Char *)(s2))
+#define strncmp(s1,s2,nmax)   VG_(strncmp) ((Char *)(s1),(Char *)(s2),nmax)
+#define strcat(s1,s2)         VG_(strcat) ((Char *)(s1),(Char *)(s2))
+#define strcpy(s1,s2)         VG_(strcpy) ((Char *)(s1),(Char *)(s2))
+#define strncpy(s1,s2,nmax)   VG_(strncpy) ((Char *)(s1),(Char *)(s2),nmax)
+#define strlen(s)             VG_(strlen) ((Char *)(s))
+#define strtok(p,s)           (char *) VG_(strtok) ((Char *)(p),(Char *)(s))
+#define strtok_r(p,s,ss)      (char *) VG_(strtok_r) ((Char *)(p),(Char *)(s),(Char **)(ss))
+#define strchr(s,c)           (char *) VG_(strchr) ((Char *)(s),c)
+/* strtol and strtoul supports base 16 or else assumes it is base 10 */
+#define strtol(s,r,b)         ((b) == 16 ? \
+                               VG_(strtoll16) ((Char *)(s),(Char **)(r)) \
+                               : VG_(strtoll10) ((Char *)(s),(Char **)(r)))
+#define strtoul(s,r,b)        ((b) == 16 ? \
+                               VG_(strtoull16) ((Char *)(s),(Char **)(r)) \
+                               : VG_(strtoull10) ((Char *)(s),(Char **)(r)))
+
+#define malloc(sz)            VG_(arena_malloc)  (VG_AR_CORE, "gdbsrv", sz)
+#define calloc(n,sz)          VG_(arena_calloc)  (VG_AR_CORE, "gdbsrv", n, sz)
+#define realloc(p,size)       VG_(arena_realloc) (VG_AR_CORE, "gdbsrv", p, size)
+#define strdup(s)             (char *) VG_(arena_strdup)  (VG_AR_CORE, "gdbsrv", (Char *)(s))
+#define free(b)               VG_(arena_free)    (VG_AR_CORE, b)
+
+#ifndef ATTR_NORETURN
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+#define ATTR_NORETURN __attribute__ ((noreturn))
+#else
+#define ATTR_NORETURN           /* nothing */
+#endif
+#endif
+
+#ifndef ATTR_FORMAT
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4))
+#define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
+#else
+#define ATTR_FORMAT(type, x, y) /* nothing */
+#endif
+#endif
+
+/* A type used for binary buffers.  */
+typedef unsigned char gdb_byte;
+
+typedef Addr CORE_ADDR;
+
+/* Generic information for tracking a list of ``inferiors'' - threads,
+   processes, etc.  */
+struct inferior_list
+{
+   struct inferior_list_entry *head;
+   struct inferior_list_entry *tail;
+};
+struct inferior_list_entry
+{
+   unsigned long id;
+   struct inferior_list_entry *next;
+};
+
+/* Opaque type for user-visible threads.  */
+struct thread_info;
+
+#include "regcache.h"
+#include "gdb/signals.h"
+
+/* signal handling with gdbserver: before delivering a signal,
+   call gdbserver_signal_encountered then give control to
+   gdbserver by calling call_gdbserver.
+   On return, call gdbserver_deliver_signal to effectively
+   deliver the signal or not. */
+extern void gdbserver_signal_encountered (Int sigNo);
+/* between these two calls, call call_gdbserver */
+/* If gdbserver_deliver_signal True, then gdb did not ask
+   to ignore the signal, so signal can be delivered to the guest. */
+extern Bool gdbserver_deliver_signal (Int sigNo);
+
+/* To optimise signal handling, gdb can instruct gdbserver to
+   not stop on some signals. In the below, a 1 indicates the signal
+   has to be passed directly to the guest, without asking gdb.
+   A 0 indicates gdb has to be consulted to see if signal has
+   or has not to be passed. The gdb consultation is to
+   be done using the above two functions. */
+int pass_signals[TARGET_SIGNAL_LAST];
+
+
+#include "target.h"
+
+/* Target-specific functions */
+
+void initialize_low (void);
+
+/* initialize or re-initialize the register set of the low target.
+   if shadow_mode, then (re-)define the normal and valgrind shadow registers
+   else (re-)define only the normal registers. */
+void initialize_shadow_low (Bool shadow_mode);
+
+/* From inferiors.c.  */
+
+extern struct inferior_list all_threads;
+void add_inferior_to_list (struct inferior_list *list,
+                          struct inferior_list_entry *new_inferior);
+void for_each_inferior (struct inferior_list *list,
+                       void (*action) (struct inferior_list_entry *));
+extern struct thread_info *current_inferior;
+void remove_inferior (struct inferior_list *list,
+                     struct inferior_list_entry *entry);
+void remove_thread (struct thread_info *thread);
+void add_thread (unsigned long thread_id, void *target_data, unsigned int);
+unsigned int thread_id_to_gdb_id (unsigned long);
+unsigned int thread_to_gdb_id (struct thread_info *);
+unsigned long gdb_id_to_thread_id (unsigned int);
+struct thread_info *gdb_id_to_thread (unsigned int);
+void clear_inferiors (void);
+struct inferior_list_entry *find_inferior (struct inferior_list *,
+                                           int (*func) (struct 
+                                                        inferior_list_entry *,
+                                                        void *),
+                                           void *arg);
+struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
+                                             unsigned long id);
+void *inferior_target_data (struct thread_info *);
+void set_inferior_target_data (struct thread_info *, void *);
+void *inferior_regcache_data (struct thread_info *);
+void set_inferior_regcache_data (struct thread_info *, void *);
+void change_inferior_id (struct inferior_list *list,
+                        unsigned long new_id);
+
+/* Public variables in server.c */
+
+extern unsigned long cont_thread;
+extern unsigned long general_thread;
+extern unsigned long step_thread;
+extern unsigned long thread_from_wait;
+extern unsigned long old_thread_from_wait;
+
+extern VG_MINIMAL_JMP_BUF(toplevel);
+
+/* From remote-utils.c */
+
+extern Bool noack_mode;
+int putpkt (char *buf);
+int putpkt_binary (char *buf, int len);
+int getpkt (char *buf);
+void remote_open (char *name);
+void remote_close (void);
+
+void sync_gdb_connection (void);
+void write_ok (char *buf);
+void write_enn (char *buf);
+void convert_ascii_to_int (char *from, unsigned char *to, int n);
+void convert_int_to_ascii (unsigned char *from, char *to, int n);
+void prepare_resume_reply (char *buf, char status, unsigned char sig);
+
+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);
+int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr,
+                    unsigned int *len_ptr, unsigned char *to);
+
+int unhexify (char *bin, const char *hex, int count);
+int hexify (char *hex, const char *bin, int count);
+int remote_escape_output (const gdb_byte *buffer, int len,
+                         gdb_byte *out_buf, int *out_len,
+                         int out_maxlen);
+
+/* Functions from ``signals.c''.  */
+enum target_signal target_signal_from_host (int hostsig);
+int target_signal_to_host_p (enum target_signal oursig);
+int target_signal_to_host (enum target_signal oursig);
+char *target_signal_to_name (enum target_signal);
+
+/* Functions from utils.c */
+
+/* error is like VG_(umsg), then VG_MINIMAL_LONGJMP to gdbserver toplevel. */
+void error (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
+/* first output a description of the error inside sr, then like VG_(umsg). */
+void sr_perror (SysRes sr,char *string,...) ATTR_FORMAT (printf, 2, 3);
+/* fatal is like VG_(umsg), then exit(1). */
+void fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
+/* warning is like VG_(umsg). */
+void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);
+
+/* Functions from the register cache definition.  */
+
+void init_registers (void);
+
+/* 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)
+
+/* PBUFSIZ : Buffers size for transferring memory, registers, etc.
+   Must be big enough to hold all the registers, at least.
+   Must be at least big as 2*DATASIZ + 5:
+      1         : packet begin ($ or %)
+    + 2*DATASIZ : encoded string
+    + 1         : packet end (#)
+    + 2         : packet checksum
+    + 1         : \0 
+
+    Max value gdb likes is 16384.
+
+    Note that what is sent/received to/from gdb does
+    not have a trailing null byte. We are adding 1 here to allow
+    null terminating the strings e.g. for printf.
+
+    => packet Packet OVERHead SIZe is 5:*/
+
+/* keep PBUFSIZ value in sync with vgdb.c */
+#define PBUFSIZ 16384
+#define POVERHSIZ 5
+
+/* Max size of a string encoded in a packet. Hex Encoding can
+   multiply the size by 2 (trailing null byte not sent). */
+#define DATASIZ ((PBUFSIZ-POVERHSIZ)/2)
+
+/* Version information, from version.c.  */
+extern const char version[];
+
+#endif /* SERVER_H */
diff --git a/coregrind/m_gdbserver/signals.c b/coregrind/m_gdbserver/signals.c
new file mode 100644 (file)
index 0000000..07b0c24
--- /dev/null
@@ -0,0 +1,744 @@
+/* Target signal translation functions for GDB.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2011 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+
+#if defined(VGO_darwin)
+// ???? darwin signal.h defines SIGPOLL conditionnally ????
+#ifndef SIGPOLL
+#define SIGPOLL 7
+#endif
+#endif
+
+enum target_signal target_signal_from_name (char *name);
+enum target_signal target_signal_from_command (int num);
+
+/* This table must match in order and size the signals in enum target_signal
+   in gdb/signals.h. */
+/* *INDENT-OFF* */
+static struct {
+   char *name;
+   char *string;
+} signals [] =
+   {
+      {"0", "Signal 0"},
+      {"SIGHUP", "Hangup"},
+      {"SIGINT", "Interrupt"},
+      {"SIGQUIT", "Quit"},
+      {"SIGILL", "Illegal instruction"},
+      {"SIGTRAP", "Trace/breakpoint trap"},
+      {"SIGABRT", "Aborted"},
+      {"SIGEMT", "Emulation trap"},
+      {"SIGFPE", "Arithmetic exception"},
+      {"SIGKILL", "Killed"},
+      {"SIGBUS", "Bus error"},
+      {"SIGSEGV", "Segmentation fault"},
+      {"SIGSYS", "Bad system call"},
+      {"SIGPIPE", "Broken pipe"},
+      {"SIGALRM", "Alarm clock"},
+      {"SIGTERM", "Terminated"},
+      {"SIGURG", "Urgent I/O condition"},
+      {"SIGSTOP", "Stopped (signal)"},
+      {"SIGTSTP", "Stopped (user)"},
+      {"SIGCONT", "Continued"},
+      {"SIGCHLD", "Child status changed"},
+      {"SIGTTIN", "Stopped (tty input)"},
+      {"SIGTTOU", "Stopped (tty output)"},
+      {"SIGIO", "I/O possible"},
+      {"SIGXCPU", "CPU time limit exceeded"},
+      {"SIGXFSZ", "File size limit exceeded"},
+      {"SIGVTALRM", "Virtual timer expired"},
+      {"SIGPROF", "Profiling timer expired"},
+      {"SIGWINCH", "Window size changed"},
+      {"SIGLOST", "Resource lost"},
+      {"SIGUSR1", "User defined signal 1"},
+      {"SIGUSR2", "User defined signal 2"},
+      {"SIGPWR", "Power fail/restart"},
+      {"SIGPOLL", "Pollable event occurred"},
+      {"SIGWIND", "SIGWIND"},
+      {"SIGPHONE", "SIGPHONE"},
+      {"SIGWAITING", "Process's LWPs are blocked"},
+      {"SIGLWP", "Signal LWP"},
+      {"SIGDANGER", "Swap space dangerously low"},
+      {"SIGGRANT", "Monitor mode granted"},
+      {"SIGRETRACT", "Need to relinquish monitor mode"},
+      {"SIGMSG", "Monitor mode data available"},
+      {"SIGSOUND", "Sound completed"},
+      {"SIGSAK", "Secure attention"},
+      {"SIGPRIO", "SIGPRIO"},
+      {"SIG33", "Real-time event 33"},
+      {"SIG34", "Real-time event 34"},
+      {"SIG35", "Real-time event 35"},
+      {"SIG36", "Real-time event 36"},
+      {"SIG37", "Real-time event 37"},
+      {"SIG38", "Real-time event 38"},
+      {"SIG39", "Real-time event 39"},
+      {"SIG40", "Real-time event 40"},
+      {"SIG41", "Real-time event 41"},
+      {"SIG42", "Real-time event 42"},
+      {"SIG43", "Real-time event 43"},
+      {"SIG44", "Real-time event 44"},
+      {"SIG45", "Real-time event 45"},
+      {"SIG46", "Real-time event 46"},
+      {"SIG47", "Real-time event 47"},
+      {"SIG48", "Real-time event 48"},
+      {"SIG49", "Real-time event 49"},
+      {"SIG50", "Real-time event 50"},
+      {"SIG51", "Real-time event 51"},
+      {"SIG52", "Real-time event 52"},
+      {"SIG53", "Real-time event 53"},
+      {"SIG54", "Real-time event 54"},
+      {"SIG55", "Real-time event 55"},
+      {"SIG56", "Real-time event 56"},
+      {"SIG57", "Real-time event 57"},
+      {"SIG58", "Real-time event 58"},
+      {"SIG59", "Real-time event 59"},
+      {"SIG60", "Real-time event 60"},
+      {"SIG61", "Real-time event 61"},
+      {"SIG62", "Real-time event 62"},
+      {"SIG63", "Real-time event 63"},
+      {"SIGCANCEL", "LWP internal signal"},
+      {"SIG32", "Real-time event 32"},
+      {"SIG64", "Real-time event 64"},
+      {"SIG65", "Real-time event 65"},
+      {"SIG66", "Real-time event 66"},
+      {"SIG67", "Real-time event 67"},
+      {"SIG68", "Real-time event 68"},
+      {"SIG69", "Real-time event 69"},
+      {"SIG70", "Real-time event 70"},
+      {"SIG71", "Real-time event 71"},
+      {"SIG72", "Real-time event 72"},
+      {"SIG73", "Real-time event 73"},
+      {"SIG74", "Real-time event 74"},
+      {"SIG75", "Real-time event 75"},
+      {"SIG76", "Real-time event 76"},
+      {"SIG77", "Real-time event 77"},
+      {"SIG78", "Real-time event 78"},
+      {"SIG79", "Real-time event 79"},
+      {"SIG80", "Real-time event 80"},
+      {"SIG81", "Real-time event 81"},
+      {"SIG82", "Real-time event 82"},
+      {"SIG83", "Real-time event 83"},
+      {"SIG84", "Real-time event 84"},
+      {"SIG85", "Real-time event 85"},
+      {"SIG86", "Real-time event 86"},
+      {"SIG87", "Real-time event 87"},
+      {"SIG88", "Real-time event 88"},
+      {"SIG89", "Real-time event 89"},
+      {"SIG90", "Real-time event 90"},
+      {"SIG91", "Real-time event 91"},
+      {"SIG92", "Real-time event 92"},
+      {"SIG93", "Real-time event 93"},
+      {"SIG94", "Real-time event 94"},
+      {"SIG95", "Real-time event 95"},
+      {"SIG96", "Real-time event 96"},
+      {"SIG97", "Real-time event 97"},
+      {"SIG98", "Real-time event 98"},
+      {"SIG99", "Real-time event 99"},
+      {"SIG100", "Real-time event 100"},
+      {"SIG101", "Real-time event 101"},
+      {"SIG102", "Real-time event 102"},
+      {"SIG103", "Real-time event 103"},
+      {"SIG104", "Real-time event 104"},
+      {"SIG105", "Real-time event 105"},
+      {"SIG106", "Real-time event 106"},
+      {"SIG107", "Real-time event 107"},
+      {"SIG108", "Real-time event 108"},
+      {"SIG109", "Real-time event 109"},
+      {"SIG110", "Real-time event 110"},
+      {"SIG111", "Real-time event 111"},
+      {"SIG112", "Real-time event 112"},
+      {"SIG113", "Real-time event 113"},
+      {"SIG114", "Real-time event 114"},
+      {"SIG115", "Real-time event 115"},
+      {"SIG116", "Real-time event 116"},
+      {"SIG117", "Real-time event 117"},
+      {"SIG118", "Real-time event 118"},
+      {"SIG119", "Real-time event 119"},
+      {"SIG120", "Real-time event 120"},
+      {"SIG121", "Real-time event 121"},
+      {"SIG122", "Real-time event 122"},
+      {"SIG123", "Real-time event 123"},
+      {"SIG124", "Real-time event 124"},
+      {"SIG125", "Real-time event 125"},
+      {"SIG126", "Real-time event 126"},
+      {"SIG127", "Real-time event 127"},
+
+      {"SIGINFO", "Information request"},
+
+      {NULL, "Unknown signal"},
+      {NULL, "Internal error: printing TARGET_SIGNAL_DEFAULT"},
+
+      /* Mach exceptions */
+      {"EXC_BAD_ACCESS", "Could not access memory"},
+      {"EXC_BAD_INSTRUCTION", "Illegal instruction/operand"},
+      {"EXC_ARITHMETIC", "Arithmetic exception"},
+      {"EXC_EMULATION", "Emulation instruction"},
+      {"EXC_SOFTWARE", "Software generated exception"},
+      {"EXC_BREAKPOINT", "Breakpoint"},
+
+      /* Last entry, used to check whether the table is the right size.  */
+      {NULL, "TARGET_SIGNAL_MAGIC"}
+   };
+/* *INDENT-ON* */
+
+
+
+/* Return the name for a signal.  */
+char *target_signal_to_name (enum target_signal sig)
+{
+   if ((sig >= TARGET_SIGNAL_FIRST) && (sig <= TARGET_SIGNAL_LAST)
+       && signals[sig].name != NULL)
+      return signals[sig].name;
+   else
+      /* I think the code which prints this will always print it along
+         with the string, so no need to be verbose (very old comment).  */
+      return "?";
+}
+
+/* Given a name, return its signal.  */
+enum target_signal target_signal_from_name (char *name)
+{
+   enum target_signal sig;
+
+   /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD"
+      for TARGET_SIGNAL_SIGCHLD.  SIGIOT, on the other hand, is more
+      questionable; seems like by now people should call it SIGABRT
+      instead.  */
+
+   /* This ugly cast brought to you by the native VAX compiler.  */
+   for (sig = TARGET_SIGNAL_HUP;
+        sig < TARGET_SIGNAL_LAST;
+        sig = (enum target_signal) ((int) sig + 1))
+      if (signals[sig].name != NULL
+          && strcmp (name, signals[sig].name) == 0)
+         return sig;
+   return TARGET_SIGNAL_UNKNOWN;
+}
+
+
+/* The following functions are to help certain targets deal
+   with the signal/waitstatus stuff.  They could just as well be in
+   a file called native-utils.c or unixwaitstatus-utils.c or whatever.  */
+
+/* Convert host signal to our signals.  */
+enum target_signal target_signal_from_host (int hostsig)
+{
+   /* A switch statement would make sense but would require special kludges
+      to deal with the cases where more than one signal has the same number.  */
+
+   if (hostsig == 0)
+      return TARGET_SIGNAL_0;
+
+#if defined (VKI_SIGHUP)
+   if (hostsig == VKI_SIGHUP)
+      return TARGET_SIGNAL_HUP;
+#endif
+#if defined (VKI_SIGINT)
+   if (hostsig == VKI_SIGINT)
+      return TARGET_SIGNAL_INT;
+#endif
+#if defined (VKI_SIGQUIT)
+   if (hostsig == VKI_SIGQUIT)
+      return TARGET_SIGNAL_QUIT;
+#endif
+#if defined (VKI_SIGILL)
+   if (hostsig == VKI_SIGILL)
+      return TARGET_SIGNAL_ILL;
+#endif
+#if defined (VKI_SIGTRAP)
+   if (hostsig == VKI_SIGTRAP)
+      return TARGET_SIGNAL_TRAP;
+#endif
+#if defined (VKI_SIGABRT)
+   if (hostsig == VKI_SIGABRT)
+      return TARGET_SIGNAL_ABRT;
+#endif
+#if defined (VKI_SIGEMT)
+   if (hostsig == VKI_SIGEMT)
+      return TARGET_SIGNAL_EMT;
+#endif
+#if defined (VKI_SIGFPE)
+   if (hostsig == VKI_SIGFPE)
+      return TARGET_SIGNAL_FPE;
+#endif
+#if defined (VKI_SIGKILL)
+   if (hostsig == VKI_SIGKILL)
+      return TARGET_SIGNAL_KILL;
+#endif
+#if defined (VKI_SIGBUS)
+   if (hostsig == VKI_SIGBUS)
+      return TARGET_SIGNAL_BUS;
+#endif
+#if defined (VKI_SIGSEGV)
+   if (hostsig == VKI_SIGSEGV)
+      return TARGET_SIGNAL_SEGV;
+#endif
+#if defined (VKI_SIGSYS)
+   if (hostsig == VKI_SIGSYS)
+      return TARGET_SIGNAL_SYS;
+#endif
+#if defined (VKI_SIGPIPE)
+   if (hostsig == VKI_SIGPIPE)
+      return TARGET_SIGNAL_PIPE;
+#endif
+#if defined (VKI_SIGALRM)
+   if (hostsig == VKI_SIGALRM)
+      return TARGET_SIGNAL_ALRM;
+#endif
+#if defined (VKI_SIGTERM)
+   if (hostsig == VKI_SIGTERM)
+      return TARGET_SIGNAL_TERM;
+#endif
+#if defined (VKI_SIGUSR1)
+   if (hostsig == VKI_SIGUSR1)
+      return TARGET_SIGNAL_USR1;
+#endif
+#if defined (VKI_SIGUSR2)
+   if (hostsig == VKI_SIGUSR2)
+      return TARGET_SIGNAL_USR2;
+#endif
+#if defined (VKI_SIGCLD)
+   if (hostsig == VKI_SIGCLD)
+      return TARGET_SIGNAL_CHLD;
+#endif
+#if defined (VKI_SIGCHLD)
+   if (hostsig == VKI_SIGCHLD)
+      return TARGET_SIGNAL_CHLD;
+#endif
+#if defined (VKI_SIGPWR)
+   if (hostsig == VKI_SIGPWR)
+      return TARGET_SIGNAL_PWR;
+#endif
+#if defined (VKI_SIGWINCH)
+   if (hostsig == VKI_SIGWINCH)
+      return TARGET_SIGNAL_WINCH;
+#endif
+#if defined (VKI_SIGURG)
+   if (hostsig == VKI_SIGURG)
+      return TARGET_SIGNAL_URG;
+#endif
+#if defined (VKI_SIGIO)
+   if (hostsig == VKI_SIGIO)
+      return TARGET_SIGNAL_IO;
+#endif
+#if defined (VKI_SIGPOLL)
+   if (hostsig == VKI_SIGPOLL)
+      return TARGET_SIGNAL_POLL;
+#endif
+#if defined (VKI_SIGSTOP)
+   if (hostsig == VKI_SIGSTOP)
+      return TARGET_SIGNAL_STOP;
+#endif
+#if defined (VKI_SIGTSTP)
+   if (hostsig == VKI_SIGTSTP)
+      return TARGET_SIGNAL_TSTP;
+#endif
+#if defined (VKI_SIGCONT)
+   if (hostsig == VKI_SIGCONT)
+      return TARGET_SIGNAL_CONT;
+#endif
+#if defined (VKI_SIGTTIN)
+   if (hostsig == VKI_SIGTTIN)
+      return TARGET_SIGNAL_TTIN;
+#endif
+#if defined (VKI_SIGTTOU)
+   if (hostsig == VKI_SIGTTOU)
+      return TARGET_SIGNAL_TTOU;
+#endif
+#if defined (VKI_SIGVTALRM)
+   if (hostsig == VKI_SIGVTALRM)
+      return TARGET_SIGNAL_VTALRM;
+#endif
+#if defined (VKI_SIGPROF)
+   if (hostsig == VKI_SIGPROF)
+      return TARGET_SIGNAL_PROF;
+#endif
+#if defined (VKI_SIGXCPU)
+   if (hostsig == VKI_SIGXCPU)
+      return TARGET_SIGNAL_XCPU;
+#endif
+#if defined (VKI_SIGXFSZ)
+   if (hostsig == VKI_SIGXFSZ)
+      return TARGET_SIGNAL_XFSZ;
+#endif
+#if defined (VKI_SIGWIND)
+   if (hostsig == VKI_SIGWIND)
+      return TARGET_SIGNAL_WIND;
+#endif
+#if defined (VKI_SIGPHONE)
+   if (hostsig == VKI_SIGPHONE)
+      return TARGET_SIGNAL_PHONE;
+#endif
+#if defined (VKI_SIGLOST)
+   if (hostsig == VKI_SIGLOST)
+      return TARGET_SIGNAL_LOST;
+#endif
+#if defined (VKI_SIGWAITING)
+   if (hostsig == VKI_SIGWAITING)
+      return TARGET_SIGNAL_WAITING;
+#endif
+#if defined (VKI_SIGCANCEL)
+   if (hostsig == VKI_SIGCANCEL)
+      return TARGET_SIGNAL_CANCEL;
+#endif
+#if defined (VKI_SIGLWP)
+   if (hostsig == VKI_SIGLWP)
+      return TARGET_SIGNAL_LWP;
+#endif
+#if defined (VKI_SIGDANGER)
+   if (hostsig == VKI_SIGDANGER)
+      return TARGET_SIGNAL_DANGER;
+#endif
+#if defined (VKI_SIGGRANT)
+   if (hostsig == VKI_SIGGRANT)
+      return TARGET_SIGNAL_GRANT;
+#endif
+#if defined (VKI_SIGRETRACT)
+   if (hostsig == VKI_SIGRETRACT)
+      return TARGET_SIGNAL_RETRACT;
+#endif
+#if defined (VKI_SIGMSG)
+   if (hostsig == VKI_SIGMSG)
+      return TARGET_SIGNAL_MSG;
+#endif
+#if defined (VKI_SIGSOUND)
+   if (hostsig == VKI_SIGSOUND)
+      return TARGET_SIGNAL_SOUND;
+#endif
+#if defined (VKI_SIGSAK)
+   if (hostsig == VKI_SIGSAK)
+      return TARGET_SIGNAL_SAK;
+#endif
+#if defined (VKI_SIGPRIO)
+   if (hostsig == VKI_SIGPRIO)
+      return TARGET_SIGNAL_PRIO;
+#endif
+
+   /* Mach exceptions.  Assumes that the values for EXC_ are positive! */
+#if defined (EXC_BAD_ACCESS) && defined (_NSIG)
+   if (hostsig == _NSIG + EXC_BAD_ACCESS)
+      return TARGET_EXC_BAD_ACCESS;
+#endif
+#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG)
+   if (hostsig == _NSIG + EXC_BAD_INSTRUCTION)
+      return TARGET_EXC_BAD_INSTRUCTION;
+#endif
+#if defined (EXC_ARITHMETIC) && defined (_NSIG)
+   if (hostsig == _NSIG + EXC_ARITHMETIC)
+      return TARGET_EXC_ARITHMETIC;
+#endif
+#if defined (EXC_EMULATION) && defined (_NSIG)
+   if (hostsig == _NSIG + EXC_EMULATION)
+      return TARGET_EXC_EMULATION;
+#endif
+#if defined (EXC_SOFTWARE) && defined (_NSIG)
+   if (hostsig == _NSIG + EXC_SOFTWARE)
+      return TARGET_EXC_SOFTWARE;
+#endif
+#if defined (EXC_BREAKPOINT) && defined (_NSIG)
+   if (hostsig == _NSIG + EXC_BREAKPOINT)
+      return TARGET_EXC_BREAKPOINT;
+#endif
+
+#if defined (VKI_SIGINFO)
+   if (hostsig == VKI_SIGINFO)
+      return TARGET_SIGNAL_INFO;
+#endif
+
+   return TARGET_SIGNAL_UNKNOWN;
+}
+
+/* Convert a OURSIG (an enum target_signal) to the form used by the
+   target operating system (refered to as the ``host'') or zero if the
+   equivalent host signal is not available.  Set/clear OURSIG_OK
+   accordingly. */
+
+static
+int do_target_signal_to_host (enum target_signal oursig,
+                         int *oursig_ok)
+{
+   *oursig_ok = 1;
+   switch (oursig) {
+   case TARGET_SIGNAL_0:
+      return 0;
+
+#if defined (VKI_SIGHUP)
+   case TARGET_SIGNAL_HUP:
+      return VKI_SIGHUP;
+#endif
+#if defined (VKI_SIGINT)
+   case TARGET_SIGNAL_INT:
+      return VKI_SIGINT;
+#endif
+#if defined (VKI_SIGQUIT)
+   case TARGET_SIGNAL_QUIT:
+      return VKI_SIGQUIT;
+#endif
+#if defined (VKI_SIGILL)
+   case TARGET_SIGNAL_ILL:
+      return VKI_SIGILL;
+#endif
+#if defined (VKI_SIGTRAP)
+   case TARGET_SIGNAL_TRAP:
+      return VKI_SIGTRAP;
+#endif
+#if defined (VKI_SIGABRT)
+   case TARGET_SIGNAL_ABRT:
+      return VKI_SIGABRT;
+#endif
+#if defined (VKI_SIGEMT)
+   case TARGET_SIGNAL_EMT:
+      return VKI_SIGEMT;
+#endif
+#if defined (VKI_SIGFPE)
+   case TARGET_SIGNAL_FPE:
+      return VKI_SIGFPE;
+#endif
+#if defined (VKI_SIGKILL)
+   case TARGET_SIGNAL_KILL:
+      return VKI_SIGKILL;
+#endif
+#if defined (VKI_SIGBUS)
+   case TARGET_SIGNAL_BUS:
+      return VKI_SIGBUS;
+#endif
+#if defined (VKI_SIGSEGV)
+   case TARGET_SIGNAL_SEGV:
+      return VKI_SIGSEGV;
+#endif
+#if defined (VKI_SIGSYS)
+   case TARGET_SIGNAL_SYS:
+      return VKI_SIGSYS;
+#endif
+#if defined (VKI_SIGPIPE)
+   case TARGET_SIGNAL_PIPE:
+      return VKI_SIGPIPE;
+#endif
+#if defined (VKI_SIGALRM)
+   case TARGET_SIGNAL_ALRM:
+      return VKI_SIGALRM;
+#endif
+#if defined (VKI_SIGTERM)
+   case TARGET_SIGNAL_TERM:
+      return VKI_SIGTERM;
+#endif
+#if defined (VKI_SIGUSR1)
+   case TARGET_SIGNAL_USR1:
+      return VKI_SIGUSR1;
+#endif
+#if defined (VKI_SIGUSR2)
+   case TARGET_SIGNAL_USR2:
+      return VKI_SIGUSR2;
+#endif
+#if defined (VKI_SIGCHLD) || defined (VKI_SIGCLD)
+   case TARGET_SIGNAL_CHLD:
+#if defined (VKI_SIGCHLD)
+      return VKI_SIGCHLD;
+#else
+      return VKI_SIGCLD;
+#endif
+#endif /* SIGCLD or SIGCHLD */
+#if defined (VKI_SIGPWR)
+   case TARGET_SIGNAL_PWR:
+      return VKI_SIGPWR;
+#endif
+#if defined (VKI_SIGWINCH)
+   case TARGET_SIGNAL_WINCH:
+      return VKI_SIGWINCH;
+#endif
+#if defined (VKI_SIGURG)
+   case TARGET_SIGNAL_URG:
+      return VKI_SIGURG;
+#endif
+#if defined (VKI_SIGIO)
+   case TARGET_SIGNAL_IO:
+      return VKI_SIGIO;
+#endif
+#if defined (VKI_SIGPOLL)
+   case TARGET_SIGNAL_POLL:
+      return VKI_SIGPOLL;
+#endif
+#if defined (VKI_SIGSTOP)
+   case TARGET_SIGNAL_STOP:
+      return VKI_SIGSTOP;
+#endif
+#if defined (VKI_SIGTSTP)
+   case TARGET_SIGNAL_TSTP:
+      return VKI_SIGTSTP;
+#endif
+#if defined (VKI_SIGCONT)
+   case TARGET_SIGNAL_CONT:
+      return VKI_SIGCONT;
+#endif
+#if defined (VKI_SIGTTIN)
+   case TARGET_SIGNAL_TTIN:
+      return VKI_SIGTTIN;
+#endif
+#if defined (VKI_SIGTTOU)
+   case TARGET_SIGNAL_TTOU:
+      return VKI_SIGTTOU;
+#endif
+#if defined (VKI_SIGVTALRM)
+   case TARGET_SIGNAL_VTALRM:
+      return VKI_SIGVTALRM;
+#endif
+#if defined (VKI_SIGPROF)
+   case TARGET_SIGNAL_PROF:
+      return VKI_SIGPROF;
+#endif
+#if defined (VKI_SIGXCPU)
+   case TARGET_SIGNAL_XCPU:
+      return VKI_SIGXCPU;
+#endif
+#if defined (VKI_SIGXFSZ)
+   case TARGET_SIGNAL_XFSZ:
+      return VKI_SIGXFSZ;
+#endif
+#if defined (VKI_SIGWIND)
+   case TARGET_SIGNAL_WIND:
+      return VKI_SIGWIND;
+#endif
+#if defined (VKI_SIGPHONE)
+   case TARGET_SIGNAL_PHONE:
+      return VKI_SIGPHONE;
+#endif
+#if defined (VKI_SIGLOST)
+   case TARGET_SIGNAL_LOST:
+      return VKI_SIGLOST;
+#endif
+#if defined (VKI_SIGWAITING)
+   case TARGET_SIGNAL_WAITING:
+      return VKI_SIGWAITING;
+#endif
+#if defined (VKI_SIGCANCEL)
+   case TARGET_SIGNAL_CANCEL:
+      return VKI_SIGCANCEL;
+#endif
+#if defined (VKI_SIGLWP)
+   case TARGET_SIGNAL_LWP:
+      return VKI_SIGLWP;
+#endif
+#if defined (VKI_SIGDANGER)
+   case TARGET_SIGNAL_DANGER:
+      return VKI_SIGDANGER;
+#endif
+#if defined (VKI_SIGGRANT)
+   case TARGET_SIGNAL_GRANT:
+      return VKI_SIGGRANT;
+#endif
+#if defined (VKI_SIGRETRACT)
+   case TARGET_SIGNAL_RETRACT:
+      return VKI_SIGRETRACT;
+#endif
+#if defined (VKI_SIGMSG)
+   case TARGET_SIGNAL_MSG:
+      return VKI_SIGMSG;
+#endif
+#if defined (VKI_SIGSOUND)
+   case TARGET_SIGNAL_SOUND:
+      return VKI_SIGSOUND;
+#endif
+#if defined (VKI_SIGSAK)
+   case TARGET_SIGNAL_SAK:
+      return VKI_SIGSAK;
+#endif
+#if defined (VKI_SIGPRIO)
+   case TARGET_SIGNAL_PRIO:
+      return VKI_SIGPRIO;
+#endif
+
+      /* Mach exceptions.  Assumes that the values for EXC_ are positive! */
+#if defined (EXC_BAD_ACCESS) && defined (_NSIG)
+   case TARGET_EXC_BAD_ACCESS:
+      return _NSIG + EXC_BAD_ACCESS;
+#endif
+#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG)
+   case TARGET_EXC_BAD_INSTRUCTION:
+      return _NSIG + EXC_BAD_INSTRUCTION;
+#endif
+#if defined (EXC_ARITHMETIC) && defined (_NSIG)
+   case TARGET_EXC_ARITHMETIC:
+      return _NSIG + EXC_ARITHMETIC;
+#endif
+#if defined (EXC_EMULATION) && defined (_NSIG)
+   case TARGET_EXC_EMULATION:
+      return _NSIG + EXC_EMULATION;
+#endif
+#if defined (EXC_SOFTWARE) && defined (_NSIG)
+   case TARGET_EXC_SOFTWARE:
+      return _NSIG + EXC_SOFTWARE;
+#endif
+#if defined (EXC_BREAKPOINT) && defined (_NSIG)
+   case TARGET_EXC_BREAKPOINT:
+      return _NSIG + EXC_BREAKPOINT;
+#endif
+
+#if defined (VKI_SIGINFO)
+   case TARGET_SIGNAL_INFO:
+      return VKI_SIGINFO;
+#endif
+
+   default:
+      *oursig_ok = 0;
+      return 0;
+   }
+}
+
+int target_signal_to_host_p (enum target_signal oursig)
+{
+   int oursig_ok;
+   do_target_signal_to_host (oursig, &oursig_ok);
+   return oursig_ok;
+}
+
+int target_signal_to_host (enum target_signal oursig)
+{
+   int oursig_ok;
+   int targ_signo = do_target_signal_to_host (oursig, &oursig_ok);
+   if (!oursig_ok) {
+      /* The user might be trying to do "signal SIGSAK" where this system
+         doesn't have SIGSAK.  */
+      warning ("Signal %s does not exist on this system.\n",
+               target_signal_to_name (oursig));
+      return 0;
+   } else {
+      return targ_signo;
+   }
+}
+
+/* In some circumstances we allow a command to specify a numeric
+   signal.  The idea is to keep these circumstances limited so that
+   users (and scripts) develop portable habits.  For comparison,
+   POSIX.2 `kill' requires that 1,2,3,6,9,14, and 15 work (and using a
+   numeric signal at all is obsolescent.  We are slightly more
+   lenient and allow 1-15 which should match host signal numbers on
+   most systems.  Use of symbolic signal names is strongly encouraged.  */
+
+enum target_signal target_signal_from_command (int num)
+{
+   if (num >= 1 && num <= 15)
+      return (enum target_signal) num;
+   error ("Only signals 1-15 are valid as numeric signals.\n\
+Use \"info signals\" for a list of symbolic signals.\n");
+}
diff --git a/coregrind/m_gdbserver/target.c b/coregrind/m_gdbserver/target.c
new file mode 100644 (file)
index 0000000..ae61c94
--- /dev/null
@@ -0,0 +1,121 @@
+/* Target operations for the remote server for GDB.
+   Copyright (C) 2002, 2004, 2005, 2011
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+
+struct target_ops *the_target;
+
+void set_desired_inferior (int use_general)
+{
+  struct thread_info *found;
+
+  if (use_general == 1) {
+     found = (struct thread_info *) find_inferior_id (&all_threads,
+                                                      general_thread);
+  } else {
+     found = NULL;
+
+     /* If we are continuing any (all) thread(s), use step_thread
+        to decide which thread to step and/or send the specified
+        signal to.  */
+     if ((step_thread != 0 && step_thread != -1)
+         && (cont_thread == 0 || cont_thread == -1))
+       found = (struct thread_info *) find_inferior_id (&all_threads,
+                                                        step_thread);
+
+     if (found == NULL)
+       found = (struct thread_info *) find_inferior_id (&all_threads,
+                                                        cont_thread);
+  }
+
+  if (found == NULL)
+     current_inferior = (struct thread_info *) all_threads.head;
+  else
+     current_inferior = found;
+  {
+     ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
+     ThreadId tid = tst->tid;
+     dlog(1, "set_desired_inferior use_general %d found %p tid %d lwpid %d\n",
+          use_general, found, tid, tst->os_state.lwpid);
+  }
+}
+
+int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+   int res;
+   res = (*the_target->read_memory) (memaddr, myaddr, len);
+   return res;
+}
+
+int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
+                           int len)
+{
+   /* Lacking cleanups, there is some potential for a memory leak if the
+      write fails and we go through error().  Make sure that no more than
+      one buffer is ever pending by making BUFFER static.  */
+   static unsigned char *buffer = 0;
+   int res;
+
+   if (buffer != NULL)
+      free (buffer);
+
+   buffer = malloc (len);
+   VG_(memcpy) (buffer, myaddr, len);
+   res = (*the_target->write_memory) (memaddr, buffer, len);
+   free (buffer);
+   buffer = NULL;
+
+   return res;
+}
+
+void set_target_ops (struct target_ops *target)
+{
+   the_target = (struct target_ops *) malloc (sizeof (*the_target));
+   VG_(memcpy) (the_target, target, sizeof (*the_target));
+}
+
+void* VG_(dmemcpy) ( void *d, const void *s, SizeT sz, Bool *mod )
+{
+   if (VG_(memcmp) (d, s, sz)) {
+      *mod = True;
+      return VG_(memcpy) (d, s, sz);
+   } else {
+      *mod = False;
+      return d;
+   }
+}
+
+void VG_(transfer) (void *valgrind,
+                    void *gdbserver,
+                    transfer_direction dir,
+                    SizeT sz,
+                    Bool *mod)
+{
+   if (dir == valgrind_to_gdbserver)
+      VG_(dmemcpy) (gdbserver, valgrind, sz, mod);
+   else if (dir == gdbserver_to_valgrind)
+      VG_(dmemcpy) (valgrind, gdbserver, sz, mod);
+   else
+      vg_assert (0);
+}
diff --git a/coregrind/m_gdbserver/target.h b/coregrind/m_gdbserver/target.h
new file mode 100644 (file)
index 0000000..d657438
--- /dev/null
@@ -0,0 +1,176 @@
+/* Target operations for the remote server for GDB.
+   Copyright (C) 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef TARGET_H
+#define TARGET_H
+
+/* 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 generally passed around
+   as an array, and terminated by a thread == -1 entry.  */
+
+struct thread_resume
+{
+  unsigned long thread;
+
+  /* If non-zero, leave this thread stopped.  */
+  int leave_stopped;
+
+  /* If non-zero, we want to single-step.  */
+  int step;
+
+  /* If non-zero, send this signal when we resume.  */
+  int sig;
+};
+
+struct target_ops
+{
+  /* Return 1 iff the thread with process ID PID is alive.  */
+
+  int (*thread_alive) (unsigned long pid);
+
+  /* Resume the inferior process.  */
+
+  void (*resume) (struct thread_resume *resume_info);
+
+  /* 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, in the
+     remote protocol numbering (e.g. TARGET_SIGNAL_STOP), or the
+     exit code as an integer if *STATUS is 'W'.  */
+
+  unsigned char (*wait) (char *status);
+
+  /* Fetch registers from the inferior process.
+
+     If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO.  */
+
+  void (*fetch_registers) (int regno);
+
+  /* Store registers to the inferior process.
+
+     If REGNO is -1, store all registers; otherwise, store at least REGNO.  */
+
+  void (*store_registers) (int 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.
+  
+     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 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.  */
+
+  int (*write_memory) (CORE_ADDR memaddr, const unsigned char *myaddr,
+                      int len);
+
+  /* Send a signal to the inferior process, however is appropriate.  */
+  void (*send_signal) (int);
+
+  /* Returns the name of the xml target description file. 
+     returns NULL if no xml target description available. */
+  char* (*target_xml)(void);
+
+  /* Same but describes also the shadow registers. */
+  char* (*shadow_target_xml)(void);
+
+  /* Insert and remove a hardware watchpoint.
+     Returns 0 on success, -1 on failure and 1 on unsupported.  
+     The type is coded as follows:
+       2 = write watchpoint
+       3 = read watchpoint
+       4 = access watchpoint
+  */
+
+  int (*insert_watchpoint) (char type, CORE_ADDR addr, int len);
+  int (*remove_watchpoint) (char type, CORE_ADDR addr, int len);
+
+  /* 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);
+
+};
+
+extern struct target_ops *the_target;
+
+void set_target_ops (struct target_ops *);
+
+#define detach_inferior() \
+  (*the_target->detach) ()
+
+#define mythread_alive(pid) \
+  (*the_target->thread_alive) (pid)
+
+#define fetch_inferior_registers(regno) \
+  (*the_target->fetch_registers) (regno)
+
+#define store_inferior_registers(regno) \
+  (*the_target->store_registers) (regno)
+
+#define mywait(statusp) \
+  (*the_target->wait) (statusp)
+
+int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
+
+int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
+                          int len);
+
+void set_desired_inferior (int id);
+
+/* like memcpy but first check if content of destination and source
+   differs. If no difference, no copy is done, *mod set to False.
+   If different; copy is done, *mod set to True. */
+extern void* VG_(dmemcpy) ( void *d, const void *s, SizeT sz, Bool *mod );
+
+typedef
+   enum {
+      valgrind_to_gdbserver,
+      gdbserver_to_valgrind} transfer_direction;
+
+// According to dir, calls VG_(dmemcpy) 
+// to copy data from/to valgrind to/from gdbserver.
+// If the transferred data differs from what is currently stored,
+// sets *mod to True otherwise set *mod to False.
+extern void  VG_(transfer) (void *valgrind,
+                            void *gdbserver,
+                            transfer_direction dir,
+                            SizeT sz,
+                            Bool *mod);
+
+#endif /* TARGET_H */
diff --git a/coregrind/m_gdbserver/utils.c b/coregrind/m_gdbserver/utils.c
new file mode 100644 (file)
index 0000000..57db175
--- /dev/null
@@ -0,0 +1,88 @@
+/* General utility routines for the remote server for GDB.
+   Copyright (C) 1986, 1989, 1993, 1995, 1996, 1997, 1999, 2000, 2002, 2003,
+   2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+/* Generally useful subroutines used throughout the program.  */
+
+/* Print the system error message for sr.
+   Then print the rest of the args. */
+void sr_perror (SysRes sr,char *string,...)
+{
+   va_list args;
+   if (sr_isError (sr))
+      VG_(umsg) ("error %ld %s\n", sr_Err(sr), VG_(strerror) (sr_Err(sr)));
+   else
+      VG_(umsg) ("sr_perror called with no error!!!\n");
+   va_start (args, string);
+   VG_(vmessage) ( Vg_UserMsg, string, args );
+   va_end (args);
+}
+
+/* Print an error message and return to command level.
+   STRING is the error message, used as a fprintf string,
+   and ARG is passed as an argument to it.  */
+
+void error (const char *string,...)
+{
+   va_list args;
+   va_start (args, string);
+   VG_(vmessage) ( Vg_UserMsg, string, args );
+   va_end(args);
+   VG_MINIMAL_LONGJMP(toplevel);
+}
+
+/* Print an error message and exit reporting failure.
+   This is for a error that we cannot continue from.
+   STRING and ARG are passed to fprintf.  */
+
+/* VARARGS */
+void fatal (const char *string,...)
+{
+   va_list args;
+   va_start (args, string);
+   VG_(vmessage) ( Vg_UserMsg, string, args );
+   va_end (args);
+   VG_(exit) (1);
+}
+
+/* VARARGS */
+void warning (const char *string,...)
+{
+   va_list args;
+   va_start (args, string);
+   VG_(vmessage) ( Vg_UserMsg, string, args );
+   va_end (args);
+}
+
+#if 0
+/* print timestamp */
+static
+void dbgts(void)
+{
+   struct vki_timeval dbgtv;
+   SysRes res;
+   res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&dbgtv, (UWord)NULL);
+   // gettimeofday(&dbgtv, NULL);
+   dlog(0, "%ld.%6ld ", dbgtv.tv_sec, dbgtv.tv_usec);
+}
+#endif
diff --git a/coregrind/m_gdbserver/valgrind-low-amd64.c b/coregrind/m_gdbserver/valgrind-low-amd64.c
new file mode 100644 (file)
index 0000000..0dc0382
--- /dev/null
@@ -0,0 +1,306 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+
+#include "valgrind_low.h"
+
+#include "libvex_guest_amd64.h"
+/* GDBTD: ??? have a cleaner way to get the f80 <> f64 conversion functions */
+/* below include needed for conversion f80 <> f64 */
+#include "../../VEX/priv/guest_generic_x87.h" 
+
+/* below loosely inspired from file generated with gdb regdat.sh */
+
+struct reg regs[] = {
+  { "rax", 0, 64 },
+  { "rbx", 64, 64 },
+  { "rcx", 128, 64 },
+  { "rdx", 192, 64 },
+  { "rsi", 256, 64 },
+  { "rdi", 320, 64 },
+  { "rbp", 384, 64 },
+  { "rsp", 448, 64 },
+  { "r8", 512, 64 },
+  { "r9", 576, 64 },
+  { "r10", 640, 64 },
+  { "r11", 704, 64 },
+  { "r12", 768, 64 },
+  { "r13", 832, 64 },
+  { "r14", 896, 64 },
+  { "r15", 960, 64 },
+  { "rip", 1024, 64 },
+  { "eflags", 1088, 32 },
+  { "cs", 1120, 32 },
+  { "ss", 1152, 32 },
+  { "ds", 1184, 32 },
+  { "es", 1216, 32 },
+  { "fs", 1248, 32 },
+  { "gs", 1280, 32 },
+  { "st0", 1312, 80 },
+  { "st1", 1392, 80 },
+  { "st2", 1472, 80 },
+  { "st3", 1552, 80 },
+  { "st4", 1632, 80 },
+  { "st5", 1712, 80 },
+  { "st6", 1792, 80 },
+  { "st7", 1872, 80 },
+  { "fctrl", 1952, 32 },
+  { "fstat", 1984, 32 },
+  { "ftag", 2016, 32 },
+  { "fiseg", 2048, 32 },
+  { "fioff", 2080, 32 },
+  { "foseg", 2112, 32 },
+  { "fooff", 2144, 32 },
+  { "fop", 2176, 32 },
+  { "xmm0", 2208, 128 },
+  { "xmm1", 2336, 128 },
+  { "xmm2", 2464, 128 },
+  { "xmm3", 2592, 128 },
+  { "xmm4", 2720, 128 },
+  { "xmm5", 2848, 128 },
+  { "xmm6", 2976, 128 },
+  { "xmm7", 3104, 128 },
+  { "xmm8", 3232, 128 },
+  { "xmm9", 3360, 128 },
+  { "xmm10", 3488, 128 },
+  { "xmm11", 3616, 128 },
+  { "xmm12", 3744, 128 },
+  { "xmm13", 3872, 128 },
+  { "xmm14", 4000, 128 },
+  { "xmm15", 4128, 128 },
+  { "mxcsr", 4256, 32  },
+#if defined(VGO_linux)
+  { "orig_rax", 4288, 64 }
+#endif
+};
+static const char *expedite_regs[] = { "rbp", "rsp", "rip", 0 };
+#define num_regs (sizeof (regs) / sizeof (regs[0]))
+
+static
+CORE_ADDR get_pc (void)
+{
+   unsigned long pc;
+
+   collect_register_by_name ("rip", &pc);
+   
+   dlog(1, "stop pc is %p\n", (void *) pc);
+   return pc;
+}
+
+static
+void set_pc (CORE_ADDR newpc)
+{
+   Bool mod;
+   supply_register_by_name ("rip", &newpc, &mod);
+   if (mod)
+      dlog(1, "set pc to %p\n", C2v (newpc));
+   else
+      dlog(1, "set pc not changed %p\n", C2v (newpc));
+}
+
+/* store registers in the guest state (gdbserver_to_valgrind)
+   or fetch register from the guest state (valgrind_to_gdbserver). */
+static
+void transfer_register (ThreadId tid, int abs_regno, void * buf,
+                        transfer_direction dir, int size, Bool *mod)
+{
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   int set = abs_regno / num_regs;
+   int regno = abs_regno % num_regs;
+   *mod = False;
+
+   VexGuestAMD64State* amd64 = (VexGuestAMD64State*) get_arch (set, tst);
+
+   switch (regno) { 
+   // numbers here have to match the order of regs above.
+   // Attention: gdb order does not match valgrind order.
+   case 0:  VG_(transfer) (&amd64->guest_RAX, buf, dir, size, mod); break;
+   case 1:  VG_(transfer) (&amd64->guest_RBX, buf, dir, size, mod); break;
+   case 2:  VG_(transfer) (&amd64->guest_RCX, buf, dir, size, mod); break;
+   case 3:  VG_(transfer) (&amd64->guest_RDX, buf, dir, size, mod); break;
+   case 4:  VG_(transfer) (&amd64->guest_RSI, buf, dir, size, mod); break;
+   case 5:  VG_(transfer) (&amd64->guest_RDI, buf, dir, size, mod); break;
+   case 6:  VG_(transfer) (&amd64->guest_RBP, buf, dir, size, mod); break;
+   case 7:  VG_(transfer) (&amd64->guest_RSP, buf, dir, size, mod); break;
+   case 8:  VG_(transfer) (&amd64->guest_R8,  buf, dir, size, mod); break;
+   case 9:  VG_(transfer) (&amd64->guest_R9,  buf, dir, size, mod); break;
+   case 10: VG_(transfer) (&amd64->guest_R10, buf, dir, size, mod); break;
+   case 11: VG_(transfer) (&amd64->guest_R11, buf, dir, size, mod); break;
+   case 12: VG_(transfer) (&amd64->guest_R12, buf, dir, size, mod); break;
+   case 13: VG_(transfer) (&amd64->guest_R13, buf, dir, size, mod); break;
+   case 14: VG_(transfer) (&amd64->guest_R14, buf, dir, size, mod); break;
+   case 15: VG_(transfer) (&amd64->guest_R15, buf, dir, size, mod); break;
+   case 16: 
+      VG_(transfer) (&amd64->guest_RIP, buf, dir, size, mod);
+      if (*mod && VG_(debugLog_getLevel)() > 2) {
+         char bufimage [2*sizeof(amd64->guest_IP_AT_SYSCALL) + 1];
+         heximage (bufimage, 
+                   (char *) &amd64->guest_IP_AT_SYSCALL, 
+                   sizeof(amd64->guest_IP_AT_SYSCALL));
+         dlog(3, "guest_IP_AT_SYSCALL %s\n", bufimage);
+      }
+      break;
+   case 17: 
+      if (dir == valgrind_to_gdbserver) {
+         ULong rflags;
+         /* we can only retrieve the real flags (set 0)
+            retrieving shadow flags is not ok */
+         if (set == 0)
+            rflags = LibVEX_GuestAMD64_get_rflags (amd64);
+         else
+            rflags = 0;
+         VG_(transfer) (&rflags, buf, dir, size, mod); 
+      } else {
+         *mod = False; //GDBTD? how do we store rflags in libvex_guest_amd64.h ???
+      }
+      break; 
+   case 18: *mod = False; break; //GDBTD VG_(transfer) (&amd64->guest_CS, buf, dir, size, mod);
+   case 19: *mod = False; break; //GDBTD VG_(transfer) (&amd64->guest_SS, buf, dir, size, mod);
+   case 20: *mod = False; break; //GDBTD VG_(transfer) (&amd64->guest_DS, buf, dir, size, mod);
+   case 21: *mod = False; break; //GDBTD VG_(transfer) (&amd64->guest_ES, buf, dir, size, mod);
+   case 22: *mod = False; break; //GDBTD VG_(transfer) (&amd64->guest_FS, buf, dir, size, mod);
+   case 23: VG_(transfer) (&amd64->guest_GS_0x60, buf, dir, size, mod); break;
+   case 24:
+   case 25:
+   case 26:
+   case 27: /* register 24 to 31 are float registers 80 bits but 64 bits in valgrind */
+   case 28:
+   case 29:
+   case 30:
+   case 31: 
+      if (dir == valgrind_to_gdbserver) {
+         UChar fpreg80[10];
+         convert_f64le_to_f80le ((UChar *)&amd64->guest_FPREG[regno-16],
+                                 fpreg80);
+         VG_(transfer) (&fpreg80, buf, dir, sizeof(fpreg80), mod);
+      } else {
+         ULong fpreg64;
+         convert_f80le_to_f64le (buf, (UChar *)&fpreg64); 
+         VG_(transfer) (&amd64->guest_FPREG[regno-16], &fpreg64,
+                        dir, sizeof(fpreg64), mod);
+      }
+      break;
+   case 32: 
+      if (dir == valgrind_to_gdbserver) {
+         // vex only models the rounding bits (see libvex_guest_amd64.h)
+         UWord value = 0x037f;
+         value |= amd64->guest_FPROUND << 10;
+         VG_(transfer)(&value, buf, dir, size, mod);
+      } else {
+         *mod = False; // GDBTD???? VEX equivalent fcrtl
+      }
+      break;
+   case 33: 
+      if (dir == valgrind_to_gdbserver) {
+         UWord value = amd64->guest_FC3210;
+         value |= (amd64->guest_FTOP & 7) << 11;
+         VG_(transfer)(&value, buf, dir, size, mod); 
+      } else {
+         *mod = False; // GDBTD???? VEX equivalent fstat
+      }
+      break;
+   case 34: 
+      if (dir == valgrind_to_gdbserver) {
+         // vex doesn't model these precisely
+         UWord value = 
+            ((amd64->guest_FPTAG[0] ? 0 : 3) << 0)  | 
+            ((amd64->guest_FPTAG[1] ? 0 : 3) << 2)  | 
+            ((amd64->guest_FPTAG[2] ? 0 : 3) << 4)  | 
+            ((amd64->guest_FPTAG[3] ? 0 : 3) << 6)  | 
+            ((amd64->guest_FPTAG[4] ? 0 : 3) << 8)  | 
+            ((amd64->guest_FPTAG[5] ? 0 : 3) << 10) | 
+            ((amd64->guest_FPTAG[6] ? 0 : 3) << 12) | 
+            ((amd64->guest_FPTAG[7] ? 0 : 3) << 14);
+         VG_(transfer)(&value, buf, dir, size, mod); 
+      } else {
+         *mod = False; // GDBTD???? VEX equivalent ftag
+      }
+      break;
+   case 35: *mod = False; break; // GDBTD ??? equivalent of fiseg
+   case 36: *mod = False; break; // GDBTD ??? equivalent of fioff
+   case 37: *mod = False; break; // GDBTD ??? equivalent of foseg
+   case 38: *mod = False; break; // GDBTD ??? equivalent of fooff
+   case 39: *mod = False; break; // GDBTD ??? equivalent of fop
+   case 40: VG_(transfer) (&amd64->guest_XMM0,  buf, dir, size, mod); break;
+   case 41: VG_(transfer) (&amd64->guest_XMM1,  buf, dir, size, mod); break;
+   case 42: VG_(transfer) (&amd64->guest_XMM2,  buf, dir, size, mod); break;
+   case 43: VG_(transfer) (&amd64->guest_XMM3,  buf, dir, size, mod); break;
+   case 44: VG_(transfer) (&amd64->guest_XMM4,  buf, dir, size, mod); break;
+   case 45: VG_(transfer) (&amd64->guest_XMM5,  buf, dir, size, mod); break;
+   case 46: VG_(transfer) (&amd64->guest_XMM6,  buf, dir, size, mod); break;
+   case 47: VG_(transfer) (&amd64->guest_XMM7,  buf, dir, size, mod); break;
+   case 48: VG_(transfer) (&amd64->guest_XMM8,  buf, dir, size, mod); break;
+   case 49: VG_(transfer) (&amd64->guest_XMM9,  buf, dir, size, mod); break;
+   case 50: VG_(transfer) (&amd64->guest_XMM10, buf, dir, size, mod); break;
+   case 51: VG_(transfer) (&amd64->guest_XMM11, buf, dir, size, mod); break;
+   case 52: VG_(transfer) (&amd64->guest_XMM12, buf, dir, size, mod); break;
+   case 53: VG_(transfer) (&amd64->guest_XMM13, buf, dir, size, mod); break;
+   case 54: VG_(transfer) (&amd64->guest_XMM14, buf, dir, size, mod); break;
+   case 55: VG_(transfer) (&amd64->guest_XMM15, buf, dir, size, mod); break;
+   case 56: 
+      if (dir == valgrind_to_gdbserver) {
+         // vex only models the rounding bits (see libvex_guest_x86.h)
+         UWord value = 0x1f80;
+         value |= amd64->guest_SSEROUND << 13;
+         VG_(transfer)(&value, buf, dir, size, mod); 
+      } else {
+         *mod = False;  // GDBTD???? VEX equivalent mxcsr
+      }
+      break;
+   case 57: *mod = False; break; // GDBTD???? VEX equivalent { "orig_rax"},
+   default: vg_assert(0);
+   }
+}
+
+static struct valgrind_target_ops low_target = {
+   num_regs,
+   regs,
+   7, //RSP
+   transfer_register,
+   get_pc,
+   set_pc,
+   "amd64",
+   NULL, // target_xml not needed.
+#if defined(VGO_linux)
+   "amd64-linux-valgrind.xml"
+#else
+   "amd64-coresse-valgrind.xml"
+#endif
+};
+
+void amd64_init_architecture (struct valgrind_target_ops *target)
+{
+   *target = low_target;
+   set_register_cache (regs, num_regs);
+   gdbserver_expedite_regs = expedite_regs;
+}
diff --git a/coregrind/m_gdbserver/valgrind-low-arm.c b/coregrind/m_gdbserver/valgrind-low-arm.c
new file mode 100644 (file)
index 0000000..d4cec3c
--- /dev/null
@@ -0,0 +1,237 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+
+#include "valgrind_low.h"
+
+#include "libvex_guest_arm.h"
+
+struct reg regs[] = {
+  { "r0", 0, 32 },
+  { "r1", 32, 32 },
+  { "r2", 64, 32 },
+  { "r3", 96, 32 },
+  { "r4", 128, 32 },
+  { "r5", 160, 32 },
+  { "r6", 192, 32 },
+  { "r7", 224, 32 },
+  { "r8", 256, 32 },
+  { "r9", 288, 32 },
+  { "r10", 320, 32 },
+  { "r11", 352, 32 },
+  { "r12", 384, 32 },
+  { "sp", 416, 32 },
+  { "lr", 448, 32 },
+  { "pc", 480, 32 },
+  { "", 512, 0 }, // It seems these entries are needed 
+  { "", 512, 0 }, // as previous versions of arm <-> gdb placed 
+  { "", 512, 0 }, // some floating point registers here. So, cpsr 
+  { "", 512, 0 }, // must be register 25.
+  { "", 512, 0 },
+  { "", 512, 0 },
+  { "", 512, 0 },
+  { "", 512, 0 },
+  { "", 512, 0 },
+  { "cpsr", 512, 32 },
+  { "d0", 544, 64 },
+  { "d1", 608, 64 },
+  { "d2", 672, 64 },
+  { "d3", 736, 64 },
+  { "d4", 800, 64 },
+  { "d5", 864, 64 },
+  { "d6", 928, 64 },
+  { "d7", 992, 64 },
+  { "d8", 1056, 64 },
+  { "d9", 1120, 64 },
+  { "d10", 1184, 64 },
+  { "d11", 1248, 64 },
+  { "d12", 1312, 64 },
+  { "d13", 1376, 64 },
+  { "d14", 1440, 64 },
+  { "d15", 1504, 64 },
+  { "d16", 1568, 64 },
+  { "d17", 1632, 64 },
+  { "d18", 1696, 64 },
+  { "d19", 1760, 64 },
+  { "d20", 1824, 64 },
+  { "d21", 1888, 64 },
+  { "d22", 1952, 64 },
+  { "d23", 2016, 64 },
+  { "d24", 2080, 64 },
+  { "d25", 2144, 64 },
+  { "d26", 2208, 64 },
+  { "d27", 2272, 64 },
+  { "d28", 2336, 64 },
+  { "d29", 2400, 64 },
+  { "d30", 2464, 64 },
+  { "d31", 2528, 64 },
+  { "fpscr", 2592, 32 }
+};
+static const char *expedite_regs[] = { "r11", "sp", "pc", 0 };
+#define num_regs (sizeof (regs) / sizeof (regs[0]))
+
+static
+CORE_ADDR get_pc (void)
+{
+   unsigned long pc;
+
+   collect_register_by_name ("pc", &pc);
+   
+   dlog(1, "stop pc is %p\n", (void *) pc);
+   return pc;
+}
+
+static
+void set_pc (CORE_ADDR newpc)
+{
+   Bool mod;
+   supply_register_by_name ("pc", &newpc, &mod);
+   if (mod)
+      dlog(1, "set pc to %p\n", C2v (newpc));
+   else
+      dlog(1, "set pc not changed %p\n", C2v (newpc));
+}
+
+/* store registers in the guest state (gdbserver_to_valgrind)
+   or fetch register from the guest state (valgrind_to_gdbserver). */
+static
+void transfer_register (ThreadId tid, int abs_regno, void * buf,
+                        transfer_direction dir, int size, Bool *mod)
+{
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   int set = abs_regno / num_regs;
+   int regno = abs_regno % num_regs;
+   *mod = False;
+
+   VexGuestARMState* arm = (VexGuestARMState*) get_arch (set, tst);
+
+   switch (regno) { 
+   // numbers here have to match the order of regs above
+   // Attention: gdb order does not match valgrind order.
+   case 0:  VG_(transfer) (&arm->guest_R0,   buf, dir, size, mod); break;
+   case 1:  VG_(transfer) (&arm->guest_R1,   buf, dir, size, mod); break;
+   case 2:  VG_(transfer) (&arm->guest_R2,   buf, dir, size, mod); break;
+   case 3:  VG_(transfer) (&arm->guest_R3,   buf, dir, size, mod); break;
+   case 4:  VG_(transfer) (&arm->guest_R4,   buf, dir, size, mod); break;
+   case 5:  VG_(transfer) (&arm->guest_R5,   buf, dir, size, mod); break;
+   case 6:  VG_(transfer) (&arm->guest_R6,   buf, dir, size, mod); break;
+   case 7:  VG_(transfer) (&arm->guest_R7,   buf, dir, size, mod); break;
+   case 8:  VG_(transfer) (&arm->guest_R8,   buf, dir, size, mod); break;
+   case 9:  VG_(transfer) (&arm->guest_R9,   buf, dir, size, mod); break;
+   case 10: VG_(transfer) (&arm->guest_R10,  buf, dir, size, mod); break;
+   case 11: VG_(transfer) (&arm->guest_R11,  buf, dir, size, mod); break;
+   case 12: VG_(transfer) (&arm->guest_R12,  buf, dir, size, mod); break;
+   case 13: VG_(transfer) (&arm->guest_R13,  buf, dir, size, mod); break;
+   case 14: VG_(transfer) (&arm->guest_R14,  buf, dir, size, mod); break;
+   case 15: VG_(transfer) (&arm->guest_R15T, buf, dir, size, mod); break;
+   case 16:
+   case 17:
+   case 18:
+   case 19:
+   case 20: /* 9 "empty registers". See struct reg regs above. */
+   case 21:
+   case 22:
+   case 23:
+   case 24: *mod = False; break;
+   case 25: {
+      UInt cpsr = LibVEX_GuestARM_get_cpsr (arm);
+      if (dir == valgrind_to_gdbserver) {
+         VG_(transfer) (&cpsr, buf, dir, size, mod); 
+      } else {
+#      if 0
+         UInt newcpsr;
+         VG_(transfer) (&newcpsr, buf, dir, size, mod);
+         *mod = newcpsr != cpsr;
+         // GDBTD ???? see FIXME in guest_arm_helpers.c
+         LibVEX_GuestARM_put_flags (newcpsr, arm);
+#      else
+         *mod = False;
+#      endif
+      }
+      break;
+   }
+   case 26: VG_(transfer) (&arm->guest_D0,  buf, dir, size, mod); break;
+   case 27: VG_(transfer) (&arm->guest_D1,  buf, dir, size, mod); break;
+   case 28: VG_(transfer) (&arm->guest_D2,  buf, dir, size, mod); break;
+   case 29: VG_(transfer) (&arm->guest_D3,  buf, dir, size, mod); break;
+   case 30: VG_(transfer) (&arm->guest_D4,  buf, dir, size, mod); break;
+   case 31: VG_(transfer) (&arm->guest_D5,  buf, dir, size, mod); break;
+   case 32: VG_(transfer) (&arm->guest_D6,  buf, dir, size, mod); break;
+   case 33: VG_(transfer) (&arm->guest_D7,  buf, dir, size, mod); break;
+   case 34: VG_(transfer) (&arm->guest_D8,  buf, dir, size, mod); break;
+   case 35: VG_(transfer) (&arm->guest_D9,  buf, dir, size, mod); break;
+   case 36: VG_(transfer) (&arm->guest_D10, buf, dir, size, mod); break;
+   case 37: VG_(transfer) (&arm->guest_D11, buf, dir, size, mod); break;
+   case 38: VG_(transfer) (&arm->guest_D12, buf, dir, size, mod); break;
+   case 39: VG_(transfer) (&arm->guest_D13, buf, dir, size, mod); break;
+   case 40: VG_(transfer) (&arm->guest_D14, buf, dir, size, mod); break;
+   case 41: VG_(transfer) (&arm->guest_D15, buf, dir, size, mod); break;
+   case 42: VG_(transfer) (&arm->guest_D16, buf, dir, size, mod); break;
+   case 43: VG_(transfer) (&arm->guest_D17, buf, dir, size, mod); break;
+   case 44: VG_(transfer) (&arm->guest_D18, buf, dir, size, mod); break;
+   case 45: VG_(transfer) (&arm->guest_D19, buf, dir, size, mod); break;
+   case 46: VG_(transfer) (&arm->guest_D20, buf, dir, size, mod); break;
+   case 47: VG_(transfer) (&arm->guest_D21, buf, dir, size, mod); break;
+   case 48: VG_(transfer) (&arm->guest_D22, buf, dir, size, mod); break;
+   case 49: VG_(transfer) (&arm->guest_D23, buf, dir, size, mod); break;
+   case 50: VG_(transfer) (&arm->guest_D24, buf, dir, size, mod); break;
+   case 51: VG_(transfer) (&arm->guest_D25, buf, dir, size, mod); break;
+   case 52: VG_(transfer) (&arm->guest_D26, buf, dir, size, mod); break;
+   case 53: VG_(transfer) (&arm->guest_D27, buf, dir, size, mod); break;
+   case 54: VG_(transfer) (&arm->guest_D28, buf, dir, size, mod); break;
+   case 55: VG_(transfer) (&arm->guest_D29, buf, dir, size, mod); break;
+   case 56: VG_(transfer) (&arm->guest_D30, buf, dir, size, mod); break;
+   case 57: VG_(transfer) (&arm->guest_D31, buf, dir, size, mod); break;
+   case 58: VG_(transfer) (&arm->guest_FPSCR, buf, dir, size, mod); break;
+   default: vg_assert(0);
+   }
+}
+
+static struct valgrind_target_ops low_target = {
+   num_regs,
+   regs,
+   13, //SP
+   transfer_register,
+   get_pc,
+   set_pc,
+   "arm",
+   "arm-with-vfpv3.xml",
+   "arm-with-vfpv3-valgrind.xml"
+};
+
+void arm_init_architecture (struct valgrind_target_ops *target)
+{
+   *target = low_target;
+   set_register_cache (regs, num_regs);
+   gdbserver_expedite_regs = expedite_regs;
+}
diff --git a/coregrind/m_gdbserver/valgrind-low-ppc32.c b/coregrind/m_gdbserver/valgrind-low-ppc32.c
new file mode 100644 (file)
index 0000000..a7e282e
--- /dev/null
@@ -0,0 +1,343 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+
+#include "valgrind_low.h"
+
+#include "libvex_guest_ppc32.h"
+
+/* this is only the basic set of registers.
+   Need to look at what is the exact ppc32 model to support.
+*/
+struct reg regs[] = {
+  { "r0", 0, 32 },
+  { "r1", 32, 32 },
+  { "r2", 64, 32 },
+  { "r3", 96, 32 },
+  { "r4", 128, 32 },
+  { "r5", 160, 32 },
+  { "r6", 192, 32 },
+  { "r7", 224, 32 },
+  { "r8", 256, 32 },
+  { "r9", 288, 32 },
+  { "r10", 320, 32 },
+  { "r11", 352, 32 },
+  { "r12", 384, 32 },
+  { "r13", 416, 32 },
+  { "r14", 448, 32 },
+  { "r15", 480, 32 },
+  { "r16", 512, 32 },
+  { "r17", 544, 32 },
+  { "r18", 576, 32 },
+  { "r19", 608, 32 },
+  { "r20", 640, 32 },
+  { "r21", 672, 32 },
+  { "r22", 704, 32 },
+  { "r23", 736, 32 },
+  { "r24", 768, 32 },
+  { "r25", 800, 32 },
+  { "r26", 832, 32 },
+  { "r27", 864, 32 },
+  { "r28", 896, 32 },
+  { "r29", 928, 32 },
+  { "r30", 960, 32 },
+  { "r31", 992, 32 },
+  { "f0", 1024, 64 },
+  { "f1", 1088, 64 },
+  { "f2", 1152, 64 },
+  { "f3", 1216, 64 },
+  { "f4", 1280, 64 },
+  { "f5", 1344, 64 },
+  { "f6", 1408, 64 },
+  { "f7", 1472, 64 },
+  { "f8", 1536, 64 },
+  { "f9", 1600, 64 },
+  { "f10", 1664, 64 },
+  { "f11", 1728, 64 },
+  { "f12", 1792, 64 },
+  { "f13", 1856, 64 },
+  { "f14", 1920, 64 },
+  { "f15", 1984, 64 },
+  { "f16", 2048, 64 },
+  { "f17", 2112, 64 },
+  { "f18", 2176, 64 },
+  { "f19", 2240, 64 },
+  { "f20", 2304, 64 },
+  { "f21", 2368, 64 },
+  { "f22", 2432, 64 },
+  { "f23", 2496, 64 },
+  { "f24", 2560, 64 },
+  { "f25", 2624, 64 },
+  { "f26", 2688, 64 },
+  { "f27", 2752, 64 },
+  { "f28", 2816, 64 },
+  { "f29", 2880, 64 },
+  { "f30", 2944, 64 },
+  { "f31", 3008, 64 },
+  { "pc", 3072, 32 },
+  { "msr", 3104, 32 },
+  { "cr", 3136, 32 },
+  { "lr", 3168, 32 },
+  { "ctr", 3200, 32 },
+  { "xer", 3232, 32 },
+  { "fpscr", 3264, 32 },
+  { "orig_r3", 3296, 32 },
+  { "trap", 3328, 32 },
+  { "vr0", 3360, 128 },
+  { "vr1", 3488, 128 },
+  { "vr2", 3616, 128 },
+  { "vr3", 3744, 128 },
+  { "vr4", 3872, 128 },
+  { "vr5", 4000, 128 },
+  { "vr6", 4128, 128 },
+  { "vr7", 4256, 128 },
+  { "vr8", 4384, 128 },
+  { "vr9", 4512, 128 },
+  { "vr10", 4640, 128 },
+  { "vr11", 4768, 128 },
+  { "vr12", 4896, 128 },
+  { "vr13", 5024, 128 },
+  { "vr14", 5152, 128 },
+  { "vr15", 5280, 128 },
+  { "vr16", 5408, 128 },
+  { "vr17", 5536, 128 },
+  { "vr18", 5664, 128 },
+  { "vr19", 5792, 128 },
+  { "vr20", 5920, 128 },
+  { "vr21", 6048, 128 },
+  { "vr22", 6176, 128 },
+  { "vr23", 6304, 128 },
+  { "vr24", 6432, 128 },
+  { "vr25", 6560, 128 },
+  { "vr26", 6688, 128 },
+  { "vr27", 6816, 128 },
+  { "vr28", 6944, 128 },
+  { "vr29", 7072, 128 },
+  { "vr30", 7200, 128 },
+  { "vr31", 7328, 128 },
+  { "vscr", 7456, 32 },
+  { "vrsave", 7488, 32 }
+};
+static const char *expedite_regs[] = { "r1", "pc", 0 };
+#define num_regs (sizeof (regs) / sizeof (regs[0]))
+
+static
+CORE_ADDR get_pc (void)
+{
+   unsigned long pc;
+
+   collect_register_by_name ("pc", &pc);
+   
+   dlog(1, "stop pc is %p\n", (void *) pc);
+   return pc;
+}
+
+static
+void set_pc (CORE_ADDR newpc)
+{
+   Bool mod;
+   supply_register_by_name ("pc", &newpc, &mod);
+   if (mod)
+      dlog(1, "set pc to %p\n", C2v (newpc));
+   else
+      dlog(1, "set pc not changed %p\n", C2v (newpc));
+}
+
+/* store registers in the guest state (gdbserver_to_valgrind)
+   or fetch register from the guest state (valgrind_to_gdbserver). */
+static
+void transfer_register (ThreadId tid, int abs_regno, void * buf,
+                        transfer_direction dir, int size, Bool *mod)
+{
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   int set = abs_regno / num_regs;
+   int regno = abs_regno % num_regs;
+   *mod = False;
+
+   VexGuestPPC32State* ppc32 = (VexGuestPPC32State*) get_arch (set, tst);
+
+   switch (regno) { 
+   // numbers here have to match the order of regs above
+   // Attention: gdb order does not match valgrind order.
+   case 0:  VG_(transfer) (&ppc32->guest_GPR0,  buf, dir, size, mod); break;
+   case 1:  VG_(transfer) (&ppc32->guest_GPR1,  buf, dir, size, mod); break;
+   case 2:  VG_(transfer) (&ppc32->guest_GPR2,  buf, dir, size, mod); break;
+   case 3:  VG_(transfer) (&ppc32->guest_GPR3,  buf, dir, size, mod); break;
+   case 4:  VG_(transfer) (&ppc32->guest_GPR4,  buf, dir, size, mod); break;
+   case 5:  VG_(transfer) (&ppc32->guest_GPR5,  buf, dir, size, mod); break;
+   case 6:  VG_(transfer) (&ppc32->guest_GPR6,  buf, dir, size, mod); break;
+   case 7:  VG_(transfer) (&ppc32->guest_GPR7,  buf, dir, size, mod); break;
+   case 8:  VG_(transfer) (&ppc32->guest_GPR8,  buf, dir, size, mod); break;
+   case 9:  VG_(transfer) (&ppc32->guest_GPR9,  buf, dir, size, mod); break;
+   case 10: VG_(transfer) (&ppc32->guest_GPR10, buf, dir, size, mod); break;
+   case 11: VG_(transfer) (&ppc32->guest_GPR11, buf, dir, size, mod); break;
+   case 12: VG_(transfer) (&ppc32->guest_GPR12, buf, dir, size, mod); break;
+   case 13: VG_(transfer) (&ppc32->guest_GPR13, buf, dir, size, mod); break;
+   case 14: VG_(transfer) (&ppc32->guest_GPR14, buf, dir, size, mod); break;
+   case 15: VG_(transfer) (&ppc32->guest_GPR15, buf, dir, size, mod); break;
+   case 16: VG_(transfer) (&ppc32->guest_GPR16, buf, dir, size, mod); break;
+   case 17: VG_(transfer) (&ppc32->guest_GPR17, buf, dir, size, mod); break;
+   case 18: VG_(transfer) (&ppc32->guest_GPR18, buf, dir, size, mod); break;
+   case 19: VG_(transfer) (&ppc32->guest_GPR19, buf, dir, size, mod); break;
+   case 20: VG_(transfer) (&ppc32->guest_GPR20, buf, dir, size, mod); break;
+   case 21: VG_(transfer) (&ppc32->guest_GPR21, buf, dir, size, mod); break;
+   case 22: VG_(transfer) (&ppc32->guest_GPR22, buf, dir, size, mod); break;
+   case 23: VG_(transfer) (&ppc32->guest_GPR23, buf, dir, size, mod); break;
+   case 24: VG_(transfer) (&ppc32->guest_GPR24, buf, dir, size, mod); break;
+   case 25: VG_(transfer) (&ppc32->guest_GPR25, buf, dir, size, mod); break;
+   case 26: VG_(transfer) (&ppc32->guest_GPR26, buf, dir, size, mod); break;
+   case 27: VG_(transfer) (&ppc32->guest_GPR27, buf, dir, size, mod); break;
+   case 28: VG_(transfer) (&ppc32->guest_GPR28, buf, dir, size, mod); break;
+   case 29: VG_(transfer) (&ppc32->guest_GPR29, buf, dir, size, mod); break;
+   case 30: VG_(transfer) (&ppc32->guest_GPR30, buf, dir, size, mod); break;
+   case 31: VG_(transfer) (&ppc32->guest_GPR31, buf, dir, size, mod); break;
+   case 32: VG_(transfer) (&ppc32->guest_VSR0,  buf, dir, size, mod); break;
+   case 33: VG_(transfer) (&ppc32->guest_VSR1,  buf, dir, size, mod); break;
+   case 34: VG_(transfer) (&ppc32->guest_VSR2,  buf, dir, size, mod); break;
+   case 35: VG_(transfer) (&ppc32->guest_VSR3,  buf, dir, size, mod); break;
+   case 36: VG_(transfer) (&ppc32->guest_VSR4,  buf, dir, size, mod); break;
+   case 37: VG_(transfer) (&ppc32->guest_VSR5,  buf, dir, size, mod); break;
+   case 38: VG_(transfer) (&ppc32->guest_VSR6,  buf, dir, size, mod); break;
+   case 39: VG_(transfer) (&ppc32->guest_VSR7,  buf, dir, size, mod); break;
+   case 40: VG_(transfer) (&ppc32->guest_VSR8,  buf, dir, size, mod); break;
+   case 41: VG_(transfer) (&ppc32->guest_VSR9,  buf, dir, size, mod); break;
+   case 42: VG_(transfer) (&ppc32->guest_VSR10, buf, dir, size, mod); break;
+   case 43: VG_(transfer) (&ppc32->guest_VSR11, buf, dir, size, mod); break;
+   case 44: VG_(transfer) (&ppc32->guest_VSR12, buf, dir, size, mod); break;
+   case 45: VG_(transfer) (&ppc32->guest_VSR13, buf, dir, size, mod); break;
+   case 46: VG_(transfer) (&ppc32->guest_VSR14, buf, dir, size, mod); break;
+   case 47: VG_(transfer) (&ppc32->guest_VSR15, buf, dir, size, mod); break;
+   case 48: VG_(transfer) (&ppc32->guest_VSR16, buf, dir, size, mod); break;
+   case 49: VG_(transfer) (&ppc32->guest_VSR17, buf, dir, size, mod); break;
+   case 50: VG_(transfer) (&ppc32->guest_VSR18, buf, dir, size, mod); break;
+   case 51: VG_(transfer) (&ppc32->guest_VSR19, buf, dir, size, mod); break;
+   case 52: VG_(transfer) (&ppc32->guest_VSR20, buf, dir, size, mod); break;
+   case 53: VG_(transfer) (&ppc32->guest_VSR21, buf, dir, size, mod); break;
+   case 54: VG_(transfer) (&ppc32->guest_VSR22, buf, dir, size, mod); break;
+   case 55: VG_(transfer) (&ppc32->guest_VSR23, buf, dir, size, mod); break;
+   case 56: VG_(transfer) (&ppc32->guest_VSR24, buf, dir, size, mod); break;
+   case 57: VG_(transfer) (&ppc32->guest_VSR25, buf, dir, size, mod); break;
+   case 58: VG_(transfer) (&ppc32->guest_VSR26, buf, dir, size, mod); break;
+   case 59: VG_(transfer) (&ppc32->guest_VSR27, buf, dir, size, mod); break;
+   case 60: VG_(transfer) (&ppc32->guest_VSR28, buf, dir, size, mod); break;
+   case 61: VG_(transfer) (&ppc32->guest_VSR29, buf, dir, size, mod); break;
+   case 62: VG_(transfer) (&ppc32->guest_VSR30, buf, dir, size, mod); break;
+   case 63: VG_(transfer) (&ppc32->guest_VSR31, buf, dir, size, mod); break;
+   case 64: VG_(transfer) (&ppc32->guest_CIA,   buf, dir, size, mod); break;
+   case 65: *mod = False; break; // VEX does not model Machine State Register
+   case 66: {
+      UInt cr = LibVEX_GuestPPC32_get_CR (ppc32);
+      if (dir == valgrind_to_gdbserver) {
+         VG_(transfer) (&cr, buf, dir, size, mod); 
+      } else {
+         UInt newcr;
+         VG_(transfer) (&newcr, buf, dir, size, mod);
+         *mod = newcr != cr;
+         LibVEX_GuestPPC32_put_CR (newcr, ppc32);
+      }
+      break;
+   }
+   case 67: VG_(transfer) (&ppc32->guest_LR,    buf, dir, size, mod); break;
+   case 68: VG_(transfer) (&ppc32->guest_CTR,   buf, dir, size, mod); break;
+   case 69: {
+      UInt xer = LibVEX_GuestPPC32_get_XER (ppc32);
+      if (dir == valgrind_to_gdbserver) {
+         VG_(transfer) (&xer, buf, dir, size, mod); 
+      } else {
+         UInt newxer;
+         VG_(transfer) (&newxer, buf, dir, size, mod);
+         *mod = newxer != xer;
+         LibVEX_GuestPPC32_put_XER (newxer, ppc32);
+      }
+      break;
+   }
+   case 70:  VG_(transfer) (&ppc32->guest_FPROUND, buf, dir, size, mod); break;
+   case 71:  *mod = False; break; // GDBTD???? VEX { "orig_r3", 3296, 32 },
+   case 72:  *mod = False; break; // GDBTD???? VEX { "trap", 3328, 32 },
+   case 73:  VG_(transfer) (&ppc32->guest_VSR32, buf, dir, size, mod); break;
+   case 74:  VG_(transfer) (&ppc32->guest_VSR33, buf, dir, size, mod); break;
+   case 75:  VG_(transfer) (&ppc32->guest_VSR34, buf, dir, size, mod); break;
+   case 76:  VG_(transfer) (&ppc32->guest_VSR35, buf, dir, size, mod); break;
+   case 77:  VG_(transfer) (&ppc32->guest_VSR36, buf, dir, size, mod); break;
+   case 78:  VG_(transfer) (&ppc32->guest_VSR37, buf, dir, size, mod); break;
+   case 79:  VG_(transfer) (&ppc32->guest_VSR38, buf, dir, size, mod); break;
+   case 80:  VG_(transfer) (&ppc32->guest_VSR39, buf, dir, size, mod); break;
+   case 81:  VG_(transfer) (&ppc32->guest_VSR40, buf, dir, size, mod); break;
+   case 82:  VG_(transfer) (&ppc32->guest_VSR41, buf, dir, size, mod); break;
+   case 83:  VG_(transfer) (&ppc32->guest_VSR42, buf, dir, size, mod); break;
+   case 84:  VG_(transfer) (&ppc32->guest_VSR43, buf, dir, size, mod); break;
+   case 85:  VG_(transfer) (&ppc32->guest_VSR44, buf, dir, size, mod); break;
+   case 86:  VG_(transfer) (&ppc32->guest_VSR45, buf, dir, size, mod); break;
+   case 87:  VG_(transfer) (&ppc32->guest_VSR46, buf, dir, size, mod); break;
+   case 88:  VG_(transfer) (&ppc32->guest_VSR47, buf, dir, size, mod); break;
+   case 89:  VG_(transfer) (&ppc32->guest_VSR48, buf, dir, size, mod); break;
+   case 90:  VG_(transfer) (&ppc32->guest_VSR49, buf, dir, size, mod); break;
+   case 91:  VG_(transfer) (&ppc32->guest_VSR50, buf, dir, size, mod); break;
+   case 92:  VG_(transfer) (&ppc32->guest_VSR51, buf, dir, size, mod); break;
+   case 93:  VG_(transfer) (&ppc32->guest_VSR52, buf, dir, size, mod); break;
+   case 94:  VG_(transfer) (&ppc32->guest_VSR53, buf, dir, size, mod); break;
+   case 95:  VG_(transfer) (&ppc32->guest_VSR54, buf, dir, size, mod); break;
+   case 96:  VG_(transfer) (&ppc32->guest_VSR55, buf, dir, size, mod); break;
+   case 97:  VG_(transfer) (&ppc32->guest_VSR56, buf, dir, size, mod); break;
+   case 98:  VG_(transfer) (&ppc32->guest_VSR57, buf, dir, size, mod); break;
+   case 99:  VG_(transfer) (&ppc32->guest_VSR58, buf, dir, size, mod); break;
+   case 100: VG_(transfer) (&ppc32->guest_VSR59, buf, dir, size, mod); break;
+   case 101: VG_(transfer) (&ppc32->guest_VSR60, buf, dir, size, mod); break;
+   case 102: VG_(transfer) (&ppc32->guest_VSR61, buf, dir, size, mod); break;
+   case 103: VG_(transfer) (&ppc32->guest_VSR62, buf, dir, size, mod); break;
+   case 104: VG_(transfer) (&ppc32->guest_VSR63, buf, dir, size, mod); break;
+   case 105: VG_(transfer) (&ppc32->guest_VSCR,  buf, dir, size, mod); break;
+   case 106: VG_(transfer) (&ppc32->guest_VRSAVE, buf, dir, size, mod); break;
+   default: vg_assert(0);
+   }
+}
+
+static struct valgrind_target_ops low_target = {
+   num_regs,
+   regs,
+   1, //r1
+   transfer_register,
+   get_pc,
+   set_pc,
+   "ppc32",
+   "powerpc-altivec32l.xml",
+   "powerpc-altivec32l-valgrind.xml"
+};
+
+void ppc32_init_architecture (struct valgrind_target_ops *target)
+{
+   *target = low_target;
+   set_register_cache (regs, num_regs);
+   gdbserver_expedite_regs = expedite_regs;
+}
+
diff --git a/coregrind/m_gdbserver/valgrind-low-ppc64.c b/coregrind/m_gdbserver/valgrind-low-ppc64.c
new file mode 100644 (file)
index 0000000..f2fdbec
--- /dev/null
@@ -0,0 +1,339 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+
+#include "valgrind_low.h"
+
+#include "libvex_guest_ppc64.h"
+
+struct reg regs[] = {
+  { "r0", 0, 64 },
+  { "r1", 64, 64 },
+  { "r2", 128, 64 },
+  { "r3", 192, 64 },
+  { "r4", 256, 64 },
+  { "r5", 320, 64 },
+  { "r6", 384, 64 },
+  { "r7", 448, 64 },
+  { "r8", 512, 64 },
+  { "r9", 576, 64 },
+  { "r10", 640, 64 },
+  { "r11", 704, 64 },
+  { "r12", 768, 64 },
+  { "r13", 832, 64 },
+  { "r14", 896, 64 },
+  { "r15", 960, 64 },
+  { "r16", 1024, 64 },
+  { "r17", 1088, 64 },
+  { "r18", 1152, 64 },
+  { "r19", 1216, 64 },
+  { "r20", 1280, 64 },
+  { "r21", 1344, 64 },
+  { "r22", 1408, 64 },
+  { "r23", 1472, 64 },
+  { "r24", 1536, 64 },
+  { "r25", 1600, 64 },
+  { "r26", 1664, 64 },
+  { "r27", 1728, 64 },
+  { "r28", 1792, 64 },
+  { "r29", 1856, 64 },
+  { "r30", 1920, 64 },
+  { "r31", 1984, 64 },
+  { "f0", 2048, 64 },
+  { "f1", 2112, 64 },
+  { "f2", 2176, 64 },
+  { "f3", 2240, 64 },
+  { "f4", 2304, 64 },
+  { "f5", 2368, 64 },
+  { "f6", 2432, 64 },
+  { "f7", 2496, 64 },
+  { "f8", 2560, 64 },
+  { "f9", 2624, 64 },
+  { "f10", 2688, 64 },
+  { "f11", 2752, 64 },
+  { "f12", 2816, 64 },
+  { "f13", 2880, 64 },
+  { "f14", 2944, 64 },
+  { "f15", 3008, 64 },
+  { "f16", 3072, 64 },
+  { "f17", 3136, 64 },
+  { "f18", 3200, 64 },
+  { "f19", 3264, 64 },
+  { "f20", 3328, 64 },
+  { "f21", 3392, 64 },
+  { "f22", 3456, 64 },
+  { "f23", 3520, 64 },
+  { "f24", 3584, 64 },
+  { "f25", 3648, 64 },
+  { "f26", 3712, 64 },
+  { "f27", 3776, 64 },
+  { "f28", 3840, 64 },
+  { "f29", 3904, 64 },
+  { "f30", 3968, 64 },
+  { "f31", 4032, 64 },
+  { "pc", 4096, 64 },
+  { "msr", 4160, 64 },
+  { "cr", 4224, 32 },
+  { "lr", 4256, 64 },
+  { "ctr", 4320, 64 },
+  { "xer", 4384, 32 },
+  { "fpscr", 4416, 32 },
+  { "orig_r3", 4448, 64 },
+  { "trap", 4512, 64 },
+  { "vr0", 4576, 128 },
+  { "vr1", 4704, 128 },
+  { "vr2", 4832, 128 },
+  { "vr3", 4960, 128 },
+  { "vr4", 5088, 128 },
+  { "vr5", 5216, 128 },
+  { "vr6", 5344, 128 },
+  { "vr7", 5472, 128 },
+  { "vr8", 5600, 128 },
+  { "vr9", 5728, 128 },
+  { "vr10", 5856, 128 },
+  { "vr11", 5984, 128 },
+  { "vr12", 6112, 128 },
+  { "vr13", 6240, 128 },
+  { "vr14", 6368, 128 },
+  { "vr15", 6496, 128 },
+  { "vr16", 6624, 128 },
+  { "vr17", 6752, 128 },
+  { "vr18", 6880, 128 },
+  { "vr19", 7008, 128 },
+  { "vr20", 7136, 128 },
+  { "vr21", 7264, 128 },
+  { "vr22", 7392, 128 },
+  { "vr23", 7520, 128 },
+  { "vr24", 7648, 128 },
+  { "vr25", 7776, 128 },
+  { "vr26", 7904, 128 },
+  { "vr27", 8032, 128 },
+  { "vr28", 8160, 128 },
+  { "vr29", 8288, 128 },
+  { "vr30", 8416, 128 },
+  { "vr31", 8544, 128 },
+  { "vscr", 8672, 32 },
+  { "vrsave", 8704, 32 },
+};
+static const char *expedite_regs[] = { "r1", "pc", 0 };
+#define num_regs (sizeof (regs) / sizeof (regs[0]))
+
+static
+CORE_ADDR get_pc (void)
+{
+   unsigned long pc;
+
+   collect_register_by_name ("pc", &pc);
+   
+   dlog(1, "stop pc is %p\n", (void *) pc);
+   return pc;
+}
+
+static
+void set_pc (CORE_ADDR newpc)
+{
+   Bool mod;
+   supply_register_by_name ("pc", &newpc, &mod);
+   if (mod)
+      dlog(1, "set pc to %p\n", C2v (newpc));
+   else
+      dlog(1, "set pc not changed %p\n", C2v (newpc));
+}
+
+/* store registers in the guest state (gdbserver_to_valgrind)
+   or fetch register from the guest state (valgrind_to_gdbserver). */
+static
+void transfer_register (ThreadId tid, int abs_regno, void * buf,
+                        transfer_direction dir, int size, Bool *mod)
+{
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   int set = abs_regno / num_regs;
+   int regno = abs_regno % num_regs;
+   *mod = False;
+
+   VexGuestPPC64State* ppc64 = (VexGuestPPC64State*) get_arch (set, tst);
+
+   switch (regno) { 
+   // numbers here have to match the order of regs above
+   // Attention: gdb order does not match valgrind order.
+   case 0:  VG_(transfer) (&ppc64->guest_GPR0,  buf, dir, size, mod); break;
+   case 1:  VG_(transfer) (&ppc64->guest_GPR1,  buf, dir, size, mod); break;
+   case 2:  VG_(transfer) (&ppc64->guest_GPR2,  buf, dir, size, mod); break;
+   case 3:  VG_(transfer) (&ppc64->guest_GPR3,  buf, dir, size, mod); break;
+   case 4:  VG_(transfer) (&ppc64->guest_GPR4,  buf, dir, size, mod); break;
+   case 5:  VG_(transfer) (&ppc64->guest_GPR5,  buf, dir, size, mod); break;
+   case 6:  VG_(transfer) (&ppc64->guest_GPR6,  buf, dir, size, mod); break;
+   case 7:  VG_(transfer) (&ppc64->guest_GPR7,  buf, dir, size, mod); break;
+   case 8:  VG_(transfer) (&ppc64->guest_GPR8,  buf, dir, size, mod); break;
+   case 9:  VG_(transfer) (&ppc64->guest_GPR9,  buf, dir, size, mod); break;
+   case 10: VG_(transfer) (&ppc64->guest_GPR10, buf, dir, size, mod); break;
+   case 11: VG_(transfer) (&ppc64->guest_GPR11, buf, dir, size, mod); break;
+   case 12: VG_(transfer) (&ppc64->guest_GPR12, buf, dir, size, mod); break;
+   case 13: VG_(transfer) (&ppc64->guest_GPR13, buf, dir, size, mod); break;
+   case 14: VG_(transfer) (&ppc64->guest_GPR14, buf, dir, size, mod); break;
+   case 15: VG_(transfer) (&ppc64->guest_GPR15, buf, dir, size, mod); break;
+   case 16: VG_(transfer) (&ppc64->guest_GPR16, buf, dir, size, mod); break;
+   case 17: VG_(transfer) (&ppc64->guest_GPR17, buf, dir, size, mod); break;
+   case 18: VG_(transfer) (&ppc64->guest_GPR18, buf, dir, size, mod); break;
+   case 19: VG_(transfer) (&ppc64->guest_GPR19, buf, dir, size, mod); break;
+   case 20: VG_(transfer) (&ppc64->guest_GPR20, buf, dir, size, mod); break;
+   case 21: VG_(transfer) (&ppc64->guest_GPR21, buf, dir, size, mod); break;
+   case 22: VG_(transfer) (&ppc64->guest_GPR22, buf, dir, size, mod); break;
+   case 23: VG_(transfer) (&ppc64->guest_GPR23, buf, dir, size, mod); break;
+   case 24: VG_(transfer) (&ppc64->guest_GPR24, buf, dir, size, mod); break;
+   case 25: VG_(transfer) (&ppc64->guest_GPR25, buf, dir, size, mod); break;
+   case 26: VG_(transfer) (&ppc64->guest_GPR26, buf, dir, size, mod); break;
+   case 27: VG_(transfer) (&ppc64->guest_GPR27, buf, dir, size, mod); break;
+   case 28: VG_(transfer) (&ppc64->guest_GPR28, buf, dir, size, mod); break;
+   case 29: VG_(transfer) (&ppc64->guest_GPR29, buf, dir, size, mod); break;
+   case 30: VG_(transfer) (&ppc64->guest_GPR30, buf, dir, size, mod); break;
+   case 31: VG_(transfer) (&ppc64->guest_GPR31, buf, dir, size, mod); break;
+   case 32: VG_(transfer) (&ppc64->guest_VSR0,  buf, dir, size, mod); break;
+   case 33: VG_(transfer) (&ppc64->guest_VSR1,  buf, dir, size, mod); break;
+   case 34: VG_(transfer) (&ppc64->guest_VSR2,  buf, dir, size, mod); break;
+   case 35: VG_(transfer) (&ppc64->guest_VSR3,  buf, dir, size, mod); break;
+   case 36: VG_(transfer) (&ppc64->guest_VSR4,  buf, dir, size, mod); break;
+   case 37: VG_(transfer) (&ppc64->guest_VSR5,  buf, dir, size, mod); break;
+   case 38: VG_(transfer) (&ppc64->guest_VSR6,  buf, dir, size, mod); break;
+   case 39: VG_(transfer) (&ppc64->guest_VSR7,  buf, dir, size, mod); break;
+   case 40: VG_(transfer) (&ppc64->guest_VSR8,  buf, dir, size, mod); break;
+   case 41: VG_(transfer) (&ppc64->guest_VSR9,  buf, dir, size, mod); break;
+   case 42: VG_(transfer) (&ppc64->guest_VSR10, buf, dir, size, mod); break;
+   case 43: VG_(transfer) (&ppc64->guest_VSR11, buf, dir, size, mod); break;
+   case 44: VG_(transfer) (&ppc64->guest_VSR12, buf, dir, size, mod); break;
+   case 45: VG_(transfer) (&ppc64->guest_VSR13, buf, dir, size, mod); break;
+   case 46: VG_(transfer) (&ppc64->guest_VSR14, buf, dir, size, mod); break;
+   case 47: VG_(transfer) (&ppc64->guest_VSR15, buf, dir, size, mod); break;
+   case 48: VG_(transfer) (&ppc64->guest_VSR16, buf, dir, size, mod); break;
+   case 49: VG_(transfer) (&ppc64->guest_VSR17, buf, dir, size, mod); break;
+   case 50: VG_(transfer) (&ppc64->guest_VSR18, buf, dir, size, mod); break;
+   case 51: VG_(transfer) (&ppc64->guest_VSR19, buf, dir, size, mod); break;
+   case 52: VG_(transfer) (&ppc64->guest_VSR20, buf, dir, size, mod); break;
+   case 53: VG_(transfer) (&ppc64->guest_VSR21, buf, dir, size, mod); break;
+   case 54: VG_(transfer) (&ppc64->guest_VSR22, buf, dir, size, mod); break;
+   case 55: VG_(transfer) (&ppc64->guest_VSR23, buf, dir, size, mod); break;
+   case 56: VG_(transfer) (&ppc64->guest_VSR24, buf, dir, size, mod); break;
+   case 57: VG_(transfer) (&ppc64->guest_VSR25, buf, dir, size, mod); break;
+   case 58: VG_(transfer) (&ppc64->guest_VSR26, buf, dir, size, mod); break;
+   case 59: VG_(transfer) (&ppc64->guest_VSR27, buf, dir, size, mod); break;
+   case 60: VG_(transfer) (&ppc64->guest_VSR28, buf, dir, size, mod); break;
+   case 61: VG_(transfer) (&ppc64->guest_VSR29, buf, dir, size, mod); break;
+   case 62: VG_(transfer) (&ppc64->guest_VSR30, buf, dir, size, mod); break;
+   case 63: VG_(transfer) (&ppc64->guest_VSR31, buf, dir, size, mod); break;
+   case 64: VG_(transfer) (&ppc64->guest_CIA,   buf, dir, size, mod); break;
+   case 65: *mod = False; break; // VEX does not model Machine State Register
+   case 66: {
+      UInt cr = LibVEX_GuestPPC64_get_CR (ppc64);
+      if (dir == valgrind_to_gdbserver) {
+         VG_(transfer) (&cr, buf, dir, size, mod); 
+      } else {
+         UInt newcr;
+         VG_(transfer) (&newcr, buf, dir, size, mod);
+         *mod = newcr != cr;
+         LibVEX_GuestPPC64_put_CR (newcr, ppc64);
+      }
+      break;
+   }
+   case 67: VG_(transfer) (&ppc64->guest_LR,    buf, dir, size, mod); break;
+   case 68: VG_(transfer) (&ppc64->guest_CTR,   buf, dir, size, mod); break;
+   case 69: {
+      UInt xer = LibVEX_GuestPPC64_get_XER (ppc64);
+      if (dir == valgrind_to_gdbserver) {
+         VG_(transfer) (&xer, buf, dir, size, mod); 
+      } else {
+         UInt newxer;
+         VG_(transfer) (&newxer, buf, dir, size, mod);
+         *mod = newxer != xer;
+         LibVEX_GuestPPC64_put_XER (newxer, ppc64);
+      }
+      break;
+   }
+   case 70:  VG_(transfer) (&ppc64->guest_FPROUND, buf, dir, size, mod); break;
+   case 71:  *mod = False; break; // GDBTD???? VEX { "orig_r3", 4448, 64 },
+   case 72:  *mod = False; break; // GDBTD???? VEX { "trap", 4512, 64 },
+   case 73:  VG_(transfer) (&ppc64->guest_VSR32, buf, dir, size, mod); break;
+   case 74:  VG_(transfer) (&ppc64->guest_VSR33, buf, dir, size, mod); break;
+   case 75:  VG_(transfer) (&ppc64->guest_VSR34, buf, dir, size, mod); break;
+   case 76:  VG_(transfer) (&ppc64->guest_VSR35, buf, dir, size, mod); break;
+   case 77:  VG_(transfer) (&ppc64->guest_VSR36, buf, dir, size, mod); break;
+   case 78:  VG_(transfer) (&ppc64->guest_VSR37, buf, dir, size, mod); break;
+   case 79:  VG_(transfer) (&ppc64->guest_VSR38, buf, dir, size, mod); break;
+   case 80:  VG_(transfer) (&ppc64->guest_VSR39, buf, dir, size, mod); break;
+   case 81:  VG_(transfer) (&ppc64->guest_VSR40, buf, dir, size, mod); break;
+   case 82:  VG_(transfer) (&ppc64->guest_VSR41, buf, dir, size, mod); break;
+   case 83:  VG_(transfer) (&ppc64->guest_VSR42, buf, dir, size, mod); break;
+   case 84:  VG_(transfer) (&ppc64->guest_VSR43, buf, dir, size, mod); break;
+   case 85:  VG_(transfer) (&ppc64->guest_VSR44, buf, dir, size, mod); break;
+   case 86:  VG_(transfer) (&ppc64->guest_VSR45, buf, dir, size, mod); break;
+   case 87:  VG_(transfer) (&ppc64->guest_VSR46, buf, dir, size, mod); break;
+   case 88:  VG_(transfer) (&ppc64->guest_VSR47, buf, dir, size, mod); break;
+   case 89:  VG_(transfer) (&ppc64->guest_VSR48, buf, dir, size, mod); break;
+   case 90:  VG_(transfer) (&ppc64->guest_VSR49, buf, dir, size, mod); break;
+   case 91:  VG_(transfer) (&ppc64->guest_VSR50, buf, dir, size, mod); break;
+   case 92:  VG_(transfer) (&ppc64->guest_VSR51, buf, dir, size, mod); break;
+   case 93:  VG_(transfer) (&ppc64->guest_VSR52, buf, dir, size, mod); break;
+   case 94:  VG_(transfer) (&ppc64->guest_VSR53, buf, dir, size, mod); break;
+   case 95:  VG_(transfer) (&ppc64->guest_VSR54, buf, dir, size, mod); break;
+   case 96:  VG_(transfer) (&ppc64->guest_VSR55, buf, dir, size, mod); break;
+   case 97:  VG_(transfer) (&ppc64->guest_VSR56, buf, dir, size, mod); break;
+   case 98:  VG_(transfer) (&ppc64->guest_VSR57, buf, dir, size, mod); break;
+   case 99:  VG_(transfer) (&ppc64->guest_VSR58, buf, dir, size, mod); break;
+   case 100: VG_(transfer) (&ppc64->guest_VSR59, buf, dir, size, mod); break;
+   case 101: VG_(transfer) (&ppc64->guest_VSR60, buf, dir, size, mod); break;
+   case 102: VG_(transfer) (&ppc64->guest_VSR61, buf, dir, size, mod); break;
+   case 103: VG_(transfer) (&ppc64->guest_VSR62, buf, dir, size, mod); break;
+   case 104: VG_(transfer) (&ppc64->guest_VSR63, buf, dir, size, mod); break;
+   case 105: VG_(transfer) (&ppc64->guest_VSCR, buf, dir, size, mod); break;
+   case 106: VG_(transfer) (&ppc64->guest_VRSAVE, buf, dir, size, mod); break;
+   default: vg_assert(0);
+   }
+}
+
+static struct valgrind_target_ops low_target = {
+   num_regs,
+   regs,
+   1, //r1
+   transfer_register,
+   get_pc,
+   set_pc,
+   "ppc64",
+   "powerpc-altivec64l.xml",
+   "powerpc-altivec64l-valgrind.xml"
+};
+
+void ppc64_init_architecture (struct valgrind_target_ops *target)
+{
+   *target = low_target;
+   set_register_cache (regs, num_regs);
+   gdbserver_expedite_regs = expedite_regs;
+}
diff --git a/coregrind/m_gdbserver/valgrind-low-s390x.c b/coregrind/m_gdbserver/valgrind-low-s390x.c
new file mode 100644 (file)
index 0000000..3e6b53c
--- /dev/null
@@ -0,0 +1,205 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+
+#include "valgrind_low.h"
+
+#include "libvex_guest_s390x.h"
+
+struct reg regs[] = {
+  { "pswm", 0, 64 },
+  { "pswa", 64, 64 },
+  { "r0", 128, 64 },
+  { "r1", 192, 64 },
+  { "r2", 256, 64 },
+  { "r3", 320, 64 },
+  { "r4", 384, 64 },
+  { "r5", 448, 64 },
+  { "r6", 512, 64 },
+  { "r7", 576, 64 },
+  { "r8", 640, 64 },
+  { "r9", 704, 64 },
+  { "r10", 768, 64 },
+  { "r11", 832, 64 },
+  { "r12", 896, 64 },
+  { "r13", 960, 64 },
+  { "r14", 1024, 64 },
+  { "r15", 1088, 64 },
+  { "acr0", 1152, 32 },
+  { "acr1", 1184, 32 },
+  { "acr2", 1216, 32 },
+  { "acr3", 1248, 32 },
+  { "acr4", 1280, 32 },
+  { "acr5", 1312, 32 },
+  { "acr6", 1344, 32 },
+  { "acr7", 1376, 32 },
+  { "acr8", 1408, 32 },
+  { "acr9", 1440, 32 },
+  { "acr10", 1472, 32 },
+  { "acr11", 1504, 32 },
+  { "acr12", 1536, 32 },
+  { "acr13", 1568, 32 },
+  { "acr14", 1600, 32 },
+  { "acr15", 1632, 32 },
+  { "fpc", 1664, 32 },
+  { "f0", 1696, 64 },
+  { "f1", 1760, 64 },
+  { "f2", 1824, 64 },
+  { "f3", 1888, 64 },
+  { "f4", 1952, 64 },
+  { "f5", 2016, 64 },
+  { "f6", 2080, 64 },
+  { "f7", 2144, 64 },
+  { "f8", 2208, 64 },
+  { "f9", 2272, 64 },
+  { "f10", 2336, 64 },
+  { "f11", 2400, 64 },
+  { "f12", 2464, 64 },
+  { "f13", 2528, 64 },
+  { "f14", 2592, 64 },
+  { "f15", 2656, 64 },
+};
+static const char *expedite_regs[] = { "r14", "r15", "pswa", 0 };
+#define num_regs (sizeof (regs) / sizeof (regs[0]))
+
+static
+CORE_ADDR get_pc (void)
+{
+   unsigned long pc;
+
+   collect_register_by_name ("pswa", &pc);
+   
+   dlog(1, "stop pc is %p\n", (void *) pc);
+   return pc;
+}
+
+static
+void set_pc (CORE_ADDR newpc)
+{
+   Bool mod;
+   supply_register_by_name ("pswa", &newpc, &mod);
+   if (mod)
+      dlog(1, "set pc to %p\n", C2v (newpc));
+   else
+      dlog(1, "set pc not changed %p\n", C2v (newpc));
+}
+
+/* store registers in the guest state (gdbserver_to_valgrind)
+   or fetch register from the guest state (valgrind_to_gdbserver). */
+static
+void transfer_register (ThreadId tid, int abs_regno, void * buf,
+                        transfer_direction dir, int size, Bool *mod)
+{
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   int set = abs_regno / num_regs;
+   int regno = abs_regno % num_regs;
+   *mod = False;
+
+   VexGuestS390XState* s390x = (VexGuestS390XState*) get_arch (set, tst);
+
+   switch (regno) { 
+   // numbers here have to match the order of regs above
+   // Attention: gdb order does not match valgrind order.
+   case 0:  *mod = False; //GDBTD??? { "pswm", 0, 64 },  
+   case 1:  VG_(transfer) (&s390x->guest_IA,  buf, dir, size, mod); break;
+   case 2:  VG_(transfer) (&s390x->guest_r0,  buf, dir, size, mod); break;
+   case 3:  VG_(transfer) (&s390x->guest_r1,  buf, dir, size, mod); break;
+   case 4:  VG_(transfer) (&s390x->guest_r2,  buf, dir, size, mod); break;
+   case 5:  VG_(transfer) (&s390x->guest_r3,  buf, dir, size, mod); break;
+   case 6:  VG_(transfer) (&s390x->guest_r4,  buf, dir, size, mod); break;
+   case 7:  VG_(transfer) (&s390x->guest_r5,  buf, dir, size, mod); break;
+   case 8:  VG_(transfer) (&s390x->guest_r6,  buf, dir, size, mod); break;
+   case 9:  VG_(transfer) (&s390x->guest_r7,  buf, dir, size, mod); break;
+   case 10: VG_(transfer) (&s390x->guest_r8,  buf, dir, size, mod); break;
+   case 11: VG_(transfer) (&s390x->guest_r9,  buf, dir, size, mod); break;
+   case 12: VG_(transfer) (&s390x->guest_r10, buf, dir, size, mod); break;
+   case 13: VG_(transfer) (&s390x->guest_r11, buf, dir, size, mod); break;
+   case 14: VG_(transfer) (&s390x->guest_r12, buf, dir, size, mod); break;
+   case 15: VG_(transfer) (&s390x->guest_r13, buf, dir, size, mod); break;
+   case 16: VG_(transfer) (&s390x->guest_r14, buf, dir, size, mod); break;
+   case 17: VG_(transfer) (&s390x->guest_r15, buf, dir, size, mod); break;
+   case 18: VG_(transfer) (&s390x->guest_a0,  buf, dir, size, mod); break;
+   case 19: VG_(transfer) (&s390x->guest_a1,  buf, dir, size, mod); break;
+   case 20: VG_(transfer) (&s390x->guest_a2,  buf, dir, size, mod); break;
+   case 21: VG_(transfer) (&s390x->guest_a3,  buf, dir, size, mod); break;
+   case 22: VG_(transfer) (&s390x->guest_a4,  buf, dir, size, mod); break;
+   case 23: VG_(transfer) (&s390x->guest_a5,  buf, dir, size, mod); break;
+   case 24: VG_(transfer) (&s390x->guest_a6,  buf, dir, size, mod); break;
+   case 25: VG_(transfer) (&s390x->guest_a7,  buf, dir, size, mod); break;
+   case 26: VG_(transfer) (&s390x->guest_a8,  buf, dir, size, mod); break;
+   case 27: VG_(transfer) (&s390x->guest_a9,  buf, dir, size, mod); break;
+   case 28: VG_(transfer) (&s390x->guest_a10, buf, dir, size, mod); break;
+   case 29: VG_(transfer) (&s390x->guest_a11, buf, dir, size, mod); break;
+   case 30: VG_(transfer) (&s390x->guest_a12, buf, dir, size, mod); break;
+   case 31: VG_(transfer) (&s390x->guest_a13, buf, dir, size, mod); break;
+   case 32: VG_(transfer) (&s390x->guest_a14, buf, dir, size, mod); break;
+   case 33: VG_(transfer) (&s390x->guest_a15, buf, dir, size, mod); break;
+   case 34: VG_(transfer) (&s390x->guest_fpc, buf, dir, size, mod); break;
+   case 35: VG_(transfer) (&s390x->guest_f0,  buf, dir, size, mod); break;
+   case 36: VG_(transfer) (&s390x->guest_f1,  buf, dir, size, mod); break;
+   case 37: VG_(transfer) (&s390x->guest_f2,  buf, dir, size, mod); break;
+   case 38: VG_(transfer) (&s390x->guest_f3,  buf, dir, size, mod); break;
+   case 39: VG_(transfer) (&s390x->guest_f4,  buf, dir, size, mod); break;
+   case 40: VG_(transfer) (&s390x->guest_f5,  buf, dir, size, mod); break;
+   case 41: VG_(transfer) (&s390x->guest_f6,  buf, dir, size, mod); break;
+   case 42: VG_(transfer) (&s390x->guest_f7,  buf, dir, size, mod); break;
+   case 43: VG_(transfer) (&s390x->guest_f8,  buf, dir, size, mod); break;
+   case 44: VG_(transfer) (&s390x->guest_f9,  buf, dir, size, mod); break;
+   case 45: VG_(transfer) (&s390x->guest_f10, buf, dir, size, mod); break;
+   case 46: VG_(transfer) (&s390x->guest_f11, buf, dir, size, mod); break;
+   case 47: VG_(transfer) (&s390x->guest_f12, buf, dir, size, mod); break;
+   case 48: VG_(transfer) (&s390x->guest_f13, buf, dir, size, mod); break;
+   case 49: VG_(transfer) (&s390x->guest_f14, buf, dir, size, mod); break;
+   case 50: VG_(transfer) (&s390x->guest_f15, buf, dir, size, mod); break;
+   default: vg_assert(0);
+   }
+}
+
+static struct valgrind_target_ops low_target = {
+   num_regs,
+   regs,
+   17, //sp = r15, which is register offset 17 in regs
+   transfer_register,
+   get_pc,
+   set_pc,
+   "s390x",
+   NULL, // target_xml not needed.
+   NULL // no xml shadow target description (yet?)
+};
+
+void s390x_init_architecture (struct valgrind_target_ops *target)
+{
+   *target = low_target;
+   set_register_cache (regs, num_regs);
+   gdbserver_expedite_regs = expedite_regs;
+}
diff --git a/coregrind/m_gdbserver/valgrind-low-x86.c b/coregrind/m_gdbserver/valgrind-low-x86.c
new file mode 100644 (file)
index 0000000..89ef329
--- /dev/null
@@ -0,0 +1,276 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+
+#include "valgrind_low.h"
+
+#include "libvex_guest_x86.h"
+/* GDBTD: ??? have a cleaner way to get the f80 <> f64 conversion functions */
+/* below include needed for conversion f80 <> f64 */
+#include "../../VEX/priv/guest_generic_x87.h"
+
+
+/* below loosely inspired from  file generated with gdb regdat.sh  */
+
+static struct reg regs[] = {
+   { "eax", 0, 32 },
+   { "ecx", 32, 32 },
+   { "edx", 64, 32 },
+   { "ebx", 96, 32 },
+   { "esp", 128, 32 },
+   { "ebp", 160, 32 },
+   { "esi", 192, 32 },
+   { "edi", 224, 32 },
+   { "eip", 256, 32 },
+   { "eflags", 288, 32 },
+   { "cs", 320, 32 },
+   { "ss", 352, 32 },
+   { "ds", 384, 32 },
+   { "es", 416, 32 },
+   { "fs", 448, 32 },
+   { "gs", 480, 32 },
+   { "st0", 512, 80 },
+   { "st1", 592, 80 },
+   { "st2", 672, 80 },
+   { "st3", 752, 80 },
+   { "st4", 832, 80 },
+   { "st5", 912, 80 },
+   { "st6", 992, 80 },
+   { "st7", 1072, 80 },
+   { "fctrl", 1152, 32 },
+   { "fstat", 1184, 32 },
+   { "ftag", 1216, 32 },
+   { "fiseg", 1248, 32 },
+   { "fioff", 1280, 32 },
+   { "foseg", 1312, 32 },
+   { "fooff", 1344, 32 },
+   { "fop", 1376, 32 },
+   { "xmm0", 1408, 128 },
+   { "xmm1", 1536, 128 },
+   { "xmm2", 1664, 128 },
+   { "xmm3", 1792, 128 },
+   { "xmm4", 1920, 128 },
+   { "xmm5", 2048, 128 },
+   { "xmm6", 2176, 128 },
+   { "xmm7", 2304, 128 },
+   { "mxcsr", 2432, 32 },
+#if defined(VGO_linux)
+   { "orig_eax", 2464, 32 }
+#endif
+};
+static const char *expedite_regs[] = { "ebp", "esp", "eip", 0 };
+#define num_regs (sizeof (regs) / sizeof (regs[0]))
+
+static
+CORE_ADDR get_pc (void)
+{
+   unsigned long pc;
+
+   collect_register_by_name ("eip", &pc);
+   
+   dlog(1, "stop pc is %p\n", (void *) pc);
+   return pc;
+}
+
+static
+void set_pc (CORE_ADDR newpc)
+{
+   Bool mod;
+   supply_register_by_name ("eip", &newpc, &mod);
+   if (mod)
+      dlog(1, "set pc to %p\n", C2v (newpc));
+   else
+      dlog(1, "set pc not changed %p\n", C2v (newpc));
+}
+
+/* store registers in the guest state (gdbserver_to_valgrind)
+   or fetch register from the guest state (valgrind_to_gdbserver). */
+static
+void transfer_register (ThreadId tid, int abs_regno, void * buf,
+                        transfer_direction dir, int size, Bool *mod)
+{
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   int set = abs_regno / num_regs;
+   int regno = abs_regno % num_regs;
+   *mod = False;
+
+   VexGuestX86State* x86 = (VexGuestX86State*) get_arch (set, tst);
+
+   switch (regno) { 
+   // numbers here have to match the order of regs above
+   // Attention: gdb order does not match valgrind order.
+   case 0:  VG_(transfer) (&x86->guest_EAX, buf, dir, size, mod); break;
+   case 1:  VG_(transfer) (&x86->guest_ECX, buf, dir, size, mod); break;
+   case 2:  VG_(transfer) (&x86->guest_EDX, buf, dir, size, mod); break;
+   case 3:  VG_(transfer) (&x86->guest_EBX, buf, dir, size, mod); break;
+   case 4:  VG_(transfer) (&x86->guest_ESP, buf, dir, size, mod); break;
+   case 5:  VG_(transfer) (&x86->guest_EBP, buf, dir, size, mod); break;
+   case 6:  VG_(transfer) (&x86->guest_ESI, buf, dir, size, mod); break;
+   case 7:  VG_(transfer) (&x86->guest_EDI, buf, dir, size, mod); break;
+   case 8:  
+      VG_(transfer) (&x86->guest_EIP, buf, dir, size, mod); 
+      if (*mod && VG_(debugLog_getLevel)() > 2) {
+         char bufimage [2*sizeof(x86->guest_IP_AT_SYSCALL) + 1];
+         heximage (bufimage, 
+                   (char *) &x86->guest_IP_AT_SYSCALL, 
+                   sizeof(x86->guest_IP_AT_SYSCALL));
+         dlog(3, "guest_IP_AT_SYSCALL %s\n", bufimage);
+      }
+      break;
+   case 9:  
+      if (dir == valgrind_to_gdbserver) {
+         UInt eflags;
+         /* we can only retrieve the real flags (set 0)
+            retrieving shadow flags is not ok */
+         if (set == 0)
+            eflags = LibVEX_GuestX86_get_eflags (x86);
+         else
+            eflags = 0;
+         VG_(transfer) (&eflags, buf, dir, size, mod); break;
+      } else {
+         *mod = False; //GDBTD? how do we store eflags in libvex_guest_x86.h ???
+      }
+      break;
+   case 10: VG_(transfer) (&x86->guest_CS, buf, dir, size, mod); break;
+   case 11: VG_(transfer) (&x86->guest_SS, buf, dir, size, mod); break;
+   case 12: VG_(transfer) (&x86->guest_DS, buf, dir, size, mod); break;
+   case 13: VG_(transfer) (&x86->guest_ES, buf, dir, size, mod); break;
+   case 14: VG_(transfer) (&x86->guest_FS, buf, dir, size, mod); break;
+   case 15: VG_(transfer) (&x86->guest_GS, buf, dir, size, mod); break;
+   case 16:
+   case 17:
+   case 18:
+   case 19: /* register 16 to 23 are float registers 80 bits but 64 bits in valgrind */
+   case 20:
+   case 21:
+   case 22:
+   case 23: {
+      if (dir == valgrind_to_gdbserver) {
+         UChar fpreg80[10];
+         convert_f64le_to_f80le ((UChar *)&x86->guest_FPREG[regno-16],
+                                 fpreg80);
+         VG_(transfer) (&fpreg80, buf, dir, sizeof(fpreg80), mod);
+      } else {
+         ULong fpreg64;
+         convert_f80le_to_f64le (buf, (UChar *)&fpreg64); 
+         VG_(transfer) (&x86->guest_FPREG[regno-16], &fpreg64, 
+                        dir, sizeof(fpreg64), mod);
+      }
+      break;
+   }
+   case 24: 
+      if (dir == valgrind_to_gdbserver) {
+         // vex only models the rounding bits (see libvex_guest_x86.h)
+         UWord value = 0x037f;
+         value |= x86->guest_FPROUND << 10;
+         VG_(transfer)(&value, buf, dir, size, mod);
+      } else {
+         *mod = False; // GDBTD???? VEX { "fctrl", 1152, 32 },
+      }
+      break; 
+   case 25:
+      if (dir == valgrind_to_gdbserver) {
+         UWord value = x86->guest_FC3210;
+         value |= (x86->guest_FTOP & 7) << 11;
+         VG_(transfer)(&value, buf, dir, size, mod); 
+      } else {
+         *mod = False; // GDBTD???? VEX { "fstat", 1184, 32 },
+      }
+      break;
+   case 26: 
+      if (dir == valgrind_to_gdbserver) {
+         // vex doesn't model these precisely
+         UWord value = 
+            ((x86->guest_FPTAG[0] ? 0 : 3) << 0)  | 
+            ((x86->guest_FPTAG[1] ? 0 : 3) << 2)  | 
+            ((x86->guest_FPTAG[2] ? 0 : 3) << 4)  | 
+            ((x86->guest_FPTAG[3] ? 0 : 3) << 6)  | 
+            ((x86->guest_FPTAG[4] ? 0 : 3) << 8)  | 
+            ((x86->guest_FPTAG[5] ? 0 : 3) << 10) | 
+            ((x86->guest_FPTAG[6] ? 0 : 3) << 12) | 
+            ((x86->guest_FPTAG[7] ? 0 : 3) << 14);
+         VG_(transfer)(&value, buf, dir, size, mod); 
+      } else {
+         *mod = False;  // GDBTD???? VEX { "ftag", 1216, 32 },
+      }
+      break;
+   case 27: *mod = False; break; // GDBTD???? VEX { "fiseg", 1248, 32 },
+   case 28: *mod = False; break; // GDBTD???? VEX { "fioff", 1280, 32 },
+   case 29: *mod = False; break; // GDBTD???? VEX { "foseg", 1312, 32 },
+   case 30: *mod = False; break; // GDBTD???? VEX { "fooff", 1344, 32 },
+   case 31: *mod = False; break; // GDBTD???? VEX { "fop", 1376, 32 },
+   case 32: VG_(transfer) (&x86->guest_XMM0, buf, dir, size, mod); break;
+   case 33: VG_(transfer) (&x86->guest_XMM1, buf, dir, size, mod); break;
+   case 34: VG_(transfer) (&x86->guest_XMM2, buf, dir, size, mod); break;
+   case 35: VG_(transfer) (&x86->guest_XMM3, buf, dir, size, mod); break;
+   case 36: VG_(transfer) (&x86->guest_XMM4, buf, dir, size, mod); break;
+   case 37: VG_(transfer) (&x86->guest_XMM5, buf, dir, size, mod); break;
+   case 38: VG_(transfer) (&x86->guest_XMM6, buf, dir, size, mod); break;
+   case 39: VG_(transfer) (&x86->guest_XMM7, buf, dir, size, mod); break;
+   case 40: 
+      if (dir == valgrind_to_gdbserver) {
+         // vex only models the rounding bits (see libvex_guest_x86.h)
+         UWord value = 0x1f80;
+         value |= x86->guest_SSEROUND << 13;
+         VG_(transfer)(&value, buf, dir, size, mod); 
+      } else {
+         *mod = False; // GDBTD???? VEX { "mxcsr", 2432, 32 },
+      }
+      break;
+   case 41: *mod = False; break; // GDBTD???? VEX { "orig_eax", 2464, 32 },
+   default: vg_assert(0);
+   }
+}
+
+static struct valgrind_target_ops low_target = {
+   num_regs,
+   regs,
+   4, //ESP
+   transfer_register,
+   get_pc,
+   set_pc,
+   "i386",
+   NULL, // target_xml not needed.
+#if defined(VGO_linux)
+   "i386-linux-valgrind.xml"
+#else
+   "i386-coresse-valgrind.xml"
+#endif
+};
+
+void x86_init_architecture (struct valgrind_target_ops *target)
+{
+   *target = low_target;
+   set_register_cache (regs, num_regs);
+   gdbserver_expedite_regs = expedite_regs;
+}
diff --git a/coregrind/m_gdbserver/valgrind-low.c b/coregrind/m_gdbserver/valgrind-low.c
new file mode 100644 (file)
index 0000000..fc376fa
--- /dev/null
@@ -0,0 +1,639 @@
+/* Low level interface to valgrind, for the remote server for GDB integrated
+   in valgrind.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of VALGRIND.
+   It has been inspired from a file from gdbserver in gdb 6.6.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+#include "valgrind_low.h"
+#include "gdb/signals.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h" 
+#include "pub_tool_debuginfo.h"
+
+/* the_low_target defines the architecture specific aspects depending
+   on the cpu */
+static struct valgrind_target_ops the_low_target;
+
+/* builds an image of bin according to byte order of the architecture 
+   Useful for register and int image */
+char* heximage (char *buf, char *bin, int count)
+{
+#if defined(VGA_x86) || defined(VGA_amd64)
+   char rev[count]; 
+   /* note: no need for trailing \0, length is known with count */
+  int i;
+  for (i = 0; i < count; i++)
+    rev[i] = bin[count - i - 1];
+  hexify (buf, rev, count);
+#else
+  hexify (buf, bin, count);
+#endif
+  return buf;
+}
+
+void* C2v(CORE_ADDR addr)
+{
+   return (void*) addr;
+}
+
+static
+char *image_ptid(unsigned long ptid)
+{
+  static char result[100];
+  VG_(sprintf) (result, "id %ld", ptid);
+  return result;
+}
+#define get_thread(inf) ((struct thread_info *)(inf))
+static
+void remove_thread_if_not_in_vg_threads (struct inferior_list_entry *inf)
+{
+  struct thread_info *thread = get_thread (inf);
+  if (!VG_(lwpid_to_vgtid)(thread_to_gdb_id(thread))) {
+     dlog(1, "removing gdb ptid %s\n", 
+          image_ptid(thread_to_gdb_id(thread)));
+     remove_thread (thread);
+  }
+}
+
+/* synchronize threads known by valgrind and threads known by gdbserver */
+static
+void valgrind_update_threads (int pid)
+{
+  ThreadId tid;
+  ThreadState *ts;
+  unsigned long ptid;
+  struct thread_info *ti;
+
+  /* call remove_thread for all gdb threads not in valgrind threads */
+  for_each_inferior (&all_threads, remove_thread_if_not_in_vg_threads);
+  
+  /* call add_thread for all valgrind threads not known in gdb all_threads */
+  for (tid = 1; tid < VG_N_THREADS; tid++) {
+
+#define LOCAL_THREAD_TRACE " ti* %p vgtid %d status %s as gdb ptid %s lwpid %d\n", \
+        ti, tid, VG_(name_of_ThreadStatus) (ts->status), \
+        image_ptid (ptid), ts->os_state.lwpid
+
+     if (VG_(is_valid_tid) (tid)) {
+        ts = VG_(get_ThreadState) (tid);
+        ptid = ts->os_state.lwpid;
+        ti = gdb_id_to_thread (ptid);
+        if (!ti) {
+           /* we do not report the threads which are not yet fully
+              initialized otherwise this creates duplicated threads
+              in gdb: once with pid xxx lwpid 0, then after that
+              with pid xxx lwpid yyy. */
+           if (ts->status != VgTs_Init) {
+              dlog(1, "adding_thread" LOCAL_THREAD_TRACE);
+              add_thread (ptid, ts, ptid);
+           }
+        } else {
+           dlog(2, "(known thread)" LOCAL_THREAD_TRACE);
+        }
+     }
+#undef LOCAL_THREAD_TRACE
+  }
+}
+
+/* Return nonzero if the given thread is still alive.  */
+static
+int valgrind_thread_alive (unsigned long tid)
+{
+  struct thread_info *ti =  gdb_id_to_thread(tid);
+  ThreadState *tst;
+
+  if (ti != NULL) {
+     tst = (ThreadState *) inferior_target_data (ti);
+     return tst->status != VgTs_Zombie;
+  }
+  else {
+    return 0;
+  }
+}
+
+/* allocate and build a register structure containing the shadow registers.
+   reg_defs is the normal registers, n is their numbers */
+static
+struct reg* build_shadow_arch (struct reg *reg_defs, int n) {
+   int i, r;
+   static char *postfix[3] = { "", "s1", "s2" };
+   struct reg *new_regs = malloc(3 * n * sizeof(reg_defs[0]));
+   int reg_set_len = reg_defs[n-1].offset + reg_defs[n-1].size;
+
+   for (i = 0; i < 3; i++) {
+      for (r = 0; r < n; r++) {
+         new_regs[i*n + r].name = malloc(strlen(reg_defs[r].name) 
+                                         + strlen (postfix[i]) + 1);
+         strcpy (new_regs[i*n + r].name, reg_defs[r].name);
+         strcat (new_regs[i*n + r].name, postfix[i]);
+         new_regs[i*n + r].offset = i*reg_set_len + reg_defs[r].offset;
+         new_regs[i*n + r].size = reg_defs[r].size;
+         dlog(1,
+              "%10s Nr %d offset(bit) %d offset(byte) %d  size(bit) %d\n",
+              new_regs[i*n + r].name, i*n + r, new_regs[i*n + r].offset,
+              (new_regs[i*n + r].offset) / 8, new_regs[i*n + r].size);
+      }  
+   }
+
+   return new_regs;
+}
+
+/* Fetch one register from valgrind VEX guest state.  */
+static
+void fetch_register (int regno)
+{
+   int size;
+   ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
+   ThreadId tid = tst->tid;
+
+   if (regno >= the_low_target.num_regs) {
+      dlog(0, "error fetch_register regno %d max %d\n",
+           regno, the_low_target.num_regs);
+      return;
+   }
+   size = register_size (regno);
+   {
+      Bool mod;
+      char buf [size];
+      VG_(memset) (buf, 0, size); // registers not fetched will be seen as 0.
+      (*the_low_target.transfer_register) (tid, regno, buf,
+                                           valgrind_to_gdbserver, size, &mod);
+      // Note: the *mod received from transfer_register is not interesting.
+      // We are interested to see if the register data in the register cache is modified.
+      supply_register (regno, buf, &mod);
+      if (mod && VG_(debugLog_getLevel)() > 1) {
+         char bufimage [2*size + 1];
+         heximage (bufimage, buf, size);
+         dlog(2, "fetched register %d size %d name %s value %s tid %d status %s\n", 
+              regno, size, the_low_target.reg_defs[regno].name, bufimage, 
+              tid, VG_(name_of_ThreadStatus) (tst->status));
+      }
+   }
+}
+
+/* Fetch all registers, or just one, from the child process.  */
+static
+void usr_fetch_inferior_registers (int regno)
+{
+   if (regno == -1 || regno == 0)
+      for (regno = 0; regno < the_low_target.num_regs; regno++)
+         fetch_register (regno);
+   else
+      fetch_register (regno);
+}
+
+/* Store our register values back into the inferior.
+   If REGNO is -1, do this for all registers.
+   Otherwise, REGNO specifies which register (so we can save time).  */
+static
+void usr_store_inferior_registers (int regno)
+{
+   int size;
+   ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
+   ThreadId tid = tst->tid;
+   
+   if (regno >= 0) {
+
+      if (regno >= the_low_target.num_regs) {
+         dlog(0, "error store_register regno %d max %d\n",
+              regno, the_low_target.num_regs);
+         return;
+      }
+      
+      size = register_size (regno);
+      {
+         Bool mod;
+         Addr old_SP, new_SP;
+         char buf[size];
+
+         if (regno == the_low_target.stack_pointer_regno) {
+            /* When the stack pointer register is changed such that
+               the stack is extended, we better inform the tool of the
+               stack increase.  This is needed in particular to avoid
+               spurious Memcheck errors during Inferior calls. So, we
+               save in old_SP the SP before the change. A change of
+               stack pointer is also assumed to have initialised this
+               new stack space. For the typical example of an inferior
+               call, gdb writes arguments on the stack, and then
+               changes the stack pointer. As the stack increase tool
+               function might mark it as undefined, we have to call it
+               at the good moment. */
+            VG_(memset) ((void *) &old_SP, 0, size);
+            (*the_low_target.transfer_register) (tid, regno, (void *) &old_SP, 
+                                                 valgrind_to_gdbserver, size, &mod);
+         }
+
+         VG_(memset) (buf, 0, size);
+         collect_register (regno, buf);
+         (*the_low_target.transfer_register) (tid, regno, buf, 
+                                              gdbserver_to_valgrind, size, &mod);
+         if (mod && VG_(debugLog_getLevel)() > 1) {
+            char bufimage [2*size + 1];
+            heximage (bufimage, buf, size);
+            dlog(2, 
+                 "stored register %d size %d name %s value %s "
+                 "tid %d status %s\n", 
+                 regno, size, the_low_target.reg_defs[regno].name, bufimage, 
+                 tid, VG_(name_of_ThreadStatus) (tst->status));
+         }
+         if (regno == the_low_target.stack_pointer_regno) {
+            VG_(memcpy) (&new_SP, buf, size);
+            if (old_SP > new_SP) {
+               Word delta  = (Word)new_SP - (Word)old_SP;
+               dlog(1, 
+                    "   stack increase by stack pointer changed from %p to %p "
+                    "delta %ld\n",
+                    (void*) old_SP, (void *) new_SP,
+                    delta);
+               VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, 0 );
+               VG_TRACK( new_mem_stack,       new_SP, -delta );
+               if (VG_(tdict).track_post_mem_write) {
+                  VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid, 
+                                                   new_SP, -delta);
+               }
+            }
+         }
+      }
+   }
+   else {
+      for (regno = 0; regno < the_low_target.num_regs; regno++)
+         usr_store_inferior_registers (regno);
+   }
+}
+
+static
+void valgrind_fetch_registers (int regno)
+{
+   usr_fetch_inferior_registers (regno);
+}
+
+static
+void valgrind_store_registers (int regno)
+{
+   usr_store_inferior_registers (regno);
+}
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+   to debugger memory starting at MYADDR.  */
+
+static
+int valgrind_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+   const void *sourceaddr = C2v (memaddr);
+   dlog(2, "reading memory %p size %d\n", sourceaddr, len);
+   if (!VG_(am_is_valid_for_client_or_free_or_resvn) ((Addr) sourceaddr, 
+                                                      len, VKI_PROT_READ)) {
+      dlog(1, "error reading memory %p size %d\n", sourceaddr, len);
+      return -1;
+   }
+   VG_(memcpy) (myaddr, sourceaddr, len);
+   return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.
+   On failure (cannot write the inferior)
+   returns the value of errno.  */
+
+static
+int valgrind_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+   void *targetaddr = C2v (memaddr);
+   dlog(2, "writing memory %p size %d\n", targetaddr, len);
+   if (!VG_(am_is_valid_for_client_or_free_or_resvn) ((Addr)targetaddr, 
+                                                      len, VKI_PROT_WRITE)) {
+      dlog(1, "error writing memory %p size %d\n", targetaddr, len);
+      return -1;
+   }
+   if (len > 0) {
+      VG_(memcpy) (targetaddr, myaddr, len);
+      if (VG_(tdict).track_post_mem_write) {
+         /* Inform the tool of the post memwrite.  Note that we do the
+            minimum necessary to avoid complains from e.g.
+            memcheck. The idea is that the debugger is as least
+            intrusive as possible.  So, we do not inform of the pre
+            mem write (and in any case, this would cause problems with
+            memcheck that does not like our CorePart in
+            pre_mem_write. */
+         ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
+         ThreadId tid = tst->tid;
+         VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid, (Addr) targetaddr, len );
+      }
+   }
+   return 0;
+}
+
+/* insert or remove a breakpoint */
+static
+int valgrind_point (Bool insert, char type, CORE_ADDR addr, int len)
+{
+   PointKind kind;
+   switch (type) {
+   case '0': /* implemented by inserting checks at each instruction in sb */
+      kind = software_breakpoint;
+      break;
+   case '1': /* hw breakpoint, same implementation as sw breakpoint */
+      kind = hardware_breakpoint;
+      break;
+   case '2':
+      kind = write_watchpoint;
+      break;
+   case '3':
+      kind = read_watchpoint;
+      break;
+   case '4':
+      kind = access_watchpoint;
+      break;
+   default:
+      vg_assert (0);
+   }
+
+   /* Attention: gdbserver convention differs: 0 means ok; 1 means not ok */
+   if (VG_(gdbserver_point) (kind, insert, addr, len))
+      return 0;
+   else
+      return 1; /* error or unsupported */
+}
+
+static
+void valgrind_send_signal (int sig)
+{
+   dlog(1, "valgrind_send_signal %d called ????\n", sig); 
+}
+
+static
+char* valgrind_target_xml (void)
+{
+   return (char *) the_low_target.target_xml;
+}
+
+static
+char* valgrind_shadow_target_xml (void)
+{
+   return (char *) the_low_target.shadow_target_xml;
+}
+
+static
+int valgrind_insert_point (char type, CORE_ADDR addr, int len)
+{
+   return valgrind_point (/* insert */ True, type, addr, len);
+}
+
+static
+int valgrind_remove_point (char type, CORE_ADDR addr, int len)
+{
+   return valgrind_point (/* insert*/ False, type, addr, len);
+}
+
+static CORE_ADDR stopped_data_address = 0;
+void VG_(set_watchpoint_stop_address) (Addr addr)
+{
+   stopped_data_address = addr;
+}
+
+static
+int valgrind_stopped_by_watchpoint (void)
+{
+   return stopped_data_address != 0;
+}
+
+static
+CORE_ADDR valgrind_stopped_data_address (void)
+{
+   return stopped_data_address;
+}
+
+/* pc at which we last stopped */
+static CORE_ADDR stop_pc;
+
+/* pc at which we resume. 
+   If stop_pc != resume_pc, it means
+      gdb/gdbserver has changed the pc so as to have either
+      a    "continue by jumping at that address"
+      or a "continue at that address to call some code from gdb".
+*/
+static CORE_ADDR resume_pc;
+
+static int signal_to_report;
+
+void gdbserver_signal_encountered (Int sigNo)
+{
+   signal_to_report = sigNo;
+}
+
+static int signal_to_deliver;
+Bool gdbserver_deliver_signal (Int sigNo)
+{
+   return sigNo == signal_to_deliver;
+}
+
+static
+char* sym (Addr addr)
+{
+   static char buf[200];
+   VG_(describe_IP) (addr, buf, 200);
+   return buf;
+}
+
+ThreadId vgdb_interrupted_tid = 0;
+/* called to wait for the process to stop */
+static
+unsigned char valgrind_wait (char *ourstatus)
+{
+   int pid;
+   unsigned long wptid;
+   ThreadState *tst;
+   enum target_signal sig;
+
+   pid = VG_(getpid) ();
+   dlog(1, "enter valgrind_wait pid %d\n", pid);
+
+   regcache_invalidate();
+   valgrind_update_threads(pid);
+
+   /* in valgrind, we consider that a wait always succeeds with STOPPED 'T' 
+      and with a signal TRAP (i.e. a breakpoint), unless there is
+      a signal to report. */
+   *ourstatus = 'T';
+   if (signal_to_report == 0)
+      sig = TARGET_SIGNAL_TRAP;
+   else
+      sig = target_signal_from_host(signal_to_report);
+   
+   if (vgdb_interrupted_tid != 0)
+      tst = VG_(get_ThreadState) (vgdb_interrupted_tid);
+   else
+      tst = VG_(get_ThreadState) (VG_(running_tid));
+   wptid = tst->os_state.lwpid;
+   /* we can only change the current_inferior when the wptid references
+      an existing thread. Otherwise, we are still in the init phase.
+      (hack similar to main thread hack in valgrind_update_threads) */
+   if (tst->os_state.lwpid)
+      current_inferior = gdb_id_to_thread (wptid);
+   stop_pc = (*the_low_target.get_pc) ();
+   
+   dlog(1,
+        "exit valgrind_wait returns ptid %s stop_pc %s signal %d\n", 
+        image_ptid (wptid), sym (stop_pc), sig);
+   return sig;
+}
+
+/* 0 => not single stepping.
+   1 => single stepping asked by gdb
+   2 => single stepping asked by valgrind (watchpoint) */
+static int stepping = 0;
+
+/* called when the process is to be resumed */
+static
+void valgrind_resume (struct thread_resume *resume_info)
+{
+   dlog(1,
+        "resume_info thread %ld leave_stopped %d step %d sig %d stepping %d\n", 
+        resume_info->thread,
+        resume_info->leave_stopped,
+        resume_info->step,
+        resume_info->sig,
+        stepping);
+   if (valgrind_stopped_by_watchpoint()) {
+      dlog(1, "clearing watchpoint stopped_data_address %p\n",
+           C2v(stopped_data_address));
+      VG_(set_watchpoint_stop_address) ((Addr) 0);
+   }
+   signal_to_deliver = resume_info->sig;
+   
+   stepping = resume_info->step;
+   resume_pc = (*the_low_target.get_pc) ();
+   if (resume_pc != stop_pc) {
+      dlog(1,
+           "stop_pc %p changed to be resume_pc %s\n",
+           C2v(stop_pc), sym(resume_pc));
+   }
+   regcache_invalidate();
+}
+
+Addr valgrind_get_ignore_break_once(void)
+{
+   if (valgrind_single_stepping())
+      return resume_pc;
+   else
+      return 0;
+}
+
+
+void valgrind_set_single_stepping(Bool set)
+{
+   if (set)
+      stepping = 2;
+   else
+      stepping = 0;
+}
+
+Bool valgrind_single_stepping(void)
+{
+   if (stepping)
+      return True;
+   else
+      return False;
+}
+
+static struct target_ops valgrind_target_ops = {
+   valgrind_thread_alive,
+   valgrind_resume,
+   valgrind_wait,
+   valgrind_fetch_registers,
+   valgrind_store_registers,
+   valgrind_read_memory,
+   valgrind_write_memory,
+   valgrind_send_signal,
+   valgrind_target_xml,
+   valgrind_shadow_target_xml,
+   valgrind_insert_point,
+   valgrind_remove_point,
+   valgrind_stopped_by_watchpoint,
+   valgrind_stopped_data_address,
+};
+
+
+/* returns a pointer to the architecture state corresponding to
+   the provided register set: 0 => normal guest registers,
+                              1 => shadow1
+                              2 => shadow2
+*/
+VexGuestArchState* get_arch (int set, ThreadState* tst) 
+{
+  switch (set) {
+  case 0: return &tst->arch.vex;
+  case 1: return &tst->arch.vex_shadow1;
+  case 2: return &tst->arch.vex_shadow2;
+  default: vg_assert(0);
+  }
+}
+
+static int non_shadow_num_regs = 0;
+static struct reg *non_shadow_reg_defs = NULL;
+void initialize_shadow_low(Bool shadow_mode)
+{
+  if (non_shadow_reg_defs == NULL) {
+    non_shadow_reg_defs = the_low_target.reg_defs;
+    non_shadow_num_regs = the_low_target.num_regs;
+  }
+
+  regcache_invalidate();
+  if (the_low_target.reg_defs != non_shadow_reg_defs) {
+     free (the_low_target.reg_defs);
+  }
+  if (shadow_mode) {
+    the_low_target.num_regs = 3 * non_shadow_num_regs;
+    the_low_target.reg_defs = build_shadow_arch (non_shadow_reg_defs, non_shadow_num_regs);
+  } else {
+    the_low_target.num_regs = non_shadow_num_regs;
+    the_low_target.reg_defs = non_shadow_reg_defs;
+  }
+  set_register_cache (the_low_target.reg_defs, the_low_target.num_regs);
+}
+
+void initialize_low(void)
+{
+   set_target_ops (&valgrind_target_ops);
+
+#if defined(VGA_x86)
+   x86_init_architecture(&the_low_target);
+#elif defined(VGA_amd64)
+   amd64_init_architecture(&the_low_target);
+#elif defined(VGA_arm)
+   arm_init_architecture(&the_low_target);
+#elif defined(VGA_ppc32)
+   ppc32_init_architecture(&the_low_target);
+#elif defined(VGA_ppc64)
+   ppc64_init_architecture(&the_low_target);
+#elif defined(VGA_s390x)
+   s390x_init_architecture(&the_low_target);
+#else
+   architecture missing in valgrind-low.c
+#endif
+
+}
diff --git a/coregrind/m_gdbserver/valgrind_low.h b/coregrind/m_gdbserver/valgrind_low.h
new file mode 100644 (file)
index 0000000..6817110
--- /dev/null
@@ -0,0 +1,91 @@
+/* Definitions of interface to the "low" (arch specific) functions
+   needed for interfacing the Valgrind gdbserver with the Valgrind
+   guest.
+
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file has been inspired from a file that is part of GDB.
+   It has been modified to integrate it in valgrind
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef VALGRIND_LOW_H
+#define VALGRIND_LOW_H
+
+/* defines the characteristics of the "low" valgrind target architecture.
+   In other words, struct valgrind_target_ops defines the functions and 
+   data which are specific to the architecture (x86 or amd64 or 
+   ppc32 or ...). */
+struct valgrind_target_ops
+{
+   int num_regs;
+   struct reg *reg_defs;
+
+   int stack_pointer_regno;
+   /* register number of the stack pointer register */
+   
+   /* transfer the register regno from/to valgrind (guest state)
+      to/from buf
+      according to transfer_direction.
+      *mod set to True if destination content is modified by the transfer
+      otherwise it is set to False. */
+   void (*transfer_register) (ThreadId tid, int regno, void * buf, 
+                              transfer_direction dir, int size, Bool *mod);
+   
+
+   CORE_ADDR (*get_pc) (void);
+   void (*set_pc) (CORE_ADDR newpc);
+
+   /* What string to report to GDB when it asks for the architecture,
+      or NULL not to answer.  */
+   const char *arch_string;
+   
+   /* Description of the set of registers.
+      For some architectures (e.g. arm), it is mandatory
+      to give a description of the registers, otherwise
+      gdb does not understand the reply to the 'g' packet
+      (which is used to get the registers). */
+   const char *target_xml;
+
+   /* Same as target_xml, but describes also the two shadow
+      registers set.
+      This is mandatory to use the option --vgdb-shadow-registers=yes. */
+   const char *shadow_target_xml;
+};
+
+
+/* convert from CORE_ADDR to void* */
+extern void* C2v(CORE_ADDR addr);
+
+/* builds an image of bin according to byte order of the architecture 
+   Useful for register and int image */
+extern char* heximage (char *buf, char *bin, int count);
+
+/* returns a pointer to the architecture state corresponding to
+   the provided register set: 0 => normal guest registers,
+                              1 => shadow1
+                              2 => shadow2 */
+VexGuestArchState* get_arch (int set, ThreadState* tst);
+
+extern void x86_init_architecture (struct valgrind_target_ops *target);
+extern void amd64_init_architecture (struct valgrind_target_ops *target);
+extern void arm_init_architecture (struct valgrind_target_ops *target);
+extern void ppc32_init_architecture (struct valgrind_target_ops *target);
+extern void ppc64_init_architecture (struct valgrind_target_ops *target);
+extern void s390x_init_architecture (struct valgrind_target_ops *target);
+
+#endif
diff --git a/coregrind/m_gdbserver/version.c b/coregrind/m_gdbserver/version.c
new file mode 100644 (file)
index 0000000..7b2af40
--- /dev/null
@@ -0,0 +1,2 @@
+#include "server.h"
+const char version[] = "gdbserver protocol box extracted from gdb 6.6";
index 98ff96b35f14f91a416eccec18147822f7111e39..6d6a2740fdf5882d077d6500a1f7d31464ff21e6 100644 (file)
@@ -89,6 +89,31 @@ Long VG_(strtoll10) ( Char* str, Char** endptr )
    return n;
 }
 
+ULong VG_(strtoull10) ( Char* str, Char** endptr )
+{
+   Bool converted = False;
+   ULong n = 0;
+   Long digit = 0;
+   Char* str0 = str;
+
+   // Skip leading whitespace.
+   while (VG_(isspace)(*str)) str++;
+
+   // Allow a leading '+'.
+   if (*str == '+') { str++; }
+
+   while (is_dec_digit(*str, &digit)) {
+      converted = True;          // Ok, we've actually converted a digit.
+      n = 10*n + digit;
+      str++;
+   }
+
+   if (!converted) str = str0;   // If nothing converted, endptr points to
+   //   the start of the string.
+   if (endptr) *endptr = str;    // Record first failing character.
+   return n;
+}
+
 Long VG_(strtoll16) ( Char* str, Char** endptr )
 {
    Bool neg = False, converted = False;
@@ -122,6 +147,39 @@ Long VG_(strtoll16) ( Char* str, Char** endptr )
    return n;
 }
 
+ULong VG_(strtoull16) ( Char* str, Char** endptr )
+{
+   Bool converted = False;
+   ULong n = 0;
+   Long digit = 0;
+   Char* str0 = str;
+
+   // Skip leading whitespace.
+   while (VG_(isspace)(*str)) str++;
+
+   // Allow a leading '+'.
+   if (*str == '+') { str++; }
+
+   // Allow leading "0x", but only if there's a hex digit
+   // following it.
+   if (*str == '0'
+    && (*(str+1) == 'x' || *(str+1) == 'X')
+    && is_hex_digit( *(str+2), &digit )) {
+      str += 2;
+   }
+
+   while (is_hex_digit(*str, &digit)) {
+      converted = True;          // Ok, we've actually converted a digit.
+      n = 16*n + digit;
+      str++;
+   }
+
+   if (!converted) str = str0;   // If nothing converted, endptr points to
+   //   the start of the string.
+   if (endptr) *endptr = str;    // Record first failing character.
+   return n;
+}
+
 double VG_(strtod) ( Char* str, Char** endptr )
 {
    Bool neg = False;
@@ -356,6 +414,88 @@ Char* VG_(strrchr) ( const Char* s, Char c )
    return NULL;
 }
 
+/* (code copied from glib then updated to valgrind types) */
+static Char *olds;
+Char *
+VG_(strtok) (Char *s, const Char *delim)
+{
+   return VG_(strtok_r) (s, delim, &olds);
+}
+
+Char *
+VG_(strtok_r) (Char* s, const Char* delim, Char** saveptr)
+{
+   Char *token;
+
+   if (s == NULL)
+      s = *saveptr;
+
+   /* Scan leading delimiters.  */
+   s += VG_(strspn (s, delim));
+   if (*s == '\0')
+      {
+         *saveptr = s;
+         return NULL;
+      }
+
+   /* Find the end of the token.  */
+   token = s;
+   s = VG_(strpbrk (token, delim));
+   if (s == NULL)
+      /* This token finishes the string.  */
+      *saveptr = token + VG_(strlen) (token);
+   else
+      {
+         /* Terminate the token and make OLDS point past it.  */
+         *s = '\0';
+         *saveptr = s + 1;
+      }
+   return token;
+}
+
+static Bool isHex ( UChar c )
+{
+  return ((c >= '0' && c <= '9') ||
+         (c >= 'a' && c <= 'f') ||
+         (c >= 'A' && c <= 'F'));
+}
+
+static UInt fromHex ( UChar c )
+{
+   if (c >= '0' && c <= '9')
+      return (UInt)c - (UInt)'0';
+   if (c >= 'a' && c <= 'f')
+      return 10 +  (UInt)c - (UInt)'a';
+   if (c >= 'A' && c <= 'F')
+      return 10 +  (UInt)c - (UInt)'A';
+   /*NOTREACHED*/
+   // ??? need to vg_assert(0);
+   return 0;
+}
+
+Bool VG_(parse_Addr) ( UChar** ppc, Addr* result )
+{
+   Int used, limit = 2 * sizeof(Addr);
+   if (**ppc != '0')
+      return False;
+   (*ppc)++;
+   if (**ppc != 'x')
+      return False;
+   (*ppc)++;
+   *result = 0;
+   used = 0;
+   while (isHex(**ppc)) {
+      // ??? need to vg_assert(d < fromHex(**ppc));
+      *result = ((*result) << 4) | fromHex(**ppc);
+      (*ppc)++;
+      used++;
+      if (used > limit) return False;
+   }
+   if (used == 0)
+      return False;
+   return True;
+}
+
 SizeT VG_(strspn) ( const Char* s, const Char* accpt )
 {
    const Char *p, *a;
index 8c1dbc9950b8bf9ef55acc24f4ce62996d20193b..2b9e44547c1c3c3542292f453f0a7a6fa633fd1f 100644 (file)
@@ -108,6 +108,17 @@ Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
 #  endif
 }
 
+SysRes VG_(mknod) ( const Char* pathname, Int mode, UWord dev )
+{  
+#  if defined(VGO_linux) || defined(VGO_aix5) || defined(VGO_darwin)
+   SysRes res = VG_(do_syscall3)(__NR_mknod,
+                                 (UWord)pathname, mode, dev);
+#  else
+#    error Unknown OS
+#  endif
+   return res;
+}
+
 SysRes VG_(open) ( const Char* pathname, Int flags, Int mode )
 {  
 #  if defined(VGO_linux) || defined(VGO_aix5)
@@ -122,6 +133,16 @@ SysRes VG_(open) ( const Char* pathname, Int flags, Int mode )
    return res;
 }
 
+Int VG_(fd_open) (const Char* pathname, Int flags, Int mode)
+{
+   SysRes sr;
+   sr = VG_(open) (pathname, flags, mode);
+   if (sr_isError (sr))
+      return -1;
+   else
+      return sr_Res (sr);
+}
+
 void VG_(close) ( Int fd )
 {
    /* Hmm.  Return value is not checked.  That's uncool. */
@@ -444,6 +465,14 @@ Bool VG_(get_startup_wd) ( Char* buf, SizeT size )
    return True;
 }
 
+Int    VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
+{
+   SysRes res;
+   res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
+   return sr_isError(res) ? -1 : sr_Res(res);
+}
+
+
 Int VG_(readlink) (const Char* path, Char* buf, UInt bufsiz)
 {
    SysRes res;
index dee9e56653237364d2f48bde62ac50fc132a5cd1..fb2544d514384dbee1b28a5e0d9f36f46acd88aa 100644 (file)
@@ -31,6 +31,7 @@
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
 #include "pub_core_debuglog.h"
+#include "pub_core_gdbserver.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"   // VG_(write)(), VG_(write_socket)()
 /* The destination sinks for normal and XML output.  These have their
    initial values here; they are set to final values by
    m_main.main_process_cmd_line_options().  See comment at the top of
-   that function for the associated logic. */
+   that function for the associated logic. 
+   After startup, the gdbserver monitor command might temporarily
+   set the fd of log_output_sink to -2 to indicate that output is
+   to be given to gdb rather than output to the startup fd */
 OutputSink VG_(log_output_sink) = {  2, False }; /* 2 = stderr */
 OutputSink VG_(xml_output_sink) = { -1, False }; /* disabled */
  
@@ -70,6 +74,8 @@ void send_bytes_to_logging_sink ( OutputSink* sink, Char* msg, Int nbytes )
          any more output. */
       if (sink->fd >= 0)
          VG_(write)( sink->fd, msg, nbytes );
+      else if (sink->fd == -2)
+         VG_(gdb_printf)("%s", msg);
    }
 }
 
@@ -107,7 +113,7 @@ static UInt vprintf_to_buf ( printf_buf_t* b,
                              const HChar *format, va_list vargs )
 {
    UInt ret = 0;
-   if (b->sink->fd >= 0) {
+   if (b->sink->fd >= 0 || b->sink->fd == -2) {
       ret = VG_(debugLog_vprintf) 
                ( add_to__printf_buf, b, format, vargs );
    }
index dbedac2edef72a8931a04827b5fb84d6e7bd25ff..96a233d74359968750f31cd003fe508d18278630 100644 (file)
@@ -418,6 +418,21 @@ Int VG_(setrlimit) (Int resource, const struct vki_rlimit *rlim)
    return sr_isError(res) ? -1 : sr_Res(res);
 }
 
+/* Support for prctl. */
+Int VG_(prctl) (Int option, 
+                ULong arg2, ULong arg3, ULong arg4, ULong arg5)
+{
+   SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
+#  if defined(VGO_linux)
+   /* res = prctl( option, arg2, arg3, arg4, arg5 ); */
+   res = VG_(do_syscall5)(__NR_prctl, (UWord) option,
+                          (UWord) arg2, (UWord) arg3, (UWord) arg4,
+                          (UWord) arg5);
+#  endif
+
+   return sr_isError(res) ? -1 : sr_Res(res);
+}
+
 /* ---------------------------------------------------------------------
    pids, etc
    ------------------------------------------------------------------ */
index 7f80f6549f2e318ebdd687deaf897fc0d7b428e1..b27b5adb274a04244d2299211b64b9b0cfab9086 100644 (file)
@@ -41,6 +41,7 @@
 #include "pub_core_debuglog.h"
 #include "pub_core_errormgr.h"
 #include "pub_core_execontext.h"
+#include "pub_core_gdbserver.h"
 #include "pub_core_initimg.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
@@ -129,6 +130,9 @@ static void usage_NORETURN ( Bool debug_help )
 "                              but check the argv[] entries for children, rather\n"
 "                              than the exe name, to make a follow/no-follow decision\n"
 "    --child-silent-after-fork=no|yes omit child output between fork & exec? [no]\n"
+"    --vgdb=no|yes|full        activate gdbserver? [yes]\n"
+"                              full is slower but provides precise watchpoint/step\n"
+"    --vgdb-error=<number>     invoke gdbserver after <number> errors [%d] \n"
 "    --track-fds=no|yes        track open file descriptors? [no]\n"
 "    --time-stamp=no|yes       add timestamps to log messages? [no]\n"
 "    --log-fd=<number>         log messages to file descriptor [2=stderr]\n"
@@ -173,6 +177,9 @@ static void usage_NORETURN ( Bool debug_help )
 "                              and use it to print better error messages in\n"
 "                              tools that make use of it (Memcheck, Helgrind,\n"
 "                              DRD) [no]\n"
+"    --vgdb-poll=<number>      gdbserver poll max every <number> basic blocks [%d] \n"
+"    --vgdb-shadow-registers=no|yes   let gdb see the shadow registers [no]\n"
+"    --vgdb-prefix=<prefix>    prefix for vgdb FIFOs [%s]\n"
 "    --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]\n"
 "    --sim-hints=hint1,hint2,...  known hints:\n"
 "                                 lax-ioctls, enable-outer [none]\n"
@@ -252,8 +259,10 @@ static void usage_NORETURN ( Bool debug_help )
    VG_(log_output_sink).fd = 1;
    VG_(log_output_sink).is_socket = False;
 
-   /* 'usage1' expects one char* argument and one SizeT argument. */
-   VG_(printf)(usage1, gdb_path, VG_MIN_MALLOC_SZB);
+   /* 'usage1' expects two int, two char* argument, and one SizeT argument. */
+   VG_(printf)(usage1, 
+               VG_(clo_vgdb_error), gdb_path, VG_MIN_MALLOC_SZB,
+               VG_(clo_vgdb_poll), VG_(clo_vgdb_prefix)); 
    if (VG_(details).name) {
       VG_(printf)("  user options for %s:\n", VG_(details).name);
       if (VG_(needs).command_line_options)
@@ -457,6 +466,14 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd,
 
       else if VG_BOOL_CLO(arg, "--stats",          VG_(clo_stats)) {}
       else if VG_BOOL_CLO(arg, "--xml",            VG_(clo_xml)) {}
+      else if VG_XACT_CLO(arg, "--vgdb=no",        VG_(clo_vgdb), Vg_VgdbNo) {}
+      else if VG_XACT_CLO(arg, "--vgdb=yes",       VG_(clo_vgdb), Vg_VgdbYes) {}
+      else if VG_XACT_CLO(arg, "--vgdb=full",      VG_(clo_vgdb), Vg_VgdbFull) {}
+      else if VG_INT_CLO (arg, "--vgdb-poll",      VG_(clo_vgdb_poll)) {}
+      else if VG_INT_CLO (arg, "--vgdb-error",     VG_(clo_vgdb_error)) {}
+      else if VG_STR_CLO (arg, "--vgdb-prefix",    VG_(clo_vgdb_prefix)) {}
+      else if VG_BOOL_CLO(arg, "--vgdb-shadow-registers",
+                            VG_(clo_vgdb_shadow_registers)) {}
       else if VG_BOOL_CLO(arg, "--db-attach",      VG_(clo_db_attach)) {}
       else if VG_BOOL_CLO(arg, "--demangle",       VG_(clo_demangle)) {}
       else if VG_BOOL_CLO(arg, "--error-limit",    VG_(clo_error_limit)) {}
@@ -671,6 +688,8 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd,
    if (VG_(clo_verbosity) < 0)
       VG_(clo_verbosity) = 0;
 
+   VG_(dyn_vgdb_error) = VG_(clo_vgdb_error);
+
    if (VG_(clo_gen_suppressions) > 0 && 
        !VG_(needs).core_errors && !VG_(needs).tool_errors) {
       VG_(fmsg_bad_option)("--gen-suppressions=yes",
@@ -2426,7 +2445,7 @@ void shutdown_actions_NORETURN( ThreadId tid,
 
    /* In XML mode, this merely prints the used suppressions. */
    if (VG_(needs).core_errors || VG_(needs).tool_errors)
-      VG_(show_all_errors)();
+      VG_(show_all_errors)(VG_(clo_verbosity), VG_(clo_xml));
 
    if (VG_(clo_xml)) {
       VG_(printf_xml)("\n");
@@ -2461,6 +2480,10 @@ void shutdown_actions_NORETURN( ThreadId tid,
    /* Flush any output cached by previous calls to VG_(message). */
    VG_(message_flush)();
 
+   /* terminate gdbserver if ever it was started. We terminate it here so that it get
+      the output above if output was redirected to gdb */
+   VG_(gdbserver) (0);
+
    /* Ok, finally exit in the os-specific way, according to the scheduler's
       return code.  In short, if the (last) thread exited by calling
       sys_exit, do likewise; if the (last) thread stopped due to a fatal
index 888e2c782d28a0968963bea6e0ac4989c0ca320a..59ec1feee09e44eafb20b307f24c764afdce46c6 100644 (file)
 VexControl VG_(clo_vex_control);
 Bool   VG_(clo_error_limit)    = True;
 Int    VG_(clo_error_exitcode) = 0;
+VgVgdb VG_(clo_vgdb)           = Vg_VgdbYes; 
+Int    VG_(clo_vgdb_poll)      = 5000; 
+Int    VG_(clo_vgdb_error)     = 999999999;
+Char*  VG_(clo_vgdb_prefix)    = VG_CLO_VGDB_PREFIX_DEFAULT;
+Bool   VG_(clo_vgdb_shadow_registers) = False;
 Bool   VG_(clo_db_attach)      = False;
 Char*  VG_(clo_db_command)     = GDB_PATH " -nw %f %p";
 Int    VG_(clo_gen_suppressions) = 0;
index 0a3d82f92937d4e7658540a9e84c5ba501afc860..6d06947238bbd45c9f83b03951d9134d00d21223 100644 (file)
@@ -67,6 +67,7 @@
 #include "pub_core_clreq.h"         // for VG_USERREQ__*
 #include "pub_core_dispatch.h"
 #include "pub_core_errormgr.h"      // For VG_(get_n_errs_found)()
+#include "pub_core_gdbserver.h"     // for VG_(gdbserver) and VG_(gdbserver_activity)
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcprint.h"
@@ -113,6 +114,13 @@ UInt VG_(dispatch_ctr);
 /* 64-bit counter for the number of basic blocks done. */
 static ULong bbs_done = 0;
 
+/* Counter to see if vgdb activity is to be verified.
+   When nr of bbs done reaches vgdb_next_poll, scheduler will
+   poll for gdbserver activity. VG_(force_vgdb_poll) and 
+   VG_(disable_vgdb_poll) allows the valgrind core (e.g. m_gdbserver)
+   to control when the next poll will be done. */
+static ULong vgdb_next_poll;
+
 /* Forwards */
 static void do_client_request ( ThreadId tid );
 static void scheduler_sanity ( ThreadId tid );
@@ -684,6 +692,20 @@ static void do_pre_run_checks ( ThreadState* tst )
 #  endif
 }
 
+// NO_VGDB_POLL value ensures vgdb is not polled, while
+// VGDB_POLL_ASAP ensures that the next scheduler call
+// will cause a poll.
+#define NO_VGDB_POLL    0xffffffffffffffffULL
+#define VGDB_POLL_ASAP  0x0ULL
+
+void VG_(disable_vgdb_poll) (void )
+{
+   vgdb_next_poll = NO_VGDB_POLL;
+}
+void VG_(force_vgdb_poll) ( void )
+{
+   vgdb_next_poll = VGDB_POLL_ASAP;
+}
 
 /* Run the thread tid for a while, and return a VG_TRC_* value
    indicating why VG_(run_innerloop) stopped. */
@@ -769,6 +791,16 @@ static UInt run_thread_for_a_while ( ThreadId tid )
    // Tell the tool this thread has stopped running client code
    VG_TRACK( stop_client_code, tid, bbs_done );
 
+   if (bbs_done >= vgdb_next_poll) {
+      if (VG_(clo_vgdb_poll))
+         vgdb_next_poll = bbs_done + (ULong)VG_(clo_vgdb_poll);
+      else
+         /* value was changed due to gdbserver invocation via ptrace */
+         vgdb_next_poll = NO_VGDB_POLL;
+      if (VG_(gdbserver_activity) (tid))
+         VG_(gdbserver) (tid);
+   }
+
    return trc;
 }
 
@@ -854,6 +886,11 @@ static UInt run_noredir_translation ( Addr hcode, ThreadId tid )
    return retval;
 }
 
+ULong VG_(bbs_done) (void)
+{
+   return bbs_done;
+}
+
 
 /* ---------------------------------------------------------------------
    The scheduler proper.
@@ -959,10 +996,69 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
 {
    UInt     trc;
    ThreadState *tst = VG_(get_ThreadState)(tid);
+   static Bool vgdb_startup_action_done = False;
 
    if (VG_(clo_trace_sched))
       print_sched_event(tid, "entering VG_(scheduler)");      
 
+   /* Do vgdb initialization (but once). Only the first (main) task
+      starting up will do the below.
+      Initialize gdbserver earlier than at the first 
+      thread VG_(scheduler) is causing problems:
+      * at the end of VG_(scheduler_init_phase2) :
+        The main thread is in VgTs_Init state, but in a not yet
+        consistent state => the thread cannot be reported to gdb
+        (e.g. causes an assert in LibVEX_GuestX86_get_eflags when giving
+        back the guest registers to gdb).
+      * at end of valgrind_main, just
+        before VG_(main_thread_wrapper_NORETURN)(1) :
+        The main thread is still in VgTs_Init state but in a
+        more advanced state. However, the thread state is not yet
+        completely initialized : a.o., the os_state is not yet fully
+        set => the thread is then not properly reported to gdb,
+        which is then confused (causing e.g. a duplicate thread be
+        shown, without thread id).
+      * it would be possible to initialize gdbserver "lower" in the
+        call stack (e.g. in VG_(main_thread_wrapper_NORETURN)) but
+        these are platform dependent and the place at which
+        the thread state is completely initialized is not
+        specific anymore to the main thread (so a similar "do it only
+        once" would be needed).
+
+        => a "once only" initialization here is the best compromise. */
+   if (!vgdb_startup_action_done) {
+      vg_assert(tid == 1); // it must be the main thread.
+      vgdb_startup_action_done = True;
+      if (VG_(clo_vgdb) != Vg_VgdbNo) {
+         /* If we have to poll, ensures we do an initial poll at first
+            scheduler call. Otherwise, ensure no poll (unless interrupted
+            by ptrace). */
+         if (VG_(clo_vgdb_poll))
+            VG_(force_vgdb_poll) ();
+         else
+            VG_(disable_vgdb_poll) ();
+
+         vg_assert (VG_(dyn_vgdb_error) == VG_(clo_vgdb_error));
+         /* As we are initializing, VG_(dyn_vgdb_error) can't have been
+            changed yet. */
+
+         if (VG_(dyn_vgdb_error) == 0) {
+            /* The below call allows gdb to attach at startup
+               before the first guest instruction is executed. */
+            VG_(umsg)("(action at startup) vgdb me ... \n");
+            VG_(gdbserver)(1); 
+         } else {
+            /* User has activated gdbserver => initialize now the FIFOs
+               to let vgdb/gdb contact us either via the scheduler poll
+               mechanism or via vgdb ptrace-ing valgrind. */
+            if (VG_(gdbserver_activity) (1))
+               VG_(gdbserver) (1);
+         }
+      } else {
+         VG_(disable_vgdb_poll) ();
+      }
+   }
+
    /* set the proper running signal mask */
    block_signals();
    
index 105c02a3fd56b6a9cff04ef44a218a7ee1bff51a..8f4bbda42e27774f81194850753c2f238c316792 100644 (file)
    VG_(sigtimedwait_zero).  This is trivial on Linux, since it's just a
    syscall.  But on Darwin and AIX, we have to cobble together the
    functionality in a tedious, longwinded and probably error-prone way.
+
+   Finally, if a gdb is debugging the process under valgrind,
+   the signal can be ignored if gdb tells this. So, before resuming the
+   scheduler/delivering the signal, a call to VG_(gdbserver_report_signal)
+   is done. If this returns True, the signal is delivered.
  */
 
 #include "pub_core_basics.h"
 #include "pub_core_aspacemgr.h"
 #include "pub_core_debugger.h"      // For VG_(start_debugger)
 #include "pub_core_errormgr.h"
+#include "pub_core_gdbserver.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcprint.h"
@@ -656,11 +662,14 @@ typedef
 
 static SKSS skss;
 
-static Bool is_sig_ign(Int sigNo)
+/* returns True if signal is to be ignored. 
+   To check this, possibly call gdbserver with tid. */
+static Bool is_sig_ign(Int sigNo, ThreadId tid)
 {
    vg_assert(sigNo >= 1 && sigNo <= _VKI_NSIG);
 
-   return scss.scss_per_sig[sigNo].scss_handler == VKI_SIG_IGN;
+   return scss.scss_per_sig[sigNo].scss_handler == VKI_SIG_IGN
+      || !VG_(gdbserver_report_signal) (sigNo, tid);
 }
 
 /* ---------------------------------------------------------------------
@@ -1795,6 +1804,9 @@ static void synth_fault_common(ThreadId tid, Addr addr, Int si_code)
    info.si_code = si_code;
    info.VKI_SIGINFO_si_addr = (void*)addr;
 
+   /* even if gdbserver indicates to ignore the signal, we will deliver it */
+   VG_(gdbserver_report_signal) (VKI_SIGSEGV, tid);
+
    /* If they're trying to block the signal, force it to be delivered */
    if (VG_(sigismember)(&VG_(threads)[tid].sig_mask, VKI_SIGSEGV))
       VG_(set_default_handler)(VKI_SIGSEGV);
@@ -1833,8 +1845,12 @@ void VG_(synth_sigill)(ThreadId tid, Addr addr)
    info.si_code  = VKI_ILL_ILLOPC; /* jrs: no idea what this should be */
    info.VKI_SIGINFO_si_addr = (void*)addr;
 
-   resume_scheduler(tid);
-   deliver_signal(tid, &info, NULL);
+   if (VG_(gdbserver_report_signal) (VKI_SIGILL, tid)) {
+      resume_scheduler(tid);
+      deliver_signal(tid, &info, NULL);
+   }
+   else
+      resume_scheduler(tid);
 }
 
 // Synthesise a SIGBUS.
@@ -1854,8 +1870,12 @@ void VG_(synth_sigbus)(ThreadId tid)
       in .si_addr.  Oh well. */
    /* info.VKI_SIGINFO_si_addr = (void*)addr; */
 
-   resume_scheduler(tid);
-   deliver_signal(tid, &info, NULL);
+   if (VG_(gdbserver_report_signal) (VKI_SIGBUS, tid)) {
+      resume_scheduler(tid);
+      deliver_signal(tid, &info, NULL);
+   }
+   else
+      resume_scheduler(tid);
 }
 
 // Synthesise a SIGTRAP.
@@ -1890,8 +1910,12 @@ void VG_(synth_sigtrap)(ThreadId tid)
 #  endif
 
    /* fixs390: do we need to do anything here for s390 ? */
-   resume_scheduler(tid);
-   deliver_signal(tid, &info, &uc);
+   if (VG_(gdbserver_report_signal) (VKI_SIGTRAP, tid)) {
+      resume_scheduler(tid);
+      deliver_signal(tid, &info, &uc);
+   }
+   else
+      resume_scheduler(tid);
 }
 
 /* Make a signal pending for a thread, for later delivery.
@@ -2070,7 +2094,7 @@ void async_signalhandler ( Int sigNo,
 
    /* (2) */
    /* Set up the thread's state to deliver a signal */
-   if (!is_sig_ign(info->si_signo))
+   if (!is_sig_ign(info->si_signo, tid))
       deliver_signal(tid, info, uc);
 
    /* It's crucial that (1) and (2) happen in the order (1) then (2)
@@ -2342,10 +2366,15 @@ void sync_signalhandler_from_kernel ( ThreadId tid,
       }
 
       if (VG_(in_generated_code)) {
-         /* Can't continue; must longjmp back to the scheduler and thus
-            enter the sighandler immediately. */
-         deliver_signal(tid, info, uc);
-         resume_scheduler(tid);
+         if (VG_(gdbserver_report_signal) (sigNo, tid)
+             || VG_(sigismember)(&tst->sig_mask, sigNo)) {
+            /* Can't continue; must longjmp back to the scheduler and thus
+               enter the sighandler immediately. */
+            deliver_signal(tid, info, uc);
+            resume_scheduler(tid);
+         }
+         else
+            resume_scheduler(tid);
       }
 
       /* If resume_scheduler returns or its our fault, it means we
@@ -2545,7 +2574,7 @@ void VG_(poll_signals)(ThreadId tid)
       /* OK, something to do; deliver it */
       if (VG_(clo_trace_signals))
          VG_(dmsg)("Polling found signal %d for tid %d\n", sip->si_signo, tid);
-      if (!is_sig_ign(sip->si_signo))
+      if (!is_sig_ign(sip->si_signo, tid))
         deliver_signal(tid, sip, NULL);
       else if (VG_(clo_trace_signals))
          VG_(dmsg)("   signal %d ignored\n", sip->si_signo);
index 5fa2dd1bc72450afe5895a2c993d988deafd16ca..17d1b69958f20b0f2c6a49a21bbf7cf031dd36ab 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "pub_core_execontext.h"  // VG_(make_depth_1_ExeContext_from_Addr)
 
+#include "pub_core_gdbserver.h"   // VG_(tool_instrument_then_gdbserver_if_needed)
 
 /*------------------------------------------------------------*/
 /*--- Stats                                                ---*/
@@ -210,6 +211,30 @@ static IRExpr* mk_ecu_Expr ( Addr64 guest_IP )
    return mkIRExpr_HWord( (HWord)ecu );
 }
 
+/* When gdbserver is activated, the translation of a block must
+   first be done by the tool function, then followed by a pass
+   which (if needed) instruments the code for gdbserver.
+*/
+static
+IRSB* tool_instrument_then_gdbserver_if_needed ( VgCallbackClosure* closureV,
+                                                 IRSB*              sb_in, 
+                                                 VexGuestLayout*    layout, 
+                                                 VexGuestExtents*   vge,
+                                                 IRType             gWordTy, 
+                                                 IRType             hWordTy )
+{
+   return VG_(instrument_for_gdbserver_if_needed)
+      (VG_(tdict).tool_instrument (closureV,
+                                   sb_in,
+                                   layout,
+                                   vge,
+                                   gWordTy,
+                                   hWordTy),
+       layout,
+       vge,
+       gWordTy,
+       hWordTy);                                   
+}
 
 /* For tools that want to know about SP changes, this pass adds
    in the appropriate hooks.  We have to do it after the tool's
@@ -1350,11 +1375,19 @@ Bool VG_(translate) ( ThreadId tid,
       if (seg != NULL) {
          /* There's some kind of segment at the requested place, but we
             aren't allowed to execute code here. */
-         VG_(synth_fault_perms)(tid, addr);
+         if (debugging_translation)
+            VG_(printf)("translations not allowed here (segment not executable)"
+                        "(0x%llx)\n", addr);
+         else
+            VG_(synth_fault_perms)(tid, addr);
       } else {
         /* There is no segment at all; we are attempting to execute in
            the middle of nowhere. */
-         VG_(synth_fault_mapping)(tid, addr);
+         if (debugging_translation)
+            VG_(printf)("translations not allowed here (no segment)"
+                        "(0x%llx)\n", addr);
+         else
+            VG_(synth_fault_mapping)(tid, addr);
       }
       return False;
    }
@@ -1460,7 +1493,9 @@ Bool VG_(translate) ( ThreadId tid,
      IRSB*(*f)(VgCallbackClosure*,
                IRSB*,VexGuestLayout*,VexGuestExtents*,
                IRType,IRType)
-       = VG_(tdict).tool_instrument;
+        = VG_(clo_vgdb) != Vg_VgdbNo
+             ? tool_instrument_then_gdbserver_if_needed
+             : VG_(tdict).tool_instrument;
      IRSB*(*g)(void*,
                IRSB*,VexGuestLayout*,VexGuestExtents*,
                IRType,IRType)
index 484303e8fdc2750507bfdd500b56d7af84ff7b54..c93b64a2ad89d4ed5c366daef35841a7cff1aad1 100644 (file)
@@ -283,12 +283,18 @@ extern SysRes VG_(am_mmap_anon_float_valgrind)( SizeT cszB );
 extern SysRes VG_(am_sbrk_anon_float_valgrind)( SizeT cszB );
 
 
-/* Map a file at an unconstrained address for V, and update the
+/* Map privately a file at an unconstrained address for V, and update the
    segment array accordingly.  This is used by V for transiently
    mapping in object files to read their debug info.  */
 extern SysRes VG_(am_mmap_file_float_valgrind)
    ( SizeT length, UInt prot, Int fd, Off64T offset );
 
+/* Map shared a file at an unconstrained address for V, and update the
+   segment array accordingly.  This is used by V for communicating
+   with vgdb.  */
+extern SysRes VG_(am_shared_mmap_file_float_valgrind)
+   ( SizeT length, UInt prot, Int fd, Off64T offset );
+
 /* Unmap the given address range and update the segment array
    accordingly.  This fails if the range isn't valid for the client.
    If *need_discard is True after a successful return, the caller
index 2b72b038f15fa8d5ac3cd43ead45f9b67b2593bf..c3462e0390e18be1d36b987d4eb8d9e4dd752cb0 100644 (file)
@@ -51,7 +51,14 @@ typedef
 
 extern void VG_(load_suppressions)        ( void );
 
-extern void VG_(show_all_errors)          ( void );
+// if verbosity == 0,           print nothing.
+// else if xml                  print suppressions used (in xml format)
+// else if verbosity == 1       print Error summary
+// else                         print all errors and suppressions used.
+extern void VG_(show_all_errors)          ( Int verbosity, Bool xml );
+
+/* Print (in readable format) the last error that occured. */
+extern void VG_(show_last_error)          ( void );
 
 extern void VG_(show_error_counts_as_XML) ( void );
 
diff --git a/coregrind/pub_core_gdbserver.h b/coregrind/pub_core_gdbserver.h
new file mode 100644 (file)
index 0000000..27ed10e
--- /dev/null
@@ -0,0 +1,186 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Handle remote gdb protocol.             pub_core_gdbserver.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011 Philippe Waroquiers
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_GDBSERVER_H
+#define __PUB_CORE_GDBSERVER_H
+
+#include "pub_tool_gdbserver.h"
+
+// True if there is some activity from vgdb
+// If it returns True, then extern void VG_(gdbserver) can be called
+// to handle this incoming vgdb request.                                
+extern Bool VG_(gdbserver_activity) (ThreadId tid);
+
+
+/* Called by low level to insert or remove a break or watch point.
+   Break or watch point implementation is done using help from the tool.
+   break point support implies some (small) specific instrumentation
+   taken in charge for all tools by m_translate.c.
+   
+   Write/read/access watchpoint can only be provided by tools which are
+   tracking addressability and/or accessibility of memory 
+   (so typically memcheck can provide it). Note that memcheck addressability
+   bits do not differentiate between read and write accessibility.
+   However, when accessing unaddressable byte, memcheck can differentiate
+   reads from write, thereby providing read/write or access watchpoints.
+
+   Note that gdbserver assumes that software breakpoint is supported
+   (as this will be done by re-instrumenting the code).
+   Note that len is ignored for sofware breakpoints. hardware_breakpoint
+   are not supported.
+
+   Returns True if the point has properly been inserted or removed
+   Returns False otherwise. */
+Bool VG_(gdbserver_point) (PointKind kind, Bool insert, 
+                           Addr addr, int len);
+
+/* Entry point invoked by vgdb when it uses ptrace to cause a gdbserver
+   invocation. A magic value is passed by vgdb in check as a verification
+   that the call has been properly pushed by vgdb. */
+extern void VG_(invoke_gdbserver) ( int check );
+
+// To be called before delivering a signal.
+// Returns True if gdb user asks to pass the signal to the client.
+// Note that if the below returns True, the signal might
+// still be ignored if this is the action desired by the
+// guest program.
+extern Bool VG_(gdbserver_report_signal) (Int signo, ThreadId tid);
+
+/* software_breakpoint, single step and jump support ------------------------*/
+/* VG_(instrument_for_gdbserver_if_needed) allows to do "standard and easy"
+   instrumentation for gdbserver.
+   VG_(instrument_for_gdbserver_if_needed) does the following:
+      * checks if gdbserver instrumentation is needed for vge.
+      * if no gdbserver instrumentation needed,
+           returns sb_in
+      * otherwise 
+        It will instrument sb_in to allow gdbserver to properly
+        handle breakpoints and single_stepping in sb_in.
+        All the target jumps of sb_in will also be invalidated
+        if these are not yet instrumented for gdbserver.
+        This allows to have single_step working, using a lazily
+        translation of the blocks which are being single stepped
+        in. 
+
+   The typical usage of this function is to call it on the block
+   instrumented by the tool instrument function i.e. :
+     return VG_(instrument_for_gdbserver_if_needed) (sb_out, 
+                                                     layout, 
+                                                     vge, 
+                                                     gWordTy, 
+                                                     hWordTy);
+   where sb_out is the block instrumented by the tool.
+
+   If the block contains a call to a dirty helper that indirectly
+   calls gdbserver, then this dirty helper can (indirectly) change
+   the IP. This implies to jump to this IP after the call to
+   gdbserver. */
+extern IRSB* VG_(instrument_for_gdbserver_if_needed)
+     (IRSB* sb_in,                   /* block to be instrumented */
+      VexGuestLayout* layout,
+      VexGuestExtents* vge,
+      IRType gWordTy, IRType hWordTy);
+
+/* reason for which gdbserver connection must be finished */
+typedef
+   enum {
+      orderly_finish,
+      reset_after_error,
+      reset_after_fork} FinishReason;
+
+/* output various gdbserver statistics and status. */
+extern void VG_(gdbserver_status_output)(void);
+
+/* Shared structure between vgdb and the process running 
+   under valgrind.
+   We define two variants: a 32 bit and a 64 bit.
+   The valgrind process will use the appropriate size,
+   according to the architecture.
+   vgdb will use what the valgrind process is using. */
+/* The below takes care that sizes will be 32 or 64 bits,
+   whatever the architecture. A.o., vgdb.c cannot use directly
+   the types from pub_core_threadstate.h as we want vgdb.c to
+   be independent of the arch it is debugging in case of bi-arch
+   Valgrind (e.g. x86 and amd64). So, the valgrind process must
+   give all the needed info/offset to vgdb in the below structure. */
+
+typedef 
+   struct {
+      // PID of the vgdb that last connected to the Valgrind gdbserver.
+      // It will be set by vgdb after connecting.
+      int vgdb_pid;
+
+      // nr of bytes vgdb has written to valgrind
+      volatile int written_by_vgdb;
+      // nr of bytes seen by valgrind
+      volatile int seen_by_valgrind;
+      
+      // address at which gdbserver can be invoked
+      Addr32 invoke_gdbserver;
+
+      // address of VG_(threads) and various sizes
+      // and offset needed by vgdb.
+      Addr32 threads;
+      int sizeof_ThreadState;
+      int offset_status;
+      int offset_lwpid;
+   } VgdbShared32;
+
+/* Same as VgdbShared32 but for 64 bits arch. */
+typedef 
+   struct {
+      int vgdb_pid;
+
+      volatile int written_by_vgdb;
+      volatile int seen_by_valgrind;
+      
+      Addr64 invoke_gdbserver;
+
+      Addr64 threads;
+      int sizeof_ThreadState;
+      int offset_status;
+      int offset_lwpid;
+   } VgdbShared64;
+
+// The below typedef makes the life of valgrind easier.
+// vgdb must however work explicitely with the specific 32 or 64 bits version.
+
+#if VEX_HOST_WORDSIZE == 8
+typedef VgdbShared64 VgdbShared;
+#elif VEX_HOST_WORDSIZE == 4
+typedef VgdbShared32 VgdbShared;
+#else
+# error "unexpected wordsize"
+#endif
+
+
+#endif   // __PUB_CORE_GDBSERVER_H
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
index ecfbd9bd31e03e824925f58f2e8050956d9489ab..bb7cb6c4d44e0645cd6735adccb8cb55182982a3 100644 (file)
@@ -54,6 +54,27 @@ extern Bool  VG_(clo_error_limit);
    default: 0 (no, return the application's exit code in the normal
    way. */
 extern Int   VG_(clo_error_exitcode);
+
+typedef 
+   enum { 
+      Vg_VgdbNo,   // Do not activate gdbserver.
+      Vg_VgdbYes,  // Activate gdbserver (default).
+      Vg_VgdbFull, // ACtivate gdbserver in full mode, allowing
+                   // a precise handling of watchpoints and single stepping
+                   // at any moment.
+   } 
+   VgVgdb;
+/* if != Vg_VgdbNo, allows valgrind to serve vgdb/gdb. */
+extern VgVgdb VG_(clo_vgdb);
+/* if > 0, checks every VG_(clo_vgdb_poll) BBS if vgdb wants to be served. */
+extern Int VG_(clo_vgdb_poll);
+/* prefix for the named pipes (FIFOs) used by vgdb/gdb to communicate with valgrind */
+extern Char* VG_(clo_vgdb_prefix);
+/* if True, gdbserver in valgrind will expose a target description containing
+   shadow registers */
+extern Bool  VG_(clo_vgdb_shadow_registers);
+#define VG_CLO_VGDB_PREFIX_DEFAULT "/tmp/vgdb-pipe"
+
 /* Enquire about whether to attach to a debugger at errors?   default: NO */
 extern Bool  VG_(clo_db_attach);
 /* The debugger command?  default: whatever gdb ./configure found */
index 73773d7950e08c3a527cbf8631309ab33b030c47..0458aaa67be7a70c173e73ea27538033c5ada679 100644 (file)
@@ -95,6 +95,14 @@ extern void VG_(scheduler_init_phase2) ( ThreadId main_tid,
                                          Addr     clstack_end, 
                                          SizeT    clstack_size );
 
+// Allows to disable the polling done to detect vgdb input
+// or to force a poll at next scheduler call.
+extern void VG_(disable_vgdb_poll) (void );
+extern void VG_(force_vgdb_poll) ( void );
+
+/* nr of bbs done since startup. */
+extern ULong VG_(bbs_done) (void);
+
 /* Stats ... */
 extern void VG_(print_scheduler_stats) ( void );
 
diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c
new file mode 100644 (file)
index 0000000..fffc7cc
--- /dev/null
@@ -0,0 +1,2141 @@
+/*--------------------------------------------------------------------*/
+/*--- Relay between gdb and gdbserver embedded in valgrind  vgdb.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011 Philippe Waroquiers
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_libcsetjmp.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_gdbserver.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include "assert.h"
+#include <sys/user.h>
+
+#  if defined(VGO_linux)
+#include <sys/prctl.h>
+#  endif
+
+/* vgdb has two usages:
+   1. relay application between gdb and the gdbserver embedded in valgrind.
+   2. standalone to send monitor commands to a running valgrind-ified process
+
+   It is made of a main program which reads arguments.  If no
+   arguments are given or only --pid and --vgdb-prefix, then usage 1 is
+   assumed.
+   
+   As relay application, vgdb reads bytes from gdb on stdin and
+   writes these bytes to valgrind.  Bytes read from valgrind are
+   written to gdb on stdout.  Read/Write from/to valgrind is done
+   using FIFOs.  There is one thread reading from stdin, writing to
+   valgrind on a FIFO.  There is one thread reading from valgrind on a
+   FIFO, writing to gdb on stdout
+
+   As a standalone utility, vgdb builds command packets to write to valgrind,
+   sends it and reads the reply. The same two threads are used to write/read.
+   Once all the commands are sent and their replies received, vgdb will exit.
+   
+*/
+
+/* define PTRACEINVOKER to compile the ptrace related code
+   which ensures a valgrind process blocked in a system call
+   can be "waken up". PTRACEINVOKER implies some architecture
+   specific code and/or some OS specific code. */
+#if defined(VGA_arm) || defined(VGA_x86) || defined(VGA_amd64) \
+    || defined(VGA_ppc32) || defined(VGA_ppc64) || defined(VGA_s390x)
+#define PTRACEINVOKER
+#else
+I_die_here : (PTRACEINVOKER) architecture missing in vgdb.c
+#endif
+
+/* Some darwin specific stuff is needed as ptrace is not
+   fully supported on MacOS. Till we find someone courageous
+   having access to Darwin, there is no PTRACEINVOKER. */
+#if defined(VGO_darwin)
+#undef PTRACEINVOKER
+#endif
+
+static int debuglevel;
+static struct timeval dbgtv;
+/* if level <= debuglevel, print timestamp, then print provided by debug info */
+#define DEBUG(level, ...) (level <= debuglevel ?                        \
+                           gettimeofday(&dbgtv, NULL),                  \
+                           fprintf(stderr, "%ld.%6.6ld ",               \
+                                   (long int)dbgtv.tv_sec,              \
+                                   (long int)dbgtv.tv_usec),            \
+                           fprintf(stderr, __VA_ARGS__),fflush(stderr)  \
+                           : 0)
+
+/* same as DEBUG but does not print time stamp info */
+#define PDEBUG(level, ...) (level <= debuglevel ?                       \
+                            fprintf(stderr, __VA_ARGS__),fflush(stderr) \
+                            : 0)
+
+/* if errno != 0, 
+   report the errno and fprintf the ... varargs on stderr. */
+#define ERROR(errno, ...) ((errno == 0 ? 0 : perror("syscall failed")), \
+                           fprintf(stderr, __VA_ARGS__),                \
+                           fflush(stderr))
+/* same as ERROR, but also exits with status 1 */
+#define XERROR(errno, ...) ((errno == 0 ? 0 : perror("syscall failed")), \
+                            fprintf(stderr, __VA_ARGS__),                \
+                            fflush(stderr),                              \
+                            exit(1))
+
+static char *vgdb_prefix = "/tmp/vgdb-pipe";
+
+/* Will be set to True when any condition indicating we have to shutdown
+   is encountered. */
+static Bool shutting_down = False;
+
+static VgdbShared32 *shared32;
+static VgdbShared64 *shared64;
+#define VS_written_by_vgdb (shared32 != NULL ?        \
+                            shared32->written_by_vgdb \
+                            : shared64->written_by_vgdb)
+#define VS_seen_by_valgrind (shared32 != NULL ?         \
+                             shared32->seen_by_valgrind \
+                             : shared64->seen_by_valgrind)
+
+#define VS_vgdb_pid (shared32 != NULL ? shared32->vgdb_pid : shared64->vgdb_pid)
+
+/* Calls malloc (size). Exits if memory can't be allocated. */
+static
+void *vmalloc(size_t size)
+{
+   void * mem = malloc(size);
+   if (mem == NULL)
+      XERROR (errno, "can't allocate memory\n");
+   return mem;
+}
+
+/* Calls realloc (size). Exits if memory can't be allocated. */
+static
+void *vrealloc(void *ptr,size_t size)
+{
+   void * mem = realloc(ptr, size);
+   if (mem == NULL)
+      XERROR (errno, "can't reallocate memory\n");
+   return mem;
+}
+
+/* add nrw to the written_by_vgdb field of shared32 or shared64 */ 
+static
+void add_written(int nrw)
+{
+   if (shared32 != NULL) 
+      shared32->written_by_vgdb += nrw;
+   else if (shared64 != NULL) 
+      shared64->written_by_vgdb += nrw;
+   else
+      assert(0);
+}
+
+static int shared_mem_fd = -1;
+static
+void map_vgdbshared (char* shared_mem)
+{
+   struct stat fdstat;
+   void **s;
+   shared_mem_fd = open(shared_mem, O_RDWR);
+   /* shared_mem_fd will not be closed till vgdb exits. */
+
+   if (shared_mem_fd == -1)
+      XERROR (errno, "error opening %s shared memory file\n", shared_mem);
+
+   if (fstat(shared_mem_fd, &fdstat) != 0)
+      XERROR (errno, "fstat");
+
+   if (fdstat.st_size == sizeof(VgdbShared64))
+      s = (void*) &shared64;
+   else if (fdstat.st_size == sizeof(VgdbShared32))
+      s = (void*) &shared32;
+   else
+#if VEX_HOST_WORDSIZE == 8
+      XERROR (0,
+              "error size shared memory file %s.\n"
+              "expecting size %d (64bits) or %d (32bits) got %ld.\n",
+              shared_mem,
+              (int) sizeof(VgdbShared64), (int) sizeof(VgdbShared32), 
+              (long int)fdstat.st_size);
+#elif VEX_HOST_WORDSIZE == 4
+      XERROR (0,
+              "error size shared memory file %s.\n"
+              "expecting size %d (32bits) got %ld.\n",
+              shared_mem,
+              (int) sizeof(VgdbShared32), 
+              fdstat.st_size);
+#else
+# error "unexpected wordsize"
+#endif
+
+#if VEX_HOST_WORDSIZE == 4
+   if (shared64 != NULL)
+      XERROR (0, "cannot use 32 bits vgdb with a 64bits valgrind process\n");
+   /* But we can use a 64 bits vgdb with a 32 bits valgrind */
+#endif
+
+   *s = (void*) mmap (NULL, fdstat.st_size, 
+                      PROT_READ|PROT_WRITE, MAP_SHARED, 
+                      shared_mem_fd, 0);
+
+   if (*s == (void *) -1)
+      XERROR (errno, "error mmap shared memory file %s\n", shared_mem);
+
+}
+
+#if VEX_HOST_WORDSIZE == 8
+typedef Addr64 CORE_ADDR;
+typedef Addr64 PTRACE_XFER_TYPE;
+typedef void* PTRACE_ARG3_TYPE;
+#elif VEX_HOST_WORDSIZE == 4
+typedef Addr32 CORE_ADDR;
+typedef Addr32 PTRACE_XFER_TYPE;
+typedef void* PTRACE_ARG3_TYPE;
+#else
+# error "unexpected wordsize"
+#endif
+
+static Bool pid_of_save_regs_continued = False;
+// True if we have continued pid_of_save_regs after PTRACE_ATTACH
+
+static Bool dying = False;
+// Set to True when loss of connection indicating that the Valgrind
+// process is dying.
+
+/* To be called when connection with valgrind is lost.  In case we
+have lost the connection, it means that Valgrind has closed the
+connection and is busy exiting. We can't and don't have to stop it in
+this case. */
+static
+void valgrind_dying(void)
+{
+   pid_of_save_regs_continued = False;
+   dying = True;
+}
+
+
+#ifdef PTRACEINVOKER
+/* ptrace_(read|write)_memory are modified extracts of linux-low.c
+   from gdb 6.6. Copyrighted FSF */
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+   to debugger memory starting at MYADDR.  */
+
+static
+int ptrace_read_memory (pid_t inferior_pid, CORE_ADDR memaddr,
+                        unsigned char *myaddr, int len)
+{
+   register int i;
+   /* Round starting address down to longword boundary.  */
+   register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
+   /* Round ending address up; get number of longwords that makes.  */
+   register int count
+      = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+      / sizeof (PTRACE_XFER_TYPE);
+   /* Allocate buffer of that many longwords.  */
+   register PTRACE_XFER_TYPE *buffer
+      = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+   
+   /* Read all the longwords */
+   for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) {
+      errno = 0;
+      buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, 
+                          (PTRACE_ARG3_TYPE) addr, 0);
+      if (errno)
+         return errno;
+   }
+   
+   /* Copy appropriate bytes out of the buffer.  */
+   memcpy (myaddr, 
+           (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
+   
+   return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.
+   On failure (cannot write the inferior)
+   returns the value of errno.  */
+
+static
+int ptrace_write_memory (pid_t inferior_pid, CORE_ADDR memaddr, 
+                         const unsigned char *myaddr, int len)
+{
+   register int i;
+   /* Round starting address down to longword boundary.  */
+   register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
+   /* Round ending address up; get number of longwords that makes.  */
+   register int count
+      = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) 
+      / sizeof (PTRACE_XFER_TYPE);
+   /* Allocate buffer of that many longwords.  */
+   register PTRACE_XFER_TYPE *buffer 
+      = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+   
+   if (debuglevel >= 1) {
+      DEBUG (1, "Writing ");
+      for (i = 0; i < len; i++)
+         PDEBUG (1, "%02x", (unsigned)myaddr[i]);
+      PDEBUG(1, " to %p\n", (void *) memaddr);
+   }
+   
+   /* Fill start and end extra bytes of buffer with existing memory data.  */
+   
+   buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+                       (PTRACE_ARG3_TYPE) addr, 0);
+   
+   if (count > 1) {
+      buffer[count - 1]
+         = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+                   (PTRACE_ARG3_TYPE) (addr + (count - 1)
+                                       * sizeof (PTRACE_XFER_TYPE)),
+                   0);
+   }
+   
+   /* 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, inferior_pid, 
+              (PTRACE_ARG3_TYPE) addr, buffer[i]);
+      if (errno)
+         return errno;
+   }
+   
+   return 0;
+}
+
+/* subset of VG_(threads) needed for vgdb ptrace.
+   This is initialized when process is attached. */
+typedef struct {
+   ThreadStatus status;
+   Int lwpid;
+}
+VgdbThreadState;
+static VgdbThreadState vgdb_threads[VG_N_THREADS];
+
+static const
+HChar* name_of_ThreadStatus ( ThreadStatus status )
+{
+   switch (status) {
+   case VgTs_Empty:     return "VgTs_Empty";
+   case VgTs_Init:      return "VgTs_Init";
+   case VgTs_Runnable:  return "VgTs_Runnable";
+   case VgTs_WaitSys:   return "VgTs_WaitSys";
+   case VgTs_Yielding:  return "VgTs_Yielding";
+   case VgTs_Zombie:    return "VgTs_Zombie";
+   default:             return "VgTs_???";
+  }
+}
+
+static 
+char *status_image (int status)
+{
+   static char result[256];
+   int sz = 0;
+#define APPEND(...) sz += snprintf (result+sz, 256 - sz - 1, __VA_ARGS__)
+  
+   result[0] = 0;
+
+   if (WIFEXITED(status))
+      APPEND ("WIFEXITED %d ", WEXITSTATUS(status));
+   
+   if (WIFSIGNALED(status)) {
+      APPEND ("WIFSIGNALED %d ", WTERMSIG(status));
+      if (WCOREDUMP(status)) APPEND ("WCOREDUMP ");
+   }
+
+   if (WIFSTOPPED(status))
+      APPEND ("WIFSTOPPED %d ", WSTOPSIG(status));
+
+   if (WIFCONTINUED(status))
+      APPEND ("WIFCONTINUED ");
+
+   return result;
+#undef APPEND
+}
+
+/* Wait till the process pid is reported as stopped with signal_expected.
+   If other signal(s) than signal_expected are received, waitstopped
+   will pass them to pid, waiting for signal_expected to stop pid.
+   Returns True when process is in stopped state with signal_expected.
+   Returns False if a problem was encountered while waiting for pid
+   to be stopped.
+
+   If pid is reported as being dead/exited, waitstopped will return False.
+*/
+static
+Bool waitstopped (int pid, int signal_expected, char *msg)
+{
+   pid_t p;
+   int status = 0;
+   int signal_received;
+   int res;
+
+   while (1) {
+      DEBUG(1, "waitstopped %s before waitpid signal_expected %d\n",
+            msg, signal_expected);
+      p = waitpid(pid, &status, __WALL);
+      DEBUG(1, "after waitpid pid %d p %d status 0x%x %s\n", pid, p, 
+            status, status_image (status));
+      if (p != pid) {
+         ERROR(errno, "%s waitpid pid %d in waitstopped %d status 0x%x %s\n", 
+               msg, pid, p, status, status_image (status));
+         return False;
+      }
+
+      if (WIFEXITED(status)) {
+         shutting_down = True;
+         return False;
+      }
+
+      assert (WIFSTOPPED(status));
+      signal_received = WSTOPSIG(status);
+      if (signal_received == signal_expected)
+         break;
+
+      /* pid received a signal which is not the signal we are waiting for.
+         We continue pid, transmitting this signal. */
+      DEBUG(1, "waitstopped PTRACE_CONT with signal %d\n", signal_received);
+      res = ptrace (PTRACE_CONT, pid, NULL, signal_received);
+      if (res != 0) {
+         ERROR(errno, "waitstopped PTRACE_CONT\n");
+         return False;
+      }
+   }
+
+   return True;
+}
+
+/* Stops the given pid, wait for the process to be stopped.
+   Returns True if succesful, False otherwise.
+   msg is used in tracing and error reporting. */
+static
+Bool stop (int pid, char *msg)
+{
+   long res;
+
+   DEBUG(1, "%s SIGSTOP pid %d\n", msg, pid);
+   res = kill (pid, SIGSTOP);
+   if (res != 0) {
+      ERROR(errno, "%s SIGSTOP pid %d %ld\n", msg, pid, res);
+      return False;
+   }
+         
+   return waitstopped (pid, SIGSTOP, msg);
+
+}
+
+/* Attaches to given pid, wait for the process to be stopped.
+   Returns True if succesful, False otherwise.
+   msg is used in tracing and error reporting. */
+static
+Bool attach (int pid, char *msg)
+{
+   long res;
+
+   DEBUG(1, "%s PTRACE_ATTACH pid %d\n", msg, pid);
+   res = ptrace (PTRACE_ATTACH, pid, NULL, NULL);
+   if (res != 0) {
+      ERROR(errno, "%s PTRACE_ATTACH pid %d %ld\n", msg, pid, res);
+      return False;
+   }
+
+   return waitstopped(pid, SIGSTOP, msg);
+}
+
+/* once we are attached to the pid, get the list of threads and stop 
+   them all.
+   Returns True if all threads properly suspended, False otherwise. */
+static
+Bool acquire_and_suspend_threads(int pid)
+{
+   int i;
+   int rw;
+   Bool pid_found = False;
+   Addr vgt;
+   int sz_tst;
+   int off_status;
+   int off_lwpid;
+   int nr_live_threads = 0;
+
+   if (shared32 != NULL) {
+      vgt = shared32->threads;
+      sz_tst = shared32->sizeof_ThreadState;
+      off_status = shared32->offset_status;
+      off_lwpid = shared32->offset_lwpid;
+   }
+   else if (shared64 != NULL) {
+      vgt = shared64->threads;
+      sz_tst = shared64->sizeof_ThreadState;
+      off_status = shared64->offset_status;
+      off_lwpid = shared64->offset_lwpid;
+   } else {
+      assert (0);
+   }
+
+   /* note: the entry 0 is unused */
+   for (i = 1; i < VG_N_THREADS; i++) {
+      vgt += sz_tst;
+      rw = ptrace_read_memory(pid, vgt+off_status,
+                              (unsigned char *)&(vgdb_threads[i].status),
+                              sizeof(ThreadStatus));
+      if (rw != 0) {
+         ERROR(rw, "status ptrace_read_memory\n");
+         return False;
+      }
+      
+      rw = ptrace_read_memory(pid, vgt+off_lwpid,
+                              (unsigned char *)&(vgdb_threads[i].lwpid),
+                              sizeof(Int));
+      if (rw != 0) {
+         ERROR(rw, "lwpid ptrace_read_memory\n");
+         return False;
+      }
+      
+      if (vgdb_threads[i].status != VgTs_Empty) {
+         DEBUG(1, "found tid %d status %s lwpid %d\n",
+               i, name_of_ThreadStatus(vgdb_threads[i].status),
+               vgdb_threads[i].lwpid);
+         nr_live_threads++;
+         if (vgdb_threads[i].lwpid <= 1) {
+            if (vgdb_threads[i].lwpid == 0 
+                && vgdb_threads[i].status == VgTs_Init) {
+               DEBUG(1, "not set lwpid tid %d status %s lwpid %d\n",
+                     i, name_of_ThreadStatus(vgdb_threads[i].status),
+                     vgdb_threads[i].lwpid);
+            } else {
+               ERROR(1, "unexpected lwpid tid %d status %s lwpid %d\n",
+                     i, name_of_ThreadStatus(vgdb_threads[i].status),
+                     vgdb_threads[i].lwpid);
+            }
+            /* in case we have a VtTs_Init thread with lwpid not yet set,
+               we try again later. */
+            return False;
+         }
+         if (vgdb_threads[i].lwpid == pid) {
+            assert (!pid_found);
+            assert (i == 1);
+            pid_found = True;
+         } else {
+            if (!attach(vgdb_threads[i].lwpid, "attach_thread")) {
+                 ERROR(0, "ERROR attach pid %d tid %d\n", 
+                       vgdb_threads[i].lwpid, i);
+               return False;
+            }
+         }
+      }
+   }
+   /* If we found no thread, it means the process is stopping, and
+      we better do not force anything to happen during that. */
+   if (nr_live_threads > 0)
+      return True;
+   else
+      return False;
+}
+
+static
+void detach_from_all_threads(int pid)
+{
+   int i;
+   long res;
+   Bool pid_found = False;
+
+   /* detach from all the threads  */
+   for (i = 1; i < VG_N_THREADS; i++) {
+      if (vgdb_threads[i].status != VgTs_Empty) {
+         if (vgdb_threads[i].status == VgTs_Init
+             && vgdb_threads[i].lwpid == 0) {
+            DEBUG(1, "skipping PTRACE_DETACH pid %d tid %d status %s\n",
+                  vgdb_threads[i].lwpid, i, 
+                  name_of_ThreadStatus (vgdb_threads[i].status));
+         } else {
+            if (vgdb_threads[i].lwpid == pid) {
+               assert (!pid_found);
+               pid_found = True;
+            }
+            DEBUG(1, "PTRACE_DETACH pid %d tid %d status %s\n",
+                  vgdb_threads[i].lwpid, i, 
+                  name_of_ThreadStatus (vgdb_threads[i].status));
+            res = ptrace (PTRACE_DETACH, vgdb_threads[i].lwpid, NULL, NULL);
+            if (res != 0) {
+               ERROR(errno, "PTRACE_DETACH pid %d tid %d status %s res %ld\n", 
+                     vgdb_threads[i].lwpid, i,
+                     name_of_ThreadStatus (vgdb_threads[i].status),
+                     res);
+            }
+         }
+      }
+   }
+
+   if (!pid_found && pid) {
+      /* No threads are live. Process is busy stopping.
+         We need to detach from pid explicitely. */
+      DEBUG(1, "no thread live => PTRACE_DETACH pid %d\n", pid);
+      res = ptrace (PTRACE_DETACH, pid, NULL, NULL);
+      if (res != 0)
+         ERROR(errno, "PTRACE_DETACH pid %d res %ld\n", pid, res);
+   }
+}
+
+// if > 0, pid for which registers have to be restored.
+static int pid_of_save_regs = 0;
+static struct user user_save;
+
+/* Get the registers from pid into regs.
+   Returns True if all ok, otherwise False. */
+static
+Bool getregs (int pid, void *regs)
+{
+#  ifdef VGA_s390x
+   char *pregs = (char *) regs;
+   long offset;
+   errno = 0;
+   DEBUG(1, "getregs PTRACE_PEEKUSER(s)\n");
+   for (offset = 0; offset < PT_ENDREGS; offset = offset + sizeof(long)) {
+      *(long *)(pregs+offset) = ptrace(PTRACE_PEEKUSER, pid, offset, NULL);
+      if (errno != 0) {
+         ERROR(errno, "PTRACE_PEEKUSER offset %ld\n", offset);
+         return False;
+      }
+   }
+   return True;
+#  else
+   // Platforms having GETREGS
+   long res;
+   DEBUG(1, "getregs PTRACE_GETREGS\n");
+   res = ptrace (PTRACE_GETREGS, pid, NULL, regs);
+   if (res != 0) {
+      ERROR(errno, "PTRACE_GETREGS %ld\n", res);
+      return False;
+   }
+   return True;
+#  endif
+}
+
+/* Set the registers of pid to regs.
+   Returns True if all ok, otherwise False. */
+static
+Bool setregs (int pid, void *regs)
+{
+#  ifdef VGA_s390x
+   char *pregs = (char *) regs;
+   long offset;
+   long res;
+   errno = 0;
+   DEBUG(1, "setregs PTRACE_POKEUSER(s)\n");
+   for (offset = 0; offset < PT_ENDREGS; offset = offset + sizeof(long)) {
+      res = ptrace(PTRACE_POKEUSER, pid, offset, *(long*)(pregs+offset));
+      if (errno != 0) {
+         ERROR(errno, "PTRACE_POKEUSER offset %ld res %ld\n", offset, res);
+         return False;
+      }
+   }
+   return True;
+#  else
+   // Platforms having SETREGS
+   long res;
+   DEBUG(1, "setregs PTRACE_SETREGS\n");
+   res = ptrace (PTRACE_SETREGS, pid, NULL, regs);
+   if (res != 0) {
+      ERROR(errno, "PTRACE_SETREGS %ld\n", res);
+      return False;
+   }
+   return True;
+#  endif
+}
+
+/* Restore the registers to the saved value, then detaches from all threads */
+static
+void restore_and_detach(int pid)
+{
+   if (pid_of_save_regs) {
+      /* In case the 'main pid' has been continued, we need to stop it
+         before resetting the registers. */
+      if (pid_of_save_regs_continued) {
+         pid_of_save_regs_continued = False;
+         if (!stop(pid_of_save_regs, "sigstop before reset regs"))
+            DEBUG(0, "Could not sigstop before reset");
+      }
+
+      DEBUG(1, "setregs restore registers pid %d\n", pid_of_save_regs);
+      if (!setregs(pid_of_save_regs, &user_save.regs)) {
+         ERROR(errno, "setregs restore registers pid %d after cont\n",
+               pid_of_save_regs);
+      }
+      pid_of_save_regs = 0;
+   } else {
+      DEBUG(1, "PTRACE_SETREGS restore registers: no pid\n");
+   }
+   detach_from_all_threads(pid);
+}
+
+/* Ensures that the gdbserver code is invoked by pid.
+   If an error occurs, resets to the valgrind process
+   to the state it has before being ptrace-d.
+   Returns True if invoke successful, False otherwise.
+*/
+static
+Bool invoke_gdbserver (int pid)
+{
+   long res;
+   Bool stopped;
+   struct user user_mod;
+   Addr sp;
+   /* A specific int value is passed to invoke_gdbserver, to check
+      everything goes according to the plan. */
+   const int check = 0x8BADF00D; // ate bad food.
+
+   const Addr bad_return = 0;
+   // A bad return address will be pushed on the stack.
+   // The function invoke_gdbserver cannot return. If ever it returns, a NULL
+   // address pushed on the stack should ensure this is detected.
+
+   /* Not yet attached. If problem, vgdb can abort,
+      no cleanup needed.
+
+      On Ubuntu>= 10.10, a /proc setting can disable ptrace.
+      So, Valgrind has to SET_PTRACER this vgdb. Once this
+      is done, this vgdb can ptrace the valgrind process. */
+
+   DEBUG(1, "attach to 'main' pid %d\n", pid);
+   if (!attach(pid, "attach main pid")) {
+      ERROR(0, "error attach main pid %d\n", pid);
+      return False;
+   }
+
+   /* Now, we are attached. If problem, detach and return. */
+
+   if (!acquire_and_suspend_threads(pid)) {
+      detach_from_all_threads(pid);
+      /* if the pid does not exist anymore, we better stop */
+      if (kill(pid, 0) != 0)
+        XERROR (errno, "invoke_gdbserver: check for pid %d existence failed\n",
+                pid);
+      return False;
+   }
+
+   if (!getregs(pid, &user_mod.regs)) {
+      detach_from_all_threads(pid);
+      return False;
+   }
+   user_save = user_mod;
+
+#if defined(VGA_x86)
+   sp = user_mod.regs.esp;
+#elif defined(VGA_amd64)
+   sp = user_mod.regs.rsp;
+   if (shared32 != NULL) {
+     /* 64bit vgdb speaking with a 32bit executable.
+        To have system call restart properly, we need to sign extend rax.
+        For more info:
+        web search '[patch] Fix syscall restarts for amd64->i386 biarch'
+        e.g. http://sourceware.org/ml/gdb-patches/2009-11/msg00592.html */
+     *(long *)&user_save.regs.rax = *(int*)&user_save.regs.rax;
+     DEBUG(1, "Sign extending %8.8lx to %8.8lx\n",
+           user_mod.regs.rax, user_save.regs.rax);
+   }
+#elif defined(VGA_arm)
+   sp = user_mod.regs.uregs[13];
+#elif defined(VGA_ppc32)
+   sp = user_mod.regs.gpr[1];
+#elif defined(VGA_ppc64)
+   sp = user_mod.regs.gpr[1];
+#elif defined(VGA_s390x)
+   sp = user_mod.regs.gprs[15];
+#else
+   I_die_here : (sp) architecture missing in vgdb.c
+#endif
+
+
+   // the magic below is derived from spying what gdb sends to
+   // the (classical) gdbserver when invoking a C function.
+   if (shared32 != NULL) {
+      // vgdb speaking with a 32bit executable.
+#if   defined(VGA_x86) || defined(VGA_amd64)
+      const int regsize = 4;
+      int rw;
+      /* push check arg on the stack */
+      sp = sp - regsize;
+      DEBUG(1, "push check arg ptrace_write_memory\n");
+      assert(regsize == sizeof(check));
+      rw = ptrace_write_memory(pid, sp, 
+                               (unsigned char *) &check, 
+                               regsize);
+      if (rw != 0) {
+         ERROR(rw, "push check arg ptrace_write_memory");
+         detach_from_all_threads(pid);
+         return False;
+      }
+
+      sp = sp - regsize;
+      DEBUG(1, "push bad_return return address ptrace_write_memory\n");
+      // Note that for a 64 bits vgdb, only 4 bytes of NULL bad_return
+      // are written.
+      rw = ptrace_write_memory(pid, sp, 
+                               (unsigned char *) &bad_return,
+                               regsize);
+      if (rw != 0) {
+         ERROR(rw, "push bad_return return address ptrace_write_memory");
+         detach_from_all_threads(pid);
+         return False;
+      }
+#if   defined(VGA_x86)
+      /* set ebp, esp, eip and orig_eax to invoke gdbserver */
+      // compiled in 32bits, speaking with a 32bits exe
+      user_mod.regs.ebp = sp; // bp set to sp
+      user_mod.regs.esp = sp;
+      user_mod.regs.eip = shared32->invoke_gdbserver;
+      user_mod.regs.orig_eax = -1L;
+#elif defined(VGA_amd64)
+      /* set ebp, esp, eip and orig_eax to invoke gdbserver */
+      // compiled in 64bits, speaking with a 32bits exe
+      user_mod.regs.rbp = sp; // bp set to sp
+      user_mod.regs.rsp = sp;
+      user_mod.regs.rip = shared32->invoke_gdbserver;
+      user_mod.regs.orig_rax = -1L;
+#else
+      I_die_here : not x86 or amd64 in x86/amd64 section/
+#endif
+
+#elif defined(VGA_ppc32) || defined(VGA_ppc64)
+      user_mod.regs.nip = shared32->invoke_gdbserver;
+      user_mod.regs.trap = -1L;
+      /* put check arg in register 3 */
+      user_mod.regs.gpr[3] = check;
+      /* put NULL return address in Link Register */
+      user_mod.regs.link = bad_return;
+
+#elif defined(VGA_arm)
+      /* put check arg in register 0 */
+      user_mod.regs.uregs[0] = check;
+      /* put NULL return address in Link Register */
+      user_mod.regs.uregs[14] = bad_return;
+      user_mod.regs.uregs[15] = shared32->invoke_gdbserver;
+
+#elif defined(VGA_s390x)
+      XERROR(0, "(fn32) s390x has no 32bits implementation");
+#else
+      I_die_here : architecture missing in vgdb.c
+#endif
+      }
+
+   else if (shared64 != NULL) {
+#if defined(VGA_x86)
+      assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
+#elif defined(VGA_amd64)
+      // vgdb speaking with a 64 bit executable.
+      const int regsize = 8;
+      int rw;
+      
+      /* give check arg in rdi */
+      user_mod.regs.rdi = check;
+
+      /* push return address on stack : return to breakaddr */
+      sp = sp - regsize;
+      DEBUG(1, "push bad_return return address ptrace_write_memory\n");
+      rw = ptrace_write_memory(pid, sp, 
+                               (unsigned char *) &bad_return,
+                               sizeof(bad_return));
+      if (rw != 0) {
+         ERROR(rw, "push bad_return return address ptrace_write_memory");
+         detach_from_all_threads(pid);
+         return False;
+      }
+
+      /* set rbp, rsp, rip and orig_rax to invoke gdbserver */
+      user_mod.regs.rbp = sp; // bp set to sp
+      user_mod.regs.rsp = sp;
+      user_mod.regs.rip = shared64->invoke_gdbserver;
+      user_mod.regs.orig_rax = -1L;
+
+#elif defined(VGA_arm)
+      assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
+#elif defined(VGA_ppc32)
+      assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
+#elif defined(VGA_ppc64)
+      Addr64 func_addr;
+      Addr64 toc_addr;
+      int rw;
+      rw = ptrace_read_memory(pid, shared64->invoke_gdbserver,
+                              (unsigned char *)&func_addr,
+                              sizeof(Addr64));
+      if (rw != 0) {
+         ERROR(rw, "ppc64 read func_addr\n");
+         detach_from_all_threads(pid);
+         return False;
+      }
+      rw = ptrace_read_memory(pid, shared64->invoke_gdbserver+8,
+                              (unsigned char *)&toc_addr,
+                              sizeof(Addr64));
+      if (rw != 0) {
+         ERROR(rw, "ppc64 read toc_addr\n");
+         detach_from_all_threads(pid);
+         return False;
+      }
+      // We are not pushing anything on the stack, so it is not
+      // very clear why the sp has to be decreased, but it seems
+      // needed. The ppc64 ABI might give some lights on this ?
+      user_mod.regs.gpr[1] = sp - 220;
+      user_mod.regs.gpr[2] = toc_addr;
+      user_mod.regs.nip = func_addr;
+      user_mod.regs.trap = -1L;
+      /* put check arg in register 3 */
+      user_mod.regs.gpr[3] = check;
+      /* put bad_return return address in Link Register */
+      user_mod.regs.link = bad_return;
+#elif defined(VGA_s390x)
+      /* put check arg in register r2 */
+      user_mod.regs.gprs[2] = check;
+      /* bad_return Return address is in r14 */
+      user_mod.regs.gprs[14] = bad_return;
+      /* minimum stack frame */
+      sp = sp - 160;
+      user_mod.regs.gprs[15] = sp;
+      /* set program counter */
+      user_mod.regs.psw.addr = shared64->invoke_gdbserver;
+#else
+      I_die_here: architecture missing in vgdb.c
+#endif
+   }
+   else {
+      assert(0);
+   }
+   
+   if (!setregs(pid, &user_mod.regs)) {
+      detach_from_all_threads(pid);
+      return False;
+   }
+   /* Now that we have modified the registers, we set
+      pid_of_save_regs to indicate that restore_and_detach
+      must restore the registers in case of cleanup. */
+   pid_of_save_regs = pid;
+   pid_of_save_regs_continued = False;
+      
+
+   /* We PTRACE_CONT-inue pid. 
+      Either gdbserver will be invoked directly (if all
+      threads are interruptible) or gdbserver will be
+      called soon by the scheduler. In the first case,
+      pid will stop on the break inserted above when
+      gdbserver returns. In the 2nd case, the break will
+      be encountered directly. */
+   DEBUG(1, "PTRACE_CONT to invoke\n");
+   res = ptrace (PTRACE_CONT, pid, NULL, NULL);
+   if (res != 0) {
+      ERROR(errno, "PTRACE_CONT\n");
+      restore_and_detach(pid);
+      return False;
+   }
+   pid_of_save_regs_continued = True;
+   
+   stopped = waitstopped (pid, SIGTRAP,
+                          "waitpid status after PTRACE_CONT to invoke");
+   if (stopped) {
+      /* Here pid has properly stopped on the break. */
+      pid_of_save_regs_continued = False;
+      restore_and_detach(pid);
+      return True;
+   } else {
+      /* Whatever kind of problem happened. We shutdown */
+      shutting_down = True;
+      return False;
+   }
+}
+#endif
+
+static 
+void cleanup_restore_and_detach(void *v_pid)
+{
+   DEBUG(1, "cleanup_restore_and_detach dying: %d\n", dying);
+#ifdef PTRACEINVOKER
+   if (!dying)
+      restore_and_detach(*(int*)v_pid);
+#endif
+}
+
+/* This function loops till shutting_down becomes true.  In this loop,
+   it verifies if valgrind process is reading the characters written
+   by vgdb.  The verification is done every max_invoke_ms ms.  If
+   valgrind is not reading characters, it will use invoke_gdbserver
+   (if PTRACE_INVOKER is defined) to ensure that the gdbserver code is
+   called soon by valgrind. */
+static int max_invoke_ms = 100;
+static
+void *invoke_gdbserver_in_valgrind(void *v_pid)
+{
+   int pid = *(int *)v_pid;
+   int written_by_vgdb_before_sleep;
+   int seen_by_valgrind_before_sleep;
+   
+   int invoked_written = -1;
+
+   pthread_cleanup_push(cleanup_restore_and_detach, v_pid);
+
+   while (!shutting_down) {
+      written_by_vgdb_before_sleep = VS_written_by_vgdb;
+      seen_by_valgrind_before_sleep = VS_seen_by_valgrind;
+      DEBUG(3, 
+            "written_by_vgdb_before_sleep %d "
+            "seen_by_valgrind_before_sleep %d\n",
+            written_by_vgdb_before_sleep,
+            seen_by_valgrind_before_sleep);
+      if (usleep(1000 * max_invoke_ms) != 0) {
+         if (errno == EINTR)
+            continue;
+         XERROR (errno, "error usleep\n");
+      }
+      /* if nothing happened during our sleep, let's try to wake up valgrind */
+      if (written_by_vgdb_before_sleep == VS_written_by_vgdb
+          && seen_by_valgrind_before_sleep == VS_seen_by_valgrind
+          && VS_written_by_vgdb > VS_seen_by_valgrind) {
+         DEBUG(2,
+               "after sleep "
+               "written_by_vgdb %d "
+               "seen_by_valgrind %d "
+               "invoked_written %d\n",
+               VS_written_by_vgdb,
+               VS_seen_by_valgrind,
+               invoked_written);
+         /* if the pid does not exist anymore, we better stop */
+         if (kill(pid, 0) != 0)
+           XERROR (errno, 
+                   "invoke_gdbserver_in_valgrind: "
+                   "check for pid %d existence failed\n", pid);
+
+         #if defined(PTRACEINVOKER)
+         /* only need to wake up if the nr written has changed since
+            last invoke. */
+         if (invoked_written != written_by_vgdb_before_sleep) {
+            if (invoke_gdbserver(pid)) {
+               /* If invoke succesful, no need to invoke again
+                  for the same value of written_by_vgdb_before_sleep. */
+               invoked_written = written_by_vgdb_before_sleep;
+            }
+         }
+         #else
+         DEBUG(2, "invoke_gdbserver via ptrace not (yet) implemented\n");
+         #endif
+      }
+   }
+   pthread_cleanup_pop(0);
+   return NULL;
+}
+
+static
+int open_fifo (char* name, int flags, char* desc)
+{
+   int fd;
+   DEBUG(1, "opening %s %s\n", name, desc);
+   fd = open(name, flags);
+   if (fd == -1)
+      XERROR (errno, "error opening %s %s\n", name, desc);
+
+   DEBUG(1, "opened %s %s fd %d\n", name, desc, fd);
+   return fd;
+}
+
+/* acquire a lock on the first byte of the given fd. If not successful,
+   exits with error.
+   This allows to avoid having two vgdb speaking with the same Valgrind
+   gdbserver as this causes serious headaches to the protocol. */
+static
+void acquire_lock (int fd, int valgrind_pid)
+{
+   if (lockf(fd, F_TLOCK, 1) < 0) {
+      if (errno == EAGAIN || errno == EACCES) {
+         XERROR(errno, 
+                "Cannot acquire lock.\n"
+                "Probably vgdb pid %d already speaks with Valgrind pid %d\n",
+                VS_vgdb_pid,
+                valgrind_pid);
+      } else {
+         XERROR(errno, "cannot acquire lock.\n");
+      }
+   }
+
+   /* Here, we have the lock. It will be released when fd will be closed. */
+   /* We indicate our pid to Valgrind gdbserver */
+   if (shared32 != NULL)
+      shared32->vgdb_pid = getpid();
+   else if (shared64 != NULL)
+      shared64->vgdb_pid = getpid();
+   else
+      assert(0);
+}
+
+#define PBUFSIZ 16384 /* keep in sync with server.h */
+
+/* read some characters from fd.
+   Returns the nr of characters read, -1 if error.
+   desc is a string used in tracing */
+static
+int read_buf (int fd, char* buf, char* desc)
+{
+   int nrread;
+   DEBUG(2, "reading %s\n", desc);
+   nrread = read(fd, buf, PBUFSIZ);
+   if (nrread == -1) {
+      ERROR (errno, "error reading %s\n", desc);
+      return -1;
+   }
+   buf[nrread] = '\0';
+   DEBUG(2, "read %s %s\n", desc, buf);
+   return nrread;
+}
+
+/* write size bytes from buf to fd.
+   desc is a description of the action for which the write is done.
+   If notify, then add size to the shared cntr indicating to the 
+   valgrind process that there is new data.
+   Returns True if write is ok, False if there was a problem. */
+static
+Bool write_buf(int fd, char* buf, int size, char* desc, Bool notify)
+{
+   int nrwritten;
+   int nrw;
+   DEBUG(2, "writing %s len %d %s notify: %d\n", desc, size, buf, notify);
+   nrwritten = 0;
+   while (nrwritten < size) {
+      nrw = write (fd, buf+nrwritten, size - nrwritten);
+      if (nrw == -1) {
+         ERROR(errno, "error write %s\n", desc);
+         return False;
+      }
+      nrwritten = nrwritten + nrw;
+      if (notify)
+         add_written(nrw);
+   }
+   return True;
+} 
+
+typedef enum {
+   FROM_GDB,
+   TO_GDB,
+   FROM_PID,
+   TO_PID } ConnectionKind;
+static const int NumConnectionKind = TO_PID+1;
+static 
+char *ppConnectionKind (ConnectionKind con)
+{
+   switch (con) {
+   case FROM_GDB: return "FROM_GDB";
+   case TO_GDB:   return "TO_GDB";
+   case FROM_PID: return "FROM_PID";
+   case TO_PID:   return "TO_PID";
+   default:       return "invalid connection kind";
+   }
+}
+
+static char *shared_mem;
+
+static const int from_gdb = 0;
+static char *from_gdb_to_pid; /* fifo name to write gdb command to pid */
+/* Returns True in case read/write operations were done properly.
+   Returns False in case of error.
+   to_pid is the file descriptor to write to the process pid. */
+static
+Bool read_from_gdb_write_to_pid(int to_pid)
+{
+   char buf[PBUFSIZ];
+   int nrread;
+
+   nrread = read_buf(from_gdb, buf, "from gdb on stdin");
+   if (nrread <= 0) {
+      if (nrread == 0) 
+         DEBUG(1, "read 0 bytes from gdb => assume exit\n");
+      else
+         DEBUG(1, "error reading bytes from gdb\n");
+      close (from_gdb);
+      shutting_down = True;
+      return False;
+   }
+   return write_buf(to_pid, buf, nrread, "to_pid", /* notify */ True);
+}
+
+static const int to_gdb = 1;
+static char *to_gdb_from_pid; /* fifo name to read pid replies */
+/* Returns True in case read/write operations were done properly.
+   Returns False in case of error.
+   from_pid is the file descriptor to read data from the process pid. */
+static
+Bool read_from_pid_write_to_gdb(int from_pid)
+{
+   char buf[PBUFSIZ];
+   int nrread;
+
+   nrread = read_buf(from_pid, buf, "from pid");
+   if (nrread <= 0) {
+      if (nrread == 0) 
+         DEBUG(1, "read 0 bytes from pid => assume exit\n");
+      else
+         DEBUG(1, "error reading bytes from pid\n");
+      close (from_pid);
+      shutting_down = True;
+      return False;
+   }
+   return write_buf(to_gdb, buf, nrread, "to_gdb", /* notify */ False);
+}
+
+/* prepares the FIFOs filenames, map the shared memory. */
+static
+void prepare_fifos_and_shared_mem(int pid)
+{
+   from_gdb_to_pid = vmalloc (strlen(vgdb_prefix) + 30);
+   to_gdb_from_pid = vmalloc (strlen(vgdb_prefix) + 30);
+   shared_mem      = vmalloc (strlen(vgdb_prefix) + 30);
+   /* below 3 lines must match the equivalent in remote-utils.c */
+   sprintf(from_gdb_to_pid, "%s-from-vgdb-to-%d",    vgdb_prefix, pid);
+   sprintf(to_gdb_from_pid, "%s-to-vgdb-from-%d",    vgdb_prefix, pid);
+   sprintf(shared_mem,      "%s-shared-mem-vgdb-%d", vgdb_prefix, pid);
+   DEBUG (1, "vgdb: using %s %s %s\n", 
+          from_gdb_to_pid, to_gdb_from_pid, shared_mem);
+
+   map_vgdbshared(shared_mem);
+}
+
+/* Convert hex digit A to a number.  */
+
+static int
+fromhex (int a)
+{
+   if (a >= '0' && a <= '9')
+      return a - '0';
+   else if (a >= 'a' && a <= 'f')
+      return a - 'a' + 10;
+   else
+      XERROR(0, "Reply contains invalid hex digit %c\n", a);
+  return 0;
+}
+
+/* Returns next char from fd.  -1 if error, -2 if EOF.
+   NB: must always call it with the same fd */
+static int
+readchar (int fd)
+{
+  static unsigned char buf[PBUFSIZ];
+  static int bufcnt = 0;
+  static unsigned char *bufp;
+
+  if (bufcnt-- > 0)
+     return *bufp++;
+
+  bufcnt = read (fd, buf, sizeof (buf));
+
+  if (bufcnt <= 0) {
+     if (bufcnt == 0) {
+        fprintf (stderr, "readchar: Got EOF\n");
+        return -2;
+     } else {
+        ERROR (errno, "readchar\n");
+        return -1;
+     }
+  }
+
+  bufp = buf;
+  bufcnt--;
+  return *bufp++;
+}
+
+/* Read a packet from fromfd, with error checking,
+   and store it in BUF.  
+   Returns length of packet, or -1 if error or -2 if EOF.
+   Writes ack on ackfd */
+
+static int
+getpkt (char *buf, int fromfd, int ackfd)
+{
+  char *bp;
+  unsigned char csum, c1, c2;
+  int c;
+  
+  while (1) {
+     csum = 0;
+
+     while (1) {
+        c = readchar (fromfd);
+        if (c == '$')
+           break;
+        DEBUG(2, "[getpkt: discarding char '%c']\n", c);
+        if (c < 0)
+           return c;
+     }
+
+     bp = buf;
+     while (1) {
+        c = readchar (fromfd);
+        if (c < 0)
+           return c;
+        if (c == '#')
+           break;
+        if (c == '*') {
+           int repeat;
+           int r;
+           int prev;
+           prev = *(bp-1);
+           csum += c;
+           repeat = readchar (fromfd);
+           csum += repeat;
+           for (r = 0; r < repeat - 29; r ++)
+              *bp++ = prev;
+        } else {
+           *bp++ = c;
+           csum += c;
+        }
+     }
+     *bp = 0;
+
+     c1 = fromhex (readchar (fromfd));
+     c2 = fromhex (readchar (fromfd));
+
+     if (csum == (c1 << 4) + c2)
+       break;
+
+     fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+              (c1 << 4) + c2, csum, buf);
+     if (write (ackfd, "-", 1) != 1)
+        ERROR(0, "error when writing - (nack)\n");
+     else
+        add_written(1);
+  }
+
+  DEBUG(2, "getpkt (\"%s\");  [sending ack] \n", buf);
+  if (write (ackfd, "+", 1) != 1)
+     ERROR(0, "error when writing + (ack)\n");
+  else
+     add_written(1);
+  return bp - buf;
+}
+
+static int sigint = 0;
+static int sigterm = 0;
+static int sigpipe = 0;
+static int sighup = 0;
+static int sigusr1 = 0;
+static int sigalrm = 0;
+static int sigusr1_fd = -1;
+static pthread_t invoke_gdbserver_in_valgrind_thread;
+
+static
+void received_signal (int signum)
+{
+   if (signum == SIGINT)
+      sigint++;
+   else if (signum == SIGUSR1) {
+      sigusr1++;
+      if (sigusr1_fd >= 0) {
+         char control_c = '\003';
+         write_buf(sigusr1_fd, &control_c, 1,
+                   "write \\003 on SIGUSR1", /* notify */ True);
+      }
+   }
+   else if (signum == SIGTERM) {
+      shutting_down = True;
+      sigterm++;
+   } else if (signum == SIGHUP) {
+      shutting_down = True;
+      sighup++;
+   } else if (signum == SIGPIPE) {
+      sigpipe++;
+   } else if (signum == SIGALRM) {
+      sigalrm++;
+      DEBUG(1, "pthread_cancel invoke_gdbserver_in_valgrind_thread\n");
+      /* Note: we cannot directly invoke restore_and_detach : this must
+         be done by the thread that has attached. 
+         We have in this thread pushed a cleanup handler that will
+         cleanup what is needed. */
+      pthread_cancel(invoke_gdbserver_in_valgrind_thread);
+   } else {
+      ERROR(0, "unexpected signal %d\n", signum);
+   }
+}
+
+/* install the signal handlers allowing e.g. vgdb to cleanup in
+   case of termination. */
+static
+void install_handlers(void)
+{
+   struct sigaction action, oldaction;
+
+   action.sa_handler = received_signal;
+   sigemptyset (&action.sa_mask);
+   action.sa_flags = 0;
+   
+   /* SIGINT: when user types C-c in gdb, this sends
+      a SIGINT to vgdb + causes a character to be sent to remote gdbserver.
+      The later is enough to wakeup the valgrind process. */
+   if (sigaction (SIGINT, &action, &oldaction) != 0)
+      XERROR (errno, "vgdb error sigaction SIGINT\n");
+   /* We might do something more intelligent than just
+      reporting this SIGINT E.g. behave similarly to the gdb: two
+      control-C without feedback from the debugged process would
+      mean to stop debugging it. */
+
+   /* SIGUSR1: this is used to facilitate automatic testing.  When
+      vgdb receives this signal, it will simulate the user typing C-c. */
+   if (sigaction (SIGUSR1, &action, &oldaction) != 0)
+      XERROR (errno, "vgdb error sigaction SIGUSR1\n");
+   
+
+   /* SIGTERM: can receive this signal (e.g. from gdb) to terminate vgdb
+      when detaching or similar. A clean shutdown will be done as both
+      the read and write side will detect an end of file. */
+   if (sigaction (SIGTERM, &action, &oldaction) != 0)
+      XERROR (errno, "vgdb error sigaction SIGTERM\n");
+   
+   /* SIGPIPE: can receive this signal when gdb detaches or kill the
+      process debugged: gdb will close its pipes to vgdb. vgdb
+      must resist to this signal to allow a clean shutdown. */
+   if (sigaction (SIGPIPE, &action, &oldaction) != 0)
+      XERROR (errno, "vgdb error sigaction SIGPIPE\n");
+   
+   /* SIGALRM: in case invoke thread is blocked, alarm is used
+      to cleanup.  */
+   if (sigaction (SIGALRM, &action, &oldaction) != 0)
+      XERROR (errno, "vgdb error sigaction SIGALRM\n");
+}
+
+/* close the FIFOs provided connections, terminate the invoker thread.  */
+static
+void close_connection(int to_pid, int from_pid)
+{
+   DEBUG(1, "nr received signals: sigint %d sigterm %d sighup %d sigpipe %d\n",
+         sigint, sigterm, sighup, sigpipe);
+   /* Note that we do not forward sigterm to the valgrind process:
+      a sigterm signal is (probably) received from gdb if the user wants to
+      kill the debugged process. The kill instruction has been given to
+      the valgrind process, which should execute a clean exit. */
+
+   /* We first close the connection to pid. The pid will then
+      terminates its gdbserver work. We keep the from pid
+      fifo opened till the invoker thread is finished.
+      This allows the gdbserver to finish sending its last reply. */
+   if (close(to_pid) != 0)
+      ERROR(errno, "close to_pid\n");
+
+   /* if there is a task that was busy trying to wake up valgrind
+      process, we wait for it to be terminated otherwise threads
+      in the valgrind process can stay stopped if vgdb main
+      exits before the invoke thread had time to detach from
+      all valgrind threads. */
+   if (max_invoke_ms > 0) {
+      int join;
+
+      /* It is surprisingly complex to properly shutdown or exit the
+         valgrind process in which gdbserver has been invoked through
+         ptrace.  In the normal case (gdb detaches from the process,
+         or process is continued), the valgrind process will reach the
+         breakpoint place.  Using ptrace, vgdb will ensure the
+         previous activity of the process is resumed (e.g. restart a
+         blocking system call).  The special case is when gdb asks the
+         valgrind process to exit (using either the "kill" command or
+         "monitor exit").  In such a case, the valgrind process will
+         call exit.  But a ptraced process will be blocked in exit,
+         waiting for the ptracing process to detach or die. vgdb
+         cannot detach unconditionally as otherwise, in the normal
+         case, the valgrind process would die abnormally with SIGTRAP
+         (as vgdb would not be there to catch it). vgdb can also not
+         die unconditionally otherwise again, similar problem.  So, we
+         assume that most of the time, we arrive here in the normal
+         case, and so, the breakpoint has been encountered by the
+         valgrind process, so the invoker thread will exit and the
+         join will succeed.  For the "kill" case, we cause an alarm
+         signal to be sent after a few seconds. This means that in the
+         normal case, the gdbserver code in valgrind process must have
+         returned the control in less than the alarm nr of seconds,
+         otherwise, valgrind will die abnormally with SIGTRAP. */
+      (void) alarm (3);
+
+      DEBUG(1, "joining with invoke_gdbserver_in_valgrind_thread\n");
+      join = pthread_join(invoke_gdbserver_in_valgrind_thread, NULL);
+      if (join != 0)
+         XERROR 
+            (join, 
+             "vgdb error pthread_join invoke_gdbserver_in_valgrind_thread\n");
+   }
+   if (close(from_pid) != 0)
+      ERROR(errno, "close from_pid\n");
+}
+
+/* Relay data between gdb and Valgrind gdbserver, till EOF or an
+   error is encountered. */
+static
+void gdb_relay (int pid)
+{
+   int from_pid = -1; /* fd to read from pid */
+   int to_pid = -1; /* fd to write to pid */
+
+   int shutdown_loop = 0;
+   fprintf (stderr, "relaying data between gdb and process %d\n", pid);
+   fflush (stderr);
+
+   if (max_invoke_ms > 0)
+      pthread_create(&invoke_gdbserver_in_valgrind_thread, NULL, 
+                     invoke_gdbserver_in_valgrind, (void *) &pid);
+   to_pid = open_fifo(from_gdb_to_pid, O_WRONLY, "write to pid");
+   acquire_lock (shared_mem_fd, pid);
+   
+   from_pid = open_fifo (to_gdb_from_pid, O_RDONLY|O_NONBLOCK, 
+                         "read mode from pid");
+
+   sigusr1_fd = to_pid; /* allow simulating user typing control-c */
+
+   while (1) {
+      ConnectionKind ck;
+      int ret;
+      struct pollfd pollfds[NumConnectionKind];
+      
+      /* watch data written by gdb, watch POLLERR on both gdb fd */
+      pollfds[FROM_GDB].fd = from_gdb;
+      pollfds[FROM_GDB].events = POLLIN;
+      pollfds[FROM_GDB].revents = 0;
+      pollfds[TO_GDB].fd = to_gdb;
+      pollfds[TO_GDB].events = 0;
+      pollfds[TO_GDB].revents = 0;
+      
+      /* watch data written by pid, watch POLLERR on both pid fd */
+      pollfds[FROM_PID].fd = from_pid;
+      pollfds[FROM_PID].events = POLLIN;
+      pollfds[FROM_PID].revents = 0;
+      pollfds[TO_PID].fd = to_pid;
+      pollfds[TO_PID].events = 0;
+      pollfds[TO_PID].revents = 0;
+      
+      ret = poll(pollfds, 
+                 NumConnectionKind, 
+                 (shutting_down ? 
+                  1 /* one second */ 
+                  : -1 /* infinite */));
+      DEBUG(2, "poll ret %d errno %d\n", ret, errno);
+
+      /* check for unexpected error */
+      if (ret <= 0 && errno != EINTR) {
+         ERROR (errno, "unexpected poll ret %d\n", ret);
+         shutting_down = True;
+         break;
+      }
+      
+      /* check for data to read */
+      for (ck = 0; ck < NumConnectionKind; ck ++) {
+         if (pollfds[ck].revents & POLLIN) {
+            switch (ck) {
+            case FROM_GDB: 
+               if (!read_from_gdb_write_to_pid(to_pid))
+                  shutting_down = True;
+               break;
+               case FROM_PID:
+                  if (!read_from_pid_write_to_gdb(from_pid))
+                     shutting_down = True;
+                  break;
+            default: XERROR(0, "unexpected POLLIN on %s\n",
+                               ppConnectionKind(ck));
+            }
+         }
+      }
+
+      /* check for an fd being in error condition */
+      for (ck = 0; ck < NumConnectionKind; ck ++) {
+         if (pollfds[ck].revents & POLLERR) {
+            DEBUG(1, "connection %s fd %d POLLERR error condition\n",
+                     ppConnectionKind(ck), pollfds[ck].fd);
+            valgrind_dying();
+            shutting_down = True;
+         }
+         if (pollfds[ck].revents & POLLHUP) {
+            DEBUG(1, "connection %s fd %d POLLHUP error condition\n",
+                  ppConnectionKind(ck), pollfds[ck].fd);
+            valgrind_dying();
+            shutting_down = True;
+         }
+         if (pollfds[ck].revents & POLLNVAL) {
+            DEBUG(1, "connection %s fd %d POLLNVAL error condition\n",
+                  ppConnectionKind(ck), pollfds[ck].fd);
+            valgrind_dying();
+            shutting_down = True;
+         }
+      }
+      
+      if (shutting_down) {
+         /* we let some time to the final packets to be transferred */
+         shutdown_loop++;
+         if (shutdown_loop > 3)
+            break;
+      }
+   }
+   close_connection(to_pid, from_pid);
+}
+
+static int packet_len_for_command(char *cmd)
+{
+   /* cmd will be send as a packet $qRcmd,xxxx....................xx#cc      */
+   return                          7+     2*strlen(cmd)             +3  + 1;
+}
+
+/* hyper-minimal protocol implementation that
+   sends the provided commands (using qRcmd packets)
+   and read and display their replies. */
+static
+void standalone_send_commands(int pid, 
+                              int last_command,
+                              char *commands[] )
+{
+   int from_pid = -1; /* fd to read from pid */
+   int to_pid = -1; /* fd to write to pid */
+
+   int i;
+   int hi;
+   unsigned char hex[3];
+   unsigned char cksum;
+   unsigned char *hexcommand;
+   unsigned char buf[PBUFSIZ];
+   int buflen;
+   int nc;
+
+
+   if (max_invoke_ms > 0)
+      pthread_create(&invoke_gdbserver_in_valgrind_thread, NULL, 
+                     invoke_gdbserver_in_valgrind, (void *) &pid);
+
+   to_pid = open_fifo(from_gdb_to_pid, O_WRONLY, "write to pid");
+   acquire_lock (shared_mem_fd, pid);
+
+   /* first send a C-c \003 to pid, so that it wakes up the process
+      After that, we can open the fifo from the pid in read mode
+      We then start to wait for packets (normally first a resume reply)
+      At that point, we send our command and expect replies */
+   buf[0] = '\003';
+   write_buf(to_pid, buf, 1, "write \\003 to wake up", /* notify */ True);
+   from_pid = open_fifo(to_gdb_from_pid, O_RDONLY, 
+                        "read cmd result from pid");
+   
+   for (nc = 0; nc <= last_command; nc++) {
+      fprintf (stderr, "sending command %s to pid %d\n", commands[nc], pid);
+      fflush (stderr);
+      
+      /* prepare hexcommand $qRcmd,xxxx....................xx#cc      */
+      hexcommand = vmalloc (packet_len_for_command(commands[nc]));
+      hexcommand[0] = 0;
+      strcat (hexcommand, "$qRcmd,");
+      for (i = 0; i < strlen(commands[nc]); i++) {
+         sprintf(hex, "%02x", commands[nc][i]);
+         strcat (hexcommand, hex);
+      }
+      /* checksum (but without the $) */
+      cksum = 0;
+      for (hi = 1; hi < strlen(hexcommand); hi++)
+         cksum+=hexcommand[hi];
+      strcat(hexcommand, "#");
+      sprintf(hex, "%02x", cksum);
+      strcat(hexcommand, hex);
+      write_buf(to_pid, hexcommand, strlen(hexcommand), 
+                "writing hex command to pid", /* notify */ True);
+
+      /* we exit of the below loop explicitely when the command has
+         been handled or because a signal handler will set
+         shutting_down. */
+      while (!shutting_down) {
+         buflen = getpkt(buf, from_pid, to_pid);
+         if (buflen < 0) {
+            ERROR (0, "error reading packet\n");
+            if (buflen == -2)
+               valgrind_dying();
+            break;
+         }
+         if (strlen(buf) == 0) {
+            DEBUG(0, "empty packet rcvd (packet qRcmd not recognised?)\n");
+            break;
+         }
+         if (strcmp(buf, "OK") == 0) {
+            DEBUG(1, "OK packet rcvd\n");
+            break;
+         }
+         if (buf[0] == 'E') {
+            DEBUG(0, 
+                  "E NN error packet rcvd: %s (unknown monitor command?)\n",
+                  buf);
+            break;
+         }
+         if (buf[0] == 'W') {
+            DEBUG(0, "W stopped packet rcvd: %s\n", buf);
+            break;
+         }
+         if (buf[0] == 'T') {
+            DEBUG(1, "T resume reply packet received: %s\n", buf);
+            continue;
+         }
+         
+         /* must be here an O packet with hex encoded string reply 
+            => decode and print it */
+         if (buf[0] != 'O') {
+            DEBUG(0, "expecting O packet, received: %s\n", buf);
+            continue;
+         }
+         {
+            char buf_print[buflen/2 + 1];
+            for (i = 1; i < buflen; i = i + 2)
+               buf_print[i/2] = (fromhex(*(buf+i)) << 4) 
+                     + fromhex(*(buf+i+1));
+            buf_print[buflen/2] = 0;
+            printf("%s", buf_print);
+            fflush(stdout);
+         }
+      }
+      free (hexcommand);
+   }
+   shutting_down = True;
+
+   close_connection(to_pid, from_pid);
+}
+
+/* report to user the existence of a vgdb-able valgrind process 
+   with given pid */
+static
+void report_pid (int pid)
+{
+   char cmdline_file[100];
+   char cmdline[1000];
+   int fd;
+   int i, sz;
+
+   sprintf(cmdline_file, "/proc/%d/cmdline", pid);
+   fd = open (cmdline_file, O_RDONLY);
+   if (fd == -1) {
+      DEBUG(1, "error opening cmdline file %s %s\n", 
+            cmdline_file, strerror(errno));
+      sprintf(cmdline, "(could not obtain process command line)");
+   } else {
+      sz = read(fd, cmdline, 1000);
+      for (i = 0; i < sz; i++)
+         if (cmdline[i] == 0)
+            cmdline[i] = ' ';
+      cmdline[sz] = 0;
+   }  
+   fprintf(stderr, "use --pid=%d for %s\n", pid, cmdline);
+   fflush(stderr);
+}
+
+/* Eventually produces additional usage information documenting the
+   ptrace restrictions. */
+static
+void ptrace_restrictions(void)
+{
+#  ifdef PR_SET_PTRACER
+   char *ptrace_scope_setting_file = "/proc/sys/kernel/yama/ptrace_scope";
+   int fd = -1;
+   char ptrace_scope = 'X';
+   fd = open (ptrace_scope_setting_file, O_RDONLY, 0);
+   if (fd >= 0 && (read (fd, &ptrace_scope, 1) == 1) && (ptrace_scope != '0')) {
+      fprintf (stderr,
+               "Note: your kernel restricts ptrace invoker using %s\n"
+               "vgdb will only be able to attach to a Valgrind process\n"
+               "blocked in a system call *after* an initial successful attach\n",
+               ptrace_scope_setting_file);
+   } else if (ptrace_scope == 'X') {
+      fprintf(stderr, "Could not determine ptrace scope from %s\n",
+              ptrace_scope_setting_file);
+   }
+   if (fd >= 0)
+      close (fd);
+#  endif
+
+#  ifndef PTRACEINVOKER
+   fprintf(stderr, 
+           "Note: ptrace invoker not implemented\n"
+           "For more info: read user manual section"
+           " 'Limitations of the Valgrind gdbserver'\n");
+#  endif
+}
+
+static
+void usage(void)
+{
+   fprintf(stderr,
+"Usage: vgdb [OPTION]... [[-c] COMMAND]...\n"
+"vgdb (valgrind gdb) has two usages\n"
+"  1. standalone to send monitor commands to a Valgrind gdbserver.\n"
+"     The OPTION(s) must be followed by the command to send\n"
+"     To send more than one command, separate the commands with -c\n"
+"  2. relay application between gdb and a Valgrind gdbserver.\n"
+"     Only OPTION(s) can be given.\n"
+"\n"
+" OPTIONS are [--pid=<number>] [--vgdb-prefix=<prefix>]\n"
+"             [--max-invoke-ms=<number>] [--wait=<number>] [-d] -D]\n"
+"  --pid arg must be given if multiple Valgrind gdbservers are found.\n"
+"  --vgdb-prefix arg must be given to both Valgrind and vgdb utility\n"
+"      if you want to change the default prefix for the FIFOs communication\n"
+"      between the Valgrind gdbserver and vgdb.\n"
+"  --wait arg tells vgdb to check during the specified number\n"
+"      of seconds if a Valgrind gdbserver can be found.\n"
+"  --max-invoke-ms gives the nr of milli-seconds after which vgdb will force\n"
+"      the invocation of the Valgrind gdbserver (if the Valgrind process\n"
+"           is blocked in a system call).\n"
+"  -d  arg tells to show debug info. Multiple -d args for more debug info\n"
+"  -D  arg tells to show shared mem status and then exit.\n"
+"\n"
+           );
+   ptrace_restrictions();  
+}
+
+/* If arg_pid == -1, waits maximum check_trials seconds to discover
+   a valgrind pid appearing.
+   Otherwise verify arg_pid is valid and corresponds to a Valgrind process
+   with gdbserver activated.
+
+   Returns the pid to work with
+   or exits in case of error (e.g. no pid found corresponding to arg_pid */
+
+static
+int search_arg_pid(int arg_pid, int check_trials)
+{
+   int i;
+   int pid = -1;
+
+   if (arg_pid == 0 || arg_pid < -1) {
+      fprintf (stderr, "vgdb error: invalid pid %d given\n", arg_pid);
+      exit (1);
+   } else {
+      /* search for a matching named fifo. 
+         If we have been given a pid, we will check that the matching FIFO is
+         there (or wait the nr of check_trials for this to appear).
+         If no pid has been given, then if we find only one FIFO,
+         we will use this to build the pid to use.
+         If we find multiple processes with valid FIFO, we report them and will
+         exit with an error. */
+      DIR *vgdb_dir;
+      char *vgdb_dir_name = vmalloc (strlen (vgdb_prefix) + 3);
+      struct dirent *f;
+      int is;
+      int nr_valid_pid = 0;
+      const char *suffix = "-from-vgdb-to-"; /* followed by pid */
+      char *vgdb_format = vmalloc (strlen(vgdb_prefix) + strlen(suffix) + 1);
+      
+      strcpy (vgdb_format, vgdb_prefix);
+      strcat (vgdb_format, suffix);
+      
+      strcpy (vgdb_dir_name, vgdb_prefix);
+      
+      for (is = strlen(vgdb_prefix) - 1; is >= 0; is--)
+         if (vgdb_dir_name[is] == '/') {
+            vgdb_dir_name[is+1] = '\0';
+            break;
+         }
+      if (strlen(vgdb_dir_name) == 0)
+         strcpy (vgdb_dir_name, "./");
+
+      DEBUG(1, "searching pid in directory %s format %s\n", 
+            vgdb_dir_name, vgdb_format);
+
+      /* try to find FIFOs with valid pid.
+         On exit of the loop, pid is set to:
+         -1 if no FIFOs matching a running process is found
+         -2 if multiple FIFOs of running processes are found
+         otherwise it is set to the (only) pid found that can be debugged
+      */
+      for (i = 0; i < check_trials; i++) {
+         DEBUG(1, "check_trial %d \n", i);
+         if (i > 0)
+           /* wait one second before checking again */
+           sleep(1);
+
+         vgdb_dir = opendir (vgdb_dir_name);
+         if (vgdb_dir == NULL)
+            XERROR (errno, 
+                    "vgdb error: opening directory %s searching vgdb fifo\n", 
+                    vgdb_dir_name);
+      
+         errno = 0; /* avoid complain if vgdb_dir is empty */
+         while ((f = readdir (vgdb_dir))) {
+            struct stat st;
+            char pathname[strlen(vgdb_dir_name) + strlen(f->d_name)];
+            char *wrongpid;
+            int newpid;
+
+            strcpy (pathname, vgdb_dir_name);
+            strcat (pathname, f->d_name);
+            DEBUG(3, "trying %s\n", pathname);
+            if (stat (pathname, &st) != 0) {
+               if (debuglevel >= 3)
+                  ERROR (errno, "vgdb error: stat %s searching vgdb fifo\n", 
+                         pathname);
+            } else if (S_ISFIFO (st.st_mode)) {
+               DEBUG(3, "trying %s\n", pathname);
+               if (strncmp (pathname, vgdb_format, 
+                            strlen (vgdb_format)) == 0) {
+                  newpid = strtol(pathname + strlen (vgdb_format), 
+                                  &wrongpid, 10);
+                  if (*wrongpid == '\0' && newpid > 0 
+                      && kill (newpid, 0) == 0) {
+                     nr_valid_pid++;
+                     if (arg_pid != -1) {
+                        if (arg_pid == newpid) {
+                           pid = newpid;
+                        }
+                     } else if (nr_valid_pid > 1) {
+                        if (nr_valid_pid == 2) {
+                           fprintf 
+                              (stderr, 
+                               "no --pid= arg given"
+                               " and multiple valgrind pids found:\n");
+                           report_pid (pid);
+                        }
+                        pid = -2;
+                        report_pid (newpid);
+                     } else {
+                        pid = newpid;
+                     }
+                  }
+               }
+            }
+            errno = 0; /* avoid complain if at the end of vgdb_dir */
+         }
+         if (f == NULL && errno != 0)
+            XERROR (errno, "vgdb error: reading directory %s for vgdb fifo\n", 
+                    vgdb_dir_name);
+
+         closedir (vgdb_dir);
+         if (pid != -1)
+            break;
+      }
+
+      free (vgdb_dir_name);
+      free (vgdb_format);
+   }
+
+   if (pid == -1) {
+      if (arg_pid == -1)
+         fprintf (stderr, "vgdb error: no FIFO found and no pid given\n");
+      else
+         fprintf (stderr, "vgdb error: no FIFO found matching pid %d\n", 
+                  arg_pid);
+      exit (1);
+   }
+   else if (pid == -2) {
+      /* no arg_pid given, multiple FIFOs found */
+      exit (1);
+   }
+   else {
+      return pid;
+   }
+}
+
+/* return true if the numeric value of an option of the 
+   form --xxxxxxxxx=<number> could properly be extracted
+   from arg. If True is returned, *value contains the
+   extracted value.*/
+static
+Bool numeric_val(char* arg, int *value)
+{
+   const char *eq_pos = strchr(arg, '=');
+   char *wrong;
+
+   if (eq_pos == NULL)
+      return False;
+
+   *value = strtol(eq_pos+1, &wrong, 10);
+   if (*wrong)
+      return False;
+
+   return True;
+}
+
+/* true if arg matches the provided option */
+static
+Bool is_opt(char* arg, char *option)
+{
+   int option_len = strlen(option);
+   if (option[option_len-1] == '=')
+      return (0 == strncmp(option, arg, option_len));
+   else
+      return (0 == strcmp(option, arg));
+}
+
+/* Parse command lines options. If error(s), exits.
+   Otherwise returns the options in *p_... args.
+   commands must be big enough for the commands extracted from argv.
+   On return, *p_last_command gives the position in commands where
+   the last command has been allocated (using vmalloc). */
+static
+void parse_options(int argc, char** argv,
+                   Bool *p_show_shared_mem,
+                   int *p_arg_pid,
+                   int *p_check_trials,
+                   int *p_last_command,
+                   char *commands[])
+{
+   Bool show_shared_mem = False;
+   int arg_pid = -1;
+   int check_trials = 1;
+   int last_command = -1;
+
+   int i;
+   int arg_errors = 0;
+
+   for (i = 1; i < argc; i++) {
+      if (is_opt(argv[i], "--help") || is_opt(argv[i], "-h")) {
+         usage();
+         exit(0);
+      } else if (is_opt(argv[i], "-d")) {
+         debuglevel++;
+      } else if (is_opt(argv[i], "-D")) {
+         show_shared_mem = True;
+      } else if (is_opt(argv[i], "--pid=")) {
+         int newpid;
+         if (!numeric_val(argv[i], &newpid)) {
+            fprintf (stderr, "invalid pid argument %s\n", argv[i]);
+            arg_errors++;
+         } else if (arg_pid != -1) {
+            fprintf (stderr, "multiple pid arguments given\n");
+            arg_errors++;
+         } else {
+            arg_pid = newpid;
+         }
+      } else if (is_opt(argv[i], "--wait=")) {
+         if (!numeric_val(argv[i], &check_trials)) {
+            fprintf (stderr, "invalid wait argument %s\n", argv[i]);
+            arg_errors++;
+         }
+      } else if (is_opt(argv[i], "--max-invoke-ms=")) {
+         if (!numeric_val(argv[i], &max_invoke_ms)) {
+            fprintf (stderr, "invalid max-invoke-ms argument %s\n", argv[i]);
+            arg_errors++;
+         }
+      } else if (is_opt(argv[i], "--vgdb-prefix=")) {
+         vgdb_prefix = argv[i] + 14;
+      } else if (is_opt(argv[i], "-c")) {
+         last_command++;
+         commands[last_command] = vmalloc (1);
+         commands[last_command][0] = '\0';
+      } else if (0 == strncmp(argv[i], "-", 1)) {
+         fprintf (stderr, "unknown or invalid argument %s\n", argv[i]);
+         arg_errors++;
+      } else {
+         int len;
+         if (last_command == -1) {
+            /* only one command, no -c command indicator */
+            last_command++;
+            commands[last_command] = vmalloc (1);
+            commands[last_command][0] = '\0';
+         }
+         len = strlen(commands[last_command]);
+         commands[last_command] = vrealloc (commands[last_command], 
+                                            len + 1 + strlen(argv[i]) + 1);
+         if (len > 0)
+            strcat (commands[last_command], " ");
+         strcat (commands[last_command], argv[i]);
+         if (packet_len_for_command(commands[last_command]) > PBUFSIZ) {
+            fprintf (stderr, "command %s too long\n", commands[last_command]);
+            arg_errors++;
+         }
+            
+      }
+   }
+   if (arg_errors > 0) {
+      fprintf (stderr, "args error. Try `vgdb --help` for more information\n");
+      exit(1);
+   }
+
+   *p_show_shared_mem = show_shared_mem;
+   *p_arg_pid = arg_pid;
+   *p_check_trials = check_trials;
+   *p_last_command = last_command;
+}
+
+int main(int argc, char** argv)
+{
+   int i;
+   int pid;
+
+   Bool show_shared_mem;
+   int arg_pid;
+   int check_trials;
+   int last_command;
+   char *commands[argc]; // we will never have more commands than args.
+
+   parse_options(argc, argv,
+                 &show_shared_mem,
+                 &arg_pid,
+                 &check_trials,
+                 &last_command,
+                 commands);
+  
+   /* when we are working as a relay for gdb, handle some signals by
+      only reporting them (according to debug level). Also handle these
+      when ptrace will be used: vgdb must clean up the ptrace effect before
+      dying. */
+   if (max_invoke_ms > 0 || last_command == -1)
+      install_handlers();
+
+   pid = search_arg_pid (arg_pid, check_trials);
+
+   prepare_fifos_and_shared_mem(pid);
+
+   if (show_shared_mem) {
+      fprintf(stderr, 
+              "vgdb %d "
+              "written_by_vgdb %d "
+              "seen_by_valgrind %d\n"
+              "vgdb pid %d\n",
+              VS_vgdb_pid,
+              VS_written_by_vgdb,
+              VS_seen_by_valgrind,
+              VS_vgdb_pid);
+      exit (0);
+   }
+
+   if (last_command >= 0) {
+      standalone_send_commands(pid, last_command, commands);
+   } else {
+      gdb_relay(pid);
+   }
+      
+
+   free (from_gdb_to_pid);
+   free (to_gdb_from_pid);
+   free (shared_mem);
+
+   for (i = 0; i <= last_command; i++)
+      free (commands[i]);
+   return 0;
+}
index 0fb6c9d33423a3a29fce6056c8a072f7b63c4350..acc8f73c761cb4a1ef86fa7b25034338f5731c5e 100644 (file)
@@ -720,6 +720,49 @@ in most cases.  We group the available options by rough categories.</para>
     </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.vgdb" xreflabel="--vgdb">
+    <term>
+      <option><![CDATA[--vgdb=<no|yes|full> [default: yes] ]]></option>
+    </term>
+    <listitem>
+      <para>Valgrind will enable its embedded gdbserver if value yes
+      or full is given. This allows an
+      external <computeroutput>gdb</computeroutput> debuggger to debug
+      your program running under Valgrind. See
+      <xref linkend="manual-core.gdbserver"/> for a detailed
+      description.
+      </para>
+
+      <para> If the embedded gdbserver is enabled but no gdb is
+      currently being used, the <xref linkend="manual-core.vgdb"/>
+      command line utility can send "monitor commands" to Valgrind
+      from a shell.  The Valgrind core provides a set of
+      <xref linkend="manual-core.valgrind-monitor-commands"/>. A tool
+      can optionally provide tool specific monitor commands, which are
+      documented in the tool specific chapter.
+      </para>
+
+      <para>The value 'full' has a significant overhead 
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry id="opt.vgdb-error" xreflabel="--vgdb-error">
+    <term>
+      <option><![CDATA[--vgdb-error=<number> [default: 999999999] ]]></option>
+    </term>
+    <listitem>
+      <para> Use this option when the Valgrind gdbserver is enabled with
+      <option>--vgdb</option> yes or full value.  Tools that report
+      errors will invoke the embedded gdbserver for each error above
+      number. The value 0 will cause gdbserver to be invoked before
+      executing your program. This is typically used to insert gdb
+      breakpoints before execution, and will also work with tools that
+      do not report errors, such as Massif.
+      </para>
+    </listitem>
+  </varlistentry>
+
   <varlistentry id="opt.track-fds" xreflabel="--track-fds">
     <term>
       <option><![CDATA[--track-fds=<yes|no> [default: no] ]]></option>
@@ -1140,6 +1183,13 @@ that can report errors, e.g. Memcheck, but not Cachegrind.</para>
       debugger, quit from it, and the program will continue. Trying to
       continue from inside the debugger doesn't work.</para>
 
+      <para>
+      Note : if you use gdb, a more powerful debugging support is
+      provided by the <option>--vgdb</option> yes or full value,
+      allowing among others to insert breakpoints, continue from
+      inside the debugger, etc.
+      </para> 
+
       <para><varname>C Ret</varname> or <varname>c Ret</varname> causes
       Valgrind not to start a debugger, and not to ask again.</para>
     </listitem>
@@ -1473,6 +1523,57 @@ need to use these.</para>
     </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.vgdb-poll" xreflabel="--vgdb-poll">
+    <term>
+      <option><![CDATA[--vgdb-poll=<number> [default: 5000] ]]></option>
+    </term>
+    <listitem>
+      <para> As part of its main loop, the Valgrind scheduler will
+      poll to check if some activity (such as an external command or
+      some input from a gdb) has to be handled by gdbserver.  This
+      activity poll will be done after having run the given number of
+      basic blocks (or slightly more than the given number of basic
+      blocks). This poll is quite cheap so the default value is set
+      relatively low. You might further decrease this value if vgdb
+      cannot use ptrace system call to interrupt Valgrind if all
+      threads are (most of the time) blocked in a system call.
+      </para>
+      <para> GDBTD??? unclear why we have sometimes slightly more BB:
+      it seems that from time to time, some BB are run outside of
+      run_thread_for_a_while.  Maybe this is due to block chasing ?  I
+      do not think this is a problem, as I never saw more than a few
+      additional basic blocks being run without being visible in the
+      blocks executed by run_thread_for_a_while.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry id="opt.vgdb-shadow-registers" xreflabel="--vgdb-shadow-registers">
+    <term>
+      <option><![CDATA[--vgdb-shadow-registers=no|yes [default: no] ]]></option>
+    </term>
+    <listitem>
+      <para> When activated, gdbserver will expose the Valgrind shadow registers
+      to gdb. With this, the value of the Valgrind shadow registers can be examined
+      or changed using gdb. Exposing shadows registers only works with a gdb version
+      &gt;= 7.1.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry id="opt.vgdb-prefix" xreflabel="--vgdb-prefix">
+    <term>
+      <option><![CDATA[--vgdb-prefix=<prefix> [default: /tmp/vgdb-pipe] ]]></option>
+    </term>
+    <listitem>
+      <para> To communicate with gdb/vgdb, the Valgrind gdbserver
+      creates 3 files (2 named FIFOs and a mmap shared memory
+      file). The prefix option controls the directory and prefix for
+      the creation of these files.
+      </para>
+    </listitem>
+  </varlistentry>
+
   <varlistentry id="opt.run-libc-freeres" xreflabel="--run-libc-freeres">
     <term>
       <option><![CDATA[--run-libc-freeres=<yes|no> [default: yes] ]]></option>
@@ -1630,6 +1731,13 @@ need to use these.</para>
 Valgrind itself.  You shouldn't need to use them in the normal run of
 things.  If you wish to see the list, use the
 <option>--help-debug</option> option.</para>
+
+<para>If you wish to debug your program rather than debugging
+Valgrind itself, then you should use the options
+<option>--vgdb=yes</option> or <option>--vgdb=full</option>
+or <option>--db-attach=yes</option>.
+</para>
+
 <!-- end of xi:include in the manpage -->
 
 </sect2>
@@ -1692,7 +1800,869 @@ don't understand
 </sect1>
 
 
+<sect1 id="manual-core.gdbserver" 
+       xreflabel="Debugging your program using Valgrind gdbserver and gdb">
+<title>Debugging your program using Valgrind gdbserver and gdb</title>
+
+<para>A program running under Valgrind is not executed directly by the
+CPU.  It rather runs on a synthetic CPU provided by Valgrind. This is
+why a debugger cannot debug your program under Valgrind the usual way.
+</para>
+<para>
+This section describes the special way gdb can interact with the
+Valgrind gdbserver to provide a fully debuggable program under
+Valgrind. Used in this way, gdb also provides an interactive usage of
+Valgrind core or tool functionalities (such as incremental leak search
+under Memcheck, on-demand Massif snapshot production, ...).
+</para>
+
+<sect2 id="manual-core.gdbserver-simple"
+       xreflabel="gdbserver simple example">
+<title>Quick Start : debugging in 3 steps</title>
+
+<para>If you want to debug a program with gdb when using Memcheck
+tool, start Valgrind the following way:
+<screen><![CDATA[
+valgrind --vgdb=yes --vgdb-error=0 prog
+]]></screen></para>
+
+<para>In another window, start a gdb the following way:
+<screen><![CDATA[
+gdb prog
+]]></screen></para>
+
+<para>Then give the following command to gdb:
+<screen><![CDATA[
+(gdb) target remote | vgdb
+]]></screen></para>
+
+<para>You can now debug your program e.g. by inserting a breakpoint
+and then using the gdb 'continue' command.</para>
+
+<para> The above quick start is enough for a basic usage of the
+Valgrind gdbserver. Read the sections below to learn about the
+advanced functionalities provided by the combination of Valgrind and
+gdb. Note that the option --vgdb=yes can be omitted, as this is the
+default value.
+</para>
+
+</sect2>
+
+<sect2 id="manual-core.gdbserver-concept"
+       xreflabel="gdbserver">
+<title>Valgrind gdbserver concept</title>
+<para>The gdb debugger is typically used to debug a process running on
+the same machine : gdb uses system calls to do actions such as read
+the values of the process variables or registers. This technique only
+allows gdb to debug a program running on the same computer.
+</para>
+
+<para>Gdb can also debug processes running on a different computer.
+For this, gdb defines a protocol (i.e. a set of query and reply
+packets) that allows to e.g. fetch the value of memory or registers,
+to set breakpoints, etc.  A gdbserver is an implementation of this
+'gdb remote debugging' protocol. To debug a process running on a
+remote computer, a gdbserver (sometimes also called a gdb stub) must
+run at the remote computer side.
+</para>
+
+<para>The Valgrind core integrates an embedded gdbserver
+implementation, which is activated using <option>--vgdb=yes</option>
+or <option>--vgdb=full</option>. This gdbserver allows the process
+running on the Valgrind synthetic CPU to be debugged 'remotely' by gdb
+: gdb sends protocol query packets (such as 'get registers values') to
+the Valgrind embedded gdbserver.  The embedded gdbserver executes the
+queries (for example, it will get the registers values of the
+synthetic CPU) and give the result back to gdb.
+</para>
+
+<para> Gdb can use various ways (tcp/ip, serial line, ...) to send and
+receive the remote protocol packets to a gdbserver. In the case of the
+Valgrind gdbserver, gdb communicates using a pipe and the
+<xref linkend="manual-core.vgdb"/> command as a relay application.  If
+no gdb is currently being used, vgdb can also be used to send monitor
+commands to the Valgrind gdbserver from the shell command line.
+</para>
+
+</sect2>
+
+<sect2 id="manual-core.gdbserver-gdb"
+       xreflabel="Connecting gdb to a Valgrind gdbserver">
+<title>Connecting gdb to a Valgrind gdbserver</title>
+<para>To debug a program <filename>prog</filename> running under
+Valgrind, ensures that the Valgrind gdbserver is activated
+(i.e. --vgdb=yes or --vgdb=full). The option
+<![CDATA[--vgdb-error=<number> ]]> can be used to ask an invocation of
+the gdbserver for each error above number.  A zero value will cause an
+invocation of the Valgrind gdbserver at startup, allowing to insert
+breakpoints before starting the execution.  Example:
+<screen><![CDATA[
+valgrind --tool=memcheck --vgdb=yes --vgdb-error=0 ./prog
+]]></screen></para>
+
+<para>With the above command, the Valgrind gdbserver is invoked at startup
+and indicates it is waiting for a connection from a gdb:</para>
+
+<programlisting><![CDATA[
+==2418== Memcheck, a memory error detector
+==2418== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
+==2418== Using Valgrind-3.7.0.SVN and LibVEX; rerun with -h for copyright info
+==2418== Command: ./prog
+==2418== 
+==2418== (action at startup) vgdb me ... 
+]]></programlisting>
+
+
+<para>A gdb in another window can then be connected to the Valgrind gdbserver.
+For this, gdb must be started on the program <filename>prog</filename>:
+<screen><![CDATA[
+gdb ./prog
+]]></screen></para>
+
+
+<para>You then indicate to gdb that a remote target debugging is to be done:
+<screen><![CDATA[
+(gdb) target remote | vgdb
+]]></screen>
+gdb then starts a vgdb relay application to communicate with the 
+Valgrind embedded gdbserver:</para>
+
+<programlisting><![CDATA[
+(gdb) target remote | vgdb
+Remote debugging using | vgdb
+relaying data between gdb and process 2418
+Reading symbols from /lib/ld-linux.so.2...done.
+Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so.debug...done.
+Loaded symbols for /lib/ld-linux.so.2
+[Switching to Thread 2418]
+0x001f2850 in _start () from /lib/ld-linux.so.2
+(gdb) 
+]]></programlisting>
+
+<para> In case vgdb detects that multiple Valgrind gdbserver can be connected
+to, it will exit after reporting the list of the debuggable Valgrind
+processes and their PIDs. You can then relaunch the gdb 'target' command, but
+specifying the process id of the process you want to debug:
+</para>
+
+<programlisting><![CDATA[
+(gdb) target remote | vgdb
+Remote debugging using | vgdb
+no --pid= arg given and multiple valgrind pids found:
+use --pid=2479 for valgrind --tool=memcheck --vgdb=yes --vgdb-error=0 ./prog 
+use --pid=2481 for valgrind --tool=memcheck --vgdb=yes --vgdb-error=0 ./prog 
+use --pid=2483 for valgrind --vgdb=yes --vgdb-error=0 ./another_prog 
+Remote communication error: Resource temporarily unavailable.
+(gdb)  target remote | vgdb --pid=2479
+Remote debugging using | vgdb --pid=2479
+relaying data between gdb and process 2479
+Reading symbols from /lib/ld-linux.so.2...done.
+Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so.debug...done.
+Loaded symbols for /lib/ld-linux.so.2
+[Switching to Thread 2479]
+0x001f2850 in _start () from /lib/ld-linux.so.2
+(gdb) 
+]]></programlisting>
+
+<para>Once gdb is connected to the Valgrind gdbserver, gdb can be used
+similarly to a native debugging session:</para>
+ <itemizedlist>
+  <listitem>
+    <para> Breakpoints can be inserted or deleted. </para>
+  </listitem>
+  <listitem>
+    <para> Variables and registers values can be examined or modified.
+    </para>
+  </listitem>
+  <listitem>
+    <para> Signal handling can be configured (printing, ignoring, ...).
+    </para>
+  </listitem>
+  <listitem>
+    <para> Execution can be controlled (continue, step, next, stepi, ...).
+    </para>
+  </listitem>
+  <listitem>
+    <para> Program execution can be interrupted using Control-C. </para>
+  </listitem>
+  <listitem>
+    <para> ... </para>
+  </listitem>
+ </itemizedlist>
+
+<para> Refer to the gdb user manual for a complete list of gdb functionalities.
+</para>
+
+</sect2>
+
+<sect2 id="manual-core.gdbserver-commandhandling"
+       xreflabel="Monitor command handling by the Valgrind gdbserver">
+<title>Monitor command handling by the Valgrind gdbserver</title>
+
+<para> The Valgrind gdbserver provides a set of additional specific
+functionalities through "monitor commands". Such monitor commands can
+be sent from the gdb command line or from the shell command line. See
+<xref linkend="manual-core.valgrind-monitor-commands"/> for the list
+of the Valgrind core monitor commands.
+</para>
+
+<para> Each tool can also provide tool specific monitor commands. An
+example of a tool specific monitor command is the Memcheck monitor
+command <computeroutput>mc.leak_check any full
+reachable</computeroutput>.  This requests a full reporting of the
+allocated memory blocks. To have this leak check executed, use the gdb
+command:
+<screen><![CDATA[
+(gdb) monitor mc.leak_check any full reachable
+]]></screen>
+</para>
+
+<para> gdb will send the mc.leak_check command to the Valgrind gdbserver. The
+Valgrind gdbserver will either execute the monitor command itself (if
+it recognises a Valgrind core monitor command) or let the tool execute the
+tool specific monitor commands:
+</para>
+<programlisting><![CDATA[
+(gdb) monitor mc.leak_check any full reachable
+==2418== 100 bytes in 1 blocks are still reachable in loss record 1 of 1
+==2418==    at 0x4006E9E: malloc (vg_replace_malloc.c:236)
+==2418==    by 0x804884F: main (prog.c:88)
+==2418== 
+==2418== LEAK SUMMARY:
+==2418==    definitely lost: 0 bytes in 0 blocks
+==2418==    indirectly lost: 0 bytes in 0 blocks
+==2418==      possibly lost: 0 bytes in 0 blocks
+==2418==    still reachable: 100 bytes in 1 blocks
+==2418==         suppressed: 0 bytes in 0 blocks
+==2418== 
+(gdb) 
+]]></programlisting>
+
+<para> Like for the gdb commands, the Valgrind gdbserver will accept
+abbreviated monitor command names and arguments, as long as the given
+abbreviation is non ambiguous. For example, the above mc.leak_check
+command can also be typed as:
+<screen><![CDATA[
+(gdb) mo mc.l a f r
+]]></screen>
+
+The letters <computeroutput>mo</computeroutput> are recognised by gdb as being
+<computeroutput>monitor</computeroutput>.  So, gdb sends the
+string <computeroutput>mc.l a f r</computeroutput> to the Valgrind
+gdbserver. The letters provided in this string are unambiguous for the
+Valgrind gdbserver.  So, this will give the same output as the non
+abbreviated command and arguments. If the provided abbreviation is
+ambiguous, the Valgrind gdbserver will report the list of commands (or
+argument values) that can match:
+<programlisting><![CDATA[
+(gdb) mo mc. a r f
+mc. can match mc.get_vbits mc.leak_check mc.make_memory mc.check_memory
+(gdb) 
+]]></programlisting>
+</para>
+
+<para> Instead of sending a monitor command from gdb, you can also
+send these from a shell command line. For example, the below command lines
+given in a shell will cause the same leak search to be executed by the
+process 3145:
+<screen><![CDATA[
+vgdb --pid=3145 mc.leak_check any full reachable
+vgdb --pid=3145 mc.l a f r
+]]></screen></para>
+
+<para>Note that the Valgrind gdbserver automatically continues the
+execution of the program after a standalone invocation of
+vgdb. Monitor commands sent from gdb do not cause the program to
+continue: the program execution is controlled explicitely using gdb
+commands such as 'continue' or 'next'.</para>
+
+</sect2>
+
+<sect2 id="manual-core.gdbserver-threads"
+       xreflabel="Valgrind gdbserver thread info">
+<title>Valgrind gdbserver thread info</title>
+
+<para> The Valgrind gdbserver enriches the output of the
+gdb <computeroutput>info threads</computeroutput> with Valgrind
+specific information. The operating system thread number is followed
+by the Valgrind 'tid' and the Valgrind scheduler thread state:</para>
+
+<programlisting><![CDATA[
+(gdb) info threads
+  4 Thread 6239 (tid 4 VgTs_Yielding)  0x001f2832 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
+* 3 Thread 6238 (tid 3 VgTs_Runnable)  make_error (s=0x8048b76 "called from London") at prog.c:20
+  2 Thread 6237 (tid 2 VgTs_WaitSys)  0x001f2832 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
+  1 Thread 6234 (tid 1 VgTs_Yielding)  main (argc=1, argv=0xbedcc274) at prog.c:105
+(gdb) 
+]]></programlisting>
+
+</sect2>
+
+<sect2 id="manual-core.gdbserver-shadowregisters"
+       xreflabel="Examining and modifying Valgrind shadow registers">
+<title>Examining and modifying Valgrind shadow registers</title>
+
+<para> When the option <![CDATA[--vgdb-shadow-registers=yes ]]> is
+given, the Valgrind gdbserver will let gdb examine and/or modify the
+Valgrind shadow registers. A gdb version &gt;= 7.1 is needed for this
+to work.</para>
+
+<para> For each CPU register, the Valgrind core maintains two
+shadow registers. These shadow registers can be accessed from
+gdb by giving a postfix s1 or s2 for respectively the first
+and second shadow registers. As an example, the x86 register
+<computeroutput>eax</computeroutput> and its two shadow
+registers can be examined using the following commands:</para>
+
+<programlisting><![CDATA[
+(gdb) p $eax
+$1 = 0
+(gdb) p $eaxs1
+$2 = 0
+(gdb) p $eaxs2
+$3 = 0
+(gdb) 
+]]></programlisting>
+
+</sect2>
+
 
+<sect2 id="manual-core.gdbserver-limitations"
+       xreflabel="Limitations of the Valgrind gdbserver">
+<title>Limitations of the Valgrind gdbserver</title>
+
+<para>Debugging with the Valgrind gdbserver is very similar to native
+debugging. The implementation of the Valgrind gdbserver is quite
+complete, and so provides most of the gdb debugging facilities. There
+are however some limitations or particularities described in details
+in this section:</para>
+ <itemizedlist>
+   <listitem>
+     <para> Precision of 'stopped at instruction'.</para>
+     <para>Gdb commands such as 'step', 'next', 'stepi', breakpoints,
+     watchpoints, ... will stop the execution of the process.  With
+     the option --vgdb=yes, the process might not stop at the exact
+     instruction needed. Instead, it might continue execution of the
+     current block and stop at one of the following blocks. This is
+     linked to the fact that Valgrind gdbserver has to instrument a
+     block to allow stopping at the exact instruction requested.
+     Currently, re-instrumenting the current block being executed is
+     not supported. So, if the action requested by gdb (e.g. single
+     stepping or inserting a breakpoint) implies to re-instrument the
+     current block, the gdb action might not be executed precisely.
+     </para>
+     <para> This limitation will be triggered when the current block
+     being executed has not (yet) been instrumented for debugging.
+     This typically happens when the gdbserver is activated due to the
+     tool reporting an error or to a watchpoint. If the gdbserver
+     block has been activated following a breakpoint (or if a
+     breakpoint has been inserted in the block before its execution),
+     then the block has already been instrumented for debugging.
+     </para>
+     <para> If you use the option --vgdb=full, then gdb 'stop actions'
+     will always be obeyed precisely, but this implies that each
+     instruction will be instrumented with an additional call to a
+     gdbserver helper function, which implies some overhead compared
+     to --vgdb=no. Option --vgdb=yes has neglectible overhead compared
+     to --vgdb=no.
+     </para>
+   </listitem>
+
+   <listitem>
+     <para>Hardware watchpoint support by the Valgrind
+     gdbserver.</para>
+
+     <para> The Valgrind gdbserver can simulate hardware watchpoints
+     (but only if the tool provides the support for this). Currently,
+     only Memcheck provides hardware watchpoint simulation. The
+     hardware watchpoint simulation provided by Memcheck is much
+     faster that gdb software watchpoints (which are implemented by
+     gdb checking the value of the watched zone(s) after each
+     instruction). Hardware watchpoint simulation also provides read
+     watchpoints.  The hardware watchpoint simulation by Memcheck has
+     some limitations compared to the real hardware
+     watchpoints. However, the number and length of simulated
+     watchpoints are not limited.
+     </para>
+     <para> Typically, the number of (real) hardware watchpoint is
+     limited.  For example, the x86 architecture supports a maximum of
+     4 hardware watchpoints, each watchpoint watching 1, 2, 4 or 8
+     bytes. The Valgrind gdbserver does not have a limitation on the
+     number of simulated hardware watchpoints. It also has no
+     limitation on the length of the memory zone being
+     watched. However, gdb currently does not (yet) understand that
+     Valgrind gdbserver watchpoints have no length limit.  A gdb patch
+     providing a command 'set remote hardware-watchpoint-length-limit'
+     has been developped. The integration of this patch in gdb would
+     allow to fully use the flexibility of the Valgrind gdbserver
+     simulated hardware watchpoints (is there a gdb developper reading
+     this ?).
+     </para>
+     <para> Memcheck implements hardware watchpoint simulation by
+     marking the watched zone(s) as being unaddressable. In case a
+     hardware watchpoint is removed, the zone is marked as addressable
+     and defined.  Hardware watchpoint simulation of addressable
+     undefined memory zones will properly work, but will have as a
+     side effect to mark the zone as defined when the watchpoint is
+     removed.</para>
+     <para> Write watchpoints might not be reported at the instruction
+     which is modifying the value unless option --vgdb=full is
+     given. Read watchpoints will always be reported at the exact
+     instruction reading the watched memory.</para>
+     <para> It is better to avoid using hardware watchpoint of not
+     addressable (yet) memory: in such a case, gdb will fallback to
+     extremely slow software watchpoints. Also, if you do not quit gdb
+     between two debugging sessions, the hardware watchpoints of the
+     previous sessions will be re-inserted as software watchpoints if
+     the watched memory zone is not addressable at program startup.
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> Stepping inside shared libraries on ARM.</para>
+     <para> For a not (yet?) clear reason, stepping inside a shared
+     library on ARM might fail. The bypass is to use the ldd command
+     to find the list of shared libraries and their loading address
+     and inform gdb of the loading address using the gdb command
+     'add-symbol-file'. Example (for a ./p executable):
+     <programlisting><![CDATA[
+(gdb) shell ldd ./p
+       libc.so.6 => /lib/libc.so.6 (0x4002c000)
+       /lib/ld-linux.so.3 (0x40000000)
+(gdb) add-symbol-file /lib/libc.so.6 0x4002c000
+add symbol table from file "/lib/libc.so.6" at
+       .text_addr = 0x4002c000
+(y or n) y
+Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
+(gdb) 
+]]></programlisting>
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> gdb version needed for ARM and PPC32/64.</para>
+     <para> You must use a gdb version which is able to read XML
+     target description sent by gdbserver (this is the standard setup
+     if the gdb was configured on a computer with the expat
+     library). If your gdb was not configured with XML support, it
+     will report an error message when using the target
+     command. Debugging will not work because gdb will then not be
+     able to fetch the registers from the Valgrind gdbserver.
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> Stack unwinding on PPC32/PPC64. </para>
+     <para> On PPC32/PPC64, stack unwinding for leaf functions
+     (i.e. functions not calling other functions) does work properly
+     only with <option>--vex-iropt-precise-memory-exns=yes</option>
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> Breakpoint encountered multiple times. </para>
+     <para> Some instructions (e.g. the x86 "rep movsb")
+     are translated by Valgrind using a loop. If a breakpoint is placed
+     on such an instruction, the breakpoint will be encountered
+     multiple times (i.e. once for each step of the "implicit" loop
+     implementing the instruction).
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> Execution of Inferior function calls by the Valgrind
+     gdbserver. </para>
+
+     <para> gdb allows the user to "call" functions inside the process
+     being debugged. Such calls are named 'Inferior calls' in the gdb
+     terminology.  A typical usage of an 'Inferior call' is to execute
+     a function that outputs a readable image of a complex data
+     structure. To make an Inferior call, use the gdb 'print' command
+     followed by the function to call and its arguments. As an
+     example, the following gdb command causes an Inferior call to the
+     libc printf function to be executed by (and inside) the process
+     being debugged:
+     </para>
+     <programlisting><![CDATA[
+(gdb) p printf("process being debugged has pid %d\n", getpid())
+$5 = 36
+(gdb) 
+]]></programlisting>
+
+     <para>The Valgrind gdbserver accepts Inferior function
+     calls. During Inferior calls, the Valgrind tool will report
+     errors as usual. If you do not want to have such errors stopping
+     the execution of the Inferior call, you can use 'vg.set
+     vgdb-error' to set a big value before the call, and reset the
+     value after the Inferior call.</para>
+
+     <para>To execute Inferior calls, gdb changes registers such as
+     the program counter, and then continues the execution of the
+     program. In a multi-thread program, all threads are continued,
+     not only the thread instructed to make an Inferior call. If
+     another thread reports an error or encounters a break, the
+     evaluation of the Inferior call is abandonned.</para>
+
+     <para> Note that Inferior function calls is a powerful gdb
+     functionality but it has to be used with caution. For example, if
+     the program being debugged is stopped inside the function printf,
+     'forcing' a recursive call to printf via an Inferior call will
+     very probably create problems. The Valgrind tool might also add
+     another level of complexity to Inferior calls, e.g. by reporting
+     tool errors during the Inferior call or due to the
+     instrumentation done.
+     </para>
+
+   </listitem>
+
+   <listitem>
+     <para>Connecting to or interrupting a Valgrind process blocked in
+     a system call.</para>
+
+     <para> Connecting to or interrupting a Valgrind process blocked
+     in a system call is depending on ptrace system call, which might
+     be disabled on your kernel. </para>
+
+     <para> At regular interval, after having executed some basic
+     blocks, the Valgrind scheduler checks if some input is to be
+     handled by the Valgrind gdbserver. However, this check is only
+     done if at least one thread of the process is executing (enough)
+     basic blocks.  If all the threads of the process are blocked in a
+     system call, then no basic blocks are being executed, and the
+     Valgrind scheduler will not invoke the Valgrind gdbserver.  In
+     such a case, the vgdb relay application will 'force' the Valgrind
+     gdbserver to be invoked, without the intervention of the Valgrind
+     scheduler.
+     </para>
+
+     <para> Such forced invocation of the Valgrind gdbserver is
+     implemented by vgdb using ptrace system calls. On a properly
+     implemented kernel, the ptrace calls done by vgdb will not
+     influence the behaviour of the program running under Valgrind. In
+     case of unexpected impact, giving the option --max-invoke-ms=0 to
+     the vgdb relay application will disable the usage of ptrace
+     system call. The consequence of disabling ptrace system call in
+     vgdb is that a Valgrind process blocked in a system call cannot
+     be waken up or interrupted from gdb till it executes (enough)
+     basic blocks to let the scheduler poll invoke the gdbserver..
+     </para>
+     <para>When ptrace is disabled in vgdb, you might increase the
+     responsiveness of the Valgrind gdbserver to commands or
+     interrupts by giving a lower value to the option --vgdb-poll: if
+     your application is most of the time blocked in a system call,
+     using a very low value for vgdb-poll will cause a faster
+     invocation of gdbserver. As the gdbserver poll done by the
+     scheduler is very efficient, the more frequent check by the
+     scheduler should not cause significant performance degradation.
+     </para>
+     <para>When ptrace is disabled in vgdb, a query packet sent by gdb
+     might take a significant time to be handled by the Valgrind
+     gdbserver.  In such a case, gdb might encounter a protocol
+     timeout.  To avoid having gdb encountering such a timeout error,
+     you can increase the value of this timeout by using the gdb
+     command 'set remotetimeout'.
+     </para>
+
+     <para> Ubuntu version &gt;= 10.10 can also restrict the scope of
+     ptrace to the children of the process calling ptrace. As the
+     Valgrind process is not a child of vgdb, such restricted scope
+     causes ptrace system call to fail.  To avoid that, when Valgrind
+     gdbserver receives the first packet from a vgdb, it calls
+     prctl(PR_SET_PTRACER, vgdb_pid, 0, 0, 0) to ensure vgdb can use
+     ptrace. Once vgdb_pid has been set as ptracer, vgdb can then
+     properly force the invocation of Valgrind gdbserver when
+     needed. To ensure the vgdb is set as ptracer before the Valgrind
+     process could be blocked in a system call, connect your gdb to
+     the Valgrind gdbserver at startup (i.e. use --vgdb-error=0).
+     Note that this 'set ptracer' is not solving the problem for the
+     connection of a standalone vgdb: the first command to be sent by
+     a standalone vgdb must wake up the Valgrind process before
+     Valgrind gdbserver will set vgdb as ptracer.
+     </para>
+
+     <para> Unblocking a process blocked in a system call is
+     not implemented on Darwin. So, waiting for vgdb on Darwin to
+     be enhanced, you cannot connect/interrupt a process blocked
+     in a system call on Darwin.
+     </para>
+
+   </listitem>
+
+   <listitem>
+     <para> Changing registers of a thread.</para>
+     <para> The Valgrind gdbserver only accepts to modify the values
+     of the registers of a thread when the thread is in status
+     Runnable or Yielding. In other states (typically, WaitSys), changing
+     registers values will not be accepted. This among others ensures
+     that Inferior calls are not executed for a thread which is in a
+     system call : the Valgrind gdbserver does not implement system
+     call restart.
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> gdb functionalities not supported.</para>
+     <para> gdb provides an awful lot of debugging functionalities.
+     At least the following are not supported: reversible debugging,
+     tracepoints.
+     </para>
+   </listitem>
+
+   <listitem>
+     <para> Unknown limitations or problems.</para>
+     <para> The combination of gdb, Valgrind and the Valgrind
+     gdbserver has for sure some still unknown other
+     limitations/problems but we do not know about these unknown
+     limitations/problems :).  If you encounter such (annoying)
+     limitations or problems, feel free to report a bug.  But first
+     verify if the limitation or problem is not inherent to gdb or the
+     gdb remote protocol e.g. by checking the behaviour with the
+     standard gdbserver part of the gdb package.
+     </para>
+   </listitem>
+
+ </itemizedlist>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="manual-core.vgdb"
+       xreflabel="vgdb">
+<title>vgdb command line options</title>
+<para> Usage: vgdb [OPTION]... [[-c] COMMAND]...</para>
+
+<para> vgdb (Valgrind to gdb) has two usages:</para>
+<orderedlist>
+  <listitem id="manual-core.vgdb-standalone" xreflabel="vgdb standalone">
+    <para>As a standalone utility, it is used from a shell command
+    line to send monitor commands to a process running under
+    Valgrind. For this usage, the vgdb OPTION(s) must be followed by
+    the monitor command to send. To send more than one command,
+    separate them with the -c option.
+    </para>
+  </listitem>
+
+  <listitem id="manual-core.vgdb-relay" xreflabel="vgdb relay">
+    <para>In combination with gdb 'target remote |' command, it is
+    used as the relay application between gdb and the Valgrind
+    gdbserver.  For this usage, only OPTION(s) can be given, no
+    command can be given.
+    </para>
+  </listitem>
+
+</orderedlist>
+
+<para><computeroutput>vgdb</computeroutput> accepts the following
+options:</para>
+<itemizedlist>
+  <listitem>
+    <para><option>--pid=&lt;number&gt;</option>: specifies the pid of
+    the process to which vgdb must connect to. This option is useful
+    in case more than one Valgrind gdbserver can be connected to. If
+    --pid argument is not given and multiple Valgrind gdbserver
+    processes are running, vgdb will report the list of such processes
+    and then exit.</para>
+  </listitem>
+
+  <listitem>
+    <para><option>--vgdb-prefix</option> must be given to both
+    Valgrind and vgdb utility if you want to change the default prefix
+    for the FIFOs communication between the Valgrind gdbserver and
+    vgdb. </para>
+  </listitem>
+
+  <listitem>
+    <para><option>--max-invoke-ms=&lt;number&gt;</option> gives the
+    number of milli-seconds after which vgdb will force the invocation
+    of gdbserver embedded in valgrind. Default value is 100
+    milli-seconds. A value of 0 disables the forced invocation.
+    </para>
+
+    <para>If you specify a big value here, you might need to increase
+    the gdb remote timeout. The default value of the gdb remotetimeout
+    is 2 seconds. You should ensure that the gdb remotetimeout (in
+    seconds) is bigger than the max-invoke-ms value. For example, for
+    a 5000 --max-invoke-ms, the following gdb command will set a value
+    big enough:
+    <screen><![CDATA[
+    (gdb) set remotetimeout 6
+    ]]></screen>
+    </para>
+  </listitem>
+   
+  <listitem>
+    <para><option>--wait=&lt;number&gt;</option> instructs vgdb to
+    check during the specified number of seconds if a Valgrind
+    gdbserver can be found. This allows to start a vgdb before the
+    Valgrind gdbserver is started. This option will be more useful in
+    combination with a --vgdb-prefix unique for the process you want
+    to wait for. Also, if you use the --wait argument in the gdb
+    'target remote' command, you must set the gdb remotetimeout to a
+    value bigger than the --wait argument value. See option
+    --max-invoke-ms for an example of setting this remotetimeout
+    value.</para>
+  </listitem>
+
+  <listitem>
+    <para><option>-c</option> To give more than one command, separate
+    the commands by an option -c. Example:
+    <screen><![CDATA[
+vgdb vg.set log_output -c mc.leak_check any
+]]></screen></para>
+  </listitem>  
+
+  <listitem>
+    <para><option>-d</option> instructs vgdb to produce debugging
+    output.  Give multiple -d args for more debug info.</para>
+  </listitem>
+  
+  <listitem>
+    <para><option>-D</option> instructs vgdb to show the state of the
+    shared memory used by the Valgrind gdbserver. vgdb will exit after
+    having shown the Valgrind gdbserver shared memory state.</para>
+  </listitem>
+</itemizedlist>
+</sect1>
+
+
+<sect1 id="manual-core.valgrind-monitor-commands" 
+       xreflabel="Valgrind monitor commands">
+<title>Valgrind monitor commands</title>
+
+<para>The Valgrind monitor commands are available whatever the
+tool. They can be sent either from a shell command line (using a
+standalone vgdb) or from gdb (using the gdb 'monitor' command).</para>
+
+<itemizedlist>
+  <listitem>
+    <para><varname>help [debug]</varname> instructs Valgrind gdbserver
+    to give the list of all monitor commands of the Valgrind core and
+    of the tool. The optional 'debug' argument tells to also give help
+    for the monitor commands aimed at Valgrind internals debugging.
+    </para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.info all_errors</varname> shows all errors found
+    so far.</para>
+  </listitem>
+  <listitem>
+    <para><varname>vg.info last_error</varname> shows the last error
+    found.</para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.info n_errs_found</varname> shows the nr of
+    errors found so far and the current value of the --vgdb-error
+    argument.</para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.set {gdb_output | log_output |
+    mixed_output}</varname> allows to redirect the Valgrind output
+    (e.g. the errors detected by the tool). By default, the setting is
+    mixed_output. </para>
+    
+    <para>With mixed_output, the Valgrind output goes to the Valgrind
+    log (typically stderr) while the output of the interactive gdb
+    monitor commands (e.g. vg.info last_error) is displayed by
+    gdb.</para>
+    
+    <para>With gdb_output, both the Valgrind output and the
+    interactive gdb monitor commands output is displayed by
+    gdb.</para>
+    
+    <para>With log_output, both the Valgrind output and the
+    interactive gdb monitor commands output go to the Valgrind
+    log.</para>
+  </listitem>
+  
+  <listitem>
+    <para><varname>vg.wait [ms (default 0)]</varname> instructs
+    Valgrind gdbserver to sleep 'ms' milli-seconds and then
+    continue. When sent from a standalone vgdb, if this is the last
+    command, the Valgrind process will continue the execution of the
+    guest process. The typical usage of this is to use vgdb to send a
+    "no-op" command to a Valgrind gdbserver so as to continue the
+    execution of the guess process.
+    </para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.kill;</varname> requests the gdbserver to kill
+    the process. This can be used from a standalone vgdb to properly
+    kill a Valgrind process which is currently expecting a vgdb
+    connection.</para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.set vgdb-error &lt;errornr&gt;</varname>
+    dynamically changes the value of the --vgdb-error argument. A
+    typical usage of this is to start with --vgdb-error=0 on the
+    command line, then set a few breakpoints, set the vgdb-error value
+    to a huge value and continue execution.</para>
+  </listitem>
+
+</itemizedlist>
+
+<para>The below Valgrind monitor commands are useful to investigate
+the behaviour of Valgrind or Valgrind gdbserver in case of problem or
+bug.</para>
+
+<itemizedlist>
+
+  <listitem>
+    <para><varname>vg.info gdbserver_status</varname> shows the
+    gdbserver status. In case of problem (e.g. of communications),
+    this gives the value of some relevant Valgrind gdbserver internal
+    variables.  Note that the variables related to breakpoints and
+    watchpoints (e.g. the nr of gdbserved addresses and the nr of
+    watchpoints) will be zero, as gdb by default removes all
+    watchpoints and breakpoints when execution stops, and re-inserts
+    them when resuming the execution of the debugged process. You can
+    change this gdb behaviour by using the gdb command 'set breakpoint
+    always-inserted on'.
+    </para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.info memory</varname> shows the statistics of
+    the Valgrind heap management. If
+    option <option>--profile-heap=yes=yes</option> was given, detailed
+    statistics will be output.
+    </para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.set debuglog &lt;intvalue&gt;</varname> sets the
+    valgrind debug log level to &lt;intvalue&gt;. This allows to
+    dynamically change the log level of Valgrind e.g. when a problem
+    is detected.</para>
+  </listitem>
+
+  <listitem>
+    <para><varname>vg.translate &lt;address&gt;
+    [&lt;traceflags&gt;]</varname> traces the translation of the block
+    containing address with the given trace flags. The traceflags is a
+    bit pattern similar to the --trace-flags option.  It can be given
+    in hexadecimal (e.g. 0x20) or decimal (e.g. 32) or in binary 1s
+    and 0s bit (e.g. 0b00100000). The default value of the traceflags
+    is 0b00100000, corresponding to 'show after instrumentation'. Note
+    that the output of this command always goes to the Valgrind
+    log. The additional bit flag 0b100000000 traces in addition the
+    gdbserver specific instrumentation. Note that bit can only enable
+    the addition of the gdbserver instrumentation in the trace.
+    Keeping this flag to 0 will not disable the tracing of the
+    gdbserver instrumentation if it is active for another reason
+    (e.g. because there is a breakpoint at this address or because
+    gdbserver is in single stepping mode). </para>
+  </listitem>
+
+</itemizedlist>
+
+</sect1>
 
 <sect1 id="manual-core.pthreads" xreflabel="Support for Threads">
 <title>Support for Threads</title>
diff --git a/gdbserver_tests/Makefile.am b/gdbserver_tests/Makefile.am
new file mode 100644 (file)
index 0000000..6d99519
--- /dev/null
@@ -0,0 +1,86 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+       invoker simulate_control_c make_local_links \
+       filter_gdb filter_make_empty \
+       filter_memcheck_monitor filter_stderr filter_vgdb
+
+EXTRA_DIST = \
+       mcbreak.stderrB.exp \
+       mcbreak.stderr.exp \
+       mcbreak.stdinB.gdb \
+       mcbreak.stdoutB.exp \
+       mcbreak.stdout.exp \
+       mcbreak.vgtest \
+       mcclean_after_fork.stderrB.exp \
+       mcclean_after_fork.stderr.exp \
+       mcclean_after_fork.stdinB.gdb \
+       mcclean_after_fork.stdoutB.exp \
+       mcclean_after_fork.vgtest \
+       mchelp.stderrB.exp \
+       mchelp.stderr.exp \
+       mchelp.stdoutB.exp \
+       mchelp.vgtest \
+       mcinfcallRU.stderrB.exp \
+       mcinfcallRU.stderr.exp \
+       mcinfcallRU.stdinB.gdb \
+       mcinfcallRU.vgtest \
+       mcinfcallWSRU.stderrB.exp \
+       mcinfcallWSRU.stderr.exp \
+       mcinfcallWSRU.stdinB.gdb \
+       mcinfcallWSRU.vgtest \
+       mcinvokeRU.stderrB.exp \
+       mcinvokeRU.stderr.exp \
+       mcinvokeRU.stdoutB.exp \
+       mcinvokeRU.vgtest \
+       mcinvokeWS.stderrB.exp \
+       mcinvokeWS.stderr.exp \
+       mcinvokeWS.stdoutB.exp \
+       mcinvokeWS.vgtest \
+       mcleak.stderrB.exp \
+       mcleak.stderr.exp \
+       mcleak.stdinB.gdb \
+       mcleak.stdoutB.exp \
+       mcleak.vgtest \
+       mcsignopass.stderrB.exp \
+       mcsignopass.stderr.exp \
+       mcsignopass.stdinB.gdb \
+       mcsignopass.stdoutB.exp \
+       mcsignopass.vgtest \
+       mcsigpass.stderrB.exp \
+       mcsigpass.stderr.exp \
+       mcsigpass.stdinB.gdb \
+       mcsigpass.stdoutB.exp \
+       mcsigpass.vgtest \
+       mcvabits.stderrB.exp \
+       mcvabits.stderr.exp \
+       mcvabits.stdinB.gdb \
+       mcvabits.stdoutB.exp \
+       mcvabits.vgtest \
+       mcwatchpoints.stderrB.exp \
+       mcwatchpoints.stderr.exp \
+       mcwatchpoints.stdinB.gdb \
+       mcwatchpoints.stdoutB.exp \
+       mcwatchpoints.vgtest \
+       mssnapshot.stderrB.exp \
+       mssnapshot.stderr.exp \
+       mssnapshot.stdinB.gdb \
+       mssnapshot.stdoutB.exp \
+       mssnapshot.vgtest \
+       nlcontrolc.stderrB.exp \
+       nlcontrolc.stderr.exp \
+       nlcontrolc.stdinB.gdb \
+       nlcontrolc.stdoutB.exp \
+       nlcontrolc.vgtest
+
+check_PROGRAMS = \
+       clean_after_fork \
+       sleepers \
+       t \
+       watchpoints
+
+AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
+AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+
+LDADD = -lpthread
diff --git a/gdbserver_tests/README_DEVELOPPERS b/gdbserver_tests/README_DEVELOPPERS
new file mode 100644 (file)
index 0000000..e9c5e11
--- /dev/null
@@ -0,0 +1,203 @@
+Automatic regression tests:
+---------------------------
+The Valgrind gdbserver automatic tests are by default
+executed as part of the Valgrind test suite:
+   make regtest
+
+By default, these tests are running with the gdb found at
+Valgrind configure time.
+
+If you want to test with another gdb version, you can do:
+  make regtest GDB=/path/to/another/gdb
+
+or (to just run the gdbserver tests with another gdb):
+  cd gdbserver_tests
+  make check
+  cd ..
+  gdbserver_tests/make_local_links /path/to/another/gdb
+  perl tests/vg_regtest gdbserver_tests
+
+The minimum version to use the Valgrind gdbserver is gdb >= 6.5.
+    Previous versions do not have the 'target remote |' command.  It
+    would be possible to use an older version by having a tcp relay
+    application between gdb and vgdb (or, alternatively, change vgdb
+    so that it could read/write from/to a tcpip socket rather than
+    read/write from stdin/stdout.
+
+The tests have been run on various platforms using gdb 7.2
+and on some platforms gdb 7.0.
+Some gdb tests implies a gdb >= 7.2. (these are automatically disabled
+if testing with a lower version).
+
+Some tests implies to have a vgdb "ptrace invoker" capable.
+
+The prerequisite are established during make regtest (using marker files).
+Each test verifies the prerequisite using the prereq: line.
+
+
+Naming conventions:
+-------------------
+
+The gdbserver tests are done with various Valgrind tools.  A gdbserver
+test using a tool xxxxxx should have its name starting with the 'short
+two letters code' of this tool.  For example, the test mcvabits.vgtest
+is using Memcheck tool, while the test mssnapshot.vgtest is using
+massif tool.
+
+Typically, a gdbserver test implies to launch two programs:
+     prog: a program running under valgrind
+     progB: another program (typically, either gdb or vgdb standalone)
+The conventions about how to specify the 2nd program in a .vgtest
+are explained in the file ../tests/vg_regtest.in
+Many tests are using gdb as progB. The input for gdb is named
+xxxxxx.stdinB.gdb.
+
+One day, we might imagine to run tests in parallel.
+So, each test gets its own '--vgdb-prefix' argument.
+This also help to avoid interactions between two successive tests:
+if a previous test stayed blocked, the vgdb of the next test
+will not report an error due to multiple possible FIFOs.
+
+
+Rational for test approach
+--------------------------
+Two approaches have been looked at:
+  V: use the 'vg_regtest' approach used by the rest of Valgrind tests
+  G: use the gdb Dejagnu test framework.
+
+Advantages of V: much simpler that G, known by Valgrind developpers,
+no additional dependency for the Valgrind build and test.
+
+Disadvantages of V: not well suited to testing of interactive tools,
+very unflexible way to test the results (everything is in "template"
+files), templates contains often irrelevant data for the test but it
+can make the test fail.  After writing 13 tests, it looks like the
+template diff approach is quite fragile (e.g. changing the gdb version
+and/or the OS version influences the output of irrelevant things which
+are part of the template).
+
+A more flexible template filtering is needed.
+Maybe something like:
+The program under test is outputting its instructions to be filtered in
+special markers e.g.
+#pushf filter_addresses | filter_messages
+... some output
+#pushf an_additional_filter
+... some other output, filtered by both the first and second push
+#popf
+... here output filtered only by the first pushf
+#popf
+
+Advantages of G: much more powerful, well suited to test a gdb with a
+gdbserver, tests can verify specifically some output without being
+impacted by other output, allow to test Valgrind gdbserver with the
+all of the gdb test suite (but a lot of tests will rather test gdb
+than Valgrind gdbserver).
+
+Disadvantages: not an easy beast to understand and master, running the
+whole gdb testsuite with Valgrind gdbserver looks to be a challenge.
+
+Currently, tests are written with vg_regtest. Approach G will be looked at it
+again (e.g. to complement V) once a basic set of tests are available. 
+
+
+Manual tests still to automate:
+-------------------------------
+
+Validate  monitor commands abbreviation recognition
+***************************************************
+mo vg.info all_errors           # to show all errors recorded so far
+mo vg.i a                       # the same
+mo v                            # must give an error: v can match vg.set vg.info
+mo vg                           # the same            vg
+mo vg.                          # the same            vg.
+
+test of gdb detaching or dying
+******************************
+valgrind --vgdb=yes --vgdb-error=0 --vgdb-poll=500 ./t
+
+in another window
+
+gdb ./t
+set remotetimeout 100
+target remote|vgdb
+detach                          valgrind continues
+target remote|vgdb             reattach
+detach                          valgrind continues
+target remote|vgdb             reattach
+monitor vg.wait                 no effect
+
+
+
+test of valgrind/gdb output redirection
+***************************************
+valgrind --vgdb=yes --vgdb-error=1 --vgdb-poll=500 ./t
+
+in another window
+
+**** command to type***         ****** expected behaviour
+gdb ./t
+set remotetimeout 1000 
+target remote | vgdb
+mo vg.set vgdb-error 1000      # so that valgrind does stop only at error 1000 and after
+mo vg.set gdb_output            # to have further valgrind errors output in gdb
+c                               # continue, some errors will appear
+C-c                             # interrupt program
+mo vg.set log_output            # to set back the valgrind output to normal process log output
+mo mc.l                         # leak output to appear in log of process
+mo vg.set mixed_output
+mo mc.l                         # leak output to appear in gdb
+
+
+
+test with a big executable: firefox
+***********************************
+valgrind --vgdb=yes --vgdb-error=1000 --vgdb-poll=50000 --trace-children=yes firefox 2>&1 | tee f.out
+
+wait for some messages from the "big" firefox executable to appear.
+Then:
+
+gdb /usr/lib/firefox-3.5/firefox
+target remote | vgdb
+... then you can do various next/print/bt/bt full/break/... to see it is working
+
+bulk test with the above
+************************
+to verify there is no race condition/no reentrance problem 
+between gdbserver code and valgrind:
+start firefox like in the previous test.
+In another window, do:
+  while true
+  do
+    vgdb mc.leak
+    sleep 1
+  done
+
+NB: this will make firefox run extremely slow, as it will do a leak
+search every second.
+
+Test of "jump" functionality
+----------------------------
+... to be done : put two breaks, jump over one.
+... same but when error is encountered
+
+
+* test with --max-invoke-ms=0
+-----------------------------
+valgrind --vgdb=yes ./t
+... wait till you see "petachounok sleeping 4 of 15
+then try to gdb it
+
+!!!! this often causes gdb to report a protocol timeout.
+use gdb set remotetimeout <a big time> to avoid that.
+The symptoms of a timeout are:
+    (gdb) tar rem|vgdb --max-invoke-ms=0
+    Remote debugging using |vgdb --max-invoke-ms=0
+    relaying data between gdb and process 2930
+    Ignoring packet error, continuing...
+    warning: unrecognized item "timeout" in "qSupported" response
+
+* tests of shadow registers
+----------------------------
+Show/modify shadow registers
diff --git a/gdbserver_tests/clean_after_fork.c b/gdbserver_tests/clean_after_fork.c
new file mode 100644 (file)
index 0000000..3ef0f67
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+main()
+{
+   int mem = 0;
+   int pid;
+   
+   pid = fork();
+   if (pid == -1) {
+      mem = 1;
+      perror("fork");
+      exit(1);
+   }
+
+   if (pid == 0) {
+      if (mem == 0)
+         exit(0);
+      else
+         exit(1);
+   } else {
+      int ret;
+      int status;
+      while((ret = waitpid(pid, &status, 0)) != pid) {
+         if (errno != EINTR) {
+            perror("waitpid");
+            exit(1);
+         }
+      }
+      mem = status;
+   }
+   if (mem == 0)
+      printf("mem is zero\n");
+}
diff --git a/gdbserver_tests/filter_gdb b/gdbserver_tests/filter_gdb
new file mode 100755 (executable)
index 0000000..9dd7a3b
--- /dev/null
@@ -0,0 +1,95 @@
+#! /bin/sh
+
+# filter the output of gdb.
+
+dir=`dirname $0`
+
+$dir/filter_stderr                                                  |
+
+# Anonymise addresses
+$dir/../tests/filter_addresses                                      |
+
+# memcheck stuff
+$dir/filter_memcheck_monitor                                        |
+
+
+# Anonymise or remove :
+#       initial tty control character sent by gdb 7.0
+#       remove missing debuginfos
+#       vgdb message
+#       pid numbers
+#       Thread numbers
+#       delete thread switches
+#       info threads output (e.g. which thread is running and syscall)
+#       delete Reading symbols file lines
+#       delete Loaded symbols file lines
+#       initial break message
+#       remove gdb prompts.
+#       remove gdb continuation prompts.
+#       remove gdb done prompts.
+#       a 'general' system calls stack trace part
+#       a more specialised system call select stack trace part
+#             (on 32 bits, we have an int_80, on 64 bits, directly select)
+#       and yet another (gdb 7.0 way) to get a system call
+#       and yet another (gdb 7.0 arm way) to get a system call
+#       and cleanup some lines for a system call (on ubuntu 10 64 bits)
+#           (pay attention : there are tab characters there in)
+#           + yet another way to get a select system call
+#       which registers can't be modified
+#       special transform for arm/ppc watchpoints which have an additional address
+#              at the beginning
+#       special transform for backtrace of arm division by zero which gives
+#             a location in the nptl lib rather than our sources (same as
+#              standard gdb gdbserver) gdb 7.0
+#       same special transform but for gdb 7.2
+#       delete lines telling that some memory can't be accessed: this is
+#         a.o. produced by gdb 7.2 on arm (same with standard gdbserver)
+#       delete empty lines (the last line (only made of prompts) sometimes
+#           finishes with a new line, sometimes not ???).
+sed -e 's/^\e\[?1034hReading symbols/Reading symbols/'                                                \
+    -e '/Missing separate debuginfos, use: debuginfo-install/d'                                       \
+    -e 's/\(relaying data between gdb and process \)[0-9][0-9]*/\1..../'                              \
+    -e 's/pid [0-9][0-9]*/pid ..../g'                                                                 \
+    -e 's/Thread [0-9][0-9]*/Thread ..../g'                                                           \
+    -e '/\[Switching to Thread ....\]/d'                                                              \
+    -e 's/^\([ \* ] [0-9] Thread .... (tid [0-9] VgTs_WaitSys)  0x........ in\).*$/\1 syscall .../'   \
+    -e 's/#[0-9]\(  0x........ in sleeper_or_burner\)/#.\1/'                                          \
+    -e '/^Reading symbols from .*\.\.\.done\./d'                                                      \
+    -e '/^Loaded symbols for .*$/d'                                                                   \
+    -e '1,8s/_start () from [^ ][^ ]*/_start () from ...start file.../'                               \
+    -e '1,8s/\(0x........ in\) ?? () from \/lib\/ld-linux\.so\../\1 _start () from ...start file.../' \
+    -e '1,8s/\(0x........ in\) ?? () from \/lib\/ld\.so\../\1 _start () from ...start file.../'       \
+    -e '1,8s/\(0x........ in\) ?? () from \/lib64\/ld64\.so\../\1 _start () from ...start file.../'   \
+    -e '1,8s/\(0x........ in\) ?? () from \/lib64\/ld-linux-x86-64\.so\../\1 _start () from ...start file.../'   \
+    -e '1,8s/\(0x........ in\) ?? ()$/\1 _start () from ...start file.../'                            \
+    -e 's/(gdb) //g'                                                                                  \
+    -e 's/^>[> ]*//'                                                                                  \
+    -e '/^done\.$/d'                                                                                  \
+    -e 's/in _dl_sysinfo_int80 () from \/lib\/ld-linux.so.*/in syscall .../'                          \
+    -e 's/in _dl_sysinfo_int80 ()/in syscall .../'                                                    \
+    -e '/^   from \/lib\/ld-linux.so.*$/d'                                                            \
+    -e 's/\(0x........\) in ?? () from \/lib\/ld-linux\.so\../\1 in syscall .../'                     \
+    -e 's/\(0x........\) in ?? () from \/lib64\/tls\/libc\.so\../\1 in syscall .../'                  \
+    -e 's/in \(.__\)\{0,1\}select () from \/.*$/in syscall .../'                                      \
+    -e '/^   from \/lib\/libc.so.*$/d'                                                                \
+    -e 's/in select ()$/in syscall .../'                                                              \
+    -e 's/in select () at \.\.\/sysdeps\/unix\/syscall-template\.S.*$/in syscall .../'                \
+    -e '/^[    ]*at \.\.\/sysdeps\/unix\/syscall-template\.S/d'                                      \
+    -e '/^[    ]*in \.\.\/sysdeps\/unix\/syscall-template\.S/d'                                      \
+    -e '/^[1-9][0-9]*[         ]*\.\.\/sysdeps\/unix\/syscall-template\.S/d'                                 \
+    -e '/^[1-9][0-9]*[         ]in *\.\.\/sysdeps\/unix\/syscall-template\.S/d'                              \
+    -e 's/\(Could not write register \)".*"/\1 "xxx"/'                                                \
+    -e 's/\(ERROR changing register \).*$/\1 xxx regno y/'                                            \
+    -e 's/0x........ in \(main (argc=1, argv=0x........) at watchpoints.c:[24][3689]\)/\1/'           \
+    -e 's/0x........ in \(main () at clean_after_fork.c:32\)/\1/'                                     \
+    -e 's/0x........ in \*__GI_raise (sig=8)/0x........ in test4 () at faultstatus.c:120/'            \
+    -e 's/    at ..\/nptl\/sysdeps\/unix\/sysv\/linux\/raise.c:[0-9]*/120              volatile int v = 44\/zero();/' \
+    -e '/      in ..\/nptl\/sysdeps\/unix\/sysv\/linux\/raise.c/d'                                   \
+    -e 's/0x........ in \.\{0,1\}raise () from \/lib[0-9]\{0,2\}\/libc\.so\../0x........ in test4 () at faultstatus.c:120\n120         volatile int v = 44\/zero();'/ \
+    -e '/Cannot access memory at address 0x......../d'                                                \
+    -e '/^$/d' |
+
+# join together two lines that gdb 7.1 splits in two (???)
+# (in a separate sed, as the below influences the behaviour of the other expressions)
+sed    -e :a -e '$!N;s/\n    at sleepers.c:39/ at sleepers.c:39/;ta' -e 'P;D'
+
diff --git a/gdbserver_tests/filter_make_empty b/gdbserver_tests/filter_make_empty
new file mode 100755 (executable)
index 0000000..f22998b
--- /dev/null
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+# A filter filtering everything.
+
+# To still allow to see what is happening, the content
+# is copied to a file, together with date and process.
+
+ps -lf -p $PPID >> garbage.filtered.out
+date            >> garbage.filtered.out
+cat             >> garbage.filtered.out
diff --git a/gdbserver_tests/filter_memcheck_monitor b/gdbserver_tests/filter_memcheck_monitor
new file mode 100755 (executable)
index 0000000..9a50336
--- /dev/null
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+# used to filter memcheck output shown by vgdb.
+
+dir=`dirname $0`
+
+$dir/../memcheck/tests/filter_stderr                   |
+
+# filter vgdb messages
+$dir/filter_vgdb                                       |
+
+
+# Bypass a s390x kernel bug which makes faultstatus test3 fail. In our case, we are
+# not interested in checking the si_code, but rather the signal passing
+# in mcsig(no)pass
+sed -e 's/Test 3:   FAIL: expected si_code==2, not 128/Test 3:   PASS/'
diff --git a/gdbserver_tests/filter_stderr b/gdbserver_tests/filter_stderr
new file mode 100755 (executable)
index 0000000..1d26ab7
--- /dev/null
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+$dir/../tests/filter_stderr_basic    |
+sed -e '/^Copyright (C) /d'
diff --git a/gdbserver_tests/filter_vgdb b/gdbserver_tests/filter_vgdb
new file mode 100755 (executable)
index 0000000..71b3511
--- /dev/null
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+$dir/filter_stderr                              |
+
+# Anonymise addresses
+$dir/../tests/filter_addresses                  |
+
+# filter vgdb process id, pid
+# gdb 7.2 sometimes tries to access address 0x0
+#   (same as with standard gdbserver)
+sed -e 's/\(relaying data between gdb and process \)[0-9][0-9]*/\1..../' \
+    -e 's/\(sending command .* to pid \)[0-9][0-9]*/\1..../'             \
+    -e '/Cannot access memory at address 0x......../d'
diff --git a/gdbserver_tests/invoker b/gdbserver_tests/invoker
new file mode 100755 (executable)
index 0000000..b9fba58
--- /dev/null
@@ -0,0 +1,19 @@
+#! /bin/sh
+
+# invoker is used to test the invocation of gdbserver.
+# The first argument is the nr of times vgdb has to be called.
+# rest of args are given to vgdb
+# At the end of the loop, an additional call is done
+# but adding " -c vg.kill" to kill Valgrind process.
+
+LOOPS=$1
+shift
+
+i=0
+while [ $i -lt $LOOPS ]
+do
+   ./vgdb "$@"  
+   i=`expr $i + 1`
+done
+
+./vgdb "$@"  -c vg.kill
diff --git a/gdbserver_tests/make_local_links b/gdbserver_tests/make_local_links
new file mode 100755 (executable)
index 0000000..f7291d6
--- /dev/null
@@ -0,0 +1,58 @@
+#! /bin/sh
+
+# (must be called from the valgrind top source dir).
+#
+# Make local links in the gdbserver_tests directory
+# so that tests needing gdb can be disabled if
+# a tool old version of gdb is provided or if no gdb is
+# provided.
+#
+# The vgdb link is needed either for gdb tests
+# or for standalone vgdb tests.
+
+ln -f -s $1 gdbserver_tests/gdb
+if [ -x gdbserver_tests/gdb ]
+then
+   # Try to extract the gdb version.
+   VERSIONLINE=`gdbserver_tests/gdb --version | head -1`
+   VERSION=`echo $VERSIONLINE                         |
+            sed -e 's/[^0-9\.]//g' -e 's/\./ /g'`
+   
+   # We need at least a 6.5 version to run any gdb test
+   VERSIONOK=`echo $VERSION |
+              awk '{ if ( ($1 >= 7) || (($1 == 6) && ($2 >= 5)) ) print "version ok"}'`
+   if [ "$VERSIONOK" = "" ]
+   then
+      echo "gdbserver tests suppressed as $1 version is not >= 6.5: " $VERSIONLINE
+      rm gdbserver_tests/gdb
+   fi
+
+   # We need at least a 7.2 version for gdb tests using eval command
+   VERSIONOK=`echo $VERSION |
+              awk '{ if ( ($1 >= 8) || (($1 == 7) && ($2 >= 2)) ) print "version ok"}'`
+   if [ "$VERSIONOK" = "" ]
+   then
+      echo "gdbserver eval tests suppressed as $1 version is not >= 7.2: " $VERSIONLINE
+      rm -f gdbserver_tests/gdb.eval
+   else
+      touch gdbserver_tests/gdb.eval
+   fi
+else
+   echo "gdbserver gdb tests suppressed as $1 is not executable"
+fi
+
+ln -f -s ../coregrind/vgdb gdbserver_tests/vgdb
+
+# if ptrace not implemented in vgdb or OS restricts the initial attach,
+# some tests would block for a loooonnnng time.
+if gdbserver_tests/vgdb --help 2>&1 |
+    grep -e 'ptrace invoker not implemented' \
+         -e 'kernel restricts ptrace invoker' > /dev/null
+then
+    rm -f gdbserver_tests/vgdb.ptraceinvoker
+else
+    touch gdbserver_tests/vgdb.ptraceinvoker
+fi
+
+# cleanup the possibly big garbage previously collected output
+rm -f gdbserver_tests/garbage.filtered.out
diff --git a/gdbserver_tests/mcbreak.stderr.exp b/gdbserver_tests/mcbreak.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcbreak.stderrB.exp b/gdbserver_tests/mcbreak.stderrB.exp
new file mode 100644 (file)
index 0000000..d5eaecf
--- /dev/null
@@ -0,0 +1,7 @@
+relaying data between gdb and process ....
+vgdb-error value changed from 0 to 999999
+vgdb-error value changed from 999999 to 0
+n_errs_found 1 (vgdb-error 0)
+vgdb-error value changed from 0 to 0
+monitor command request to kill this process
+Remote connection closed
diff --git a/gdbserver_tests/mcbreak.stdinB.gdb b/gdbserver_tests/mcbreak.stdinB.gdb
new file mode 100644 (file)
index 0000000..a154925
--- /dev/null
@@ -0,0 +1,68 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcbreak
+monitor vg.set vgdb-error 999999
+#
+define checkstep
+  set $old_pc=$pc
+  step
+  if $old_pc == $pc
+    echo Bizarre the oldpc has not changed after step\n
+    print $oldpc
+    print $pc
+  else
+    echo old_pc has changed after step\n
+  end
+end
+#
+# break1 and break2
+break t.c:112
+break t.c:117
+#
+continue
+# first break encountered.
+checkstep
+checkstep
+checkstep
+#
+monitor vg.set vgdb-error 0
+#
+next
+print whoami("first")
+print undefined
+print i
+checkstep
+checkstep
+next
+print whoami("second")
+print undefined
+print i
+next
+print whoami("third")
+print undefined
+print i
+next
+print whoami("fourth")
+print undefined
+print i
+# modify sleeps so as to have a shorter test:
+print sleeps=1
+#
+print whoami("after next: inferior call pushed from mcbreak.stdinB.gdb")
+continue
+#
+# encountered second break
+step
+finish
+# delete all breaks
+delete
+continue
+monitor vg.info n_errs_found 
+# inferior call "in the middle" of an instruction is not working at least
+# on all platforms, so comment the below.
+# print whoami("after error: inferior call pushed from mcbreak.stdinB.gdb")
+checkstep
+monitor vg.set vgdb-error 0
+continue
+# stop the process a.o. to avoid non deterministic output
+monitor vg.kill
+quit
diff --git a/gdbserver_tests/mcbreak.stdout.exp b/gdbserver_tests/mcbreak.stdout.exp
new file mode 100644 (file)
index 0000000..8907c6f
--- /dev/null
@@ -0,0 +1,8 @@
+pid .... Thread .... first
+pid .... Thread .... second
+pid .... Thread .... third
+pid .... Thread .... fourth
+pid .... Thread .... after next: inferior call pushed from mcbreak.stdinB.gdb
+pid .... Thread .... called from level
+called from level int_und is not zero
+pid .... Thread .... called from main
diff --git a/gdbserver_tests/mcbreak.stdoutB.exp b/gdbserver_tests/mcbreak.stdoutB.exp
new file mode 100644 (file)
index 0000000..2c51b39
--- /dev/null
@@ -0,0 +1,56 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcbreak
+0x........ in _start () from ...start file...
+Breakpoint 1 at 0x........: file t.c, line 112.
+Breakpoint 2 at 0x........: file t.c, line 117.
+Continuing.
+Breakpoint 1, main (argc=1, argv=0x........) at t.c:112
+112      breakme(__LINE__); //break1
+breakme (line=112) at t.c:100
+100       if (line > 1000)
+old_pc has changed after step
+102    }
+old_pc has changed after step
+main (argc=1, argv=0x........) at t.c:113
+113      for (i = len-1; i >= 0; i=i-2)
+old_pc has changed after step
+114         undefined[i] = undef;
+$1 = void
+$2 = "undefined"
+$3 = 8
+113      for (i = len-1; i >= 0; i=i-2)
+old_pc has changed after step
+114         undefined[i] = undef;
+old_pc has changed after step
+113      for (i = len-1; i >= 0; i=i-2)
+$4 = void
+$5 = "undefi?e?"
+$6 = 6
+114         undefined[i] = undef;
+$7 = void
+$8 = "undefi?e?"
+$9 = 4
+113      for (i = len-1; i >= 0; i=i-2)
+$10 = void
+$11 = "unde?i?e?"
+$12 = 4
+$13 = 1
+$14 = void
+Continuing.
+Breakpoint 2, main (argc=1, argv=0x........) at t.c:117
+117      breakme(__LINE__); //break2
+breakme (line=117) at t.c:100
+100       if (line > 1000)
+Run till exit from #0  breakme (line=117) at t.c:100
+main (argc=1, argv=0x........) at t.c:119
+119      if (argc > 1)
+Delete all breakpoints? (y or n) [answered Y; input not from terminal]
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in make_error (s=0x........ "called from level") at t.c:40
+40       if (int_und == 0)
+43          printf ("%s int_und is not zero\n", s);
+old_pc has changed after step
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in make_error (s=0x........ "called from main") at t.c:40
+40       if (int_und == 0)
diff --git a/gdbserver_tests/mcbreak.vgtest b/gdbserver_tests/mcbreak.vgtest
new file mode 100644 (file)
index 0000000..b79f41a
--- /dev/null
@@ -0,0 +1,11 @@
+# test execution control (break, next, step) and inferior calls
+# when stopped on these events
+prog: t
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcbreak
+stdout_filter: filter_gdb
+stderr_filter: filter_make_empty
+progB: gdb
+argsB:  --quiet -l 60 --nx ./t
+stdinB: mcbreak.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_memcheck_monitor
diff --git a/gdbserver_tests/mcclean_after_fork.stderr.exp b/gdbserver_tests/mcclean_after_fork.stderr.exp
new file mode 100644 (file)
index 0000000..0e8e017
--- /dev/null
@@ -0,0 +1,12 @@
+
+(action at startup) vgdb me ... 
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+Reset valgrind output to log (orderly_finish)
diff --git a/gdbserver_tests/mcclean_after_fork.stderrB.exp b/gdbserver_tests/mcclean_after_fork.stderrB.exp
new file mode 100644 (file)
index 0000000..995b42f
--- /dev/null
@@ -0,0 +1,4 @@
+relaying data between gdb and process ....
+vgdb-error value changed from 0 to 999999
+monitor command request to kill this process
+Remote connection closed
diff --git a/gdbserver_tests/mcclean_after_fork.stdinB.gdb b/gdbserver_tests/mcclean_after_fork.stdinB.gdb
new file mode 100644 (file)
index 0000000..145ad93
--- /dev/null
@@ -0,0 +1,24 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcclean_after_fork
+monitor vg.set vgdb-error 999999
+#
+# put a break in main, and then a watch
+# also put breaks in code that only the child will execute.
+# These breaks should not be encountered.
+break clean_after_fork.c:9
+break clean_after_fork.c:18
+break clean_after_fork.c:20
+#
+continue
+# first break encountered.
+# put a read watchpoint on mem
+# we expect that the read watchpoint is not triggered in the child
+# (as we expect it will be cleared at fork).
+rwatch mem
+#
+continue
+#
+# we should now have encountered the read watchpoint in the parent.
+# let's kill the parent:
+monitor vg.kill
+quit
diff --git a/gdbserver_tests/mcclean_after_fork.stdoutB.exp b/gdbserver_tests/mcclean_after_fork.stdoutB.exp
new file mode 100644 (file)
index 0000000..8c6a8d3
--- /dev/null
@@ -0,0 +1,14 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcclean_after_fork
+0x........ in _start () from ...start file...
+Breakpoint 1 at 0x........: file clean_after_fork.c, line 9.
+Breakpoint 2 at 0x........: file clean_after_fork.c, line 18.
+Breakpoint 3 at 0x........: file clean_after_fork.c, line 20.
+Continuing.
+Breakpoint 1, main () at clean_after_fork.c:9
+9         pid = fork();
+Hardware read watchpoint 4: mem
+Continuing.
+Hardware read watchpoint 4: mem
+Value = 0
+main () at clean_after_fork.c:32
+32        if (mem == 0)
diff --git a/gdbserver_tests/mcclean_after_fork.vgtest b/gdbserver_tests/mcclean_after_fork.vgtest
new file mode 100644 (file)
index 0000000..d953ed7
--- /dev/null
@@ -0,0 +1,9 @@
+# test cleanup of break and watchpoints after fork
+prog: clean_after_fork
+vgopts: --tool=memcheck --vgdb=full --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcclean_after_fork
+stderr_filter: filter_memcheck_monitor
+progB: gdb
+argsB:  --quiet -l 60 --nx ./clean_after_fork
+stdinB: mcclean_after_fork.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_memcheck_monitor
diff --git a/gdbserver_tests/mchelp.stderr.exp b/gdbserver_tests/mchelp.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mchelp.stderrB.exp b/gdbserver_tests/mchelp.stderrB.exp
new file mode 100644 (file)
index 0000000..55888e3
--- /dev/null
@@ -0,0 +1,5 @@
+sending command help to pid ....
+sending command help debug to pid ....
+sending command vg.kill to pid ....
+readchar: Got EOF
+error reading packet
diff --git a/gdbserver_tests/mchelp.stdoutB.exp b/gdbserver_tests/mchelp.stdoutB.exp
new file mode 100644 (file)
index 0000000..6499f33
--- /dev/null
@@ -0,0 +1,66 @@
+general valgrind monitor commands:
+  help [debug]             : monitor command help. With debug: + debugging commands
+  vg.wait [<ms>]           : sleep <ms> (default 0) then continue
+  vg.info all_errors       : show all errors found so far
+  vg.info last_error       : show last error found
+  vg.info n_errs_found     : show the nr of errors found so far
+  vg.kill                  : kill the Valgrind process
+  vg.set gdb_output        : set valgrind output to gdb
+  vg.set log_output        : set valgrind output to log
+  vg.set mixed_output      : set valgrind output to log, interactive output to gdb
+  vg.set vgdb-error <errornr> : debug me at error >= <errornr> 
+
+memcheck monitor commands:
+  mc.get_vbits <addr> [<len>]
+        returns validity bits for <len> (or 1) bytes at <addr>
+            bit values 0 = valid, 1 = invalid, __ = unaddressable byte
+        Example: mc.get_vbits 0x........ 10
+  mc.make_memory [noaccess|undefined
+                     |defined|ifaddressabledefined] <addr> [<len>]
+        mark <len> (or 1) bytes at <addr> with the given accessibility
+  mc.check_memory [addressable|defined] <addr> [<len>]
+        check that <len> (or 1) bytes at <addr> have the given accessibility
+            and outputs a description of <addr>
+  mc.leak_check [full*|summary]
+                [reachable|leakpossible*|definiteleak]
+            * = defaults
+        Examples: mc.leak_check
+                  mc.leak_check any summary
+
+general valgrind monitor commands:
+  help [debug]             : monitor command help. With debug: + debugging commands
+  vg.wait [<ms>]           : sleep <ms> (default 0) then continue
+  vg.info all_errors       : show all errors found so far
+  vg.info last_error       : show last error found
+  vg.info n_errs_found     : show the nr of errors found so far
+  vg.kill                  : kill the Valgrind process
+  vg.set gdb_output        : set valgrind output to gdb
+  vg.set log_output        : set valgrind output to log
+  vg.set mixed_output      : set valgrind output to log, interactive output to gdb
+  vg.set vgdb-error <errornr> : debug me at error >= <errornr> 
+debugging valgrind internals monitor commands:
+  vg.info gdbserver_status : show gdbserver status
+  vg.info memory           : show valgrind heap memory stats
+  vg.set debuglog <level>  : set valgrind debug log level to <level>
+  vg.translate <addr> [<traceflags>]  : debug translation of <addr> with <traceflags>
+    (default traceflags 0b00100000 : show after instrumentation)
+   An additional flag  0b100000000 allows to show gdbserver instrumentation
+
+memcheck monitor commands:
+  mc.get_vbits <addr> [<len>]
+        returns validity bits for <len> (or 1) bytes at <addr>
+            bit values 0 = valid, 1 = invalid, __ = unaddressable byte
+        Example: mc.get_vbits 0x........ 10
+  mc.make_memory [noaccess|undefined
+                     |defined|ifaddressabledefined] <addr> [<len>]
+        mark <len> (or 1) bytes at <addr> with the given accessibility
+  mc.check_memory [addressable|defined] <addr> [<len>]
+        check that <len> (or 1) bytes at <addr> have the given accessibility
+            and outputs a description of <addr>
+  mc.leak_check [full*|summary]
+                [reachable|leakpossible*|definiteleak]
+            * = defaults
+        Examples: mc.leak_check
+                  mc.leak_check any summary
+
+monitor command request to kill this process
diff --git a/gdbserver_tests/mchelp.vgtest b/gdbserver_tests/mchelp.vgtest
new file mode 100644 (file)
index 0000000..9f88c49
--- /dev/null
@@ -0,0 +1,9 @@
+# test the memcheck monitor help
+prog: t
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mchelp
+stdout_filter: filter_make_empty
+stderr_filter: filter_make_empty
+progB: vgdb
+argsB: --wait=60 --vgdb-prefix=./vgdb-prefix-mchelp -c help -c help debug -c vg.kill
+stdoutB_filter: filter_memcheck_monitor
+stderrB_filter: filter_vgdb
diff --git a/gdbserver_tests/mcinfcallRU.stderr.exp b/gdbserver_tests/mcinfcallRU.stderr.exp
new file mode 100644 (file)
index 0000000..c1dd15b
--- /dev/null
@@ -0,0 +1,7 @@
+loops/sleep_ms/burn/threads_spec:  1 0 2000000000 B-B-B-B-
+Brussels ready to sleep and/or burn
+London ready to sleep and/or burn
+Petaouchnok ready to sleep and/or burn
+main ready to sleep and/or burn
+pid .... Thread .... inferior call pushed from gdb in mcinfcallRU.stdinB.gdb
+Reset valgrind output to log (orderly_finish)
diff --git a/gdbserver_tests/mcinfcallRU.stderrB.exp b/gdbserver_tests/mcinfcallRU.stderrB.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcinfcallRU.stdinB.gdb b/gdbserver_tests/mcinfcallRU.stdinB.gdb
new file mode 100644 (file)
index 0000000..08a149b
--- /dev/null
@@ -0,0 +1,21 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcinfcallRU
+monitor vg.set vgdb-error 999999
+#
+# We will interrupt in a few seconds (be sure all tasks are in
+# Runnable/Yielding state). We need to wait enough seconds to be sure
+# Valgrind has started to execute the threads.
+# On a heavily loaded slow arm gcc compile farm system, 5 seconds
+# was not enough.
+shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-mcinfcallRU 10
+#
+continue
+info threads
+thread apply all bt full
+# Would like to call this for all threads with 'thread apply all', but due to unfair scheduling,
+# the below can either take a long time and/or have threads finished
+# before they have a chance to execute the whoami
+# thread apply all
+print whoami("inferior call pushed from gdb in mcinfcallRU.stdinB.gdb")
+monitor vg.kill
+quit
diff --git a/gdbserver_tests/mcinfcallRU.vgtest b/gdbserver_tests/mcinfcallRU.vgtest
new file mode 100644 (file)
index 0000000..957458b
--- /dev/null
@@ -0,0 +1,15 @@
+# test inferior calls when all threads are in Runnable or Yielding mode
+prog: sleepers
+args: 1 0 2000000000 B-B-B-B-
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcinfcallRU
+# filter_gdb to replace pid and Thread numbers.
+# Well, the test will verify we have 4 calls (for each thread)
+# but no way to check that this is effectively in the 4 different threads.
+stderr_filter: filter_gdb
+# Disable on Darwin: inferior call rejected as it cannot find malloc.
+prereq: ../tests/os_test linux
+progB: gdb
+argsB:  --quiet -l 60 --nx ./sleepers
+stdinB: mcinfcallRU.stdinB.gdb
+stdoutB_filter: filter_make_empty
+stderrB_filter: filter_make_empty
diff --git a/gdbserver_tests/mcinfcallWSRU.stderr.exp b/gdbserver_tests/mcinfcallWSRU.stderr.exp
new file mode 100644 (file)
index 0000000..227f862
--- /dev/null
@@ -0,0 +1,8 @@
+loops/sleep_ms/burn/threads_spec:  100 100000000 1000000000 -S-SB-B-
+Brussels ready to sleep and/or burn
+London ready to sleep and/or burn
+Petaouchnok ready to sleep and/or burn
+main ready to sleep and/or burn
+pid .... Thread .... thread 1 inferior call pushed from gdb in mcinfcallWSRU.stdinB.gdb
+pid .... Thread .... thread 4 inferior call pushed from gdb in mcinfcallWSRU.stdinB.gdb
+Reset valgrind output to log (orderly_finish)
diff --git a/gdbserver_tests/mcinfcallWSRU.stderrB.exp b/gdbserver_tests/mcinfcallWSRU.stderrB.exp
new file mode 100644 (file)
index 0000000..2e954db
--- /dev/null
@@ -0,0 +1,48 @@
+relaying data between gdb and process ....
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcinfcallWSRU
+0x........ in _start () from ...start file...
+vgdb-error value changed from 0 to 999999
+Breakpoint 1 at 0x........: file sleepers.c, line 72.
+Continuing.
+[New Thread ....]
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
+72        int i = 0;
+Continuing.
+[New Thread ....]
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
+72        int i = 0;
+Continuing.
+[New Thread ....]
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
+72        int i = 0;
+Continuing.
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
+72        int i = 0;
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in do_burn () at sleepers.c:39
+39        for (i = 0; i < burn; i++) loopnr++;
+[Switching to thread 1 (Thread ....)]#0  0x........ in do_burn () at sleepers.c:39
+39        for (i = 0; i < burn; i++) loopnr++;
+$1 = void
+[Switching to thread 2 (Thread ....)]#0  0x........ in syscall ...
+Could not write register  "xxx"; remote failure reply 'E.
+ERROR changing register  xxx regno y
+gdb commands changing registers (pc, sp, ...) (e.g. 'jump',
+set pc, calling from gdb a function in the debugged process, ...)
+can only be accepted if the thread is VgTs_Runnable or VgTs_Yielding state
+Thread status is VgTs_WaitSys
+'
+[Switching to thread 3 (Thread ....)]#0  0x........ in syscall ...
+Could not write register  "xxx"; remote failure reply 'E.
+ERROR changing register  xxx regno y
+gdb commands changing registers (pc, sp, ...) (e.g. 'jump',
+set pc, calling from gdb a function in the debugged process, ...)
+can only be accepted if the thread is VgTs_Runnable or VgTs_Yielding state
+Thread status is VgTs_WaitSys
+'
+[Switching to thread 4 (Thread ....)]#0  0x........ in do_burn () at sleepers.c:39
+39        for (i = 0; i < burn; i++) loopnr++;
+$2 = void
+monitor command request to kill this process
+Remote connection closed
diff --git a/gdbserver_tests/mcinfcallWSRU.stdinB.gdb b/gdbserver_tests/mcinfcallWSRU.stdinB.gdb
new file mode 100644 (file)
index 0000000..8429dde
--- /dev/null
@@ -0,0 +1,28 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcinfcallWSRU
+monitor vg.set vgdb-error 999999
+#
+# ensure all threads are known
+break sleeper_or_burner
+continue
+continue
+continue
+continue
+#
+# Here the 4 threads have been started.
+# We will interrupt in a few seconds (be sure all tasks are in Runnable/Yielding state
+# or in WaitSys state.
+shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-mcinfcallWSRU 10
+#
+continue
+#
+thread 1
+print whoami("thread 1 inferior call pushed from gdb in mcinfcallWSRU.stdinB.gdb")
+thread 2
+print whoami("thread 2 inferior call pushed from gdb in mcinfcallWSRU.stdinB.gdb")
+thread 3
+print whoami("thread 3 inferior call pushed from gdb in mcinfcallWSRU.stdinB.gdb")
+thread 4
+print whoami("thread 4 inferior call pushed from gdb in mcinfcallWSRU.stdinB.gdb")
+monitor vg.kill
+quit
diff --git a/gdbserver_tests/mcinfcallWSRU.vgtest b/gdbserver_tests/mcinfcallWSRU.vgtest
new file mode 100644 (file)
index 0000000..859ba17
--- /dev/null
@@ -0,0 +1,13 @@
+# test inferior calls when some threads are in Runnable or Yielding mode,
+# some threads are in WaitSys.
+prog: sleepers
+args: 100 100000000 1000000000 -S-SB-B-
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcinfcallWSRU
+# Disable on Darwin: inferior call rejected as it cannot find malloc.
+prereq: ../tests/os_test linux
+# filter_gdb to replace pid and Thread numbers.
+stderr_filter: filter_gdb
+progB: gdb
+argsB:  --quiet -l 60 --nx 1>&2 ./sleepers
+stdinB: mcinfcallWSRU.stdinB.gdb
+stderrB_filter: filter_gdb
diff --git a/gdbserver_tests/mcinvokeRU.stderr.exp b/gdbserver_tests/mcinvokeRU.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcinvokeRU.stderrB.exp b/gdbserver_tests/mcinvokeRU.stderrB.exp
new file mode 100644 (file)
index 0000000..41e660b
--- /dev/null
@@ -0,0 +1,14 @@
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.kill to pid ....
+readchar: Got EOF
+error reading packet
diff --git a/gdbserver_tests/mcinvokeRU.stdoutB.exp b/gdbserver_tests/mcinvokeRU.stdoutB.exp
new file mode 100644 (file)
index 0000000..e12ed90
--- /dev/null
@@ -0,0 +1,23 @@
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+monitor command request to kill this process
diff --git a/gdbserver_tests/mcinvokeRU.vgtest b/gdbserver_tests/mcinvokeRU.vgtest
new file mode 100644 (file)
index 0000000..ab933bb
--- /dev/null
@@ -0,0 +1,12 @@
+# test that vgdb can invoke a process when all threads are in Runnable or Yielding mode
+# If the test goes wrong, it might consume CPU during a long time.
+prog: sleepers
+args: 1 0 1000000000 B-B-B-B-
+vgopts: --tool=memcheck --vgdb=yes --vgdb-prefix=./vgdb-prefix-mcinvokeRU
+stderr_filter: filter_make_empty
+# as the Valgrind process is always busy, we do not need the vgdb.ptraceinvoker prereq.
+progB: invoker
+argsB: 10 --vgdb-prefix=./vgdb-prefix-mcinvokeRU --wait=60 -c vg.wait 0
+# if the --wait is not enough, the test will fail or block.
+stdoutB_filter: filter_memcheck_monitor
+stderrB_filter: filter_vgdb
diff --git a/gdbserver_tests/mcinvokeWS.stderr.exp b/gdbserver_tests/mcinvokeWS.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcinvokeWS.stderrB.exp b/gdbserver_tests/mcinvokeWS.stderrB.exp
new file mode 100644 (file)
index 0000000..41e660b
--- /dev/null
@@ -0,0 +1,14 @@
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.wait 0 to pid ....
+sending command vg.kill to pid ....
+readchar: Got EOF
+error reading packet
diff --git a/gdbserver_tests/mcinvokeWS.stdoutB.exp b/gdbserver_tests/mcinvokeWS.stdoutB.exp
new file mode 100644 (file)
index 0000000..e12ed90
--- /dev/null
@@ -0,0 +1,23 @@
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+gdbserver: continuing in 0 ms ...
+gdbserver: continuing after wait ...
+monitor command request to kill this process
diff --git a/gdbserver_tests/mcinvokeWS.vgtest b/gdbserver_tests/mcinvokeWS.vgtest
new file mode 100644 (file)
index 0000000..1be48e8
--- /dev/null
@@ -0,0 +1,12 @@
+# test that vgdb can invoke a process when all threads are in WaitSys mode.
+# If the test goes wrong, it might be blocked during 10000 seconds.
+prog: sleepers
+args: 1 10000000 0 -S-S-S-S
+vgopts: --tool=memcheck --vgdb=yes --vgdb-prefix=./vgdb-prefix-mcinvokeWS
+stderr_filter: filter_make_empty
+prereq: test -f vgdb.ptraceinvoker
+progB: invoker
+argsB: 10 --vgdb-prefix=./vgdb-prefix-mcinvokeWS --wait=60 -c vg.wait 0
+# if the --wait is not enough, the test will fail or block
+stdoutB_filter: filter_memcheck_monitor
+stderrB_filter: filter_vgdb
diff --git a/gdbserver_tests/mcleak.stderr.exp b/gdbserver_tests/mcleak.stderr.exp
new file mode 100644 (file)
index 0000000..734ff4a
--- /dev/null
@@ -0,0 +1,40 @@
+(action at startup) vgdb me ... 
+expecting details 10 bytes reachable
+10 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+expecting to have NO details
+expecting details +10 bytes lost, +21 bytes reachable
+expecting details +65 bytes reachable
+expecting to have NO details
+expecting details +10 bytes reachable
+expecting details -10 bytes reachable, +10 bytes lost
+expecting details -10 bytes lost, +10 bytes reachable
+expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable
+finished
+leaked:      32 bytes in  1 blocks
+dubious:      0 bytes in  0 blocks
+reachable:   64 bytes in  3 blocks
+suppressed:   0 bytes in  0 blocks
+10 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+21 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:23)
+   by 0x........: main (leak-delta.c:60)
+
+32 bytes in 1 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+33 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
diff --git a/gdbserver_tests/mcleak.stderrB.exp b/gdbserver_tests/mcleak.stderrB.exp
new file mode 100644 (file)
index 0000000..081cde7
--- /dev/null
@@ -0,0 +1,58 @@
+relaying data between gdb and process ....
+vgdb-error value changed from 0 to 999999
+10 bytes in 1 blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+10 (+10) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+21 (+21) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:23)
+   by 0x........: main (leak-delta.c:60)
+
+65 (+65) bytes in 2 (+2) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+10 (+10) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+0 (-10) bytes in 0 (-1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+10 (+10) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+0 (-10) bytes in 0 (-1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+10 (+10) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:14)
+   by 0x........: main (leak-delta.c:60)
+
+32 (+32) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+33 (-32) bytes in 1 (-1) blocks are still reachable in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: f (leak-delta.c:28)
+   by 0x........: main (leak-delta.c:60)
+
+Remote connection closed
diff --git a/gdbserver_tests/mcleak.stdinB.gdb b/gdbserver_tests/mcleak.stdinB.gdb
new file mode 100644 (file)
index 0000000..5cdcbe9
--- /dev/null
@@ -0,0 +1,75 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcleak
+monitor vg.set vgdb-error 999999
+#
+#
+# insert break:
+break breakme
+#
+# continue till each break and execute via gdb the leak search as done in the C code.
+continue
+#
+#
+#   fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check any reachable full
+continue
+#   VALGRIND_DO_LEAK_CHECK;
+#
+#   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr);
+up
+monitor mc.leak_check increased reachable full
+continue
+#   VALGRIND_DO_ADDED_LEAK_CHECK;
+#
+#   b10--; // lose b10
+#   b21 = malloc (21);
+#   fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check increased reachable full
+continue
+#   VALGRIND_DO_ADDED_LEAK_CHECK;
+#
+#   for (i = 0; i < 2; i ++)
+#      b32_33[i] = malloc (32+i);
+#   fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check increased reachable full
+continue
+#   VALGRIND_DO_ADDED_LEAK_CHECK;
+#
+#   fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check increased reachable full
+continue
+#   VALGRIND_DO_ADDED_LEAK_CHECK;
+#
+#   b10++;
+#   fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check increased reachable full
+continue
+#   VALGRIND_DO_ADDED_LEAK_CHECK;
+#
+#   b10--;
+#   fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check changed reachable full
+continue
+#   VALGRIND_DO_CHANGED_LEAK_CHECK;
+#
+#   b10++;
+#   fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check changed reachable full
+continue
+#   VALGRIND_DO_CHANGED_LEAK_CHECK;
+#
+#   b32_33[0]--;
+#   fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
+up
+monitor mc.leak_check changed reachable full
+continue
+#   VALGRIND_DO_CHANGED_LEAK_CHECK;
+#
+quit
diff --git a/gdbserver_tests/mcleak.stdoutB.exp b/gdbserver_tests/mcleak.stdoutB.exp
new file mode 100644 (file)
index 0000000..b3e1aec
--- /dev/null
@@ -0,0 +1,49 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcleak
+0x........ in _start () from ...start file...
+Breakpoint 1 at 0x........: file leak-delta.c, line 9.
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:16
+16        fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:19
+19        fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:24
+24        fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:29
+29        fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:32
+32        fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:36
+36        fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:40
+40        fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:44
+44        fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
+Breakpoint 1, breakme () at leak-delta.c:9
+9      static void breakme() {};
+#1  0x........ in f () at leak-delta.c:48
+48        fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
+Continuing.
diff --git a/gdbserver_tests/mcleak.vgtest b/gdbserver_tests/mcleak.vgtest
new file mode 100644 (file)
index 0000000..3cdd1ea
--- /dev/null
@@ -0,0 +1,12 @@
+# test the memcheck leak functionality.
+prog: ../memcheck/tests/leak-delta
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcleak -q --leak-check=yes --show-reachable=yes --leak-resolution=high
+# temorarily disabled, waiting for leak-delta test program (next patch)
+prereq: test -x ../memcheck/tests/leak-delta
+stdout_filter: filter_memcheck_monitor
+stderr_filter: filter_memcheck_monitor
+progB: gdb
+argsB: --quiet -l 60 --nx ../memcheck/tests/leak-delta
+stdinB: mcleak.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_memcheck_monitor
diff --git a/gdbserver_tests/mcsignopass.stderr.exp b/gdbserver_tests/mcsignopass.stderr.exp
new file mode 100644 (file)
index 0000000..f60f30e
--- /dev/null
@@ -0,0 +1,20 @@
+
+(action at startup) vgdb me ... 
+Test 1: Invalid write of size 4
+   at 0x........: test1 (faultstatus.c:105)
+   by 0x........: main (faultstatus.c:168)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+  PASS
+Test 2:   PASS
+Test 3:   PASS
+Test 4:   PASS
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 11 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/gdbserver_tests/mcsignopass.stderrB.exp b/gdbserver_tests/mcsignopass.stderrB.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcsignopass.stdinB.gdb b/gdbserver_tests/mcsignopass.stdinB.gdb
new file mode 100644 (file)
index 0000000..44a5c08
--- /dev/null
@@ -0,0 +1,41 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcsignopass
+monitor vg.set vgdb-error 999999
+#
+# instruct gdb to not pass (i.e. ignore) these signals.
+#
+# Trap the below signals, we make them stop and then continue.
+# For SIGSEGV, we make it continue a few times, till we pass it.
+handle SIGSEGV nopass print stop
+handle SIGBUS  pass print stop
+handle SIGFPE  pass print stop
+#
+continue
+#
+# SIGTRAP : caused by invalid write error detected by memcheck
+continue
+#
+# SIGSEGV can't be ignored, so it is re-signaled. We continue many times
+# to be sure it is this signal which is re-signalled. Then will pass it.
+continue
+continue
+continue
+continue
+continue
+continue
+continue
+continue
+continue
+#
+# Change handling so that we just see the 2nd SIGSEGV
+handle SIGSEGV pass print nostop
+continue
+#
+# SIGBUS will be shown and passed:
+continue
+#
+# then SIGFPE is shown and passed:
+continue
+#
+# program will exit
+quit
diff --git a/gdbserver_tests/mcsignopass.stdoutB.exp b/gdbserver_tests/mcsignopass.stdoutB.exp
new file mode 100644 (file)
index 0000000..70ff5ba
--- /dev/null
@@ -0,0 +1,64 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcsignopass
+0x........ in _start () from ...start file...
+Signal        Stop     Print   Pass to program Description
+SIGSEGV       Yes      Yes     No              Segmentation fault
+Signal        Stop     Print   Pass to program Description
+SIGBUS        Yes      Yes     Yes             Bus error
+Signal        Stop     Print   Pass to program Description
+SIGFPE        Yes      Yes     Yes             Arithmetic exception
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Signal        Stop     Print   Pass to program Description
+SIGSEGV       No       Yes     Yes             Segmentation fault
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+Program received signal SIGBUS, Bus error.
+0x........ in test3 () at faultstatus.c:115
+115            mapping[FILESIZE+10];
+Continuing.
+Program received signal SIGFPE, Arithmetic exception.
+0x........ in test4 () at faultstatus.c:120
+120            volatile int v = 44/zero();
+Continuing.
diff --git a/gdbserver_tests/mcsignopass.vgtest b/gdbserver_tests/mcsignopass.vgtest
new file mode 100644 (file)
index 0000000..6568c62
--- /dev/null
@@ -0,0 +1,15 @@
+# test the signal handling, when signals are *not* passed to the Valgrind guest.
+# We detect this two ways:
+#   the gdb output will not contain the signal handling
+#   faultstatus C code will report a failure for the signal not passed
+#      (i.e. SIGBUG, Test 3). Other tests will be succesful, because signals
+#      are eventually passed.
+prog: ../none/tests/faultstatus
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcsignopass
+stderr_filter: filter_memcheck_monitor
+progB: gdb
+argsB: --quiet -l 60 --nx ../none/tests/faultstatus
+stdinB: mcsignopass.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_make_empty
+
diff --git a/gdbserver_tests/mcsigpass.stderr.exp b/gdbserver_tests/mcsigpass.stderr.exp
new file mode 100644 (file)
index 0000000..af2b53a
--- /dev/null
@@ -0,0 +1,20 @@
+
+(action at startup) vgdb me ... 
+Test 1: Invalid write of size 4
+   at 0x........: test1 (faultstatus.c:105)
+   by 0x........: main (faultstatus.c:168)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+  PASS
+Test 2:   PASS
+Test 3:   PASS
+Test 4:   PASS
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/gdbserver_tests/mcsigpass.stderrB.exp b/gdbserver_tests/mcsigpass.stderrB.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcsigpass.stdinB.gdb b/gdbserver_tests/mcsigpass.stdinB.gdb
new file mode 100644 (file)
index 0000000..ebd0cc7
--- /dev/null
@@ -0,0 +1,25 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcsigpass
+monitor vg.set vgdb-error 999999
+#
+# After this continue, we will receive 5 signals.
+continue
+#
+# SIGTRAP : caused by invalid write error detected by memcheck
+continue
+#
+# SIGSEGV : line 99
+continue
+#
+# SIGSEGV : line 104
+continue
+#
+# SIGBUS  : line 109
+continue
+#
+# SIGFPE  : line 114
+continue
+#
+# program will exit
+quit
+
diff --git a/gdbserver_tests/mcsigpass.stdoutB.exp b/gdbserver_tests/mcsigpass.stdoutB.exp
new file mode 100644 (file)
index 0000000..e924592
--- /dev/null
@@ -0,0 +1,19 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcsigpass
+0x........ in _start () from ...start file...
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test1 () at faultstatus.c:105
+105            *BADADDR = 'x';
+Continuing.
+Program received signal SIGSEGV, Segmentation fault.
+0x........ in test2 () at faultstatus.c:110
+110            mapping[0] = 'x';
+Continuing.
+Program received signal SIGBUS, Bus error.
+0x........ in test3 () at faultstatus.c:115
+115            mapping[FILESIZE+10];
+Continuing.
+Program received signal SIGFPE, Arithmetic exception.
+0x........ in test4 () at faultstatus.c:120
+120            volatile int v = 44/zero();
+Continuing.
diff --git a/gdbserver_tests/mcsigpass.vgtest b/gdbserver_tests/mcsigpass.vgtest
new file mode 100644 (file)
index 0000000..6cb0e3f
--- /dev/null
@@ -0,0 +1,10 @@
+# test the signal handling, when signals are passed to the Valgrind guest.
+prog: ../none/tests/faultstatus
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcsigpass
+stderr_filter: filter_memcheck_monitor
+progB: gdb
+argsB: --quiet -l 60 --nx ../none/tests/faultstatus
+stdinB: mcsigpass.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_make_empty
+
diff --git a/gdbserver_tests/mcvabits.stderr.exp b/gdbserver_tests/mcvabits.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcvabits.stderrB.exp b/gdbserver_tests/mcvabits.stderrB.exp
new file mode 100644 (file)
index 0000000..6b4635e
--- /dev/null
@@ -0,0 +1,55 @@
+relaying data between gdb and process ....
+vgdb-error value changed from 0 to 999999
+Address 0x........ len 10 addressable
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+Address 0x........ len 10 defined
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+00000000 00000000 0000
+Address 0x........ len 10 addressable
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+Address 0x........ len 10 not defined:
+Uninitialised value at 0x........
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+ff00ff00 ff00ff00 ff00
+Address 0x........ len 10 addressable
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+Address 0x........ len 10 not defined:
+Uninitialised value at 0x........
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+ff000000 0000ff00 ff00
+Address 0x........ len 10 addressable
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+Address 0x........ len 10 not defined:
+Uninitialised value at 0x........
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+ff00ffff ffffff00 ff00
+Address 0x........ len 2 addressable
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+Address 0x........ len 2 not defined:
+Uninitialised value at 0x........
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+ff00
+Address 0x........ len 2 not addressable:
+bad address 0x........
+ Address 0x........ is 2 bytes inside data symbol "undefined"
+Address 0x........ len 2 not addressable:
+bad address 0x........
+ Address 0x........ is 2 bytes inside data symbol "undefined"
+____
+Address 0x........ len 2 has 2 bytes unaddressable
+Address 0x........ len 6 addressable
+ Address 0x........ is 4 bytes inside data symbol "undefined"
+Address 0x........ len 6 not defined:
+Uninitialised value at 0x........
+ Address 0x........ is 4 bytes inside data symbol "undefined"
+ffffff00 ff00
+Address 0x........ len 10 not addressable:
+bad address 0x........
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+Address 0x........ len 10 not addressable:
+bad address 0x........
+ Address 0x........ is 0 bytes inside data symbol "undefined"
+0000____ 00000000 0000
+Address 0x........ len 10 has 2 bytes unaddressable
+monitor command request to kill this process
+Remote connection closed
diff --git a/gdbserver_tests/mcvabits.stdinB.gdb b/gdbserver_tests/mcvabits.stdinB.gdb
new file mode 100644 (file)
index 0000000..7aa423a
--- /dev/null
@@ -0,0 +1,73 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcvabits
+monitor vg.set vgdb-error 999999
+#
+#
+# insert break:
+break breakme
+#
+# continue till //1break:
+continue
+#
+# up to main:
+up
+#
+# print local string variables:
+print main_name
+print undefined
+# save address of undefined 
+set $0xundefined = &undefined
+#
+# Verif A-bits, V-bits, Get V-bits: A,V,G [0..9]
+eval "monitor mc.check_memory addressable 0x%x 10", $0xundefined
+eval "monitor mc.check_memory defined     0x%x 10", $0xundefined
+eval "monitor mc.get_vbits                0x%x 10", $0xundefined
+#
+# continue till //2break:
+continue
+#
+# A,V,G [0..9] after the undefinition of some bytes by executable:
+eval "monitor mc.check_memory addressable 0x%x 10", $0xundefined
+eval "monitor mc.check_memory defined     0x%x 10", $0xundefined
+eval "monitor mc.get_vbits                0x%x 10", $0xundefined
+#
+# Redefine [2..4]
+set $0xundefined_2 = (char*)$0xundefined + 2
+eval "monitor mc.make_memory defined 0x%x 3", $0xundefined_2
+# A,V,G
+eval "monitor mc.check_memory addressable 0x%x 10", $0xundefined
+eval "monitor mc.check_memory defined     0x%x 10", $0xundefined
+eval "monitor mc.get_vbits                0x%x 10", $0xundefined
+#
+# Undefine [2..5]
+eval "monitor mc.make_memory  undefined   0x%x 4", $0xundefined_2
+# A,V,G [0..9]
+eval "monitor mc.check_memory addressable 0x%x 10", $0xundefined
+eval "monitor mc.check_memory defined     0x%x 10", $0xundefined
+eval "monitor mc.get_vbits                0x%x 10", $0xundefined
+#
+# noaccess [2..3]
+eval "monitor mc.make_memory  noaccess    0x%x 2", $0xundefined_2
+# A,V,G [0..1]
+eval "monitor mc.check_memory addressable 0x%x 2", $0xundefined
+eval "monitor mc.check_memory defined     0x%x 2", $0xundefined
+eval "monitor mc.get_vbits                0x%x 2", $0xundefined
+# A,V,G [2..3]
+eval "monitor mc.check_memory addressable 0x%x 2", $0xundefined_2
+eval "monitor mc.check_memory defined     0x%x 2", $0xundefined_2
+eval "monitor mc.get_vbits                0x%x 2", $0xundefined_2
+# A,V,G [4..9]
+set  $0xundefined_4 = (char*) $0xundefined_2 + 2
+eval "monitor mc.check_memory addressable 0x%x 6", $0xundefined_4
+eval "monitor mc.check_memory defined     0x%x 6", $0xundefined_4
+eval "monitor mc.get_vbits                0x%x 6", $0xundefined_4
+#
+# ifaddressabledefined undefined[0..9]
+eval "monitor mc.make_memory  ifaddressabledefined 0x%x 10", $0xundefined
+# A,V,G
+eval "monitor mc.check_memory addressable 0x%x 10", $0xundefined
+eval "monitor mc.check_memory defined     0x%x 10", $0xundefined
+eval "monitor mc.get_vbits                0x%x 10", $0xundefined
+#
+monitor vg.kill
+quit
diff --git a/gdbserver_tests/mcvabits.stdoutB.exp b/gdbserver_tests/mcvabits.stdoutB.exp
new file mode 100644 (file)
index 0000000..68df7e1
--- /dev/null
@@ -0,0 +1,13 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcvabits
+0x........ in _start () from ...start file...
+Breakpoint 1 at 0x........: file t.c, line 100.
+Continuing.
+Breakpoint 1, breakme (line=112) at t.c:100
+100       if (line > 1000)
+#1  0x........ in main (argc=1, argv=0x........) at t.c:112
+112      breakme(__LINE__); //break1
+$1 = 0x........ "main name"
+$2 = "undefined"
+Continuing.
+Breakpoint 1, breakme (line=117) at t.c:100
+100       if (line > 1000)
diff --git a/gdbserver_tests/mcvabits.vgtest b/gdbserver_tests/mcvabits.vgtest
new file mode 100644 (file)
index 0000000..689c26f
--- /dev/null
@@ -0,0 +1,12 @@
+# test the memcheck V and A bits monitor functionality
+prog: t
+vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcvabits
+stdout_filter: filter_make_empty
+stderr_filter: filter_make_empty
+prereq: test -e ./gdb.eval
+progB: gdb
+argsB: --quiet -l 60 --nx ./t
+stdinB: mcvabits.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_memcheck_monitor
+
diff --git a/gdbserver_tests/mcwatchpoints.stderr.exp b/gdbserver_tests/mcwatchpoints.stderr.exp
new file mode 100644 (file)
index 0000000..b73233a
--- /dev/null
@@ -0,0 +1,25 @@
+
+(action at startup) vgdb me ... 
+breakme function called from line 19
+before reading 0/4/8
+u: Expected value at 0
+f: Expected value at 4
+d: Expected value at 8
+before writing 0
+before writing 4
+before writing 8
+after writing 8
+value UndeFineD
+before rewriting 0
+before rewriting 4
+before rewriting 8
+value 0nde4ine8
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/gdbserver_tests/mcwatchpoints.stderrB.exp b/gdbserver_tests/mcwatchpoints.stderrB.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mcwatchpoints.stdinB.gdb b/gdbserver_tests/mcwatchpoints.stdinB.gdb
new file mode 100644 (file)
index 0000000..5ec79fa
--- /dev/null
@@ -0,0 +1,24 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcwatchpoints
+monitor vg.set vgdb-error 999999
+#
+#
+# insert break:
+break breakme
+#
+# continue till //break1:
+continue
+#
+# insert the watchpoints
+rwatch undefined[0]
+awatch undefined[4]
+watch  undefined[8]
+#
+# now we should encounter 4 break points
+continue
+continue
+continue
+continue
+del
+continue
+quit
diff --git a/gdbserver_tests/mcwatchpoints.stdoutB.exp b/gdbserver_tests/mcwatchpoints.stdoutB.exp
new file mode 100644 (file)
index 0000000..7c6e09d
--- /dev/null
@@ -0,0 +1,33 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcwatchpoints
+0x........ in _start () from ...start file...
+Breakpoint 1 at 0x........: file watchpoints.c, line 7.
+Continuing.
+Breakpoint 1, breakme (line=19) at watchpoints.c:7
+7         fprintf(stderr, "breakme function called from line %d\n", line);
+Hardware read watchpoint 2: undefined[0]
+Hardware access (read/write) watchpoint 3: undefined[4]
+Hardware watchpoint 4: undefined[8]
+Continuing.
+Hardware read watchpoint 2: undefined[0]
+Value = 117 'u'
+main (argc=1, argv=0x........) at watchpoints.c:23
+23        if (undefined[0] == 'u')
+Continuing.
+Hardware access (read/write) watchpoint 3: undefined[4]
+Value = 102 'f'
+main (argc=1, argv=0x........) at watchpoints.c:28
+28        if (undefined[4] == 'f')
+Continuing.
+Hardware access (read/write) watchpoint 3: undefined[4]
+Old value = 102 'f'
+New value = 70 'F'
+main (argc=1, argv=0x........) at watchpoints.c:46
+46        fprintf(stderr, "before writing 8\n");
+Continuing.
+Hardware watchpoint 4: undefined[8]
+Old value = 100 'd'
+New value = 68 'D'
+main (argc=1, argv=0x........) at watchpoints.c:49
+49        fprintf(stderr, "after writing 8\n");
+Delete all breakpoints? (y or n) [answered Y; input not from terminal]
+Continuing.
diff --git a/gdbserver_tests/mcwatchpoints.vgtest b/gdbserver_tests/mcwatchpoints.vgtest
new file mode 100644 (file)
index 0000000..72714eb
--- /dev/null
@@ -0,0 +1,12 @@
+# test the memcheck watchpoint functionality
+# Note: we need --vgdb=full to stop at the instruction following the watchpoint.
+prog: watchpoints
+vgopts: --tool=memcheck --vgdb=full --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcwatchpoints
+stdout_filter: filter_make_empty
+stderr_filter: filter_memcheck_monitor
+progB: gdb
+argsB: --quiet -l 60 --nx ./watchpoints
+stdinB: mcwatchpoints.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_make_empty
+
diff --git a/gdbserver_tests/mssnapshot.stderr.exp b/gdbserver_tests/mssnapshot.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/mssnapshot.stderrB.exp b/gdbserver_tests/mssnapshot.stderrB.exp
new file mode 100644 (file)
index 0000000..4b7a012
--- /dev/null
@@ -0,0 +1,22 @@
+relaying data between gdb and process ....
+vgdb-error value changed from 0 to 999999
+general valgrind monitor commands:
+  help [debug]             : monitor command help. With debug: + debugging commands
+  vg.wait [<ms>]           : sleep <ms> (default 0) then continue
+  vg.info all_errors       : show all errors found so far
+  vg.info last_error       : show last error found
+  vg.info n_errs_found     : show the nr of errors found so far
+  vg.kill                  : kill the Valgrind process
+  vg.set gdb_output        : set valgrind output to gdb
+  vg.set log_output        : set valgrind output to log
+  vg.set mixed_output      : set valgrind output to log, interactive output to gdb
+  vg.set vgdb-error <errornr> : debug me at error >= <errornr> 
+
+massif monitor commands:
+  ms.snapshot [<filename>] [detailed]
+       takes a snapshot and saves it in <filename>
+             default <filename> is massif.vgdb.out
+             if present, detailed argument indicates to take a detailed snapshot
+
+monitor command request to kill this process
+Remote connection closed
diff --git a/gdbserver_tests/mssnapshot.stdinB.gdb b/gdbserver_tests/mssnapshot.stdinB.gdb
new file mode 100644 (file)
index 0000000..42b56fe
--- /dev/null
@@ -0,0 +1,21 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mssnapshot
+monitor vg.set vgdb-error 999999
+#
+#
+# insert break:
+break main
+#
+# continue till main
+continue
+#
+# test the massif help
+monitor help
+#
+# test non detailed and detailed snapshot
+monitor ms.snapshot
+monitor ms.snapshot detailed
+#
+#
+monitor vg.kill
+quit
diff --git a/gdbserver_tests/mssnapshot.stdoutB.exp b/gdbserver_tests/mssnapshot.stdoutB.exp
new file mode 100644 (file)
index 0000000..274eab0
--- /dev/null
@@ -0,0 +1,6 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mssnapshot
+0x........ in _start () from ...start file...
+Breakpoint 1 at 0x........: file t.c, line 105.
+Continuing.
+Breakpoint 1, main (argc=1, argv=0x........) at t.c:105
+105      char *main_name = "main name";
diff --git a/gdbserver_tests/mssnapshot.vgtest b/gdbserver_tests/mssnapshot.vgtest
new file mode 100644 (file)
index 0000000..a11a04d
--- /dev/null
@@ -0,0 +1,10 @@
+# test the memcheck monitor help
+prog: t
+vgopts: --tool=massif --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mssnapshot
+stdout_filter: filter_make_empty
+stderr_filter: filter_make_empty
+progB: gdb
+argsB: --quiet -l 60 --nx ./t
+stdinB: mssnapshot.stdinB.gdb
+stdoutB_filter: filter_gdb
+stderrB_filter: filter_vgdb
diff --git a/gdbserver_tests/nlcontrolc.stderr.exp b/gdbserver_tests/nlcontrolc.stderr.exp
new file mode 100644 (file)
index 0000000..f6eef78
--- /dev/null
@@ -0,0 +1,9 @@
+Nulgrind, the minimal Valgrind tool
+
+(action at startup) vgdb me ... 
+loops/sleep_ms/burn/threads_spec:  1000000000 1000000000 1000000000 BSBSBSBS
+Brussels ready to sleep and/or burn
+London ready to sleep and/or burn
+Petaouchnok ready to sleep and/or burn
+main ready to sleep and/or burn
+
diff --git a/gdbserver_tests/nlcontrolc.stderrB.exp b/gdbserver_tests/nlcontrolc.stderrB.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdbserver_tests/nlcontrolc.stdinB.gdb b/gdbserver_tests/nlcontrolc.stdinB.gdb
new file mode 100644 (file)
index 0000000..53a8d68
--- /dev/null
@@ -0,0 +1,38 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-nlcontrolc
+monitor vg.set vgdb-error 999999
+#
+#
+# simulate control-c in a few seconds
+shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-nlcontrolc 10
+#
+continue
+#
+# Here, all tasks should be blocked in a loooonnnng select, all in WaitSys
+info threads
+# We will unblock them by changing their timeout argument
+# To avoid going into the frame where the timeval arg is,
+# it has been defined as global variables, as the nr
+# of calls on the stack differs between 32bits and 64bits,
+# and/or between OS.
+# ensure select finishes in a few milliseconds max:
+p t[0].tv_sec = 0
+p t[1].tv_sec = 0
+p t[2].tv_sec = 0
+p t[3].tv_sec = 0
+#
+# We will change the burning parameters in a few  seconds
+shell ./simulate_control_c --vgdb-prefix=./vgdb-prefix-nlcontrolc 10
+#
+continue
+#
+# Threads are burning cpu now
+# We would like to test info threads here, but which thread are Runnable or Yielding
+# is unpredictable.
+# info threads
+p burn = 0
+p loops = 0
+p report_finished = 0
+continue
+# and the process should stop very quickly now
+quit
diff --git a/gdbserver_tests/nlcontrolc.stdoutB.exp b/gdbserver_tests/nlcontrolc.stdoutB.exp
new file mode 100644 (file)
index 0000000..a79f5d2
--- /dev/null
@@ -0,0 +1,24 @@
+Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-nlcontrolc
+0x........ in _start () from ...start file...
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in syscall ...
+[New Thread ....]
+[New Thread ....]
+[New Thread ....]
+  4 Thread .... (tid 4 VgTs_WaitSys)  0x........ in syscall ...
+  3 Thread .... (tid 3 VgTs_WaitSys)  0x........ in syscall ...
+  2 Thread .... (tid 2 VgTs_WaitSys)  0x........ in syscall ...
+* 1 Thread .... (tid 1 VgTs_WaitSys)  0x........ in syscall ...
+$1 = 0
+$2 = 0
+$3 = 0
+$4 = 0
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in do_burn () at sleepers.c:39
+39        for (i = 0; i < burn; i++) loopnr++;
+$5 = 0
+$6 = 0
+$7 = 0
+Continuing.
diff --git a/gdbserver_tests/nlcontrolc.vgtest b/gdbserver_tests/nlcontrolc.vgtest
new file mode 100644 (file)
index 0000000..6c05901
--- /dev/null
@@ -0,0 +1,20 @@
+# test :
+#   info threads valgrind specific output
+#   the user can control-c an process with all threads in WaitSys
+#          and modify some variables
+#   the user can control-c an process with all threads in Running/Yielding
+#          and modify some variables
+# sleepers is started with argument so that it will compute during ages.
+# The variable modifications means it will exit in a reasonable time.
+prog: sleepers
+args: 1000000000 1000000000 1000000000 BSBSBSBS
+vgopts: --tool=none --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-nlcontrolc
+stderr_filter: filter_stderr
+prereq: test -f vgdb.ptraceinvoker
+progB: gdb
+argsB: --quiet -l 60 --nx ./sleepers
+stdinB: nlcontrolc.stdinB.gdb
+#stdoutB_filter: /bin/cat
+stdoutB_filter: filter_gdb
+#stderrB_filter: /bin/cat
+stderrB_filter: filter_make_empty
diff --git a/gdbserver_tests/simulate_control_c b/gdbserver_tests/simulate_control_c
new file mode 100755 (executable)
index 0000000..cea1e59
--- /dev/null
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+# simulate control_c by sending SIGUSR1 to the vgdb using prefix $1 in $2 seconds
+VGDBPID=`./vgdb -D $1 2>&1 | awk '/vgdb pid/ {print $3}'`
+if [ "$VGDBPID" = "" ]
+then
+  echo "simulate_control_c could not determine the vgdb pid with " $1
+  exit 1
+fi
+(sleep $2; kill -10 $VGDBPID) &
+
diff --git a/gdbserver_tests/sleepers.c b/gdbserver_tests/sleepers.c
new file mode 100644 (file)
index 0000000..cea20cb
--- /dev/null
@@ -0,0 +1,187 @@
+#define _GNU_SOURCE
+#include <string.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sched.h>
+
+static int loops = 15; // each thread+main will do this amount of loop
+static int sleepms = 1000; // in each loop, will sleep "sleepms" milliseconds
+static int burn = 0; // after each sleep, will burn cpu in a tight 'burn' loop 
+
+
+static pid_t gettid()
+{
+#ifdef __NR_gettid
+   return syscall(__NR_gettid);
+#else
+   return getpid();
+#endif
+}
+
+// will be invoked from gdb.
+static void whoami(char *msg)
+{
+   fprintf(stderr, "pid %d Thread %d %s\n", getpid(), gettid(), msg);
+   fflush(stderr);
+}
+
+
+static void do_burn ()
+{
+   int i;
+   int loopnr = 0;
+   // one single line for the below, to ensure interrupt on this line.
+   for (i = 0; i < burn; i++) loopnr++;
+}
+
+static int thread_ready = 0;
+static pthread_cond_t ready = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void signal_ready (void)
+{
+   int rc;
+   rc = pthread_mutex_lock(&ready_mutex);
+   if (rc != 0)
+      fprintf(stderr, "signal_ready lock error %d_n", rc);
+   thread_ready = 1;
+   rc = pthread_cond_signal(&ready);
+   if (rc != 0)
+      fprintf(stderr, "signal_ready signal error %d_n", rc);
+   rc = pthread_mutex_unlock(&ready_mutex);
+   if (rc != 0)
+      fprintf(stderr, "signal_ready unlock error %d_n", rc);
+}
+
+struct spec {
+   char *name;
+   int sleep;
+   int burn;
+   int t;
+};
+static struct timeval t[4];
+static int nr_sleeper_or_burner = 0;
+static volatile int report_finished = 1; 
+// set to 0 to have no finish msg (as order is non-deterministic)
+static void *sleeper_or_burner(void *v)
+{
+   int i = 0;
+   struct spec* s = (struct spec*)v;
+
+   fprintf(stderr, "%s ready to sleep and/or burn\n", s->name);
+   fflush (stderr);
+   signal_ready();
+   nr_sleeper_or_burner++;
+
+   for (i = 0; i < loops; i++) {
+      if (sleepms > 0 && s->sleep) {
+         t[s->t].tv_sec = sleepms / 1000;
+         t[s->t].tv_usec = (sleepms % 1000) * 1000;
+         select (0, NULL, NULL, NULL, &t[s->t]);
+      }
+      if (burn > 0 && s->burn)
+         do_burn();
+   }
+   if (report_finished) {
+      fprintf(stderr, "%s finished to sleep and/or burn\n", s->name);
+      fflush (stderr);
+   }
+   return NULL;
+}
+
+// wait till a thread signals it is ready
+static void wait_ready(void)
+{
+   int rc;
+   rc = pthread_mutex_lock(&ready_mutex);
+   if (rc != 0)
+      fprintf(stderr, "wait_ready lock error %d_n", rc);
+   while (! thread_ready && rc == 0) {
+      rc = pthread_cond_wait(&ready, &ready_mutex);
+      if (rc != 0)
+         fprintf(stderr, "wait_ready wait error %d_n", rc);
+   }
+   thread_ready = 0;
+   rc = pthread_mutex_unlock(&ready_mutex);
+   if (rc != 0)
+      fprintf(stderr, "wait_ready unlock error %d_n", rc);
+}
+
+// We will lock ourselves on one single cpu.
+// This bypasses the unfairness of the Valgrind scheduler
+// when a multi-cpu machine has enough cpu to run all the
+// threads wanting to burn cpu.
+static void setaffinity(void)
+{
+#ifdef VGO_linux
+   cpu_set_t single_cpu;
+   CPU_ZERO(&single_cpu);
+   CPU_SET(1, &single_cpu);
+   (void) sched_setaffinity(0, sizeof(single_cpu), &single_cpu);
+#endif
+   // GDBTD: equivalent for Darwin ?
+}
+
+int main (int argc, char *argv[])
+{
+  char *threads_spec;
+  pthread_t ebbr, egll, zzzz;
+  struct spec b, l, p, m;
+  char *some_mem = malloc(100);
+  setaffinity();
+
+  if (argc > 1)
+     loops = atoi(argv[1]);
+
+  if (argc > 2)
+     sleepms = atoi(argv[2]);
+
+  if (argc > 3)
+     burn = atoll(argv[3]);
+
+  if (argc > 4)
+     threads_spec = argv[4];
+  else
+     threads_spec = "BSBSBSBS";
+  
+  fprintf(stderr, "loops/sleep_ms/burn/threads_spec:  %d %d %d %s\n",
+          loops, sleepms, burn, threads_spec);
+  fflush(stderr);
+
+  b.name = "Brussels";
+  b.burn = *threads_spec++ == 'B';
+  b.sleep = *threads_spec++ == 'S';
+  b.t = 1;
+  pthread_create(&ebbr, NULL, sleeper_or_burner, &b);
+  wait_ready();
+  
+  l.name = "London";
+  l.burn = *threads_spec++ == 'B';
+  l.sleep = *threads_spec++ == 'S';
+  l.t = 2;
+  pthread_create(&egll, NULL, sleeper_or_burner, &l);
+  wait_ready();
+
+  p.name = "Petaouchnok";
+  p.burn = *threads_spec++ == 'B';
+  p.sleep = *threads_spec++ == 'S';
+  p.t = 3;
+  pthread_create(&zzzz, NULL, sleeper_or_burner, &p);
+  wait_ready();
+
+  m.name = "main";
+  m.burn = *threads_spec++ == 'B';
+  m.sleep = *threads_spec++ == 'S';
+  m.t = 0;
+  sleeper_or_burner(&m);
+
+  pthread_join(ebbr, NULL);
+  pthread_join(egll, NULL);
+  pthread_join(zzzz, NULL);
+
+  return 0;
+}
diff --git a/gdbserver_tests/t.c b/gdbserver_tests/t.c
new file mode 100644 (file)
index 0000000..8600480
--- /dev/null
@@ -0,0 +1,153 @@
+#include <string.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include "../memcheck/memcheck.h"
+int using_threads = 0; /* test collision with a global in gdbserver */
+/* we will undefine one char on two */
+static char undefined[10] = "undefined";
+
+#define LOOPS 10000000
+static int loopmain, loopt1, loopt2;
+
+static double pi = 3.14159265358979323846264338327950288;
+
+static pid_t gettid()
+{
+#ifdef __NT_gettid
+   return syscall(__NR_gettid);
+#else
+   return getpid();
+#endif
+}
+static void whoami(char *msg)
+{
+   printf("pid %d Thread %d %s\n", getpid(), gettid(), msg); fflush(stdout);
+}
+
+static int int_und;
+static int sleeps = 15;
+static void make_error (char *s)
+{
+  char *make_error_name = "make_error name";
+  char c;
+  double pi2 = 2.0 * pi;
+  whoami(s);
+  if (int_und == 0)
+     printf ("%s int_und is zero %d\n", s, int_und);
+  else
+     printf ("%s int_und is not zero\n", s);
+  fflush(stdout);
+}
+
+static void level ()
+{
+  char *level_name = "level name";
+  make_error ("called from level");
+}
+
+static void loops (int *loopnr)
+{
+  int i, j;
+  for (i = 0; i < LOOPS; i++)
+    for (j = 0; i < LOOPS; i++)
+      *loopnr++;
+}
+static void *brussels_fn(void *v)
+{
+  char *brussels_name = "Brussels";
+  make_error ("called from Brussels");
+  loopt1 = 1;
+  while (! (loopt1 && loopt2 && loopmain))
+    loopt1++;
+  loops (&loopt1);
+  return NULL;
+}
+static void *london_fn(void *v)
+{
+  char *london_name = "London";
+  make_error ("called from London");
+  loopt2 = 1;
+  while (! (loopt1 && loopt2 && loopmain))
+    loopt2++;
+  loops (&loopt2);
+  sleep(10);
+  return NULL;
+}
+static void *petaouchnok_fn(void *v)
+{
+  char *petaouchnok_name = "Petaouchnok";
+  struct timeval t;
+  int i;
+  for (i = 1; i <= sleeps; i++) {
+      t.tv_sec = 5;
+      t.tv_usec = 0;
+      fprintf (stderr, "Petaouchnok sleep nr %d out of %d sleeping 5 seconds\n",
+               i, sleeps);
+      fflush(stderr);
+      select (0, NULL, NULL, NULL, &t);
+  }
+  return NULL;
+}
+static void leaf(void) {}
+static void breakme(int line)
+{
+   if (line > 1000)
+      leaf(); // ensures not leaf, as ppc unwind implies VEX iropt precise exns
+}
+int main (int argc, char *argv[])
+{
+  char *main_name = "main name";
+  pthread_t ebbr, egll, zzzz;
+  int i = 1234;
+  char undef = '?';
+  char *some_mem = malloc(100);
+  VALGRIND_MAKE_MEM_UNDEFINED(&undef, 1);
+  int len = strlen(undefined);
+  breakme(__LINE__); //break1
+  for (i = len-1; i >= 0; i=i-2)
+     undefined[i] = undef;
+  *(char*)&int_und = undef;
+
+  breakme(__LINE__); //break2
+
+  if (argc > 1)
+    sleeps = atoi(argv[1]);
+
+  level();
+  make_error ("called from main");
+
+  pthread_create(&ebbr, NULL, brussels_fn, NULL);      
+  pthread_create(&egll, NULL, london_fn, NULL);        
+  pthread_create(&zzzz, NULL, petaouchnok_fn, NULL);   
+
+  loopmain = 1;
+  while (! (loopt1 && loopt2 && loopmain))
+    loopmain++;
+  for (i = 0; i < LOOPS; i++) {
+     loopmain++;
+
+     if (loopmain == 10000)
+        make_error ("in main loop");
+  }
+  
+  pthread_join(ebbr, NULL);
+
+  make_error ("called from main (the end, before joining t3)");
+
+  pthread_join(zzzz, NULL);
+
+  if (argc > 2) {
+     for (i = 0; i < 100; i++)
+        if ((*(&undef + i*4000) == 0) || (*(&undef - i*4000) == 0)) {
+           printf ("there are some null bytes here and there %d\n", i);
+           fflush(stdout);
+        }
+  }
+  exit(0);
+}
diff --git a/gdbserver_tests/watchpoints.c b/gdbserver_tests/watchpoints.c
new file mode 100644 (file)
index 0000000..ae05d8f
--- /dev/null
@@ -0,0 +1,67 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static void breakme(int line)
+{
+   fprintf(stderr, "breakme function called from line %d\n", line);
+   fflush(stderr);
+}
+static char undefined[10] = "undefined";
+int main (int argc, char *argv[])
+{
+
+   /* we will test 
+      read watchpoint at 0,
+      read/write watchpoints at 4
+      write watchpoints at 8 */
+
+   breakme(__LINE__); //break1
+
+   /* We verify read watchpoints are triggered at 0 and 4, not at 8 */
+   fprintf(stderr, "before reading 0/4/8\n");
+   if (undefined[0] == 'u')
+      fprintf(stderr, "u: Expected value at 0\n");
+   else
+      fprintf(stderr, "u: Unexpected value at 0\n");
+   
+   if (undefined[4] == 'f')
+      fprintf(stderr, "f: Expected value at 4\n");
+   else
+      fprintf(stderr, "f: Unexpected value at 4\n");
+   
+   if (undefined[8] == 'd')
+      fprintf(stderr, "d: Expected value at 8\n");
+   else
+      fprintf(stderr, "d: Unexpected value at 8\n");
+
+
+   /* We verify write watchpoints are triggered at 4 and 8, not at 0 */
+   fprintf(stderr, "before writing 0\n");
+   undefined[0] = 'U';
+
+   fprintf(stderr, "before writing 4\n");
+   undefined[4] = 'F';
+
+   fprintf(stderr, "before writing 8\n");
+   undefined[8] = 'D';
+
+   fprintf(stderr, "after writing 8\n");
+
+   /* after having remove the watchpoints, check we can read and write
+      without break. */
+   fprintf(stderr, "value %s\n", undefined);
+
+   fprintf(stderr, "before rewriting 0\n");
+   undefined[0] = '0';
+
+   fprintf(stderr, "before rewriting 4\n");
+   undefined[4] = '4';
+
+   fprintf(stderr, "before rewriting 8\n");
+   undefined[8] = '8';
+   
+   fprintf(stderr, "value %s\n", undefined);
+
+   exit(0);
+}
diff --git a/include/pub_tool_gdbserver.h b/include/pub_tool_gdbserver.h
new file mode 100644 (file)
index 0000000..514bcaa
--- /dev/null
@@ -0,0 +1,179 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Handle remote gdb protocol.             pub_tool_gdbserver.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011 Philippe Waroquiers
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_TOOL_GDBSERVER_H
+#define __PUB_TOOL_GDBSERVER_H
+
+#include "libvex.h"
+#include "libvex_ir.h"
+
+//--------------------------------------------------------------------
+// PURPOSE: This module provides the support to have a gdb
+// connecting to a valgrind process using remote gdb protocol. It provides
+//  * A function to allow a tool (or the valgrind core) to
+//    wait for a gdb to connect and then handle gdb commands.
+//    Typically, this can be used to let the user debug the process
+//    when valgrind reports an error.
+//  * A function allowing to instrument the code to support gdb breakpoints.
+//  * A function allowing the tool to support watchpoints.
+//  * A utility function to help implementing the processing of the
+//    gdb_monitor_command strings.
+
+
+// Function to be used by tool or coregrind to allow a gdb to connect
+// to this process. 
+// Calling VG_(gdbserver) with tid > 0 means to let a debugger attach
+// to the valgrind process. gdbserver will report to gdb that the
+// process stopped in thread tid.
+// tid == 0 indicates to stop gdbserver and report to gdb
+// that the valgrind-ified process has exited.
+//--------------------------------------------------------------------
+extern void VG_(gdbserver) ( ThreadId tid );
+
+/* VG_(dyn_vgdb_error) gets its initial value from
+   VG_(clo_vgdb_error).  It can be changed after initial command
+   processing in order to enable/disable the call to VG_(gdbserver) in
+   m_errormgr.c.  The main reasons to change the below is either
+   because the user updates it via a monitor command or to
+   (temporarily) avoid calling gdbserver for error reporting during
+   monitor command handling.
+*/
+extern Int VG_(dyn_vgdb_error);
+
+/* defines the various kinds of breakpoints that gdbserver
+   might ask to insert/remove. Note that the below matches
+   the gdbserver protocol definition. The level of support
+   of the various breakpoint kinds depends on the tool.
+
+   For the moment, it is unclear how a tool would implement
+   hardware_breakpoint in valgrind  :).
+
+   software_breakpoint implies some (small) specific
+   instrumentation to be done for gdbserver. This instrumentation
+   is implemented for all tools in m_translate.c.
+
+   write/read/access watchpoints can only be done by tools
+   which are maintaining some notion of address accessibility
+   as part of their instrumentation. watchpoints can then
+   be done by marking the watched address(es) as not accessible.
+   But instead of giving back an error (or whatever the tool
+   wants to do with unaccessible mechanism), the tool must then
+   just call gdbserver. See memcheck for an example of reusing
+   accessibility for watchpoint support.
+*/
+typedef
+   enum {
+      software_breakpoint,
+      hardware_breakpoint,
+      write_watchpoint,
+      read_watchpoint,
+      access_watchpoint } PointKind;
+extern char* VG_(ppPointKind) (PointKind kind);
+
+
+/* watchpoint support --------------------------------------*/
+/* True if one or more bytes in [addr, addr+len[ are being watched by
+   gdbserver for write or read or access.
+   In addition, VG_(is_watched) will invoke gdbserver if
+   the access provided by the tool matches the watchpoint kind.
+   For this, the tool must pass the kind of access it has detected:
+      write_watchpoint indicates the tool has detected a write
+      read_watchpoint indicates the tool has detected a read
+      access_watchpoint indicates the tool has detected an access but does
+      not know if this is a read or a write
+*/
+extern Bool VG_(is_watched)(PointKind kind, Addr addr, Int szB);
+
+extern void VG_(needs_watchpoint) (
+   // indicates the given Addr/len is being watched (insert)
+   // or not watched anymore (! insert).
+   // gdbserver will maintain the list of watched addresses.
+   // The tool can use VG_(is_watched) to verify if an
+   // access to an Addr is in one of the watched intervals.
+   // Must return True if the watchpoint has been properly inserted or
+   // removed. False if not supported.
+   // Note that an address can only be watched for a single kind.
+   // The tool must be ready to be called successively with
+   // multiple kinds for the same addr and len and with
+   // different kinds. The last kind must replace the previous values.
+   // Behaviour with multiple watches having overlapping addr+len
+   // is undefined.
+   Bool (*watchpoint) (PointKind kind, Bool insert, Addr addr, SizeT len)
+);
+
+
+// can be used during the processing of the VG_USERREQ__GDB_MONITOR_COMMAND 
+// tool client request to output information to gdb or vgdb.
+extern UInt VG_(gdb_printf) ( const HChar *format, ... ) PRINTF_CHECK(1, 2);
+
+/* Utility functions to (e.g.) parse gdb monitor commands.
+
+   keywords is a set of keywords separated by a space
+   keyword_id will search for the keyword starting with the string input_word
+   and return its position.
+   It returns -1 if no keyword matches.
+   It returns -2 if two or more keywords are starting with input_word
+                 and none of these matches exactly input_word
+   Example with keywords = "hello world here is hell" :
+   input_word    result
+   ----------    ------
+   paradise   => -1
+   i          =>  3
+   hell       =>  4
+   hel        => -2
+   ishtar     => -1
+
+   report indicates when to output an error msg with VG_(gdb_printf).
+   kwd_report_none : no error is reported.
+   kwd_report_all : the error msg will show all possible keywords
+   kwd_report_duplicated_matches : the error msg will show only the
+     ambiguous matches.
+*/
+typedef
+   enum {
+      kwd_report_none,
+      kwd_report_all,
+      kwd_report_duplicated_matches } kwd_report_error;
+extern Int VG_(keyword_id) (Char* keywords, Char* input_word, 
+                            kwd_report_error report);
+
+/* Extract an address and (optionally) a size from the string
+   currently being parsed by strtok_r (see pub_tool_libcbase.h).
+   If no size in the string, keeps the current value of szB.
+   Returns address 0 and szB 0 if there is an error.  Reports to the
+   user problems via VG_(gdb_printf).  */
+extern void VG_(strtok_get_address_and_size) (Addr* address, 
+                                              SizeT* szB, 
+                                              Char **ssaveptr);
+
+#endif   // __PUB_TOOL_GDBSERVER_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
index 2897235c6fed22b64cda34b64e4dcced9332473a..0e616913f44f9e08d889e7f3a74f2c7b3f4ca9e7 100644 (file)
@@ -63,6 +63,8 @@ extern Char VG_(tolower) ( Char c );
 // If you really want that behaviour, you can use "VG_(strtoll10)(str, NULL)".
 extern Long  VG_(strtoll10) ( Char* str, Char** endptr );
 extern Long  VG_(strtoll16) ( Char* str, Char** endptr );
+extern ULong  VG_(strtoull10) ( Char* str, Char** endptr );
+extern ULong  VG_(strtoull16) ( Char* str, Char** endptr );
 
 // Convert a string to a double.  After leading whitespace is ignored, a
 // '+' or '-' is allowed, and then it accepts a non-empty sequence of
@@ -97,6 +99,16 @@ extern Char* VG_(strrchr)        ( const Char* s, Char c );
 extern SizeT VG_(strspn)         ( const Char* s, const Char* accpt );
 extern SizeT VG_(strcspn)        ( const Char* s, const char* reject );
 
+/* strtok* functions and some parsing utilities. */
+extern Char* VG_(strtok_r)       (Char* s, const Char* delim, Char** saveptr);
+extern Char* VG_(strtok)         (Char* s, const Char* delim);
+
+/* Parse a 32- or 64-bit hex number, including leading 0x, from string
+   starting at *ppc, putting result in *result, and return True.  Or
+   fail, in which case *ppc and *result are undefined, and return
+   False. */
+extern Bool VG_(parse_Addr) ( UChar** ppc, Addr* result );
+
 /* Like strncpy(), but if 'src' is longer than 'ndest' inserts a '\0' as the
    last character. */
 extern void  VG_(strncpy_safely) ( Char* dest, const Char* src, SizeT ndest );
index 8f08cd2cf8b2791fc912f4fa87ae4ad8cb3953e0..4b63a53747b96a9990227e4e1d83de5419643dd2 100644 (file)
@@ -68,7 +68,11 @@ struct vg_stat {
    ULong   ctime_nsec;
 };
 
+extern SysRes VG_(mknod)  ( const Char* pathname, Int mode, UWord dev );
 extern SysRes VG_(open)   ( const Char* pathname, Int flags, Int mode );
+/* fd_open words like the open(2) system call: 
+   returns fd if success, -1 otherwise */
+extern Int VG_(fd_open)  (const Char* pathname, Int flags, Int mode);
 extern void   VG_(close)  ( Int fd );
 extern Int    VG_(read)   ( Int fd, void* buf, Int count);
 extern Int    VG_(write)  ( Int fd, const void* buf, Int count);
@@ -82,6 +86,8 @@ extern SysRes VG_(dup2)   ( Int oldfd, Int newfd );
 extern Int    VG_(rename) ( const Char* old_name, const Char* new_name );
 extern Int    VG_(unlink) ( const Char* file_name );
 
+extern Int    VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout);
+
 extern Int    VG_(readlink)( const Char* path, Char* buf, UInt bufsize );
 extern Int    VG_(getdents)( Int fd, struct vki_dirent *dirp, UInt count );
 
index 2770dda6a0c88c8adafcb5110a6145936f908f82..423a7f75dc0505acb5fb9cc92d0f9c0002cfb099 100644 (file)
@@ -58,11 +58,13 @@ extern Int  VG_(fork)   ( void);
 extern void VG_(execv)  ( Char* filename, Char** argv );
 
 /* ---------------------------------------------------------------------
-   Resource limits
+   Resource limits and capabilities
    ------------------------------------------------------------------ */
 
 extern Int VG_(getrlimit) ( Int resource, struct vki_rlimit *rlim );
 extern Int VG_(setrlimit) ( Int resource, const struct vki_rlimit *rlim );
+extern Int VG_(prctl) (Int option, 
+                       ULong arg2, ULong arg3, ULong arg4, ULong arg5);
 
 /* ---------------------------------------------------------------------
    pids, etc
index 7f85492518ba340acfa5ce2a9d4e90f53accb206..3dffd42b5b8d58aaf2b0fafc35a7ab2c9e71d711 100644 (file)
@@ -146,6 +146,12 @@ extern Int  VG_(clo_verbosity);
 /* Show tool and core statistics */
 extern Bool VG_(clo_stats);
 
+/* wait for vgdb/gdb after reporting that amount of error.
+   Note that this is the initial value provided from the command line.
+   The real value is maintained in VG_(dyn_vgdb_error) and
+   can be changed dynamically.*/
+extern Int VG_(clo_vgdb_error);
+
 /* Emit all messages as XML? default: NO */
 /* If clo_xml is set, various other options are set in a non-default
    way.  See vg_main.c and mc_main.c. */
index 8933e0f0f7260296328c06421a9490af7eee69f3..10f3d9bc8847a12f7c04b2a2af210527fdc9158a 100644 (file)
@@ -4843,6 +4843,10 @@ typedef
              errors. */
           VG_USERREQ__COUNT_ERRORS = 0x1201,
 
+          /* Allows a string (gdb monitor command) to be passed to the tool
+             Used for interaction with vgdb/gdb */
+          VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202,
+
           /* These are useful and can be interpreted by any tool that
              tracks malloc() et al, by using vg_replace_malloc.c. */
           VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
index 7d554fde09c4a04b9826ee1b966f966cc0764a0b..ccc73a4c434ed1867909ccc7380e22b2766e772e 100644 (file)
@@ -296,6 +296,7 @@ typedef struct vki_sigaltstack {
                                           extend change to end
                                           of growsup vma */
 
+#define VKI_MAP_SHARED         0x0001  /* Share changes */
 #define VKI_MAP_PRIVATE        0x0002  /*  */
 #define VKI_MAP_FIXED          0x0010  /*  */
 #define VKI_MAP_ANONYMOUS      0x0020  /*  */
@@ -314,6 +315,7 @@ typedef struct vki_sigaltstack {
 #define VKI_O_NOCTTY        00000400        /* not fcntl */
 #define VKI_O_TRUNC         00001000        /* not fcntl */
 #define VKI_O_APPEND        00002000
+#define VKI_O_NONBLOCK      00004000
 
 #define VKI_AT_FDCWD            -100
 
@@ -605,6 +607,7 @@ struct vki_pollfd {
        short revents;
 };
 
+#define VKI_POLLIN          0x0001
 
 //----------------------------------------------------------------------
 // From linux-2.6.16.60/include/asm-s390/ptrace.h
index 51f872b95e6dff0e51e6eccbf85a99b028322048..f9cc1ff6f0f10090a74edda1f3543d0f146f98e7 100644 (file)
@@ -858,6 +858,21 @@ in a particular column, which makes following the allocation chains easier.
 
 </sect1>
 
+<sect1 id="ms-manual.monitor-commands" xreflabel="Massif Monitor Commands">
+<title>Massif Monitor Commands</title>
+<para>The Massif tool provides monitor commands handled by the Valgrind
+gdbserver (see <xref linkend="manual-core.gdbserver-commandhandling"/>).
+</para>
+
+<itemizedlist>
+  <listitem>
+    <para><varname>ms.snapshot [&lt;filename&gt;] [detailed]</varname> requests to take
+    a snapshot and save it in the given &lt;filename&gt; (default massif.vgdb.out).
+    If present, the 'detailed' argument indicates to take a detailed snapshot.
+    </para>
+  </listitem>
+</itemizedlist>
+</sect1>
 
 <sect1 id="ms-manual.clientreqs" xreflabel="Client requests">
 <title>Massif Client Requests</title>
index 67702cda8f728f7d2d51b4be5b5256760d6b7d3f..6bc49254f15901265f005c51b60a9009f768ffd8 100644 (file)
@@ -180,6 +180,7 @@ Number of snapshots: 50
 #include "pub_tool_tooliface.h"
 #include "pub_tool_xarray.h"
 #include "pub_tool_clientstate.h"
+#include "pub_tool_gdbserver.h"
 
 #include "valgrind.h"           // For {MALLOC,FREE}LIKE_BLOCK
 
@@ -1977,6 +1978,21 @@ static void die_mem_stack_signal(Addr a, SizeT len)
 //--- Client Requests                                      ---//
 //------------------------------------------------------------//
 
+static void print_monitor_help ( void )
+{
+   VG_(gdb_printf) ("\n");
+   VG_(gdb_printf) ("massif monitor commands:\n");
+   VG_(gdb_printf) ("  ms.snapshot [<filename>] [detailed]\n");
+   VG_(gdb_printf) ("       takes a snapshot and saves it in <filename>\n");
+   VG_(gdb_printf) ("             default <filename> is massif.vgdb.out\n");
+   VG_(gdb_printf) ("             if present, detailed argument indicates to take a detailed snapshot\n");
+   VG_(gdb_printf) ("\n");
+}
+
+
+/* Forward declaration.
+   return True if request recognised, False otherwise */
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req);
 static Bool ms_handle_client_request ( ThreadId tid, UWord* argv, UWord* ret )
 {
    switch (argv[0]) {
@@ -2003,6 +2019,15 @@ static Bool ms_handle_client_request ( ThreadId tid, UWord* argv, UWord* ret )
       *ret = 0;
       return True;
    }
+   case VG_USERREQ__GDB_MONITOR_COMMAND: {
+     Bool handled = handle_gdb_monitor_command (tid, (Char*)argv[1]);
+     if (handled)
+       *ret = 1;
+     else
+       *ret = 0;
+     return handled;
+   }
+
    default:
       *ret = 0;
       return False;
@@ -2287,19 +2312,13 @@ static void pp_snapshot(Int fd, Snapshot* snapshot, Int snapshot_n)
    }
 }
 
-static void write_snapshots_to_file(void)
+static void write_snapshots_to_file(Char* massif_out_file, 
+                                    Snapshot snapshots_array[], 
+                                    Int nr_elements)
 {
    Int i, fd;
    SysRes sres;
 
-   // Setup output filename.  Nb: it's important to do this now, ie. as late
-   // as possible.  If we do it at start-up and the program forks and the
-   // output file format string contains a %p (pid) specifier, both the
-   // parent and child will incorrectly write to the same file;  this
-   // happened in 3.3.0.
-   Char* massif_out_file =
-      VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
-
    sres = VG_(open)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
                                      VKI_S_IRUSR|VKI_S_IWUSR);
    if (sr_isError(sres)) {
@@ -2307,11 +2326,9 @@ static void write_snapshots_to_file(void)
       // between multiple cachegrinded processes?), give up now.
       VG_(umsg)("error: can't open output file '%s'\n", massif_out_file );
       VG_(umsg)("       ... so profiling results will be missing.\n");
-      VG_(free)(massif_out_file);
       return;
    } else {
       fd = sr_Res(sres);
-      VG_(free)(massif_out_file);
    }
 
    // Print massif-specific options that were used.
@@ -2342,12 +2359,75 @@ static void write_snapshots_to_file(void)
 
    FP("time_unit: %s\n", TimeUnit_to_string(clo_time_unit));
 
-   for (i = 0; i < next_snapshot_i; i++) {
-      Snapshot* snapshot = & snapshots[i];
+   for (i = 0; i < nr_elements; i++) {
+      Snapshot* snapshot = & snapshots_array[i];
       pp_snapshot(fd, snapshot, i);     // Detailed snapshot!
    }
+   VG_(close) (fd);
+}
+
+static void write_snapshots_array_to_file(void)
+{
+   // Setup output filename.  Nb: it's important to do this now, ie. as late
+   // as possible.  If we do it at start-up and the program forks and the
+   // output file format string contains a %p (pid) specifier, both the
+   // parent and child will incorrectly write to the same file;  this
+   // happened in 3.3.0.
+   Char* massif_out_file =
+      VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
+   write_snapshots_to_file (massif_out_file, snapshots, next_snapshot_i);
+   VG_(free)(massif_out_file);
 }
 
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
+{
+   Char* wcmd;
+   Char s[VG_(strlen(req))]; /* copy for strtok_r */
+   Char *ssaveptr;
+
+   VG_(strcpy) (s, req);
+
+   wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
+   switch (VG_(keyword_id) ("help ms.snapshot", 
+                            wcmd, kwd_report_duplicated_matches)) {
+   case -2: /* multiple matches */
+      return True;
+   case -1: /* not found */
+      return False;
+   case  0: /* help */
+      print_monitor_help();
+      return True;
+   case  1: { /* ms.snapshot */
+      Char* kw;
+      Char* filename = NULL;
+      Bool detailed = False;
+      Snapshot snapshot;
+      
+      for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr); 
+           kw != NULL; 
+           kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
+        if (filename == NULL)
+           filename = kw;
+        else if (0 == VG_(strncmp)(kw, "detailed", VG_(strlen) (kw))) 
+           detailed = True;
+        else {
+           VG_(gdb_printf) ("invalid 2nd arg\n");
+           return True;
+        }
+      }
+      clear_snapshot(&snapshot, /* do_sanity_check */ False);
+      take_snapshot(&snapshot, Normal, get_time(), detailed);
+      write_snapshots_to_file ((filename == NULL) ? (Char*) "massif.vgdb.out" : filename,
+                               &snapshot,
+                               1);
+      delete_snapshot(&snapshot);
+      return True;
+   }
+   default: 
+      tl_assert(0);
+      return False;
+   }
+}
 
 //------------------------------------------------------------//
 //--- Finalisation                                         ---//
@@ -2356,7 +2436,7 @@ static void write_snapshots_to_file(void)
 static void ms_fini(Int exit_status)
 {
    // Output.
-   write_snapshots_to_file();
+   write_snapshots_array_to_file();
 
    // Stats
    tl_assert(n_xpts > 0);  // always have alloc_xpt
index 433e2e0558fa38e067ec30435533c7abc7d1a5e3..8c6294c6fa12c6d4bcf54bbab3b53c68efdc814e 100644 (file)
@@ -1270,7 +1270,126 @@ is:</para>
 </sect2>
 </sect1>
 
+<sect1 id="mc-manual.monitor-commands" xreflabel="Memcheck Monitor Commands">
+<title>Memcheck Monitor Commands</title>
+<para>The Memcheck tool provides monitor commands handled by the Valgrind
+gdbserver (see <xref linkend="manual-core.gdbserver-commandhandling"/>).
+</para>
+
+<itemizedlist>
+  <listitem>
+    <para><varname>mc.get_vbits &lt;addr&gt; [&lt;len&gt;]</varname>
+    outputs the validity bits for the range of &lt;len&gt; (default 1)
+    bytes at &lt;addr&gt;.  The validity of each byte of the range is
+    given using two hexadecimal digits.  These hexadecimal digits are
+    encoding the validity of each bit of the corresponding byte, using
+    0 if the bit is valid and 1 if the bit is invalid. In the
+    following example, 'string10' is an array of 10 characters in
+    which one byte on two is undefined. If a byte is not addressable,
+    its validity bits are replaced by __. In the below example, the byte 6
+    is not addressable.</para>
+<programlisting><![CDATA[
+(gdb) p &string10
+$4 = (char (*)[10]) 0x8049e28
+(gdb) monitor mc.get_vbits 0x8049e28 10
+ff00ff00 ff__ff00 ff00
+(gdb) 
+]]></programlisting>
+  </listitem>
+
+  <listitem>
+    <para><varname>mc.make_memory [noaccess|undefined|defined|ifaddressabledefined] &lt;addr&gt; [&lt;len&gt;]</varname>
+    marks the range of &lt;len&gt; (default 1) bytes at &lt;addr&gt;
+    with the given accessibility. Marking with 'noaccess' changes the
+    (A) bits of the range to be not addressable.  Marking with
+    'undefined' or 'defined' are changing the definedness of the
+    range.  'ifaddressabledefined' marks the range as defined but only
+    if the range is addressable.  In the following example, the first
+    byte of the 'string10' is marked as defined.
+    </para>
+<programlisting><![CDATA[
+(gdb) monitor mc.make_memory defined 0x8049e28  1
+(gdb) monitor mc.get_vbits 0x8049e28 10
+0000ff00 ff00ff00 ff00
+(gdb) 
+]]></programlisting>
+  </listitem>
 
+  <listitem>
+    <para><varname>mc.check_memory [addressable|defined] &lt;addr&gt;
+    [&lt;len&gt;]</varname> checks that the range of &lt;len&gt;
+    (default 1) bytes at &lt;addr&gt; has the given accessibility.  It
+    then outputs a description of &lt;addr&gt;. In the below case, a
+    detailed description is given as the option --read-var-info=yes
+    was used to start Valgrind.
+    </para>
+<programlisting><![CDATA[
+(gdb) monitor mc.check_memory defined 0x8049e28  1
+Address 0x8049E28 len 1 defined
+==14698==  Location 0x8049e28 is 0 bytes inside string10[0],
+==14698==  declared at prog.c:10, in frame #0 of thread 1
+(gdb) 
+]]></programlisting>
+  </listitem>
+
+  <listitem>
+    <para><varname>mc.leak_check
+    [full*|summary] [reachable|leakpossible*|definiteleak]</varname>
+    starts a leak checking. The * in the arguments above indicates the
+    default value. </para>
+
+    <para> If the first argument is 'summary', only a summary of
+    the leak search is given.
+    </para>
+
+    <para>The second argument controls which entries are output
+    for a 'full' leak search.  The value 'definiteleak' indicates to
+    output only the definitely leaked blocks. The value 'leakpossible'
+    will output in addition the possibly leaked blocks. The value
+    'reachable' will output all blocks (reachable, possibly leaked,
+    definitely leaked).
+    </para>
+    <para>The below is an example of using the mc.leak_check monitor
+    command on the leak-cases Memcheck regression tests.</para>
+<programlisting><![CDATA[
+(gdb)  monitor mc.leak_check full leakpossible
+==14729== 16 bytes in 1 blocks are possibly lost in loss record 13 of 16
+==14729==    at 0x4006E9E: malloc (vg_replace_malloc.c:236)
+==14729==    by 0x80484D5: mk (leak-cases.c:52)
+==14729==    by 0x804855F: f (leak-cases.c:81)
+==14729==    by 0x80488F5: main (leak-cases.c:107)
+==14729== 
+==14729== LEAK SUMMARY:
+==14729==    definitely lost: 32 bytes in 2 blocks
+==14729==    indirectly lost: 16 bytes in 1 blocks
+==14729==      possibly lost: 32 bytes in 2 blocks
+==14729==    still reachable: 96 bytes in 6 blocks
+==14729==         suppressed: 0 bytes in 0 blocks
+==14729== Reachable blocks (those to which a pointer was found) are not shown.
+==14729== To see them, rerun with: --leak-check=full --show-reachable=yes
+==14729== 
+(gdb) mo mc.l
+==14729== LEAK SUMMARY:
+==14729==    definitely lost: 32 bytes in 2 blocks
+==14729==    indirectly lost: 16 bytes in 1 blocks
+==14729==      possibly lost: 32 bytes in 2 blocks
+==14729==    still reachable: 96 bytes in 6 blocks
+==14729==         suppressed: 0 bytes in 0 blocks
+==14729== Reachable blocks (those to which a pointer was found) are not shown.
+==14729== To see them, rerun with: --leak-check=full --show-reachable=yes
+==14729== 
+(gdb) 
+]]></programlisting>
+    <para>Note that when using the Valgrind gdbserver, it is not
+    needed to rerun with --leak-check=full --show-reachable=yes to see
+    the reachable blocks. You can obtain the same information without
+    rerunning by using the gdb command 'monitor mc.leak_check full
+    reachable' (or, using abbreviation: 'mo mc.l f r').
+    </para>
+  </listitem>
+</itemizedlist>
+
+</sect1>
 
 <sect1 id="mc-manual.clientreqs" xreflabel="Client requests">
 <title>Client Requests</title>
index e09d5147e5af39a867b6e00c449b9428a30ac0ee..e01332896f458f1f6026c8a737db2202f0c6ab4d 100644 (file)
@@ -30,6 +30,7 @@
 */
 
 #include "pub_tool_basics.h"
+#include "pub_tool_gdbserver.h"
 #include "pub_tool_hashtable.h"     // For mc_include.h
 #include "pub_tool_libcbase.h"
 #include "pub_tool_libcassert.h"
@@ -787,6 +788,9 @@ void MC_(record_address_error) ( ThreadId tid, Addr a, Int szB,
    if (MC_(in_ignored_range)(a)) 
       return;
 
+   if (VG_(is_watched)( (isWrite ? write_watchpoint : read_watchpoint), a, szB))
+      return;
+
 #  if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    /* AIX zero-page handling.  On AIX, reads from page zero are,
       bizarrely enough, legitimate.  Writes to page zero aren't,
@@ -1182,6 +1186,15 @@ static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai )
    return;
 }
 
+void MC_(pp_describe_addr) ( Addr a )
+{
+   AddrInfo ai;
+
+   ai.tag = Addr_Undescribed;
+   describe_addr (a, &ai);
+   mc_pp_AddrInfo (a, &ai, /* maybe_gcc */ False);
+}
+
 /* Fill in *origin_ec as specified by otag, or NULL it out if otag
    does not refer to a known origin. */
 static void update_origin ( /*OUT*/ExeContext** origin_ec,
index ece6eac3144c81554877d8a595dd5d6af0697500..d6edbf2d7dc0d61d7508b5928c325ef29f1ec02f 100644 (file)
@@ -355,6 +355,9 @@ Bool MC_(record_leak_error)     ( ThreadId tid,
                                   Bool print_record,
                                   Bool count_error );
 
+/* prints a description of address a */
+void MC_(pp_describe_addr) (Addr a);
+
 /* Is this address in a user-specified "ignored range" ? */
 Bool MC_(in_ignored_range) ( Addr a );
 
index 47122215310df88f048df7ebe56f453fce309d2f..0cdb4a509a2277b130ff0951bdbbddfcca24110d 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "pub_tool_basics.h"
 #include "pub_tool_aspacemgr.h"
+#include "pub_tool_gdbserver.h"
 #include "pub_tool_hashtable.h"     // For mc_include.h
 #include "pub_tool_libcbase.h"
 #include "pub_tool_libcassert.h"
@@ -1049,67 +1050,17 @@ INLINE Bool MC_(in_ignored_range) ( Addr a )
    return False;
 }
 
-
-/* Parse a 32- or 64-bit hex number, including leading 0x, from string
-   starting at *ppc, putting result in *result, and return True.  Or
-   fail, in which case *ppc and *result are undefined, and return
-   False. */
-
-static Bool isHex ( UChar c )
-{
-  return ((c >= '0' && c <= '9') ||
-         (c >= 'a' && c <= 'f') ||
-         (c >= 'A' && c <= 'F'));
-}
-
-static UInt fromHex ( UChar c )
-{
-   if (c >= '0' && c <= '9')
-      return (UInt)c - (UInt)'0';
-   if (c >= 'a' && c <= 'f')
-      return 10 +  (UInt)c - (UInt)'a';
-   if (c >= 'A' && c <= 'F')
-      return 10 +  (UInt)c - (UInt)'A';
-   /*NOTREACHED*/
-   tl_assert(0);
-   return 0;
-}
-
-static Bool parse_Addr ( UChar** ppc, Addr* result )
-{
-   Int used, limit = 2 * sizeof(Addr);
-   if (**ppc != '0')
-      return False;
-   (*ppc)++;
-   if (**ppc != 'x')
-      return False;
-   (*ppc)++;
-   *result = 0;
-   used = 0;
-   while (isHex(**ppc)) {
-      UInt d = fromHex(**ppc);
-      tl_assert(d < 16);
-      *result = ((*result) << 4) | fromHex(**ppc);
-      (*ppc)++;
-      used++;
-      if (used > limit) return False;
-   }
-   if (used == 0)
-      return False;
-   return True;
-}
-
-/* Parse two such numbers separated by a dash, or fail. */
+/* Parse two Addr separated by a dash, or fail. */
 
 static Bool parse_range ( UChar** ppc, Addr* result1, Addr* result2 )
 {
-   Bool ok = parse_Addr(ppc, result1);
+   Bool ok = VG_(parse_Addr) (ppc, result1);
    if (!ok)
       return False;
    if (**ppc != '-')
       return False;
    (*ppc)++;
-   ok = parse_Addr(ppc, result2);
+   ok = VG_(parse_Addr) (ppc, result2);
    if (!ok)
       return False;
    return True;
@@ -4513,17 +4464,20 @@ static Int mc_get_or_set_vbits_for_client (
    Addr a, 
    Addr vbits, 
    SizeT szB, 
-   Bool setting /* True <=> set vbits,  False <=> get vbits */ 
+   Bool setting, /* True <=> set vbits,  False <=> get vbits */ 
+   Bool is_client_request /* True <=> real user request 
+                             False <=> internal call from gdbserver */ 
 )
 {
    SizeT i;
    Bool  ok;
    UChar vbits8;
 
-   /* Check that arrays are addressible before doing any getting/setting. */
+   /* Check that arrays are addressible before doing any getting/setting.
+      vbits to be checked only for real user request. */
    for (i = 0; i < szB; i++) {
       if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
-          VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
+          (is_client_request && VA_BITS2_NOACCESS == get_vabits2(vbits + i))) {
          return 3;
       }
    }
@@ -4542,8 +4496,9 @@ static Int mc_get_or_set_vbits_for_client (
          tl_assert(ok);
          ((UChar*)vbits)[i] = vbits8;
       }
-      // The bytes in vbits[] have now been set, so mark them as such.
-      MC_(make_mem_defined)(vbits, szB);
+      if (is_client_request)
+        // The bytes in vbits[] have now been set, so mark them as such.
+        MC_(make_mem_defined)(vbits, szB);
    }
 
    return 1;
@@ -4974,6 +4929,220 @@ static void show_client_block_stats ( void )
    );
 }
 
+static void print_monitor_help ( void )
+{
+   VG_(gdb_printf) 
+      (
+"\n"
+"memcheck monitor commands:\n"
+"  mc.get_vbits <addr> [<len>]\n"
+"        returns validity bits for <len> (or 1) bytes at <addr>\n"
+"            bit values 0 = valid, 1 = invalid, __ = unaddressable byte\n"
+"        Example: mc.get_vbits 0x8049c78 10\n"
+"  mc.make_memory [noaccess|undefined\n"
+"                     |defined|ifaddressabledefined] <addr> [<len>]\n"
+"        mark <len> (or 1) bytes at <addr> with the given accessibility\n"
+"  mc.check_memory [addressable|defined] <addr> [<len>]\n"
+"        check that <len> (or 1) bytes at <addr> have the given accessibility\n"
+"            and outputs a description of <addr>\n"
+"  mc.leak_check [full*|summary]\n"
+"                [reachable|leakpossible*|definiteleak]\n"
+"            * = defaults\n"
+"        Examples: mc.leak_check\n"
+"                  mc.leak_check any summary\n"
+"\n");
+}
+
+/* return True if request recognised, False otherwise */
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
+{
+   Char* wcmd;
+   Char s[VG_(strlen(req))]; /* copy for strtok_r */
+   Char *ssaveptr;
+
+   VG_(strcpy) (s, req);
+
+   wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
+   /* NB: if possible, avoid introducing a new command below which
+      starts with the same 4 first letters as an already existing
+      command. This ensures a shorter abbreviation for the user. */
+   switch (VG_(keyword_id) 
+           ("help mc.get_vbits mc.leak_check mc.make_memory mc.check_memory", 
+            wcmd, kwd_report_duplicated_matches)) {
+   case -2: /* multiple matches */
+      return True;
+   case -1: /* not found */
+      return False;
+   case  0: /* help */
+      print_monitor_help();
+      return True;
+   case  1: { /* mc.get_vbits */
+      Addr address;
+      SizeT szB = 1;
+      VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+      if (szB != 0) {
+         UChar vbits;
+         Int i;
+         Int unaddressable = 0;
+         for (i = 0; i < szB; i++) {
+            Int res = mc_get_or_set_vbits_for_client 
+               (address+i, (Addr) &vbits, 1, 
+                False, /* get them */
+                False  /* is client request */ ); 
+            if ((i % 32) == 0 && i != 0)
+               VG_(gdb_printf) ("\n");
+            else if ((i % 4) == 0 && i != 0)
+               VG_(gdb_printf) (" ");
+            if (res == 1) {
+               VG_(gdb_printf) ("%02x", vbits);
+            } else {
+               tl_assert(3 == res);
+               unaddressable++;
+               VG_(gdb_printf) ("__");
+            }
+         }
+         if ((i % 80) != 0)
+            VG_(gdb_printf) ("\n");
+         if (unaddressable) {
+            VG_(gdb_printf)
+               ("Address %p len %ld has %d bytes unaddressable\n",
+                (void *)address, szB, unaddressable);
+         }
+      }
+      return True;
+   }
+   case  2: { /* mc.leak_check */
+      Int err = 0;
+      Bool save_clo_show_reachable = MC_(clo_show_reachable);
+      Bool save_clo_show_possibly_lost = MC_(clo_show_possibly_lost);
+      Char* kw;
+
+      LeakCheckMode mode;
+      
+      MC_(clo_show_reachable) = False;
+      mode = LC_Full;
+      
+      for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr); 
+           kw != NULL; 
+           kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
+         switch (VG_(keyword_id) 
+                 ("full summary "
+                  "reachable leakpossible definiteleak",
+                  kw, kwd_report_all)) {
+         case -2: err++; break;
+         case -1: err++; break;
+         case  0: mode = LC_Full; break;
+         case  1: mode = LC_Summary; break;
+         case  2: MC_(clo_show_reachable) = True; 
+                  MC_(clo_show_possibly_lost) = True; break;
+         case  3: MC_(clo_show_reachable) = False;
+                  MC_(clo_show_possibly_lost) = True; break;
+         case  4: MC_(clo_show_reachable) = False;
+                  MC_(clo_show_possibly_lost) = False; break;
+         default: tl_assert (0);
+         }
+      }
+      if (!err)
+         MC_(detect_memory_leaks)(tid, mode);
+      
+      MC_(clo_show_reachable) = save_clo_show_reachable;
+      MC_(clo_show_possibly_lost) = save_clo_show_possibly_lost;
+      return True;
+   }
+      
+   case  3: { /* mc.make_memory */
+      Addr address;
+      SizeT szB = 1;
+      int kwdid = VG_(keyword_id) 
+         ("noaccess undefined defined ifaddressabledefined",
+          VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
+      VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+      if (address == (Addr) 0 && szB == 0) return True;
+      switch (kwdid) {
+      case -2: break;
+      case -1: break;
+      case  0: MC_(make_mem_noaccess) (address, szB); break;
+      case  1: make_mem_undefined_w_tid_and_okind ( address, szB, tid, 
+                                                    MC_OKIND_USER ); break;
+      case  2: MC_(make_mem_defined) ( address, szB ); break;
+      case  3: make_mem_defined_if_addressable ( address, szB ); break;;
+      default: tl_assert(0);
+      }
+      return True;
+   }
+
+   case  4: { /* mc.check_memory */
+      Addr address;
+      SizeT szB = 1;
+      Addr bad_addr;
+      UInt okind;
+      char* src;
+      UInt otag;
+      UInt ecu;
+      ExeContext* origin_ec;
+      MC_ReadResult res;
+
+      int kwdid = VG_(keyword_id) 
+         ("addressable defined",
+          VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
+      VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+      if (address == (Addr) 0 && szB == 0) return True;
+      switch (kwdid) {
+      case -2: break;
+      case -1: break;
+      case  0: 
+         if (is_mem_addressable ( address, szB, &bad_addr ))
+            VG_(gdb_printf) ("Address %p len %ld addressable\n", 
+                             (void *)address, szB);
+         else
+            VG_(gdb_printf)
+               ("Address %p len %ld not addressable:\nbad address %p\n",
+                (void *)address, szB, (void *) bad_addr);
+         MC_(pp_describe_addr) (address);
+         break;
+      case  1: res = is_mem_defined ( address, szB, &bad_addr, &otag );
+         if (MC_AddrErr == res)
+            VG_(gdb_printf)
+               ("Address %p len %ld not addressable:\nbad address %p\n",
+                (void *)address, szB, (void *) bad_addr);
+         else if (MC_ValueErr == res) {
+            okind = otag & 3;
+            switch (okind) {
+            case MC_OKIND_STACK:   
+               src = " was created by a stack allocation"; break;
+            case MC_OKIND_HEAP:    
+               src = " was created by a heap allocation"; break;
+            case MC_OKIND_USER:    
+               src = " was created by a client request"; break;
+            case MC_OKIND_UNKNOWN: 
+               src = ""; break;
+            default: tl_assert(0);
+            }
+            VG_(gdb_printf) 
+               ("Address %p len %ld not defined:\n"
+                "Uninitialised value at %p%s\n",
+                (void *)address, szB, (void *) bad_addr, src);
+            ecu = otag & ~3;
+            if (VG_(is_plausible_ECU)(ecu)) {
+               origin_ec = VG_(get_ExeContext_from_ECU)( ecu );
+               VG_(pp_ExeContext)( origin_ec );
+            }
+         }
+         else
+            VG_(gdb_printf) ("Address %p len %ld defined\n",
+                             (void *)address, szB);
+         MC_(pp_describe_addr) (address);
+         break;
+      default: tl_assert(0);
+      }
+      return True;
+   }
+
+   default: 
+      tl_assert(0);
+      return False;
+   }
+}
 
 /*------------------------------------------------------------*/
 /*--- Client requests                                      ---*/
@@ -4996,7 +5165,8 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
        && VG_USERREQ__MEMPOOL_TRIM     != arg[0]
        && VG_USERREQ__MOVE_MEMPOOL     != arg[0]
        && VG_USERREQ__MEMPOOL_CHANGE   != arg[0]
-       && VG_USERREQ__MEMPOOL_EXISTS   != arg[0])
+       && VG_USERREQ__MEMPOOL_EXISTS   != arg[0]
+       && VG_USERREQ__GDB_MONITOR_COMMAND   != arg[0])
       return False;
 
    switch (arg[0]) {
@@ -5074,12 +5244,16 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 
       case VG_USERREQ__GET_VBITS:
          *ret = mc_get_or_set_vbits_for_client
-                   ( arg[1], arg[2], arg[3], False /* get them */ );
+                   ( arg[1], arg[2], arg[3],
+                     False /* get them */, 
+                     True /* is client request */ );
          break;
 
       case VG_USERREQ__SET_VBITS:
          *ret = mc_get_or_set_vbits_for_client
-                   ( arg[1], arg[2], arg[3], True /* set them */ );
+                   ( arg[1], arg[2], arg[3],
+                     True /* set them */,
+                     True /* is client request */ );
          break;
 
       case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
@@ -5215,6 +5389,14 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
         return True;
       }
 
+      case VG_USERREQ__GDB_MONITOR_COMMAND: {
+         Bool handled = handle_gdb_monitor_command (tid, (Char*)arg[1]);
+         if (handled)
+            *ret = 1;
+         else
+            *ret = 0;
+         return handled;
+      }
 
       default:
          VG_(message)(
@@ -5790,6 +5972,22 @@ static void mc_fini ( Int exitcode )
    }
 }
 
+/* mark the given addr/len unaddressable for watchpoint implementation
+   The PointKind will be handled at access time */
+static Bool mc_mark_unaddressable_for_watchpoint (PointKind kind, Bool insert,
+                                                  Addr addr, SizeT len)
+{
+   /* GDBTD this is somewhat fishy. We might rather have to save the previous
+      accessibility and definedness in gdbserver so as to allow restoring it
+      properly. Currently, we assume that the user only watches things
+      which are properly addressable and defined */
+   if (insert)
+      MC_(make_mem_noaccess) (addr, len);
+   else
+      MC_(make_mem_defined)  (addr, len);
+   return True;
+}
+
 static void mc_pre_clo_init(void)
 {
    VG_(details_name)            ("Memcheck");
@@ -5935,6 +6133,8 @@ static void mc_pre_clo_init(void)
    VG_(track_post_reg_write)                  ( mc_post_reg_write );
    VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
 
+   VG_(needs_watchpoint)          ( mc_mark_unaddressable_for_watchpoint );
+
    init_shadow_memory();
    MC_(malloc_list)  = VG_(HT_construct)( "MC_(malloc_list)" );
    MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );
index fadaa59537135a220ab787538d4ed4e21efdb17d..641304a8948412a1805722011b751380e612e8a5 100644 (file)
@@ -16,6 +16,9 @@ usage: valgrind [options] prog-and-args
                               but check the argv[] entries for children, rather
                               than the exe name, to make a follow/no-follow decision
     --child-silent-after-fork=no|yes omit child output between fork & exec? [no]
+    --vgdb=no|yes|full        activate gdbserver? [yes]
+                              full is slower but provides precise watchpoint/step
+    --vgdb-error=<number>     invoke gdbserver after <number> errors [999999999] 
     --track-fds=no|yes        track open file descriptors? [no]
     --time-stamp=no|yes       add timestamps to log messages? [no]
     --log-fd=<number>         log messages to file descriptor [2=stderr]
@@ -60,6 +63,9 @@ usage: valgrind [options] prog-and-args
                               and use it to print better error messages in
                               tools that make use of it (Memcheck, Helgrind,
                               DRD) [no]
+    --vgdb-poll=<number>      gdbserver poll max every <number> basic blocks [5000] 
+    --vgdb-shadow-registers=no|yes   let gdb see the shadow registers [no]
+    --vgdb-prefix=<prefix>    prefix for vgdb FIFOs [/tmp/vgdb-pipe]
     --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]
     --sim-hints=hint1,hint2,...  known hints:
                                  lax-ioctls, enable-outer [none]
index 6603e25b44aa120c89dcbc0074bc58d9aeaf730d..e66858d385b93034d914c511b87e409fbcfa6911 100644 (file)
@@ -16,6 +16,9 @@ usage: valgrind [options] prog-and-args
                               but check the argv[] entries for children, rather
                               than the exe name, to make a follow/no-follow decision
     --child-silent-after-fork=no|yes omit child output between fork & exec? [no]
+    --vgdb=no|yes|full        activate gdbserver? [yes]
+                              full is slower but provides precise watchpoint/step
+    --vgdb-error=<number>     invoke gdbserver after <number> errors [999999999] 
     --track-fds=no|yes        track open file descriptors? [no]
     --time-stamp=no|yes       add timestamps to log messages? [no]
     --log-fd=<number>         log messages to file descriptor [2=stderr]
@@ -60,6 +63,9 @@ usage: valgrind [options] prog-and-args
                               and use it to print better error messages in
                               tools that make use of it (Memcheck, Helgrind,
                               DRD) [no]
+    --vgdb-poll=<number>      gdbserver poll max every <number> basic blocks [5000] 
+    --vgdb-shadow-registers=no|yes   let gdb see the shadow registers [no]
+    --vgdb-prefix=<prefix>    prefix for vgdb FIFOs [/tmp/vgdb-pipe]
     --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]
     --sim-hints=hint1,hint2,...  known hints:
                                  lax-ioctls, enable-outer [none]
index f4edade70a0387a5d8207b807aed310cfccb047f..41a522b5ed939e96ec563691f4eb5901ca48edab 100644 (file)
@@ -9,9 +9,9 @@
 #include "pub_tool_libcbase.h"
 #include "pub_tool_mallocfree.h"
 #include "pub_tool_libcprint.h"
+#include "pub_tool_vki.h"
 #include "pub_tool_libcfile.h"
 #include "pub_tool_libcproc.h"
-#include "pub_tool_vki.h"
 #include "pub_tool_threadstate.h"
 #include "pub_tool_errormgr.h"
 #include "pub_tool_options.h"
index adf3b9aadfa15aabf5d91324c1b25ce64cdba81e..68e31388a21c9e29642ee25cc357568c9a1fa909 100755 (executable)
 #                                                    multiple are allowed)
 #   - stdout_filter: <filter to run stdout through> (default: none)
 #   - stderr_filter: <filter to run stderr through> (default: ./filter_stderr)
+#
+#   - progB:  <prog to run in parallel with prog>   (default: none)
+#   - argsB:  <args for progB>                      (default: none)
+#   - stdinB: <input file for progB>                (default: none)
+#   - stdoutB_filter: <filter progB stdout through> (default: none)
+#   - stderrB_filter: <filter progB stderr through> (default: ./filter_stderr)
+#
 #   - prereq: <prerequisite command>                (default: none)
 #   - post: <post-test check command>               (default: none)
 #   - cleanup: <post-test cleanup cmd>              (default: none)
 #
+# If prog or probB is a relative path, it will be prefix with the test directory.
 # Note that filters are necessary for stderr results to filter out things that
 # always change, eg. process id numbers.
+# Note that if a progB is specified, it is started in background (before prog).
 #
 # Expected stdout (filtered) is kept in <test>.stdout.exp* (can be more
 # than one expected output).  It can be missing if it would be empty.  Expected
 # one stderr.exp* file.  Any .exp* file that ends in '~' or '#' is ignored;
 # this is because Emacs creates temporary files of these names.
 #
+# Expected output for progB is handled similarly, except that
+# expected stdout and stderr for progB are in  <test>.stdoutB.exp*
+# and <test>.stderrB.exp*.
+#
 # If results don't match, the output can be found in <test>.std<strm>.out,
 # and the diff between expected and actual in <test>.std<strm>.diff*.
+# (for progB, in <test>.std<strm>2.out and <test>.std<strm>2.diff*).
 #
 # The prerequisite command, if present, works like this:
 # - if it returns 0 the test is run
@@ -112,6 +126,11 @@ my $prog;               # test prog
 my $args;               # test prog args
 my $stdout_filter;      # filter program to run stdout results file through
 my $stderr_filter;      # filter program to run stderr results file through
+my $progB;              # Same but for progB
+my $argsB;              # 
+my $stdoutB_filter;     # 
+my $stderrB_filter;     # 
+my $stdinB;             # Input file for progB
 my $prereq;             # prerequisite test to satisfy before running test
 my $post;               # check command after running test
 my $cleanup;            # cleanup command to run
@@ -119,7 +138,9 @@ my $cleanup;            # cleanup command to run
 my @failures;           # List of failed tests
 
 my $num_tests_done      = 0;
-my %num_failures        = (stderr => 0, stdout => 0, post => 0);
+my %num_failures        = (stderr => 0, stdout => 0, 
+                           stderrB => 0, stdoutB => 0,
+                           post => 0);
 
 # Default valgrind to use is this build tree's (uninstalled) one
 my $valgrind = "./coregrind/valgrind";
@@ -204,12 +225,16 @@ sub read_vgtest_file($)
     my ($f) = @_;
 
     # Defaults.
-    ($vgopts, $prog, $args)          = ("", undef, "");
-    ($stdout_filter, $stderr_filter) = (undef, undef);
-    ($prereq, $post, $cleanup)       = (undef, undef, undef);
+    ($vgopts, $prog, $args)            = ("", undef, "");
+    ($stdout_filter, $stderr_filter)   = (undef, undef);
+    ($progB, $argsB, $stdinB)          = (undef, "", undef);
+    ($stdoutB_filter, $stderrB_filter) = (undef, undef);
+    ($prereq, $post, $cleanup)         = (undef, undef, undef);
 
     # Every test directory must have a "filter_stderr"
     $stderr_filter = validate_program(".", $default_stderr_filter, 1, 1);
+    $stderrB_filter = validate_program(".", $default_stderr_filter, 1, 1);
+    
 
     open(INPUTFILE, "< $f") || die "File $f not openable\n";
 
@@ -228,6 +253,16 @@ sub read_vgtest_file($)
             $stdout_filter = validate_program(".", $1, 1, 1);
         } elsif ($line =~ /^\s*stderr_filter:\s*(.*)$/) {
             $stderr_filter = validate_program(".", $1, 1, 1);
+        } elsif ($line =~ /^\s*progB:\s*(.*)$/) {
+            $progB = validate_program(".", $1, 0, 0);
+        } elsif ($line =~ /^\s*argsB:\s*(.*)$/) {
+            $argsB = $1;
+        } elsif ($line =~ /^\s*stdinB:\s*(.*)$/) {
+            $stdinB = $1;
+        } elsif ($line =~ /^\s*stdoutB_filter:\s*(.*)$/) {
+            $stdoutB_filter = validate_program(".", $1, 1, 1);
+        } elsif ($line =~ /^\s*stderrB_filter:\s*(.*)$/) {
+            $stderrB_filter = validate_program(".", $1, 1, 1);
         } elsif ($line =~ /^\s*prereq:\s*(.*)$/) {
             $prereq = $1;
         } elsif ($line =~ /^\s*post:\s*(.*)$/) {
@@ -333,8 +368,27 @@ sub do_one_test($$)
         }
     }
 
-    printf("%-16s valgrind $extraopts $vgopts $prog $args\n", "$name:");
 
+    if (defined $progB) {
+        # If there is a progB, let's start it in background:
+        printf("%-16s valgrind $extraopts $vgopts $prog $args (progB: $progB $argsB)\n",
+               "$name:");
+        # progB.done used to detect child has finished. See below.
+        # Note: redirection of stdout and stderr is before $progB to allow argsB
+        # to e.g. redirect stdoutB to stderrB
+        if (defined $stdinB) {
+            mysystem("(rm -f progB.done;"
+                     . " < $stdinB > $name.stdoutB.out 2> $name.stderrB.out $progB $argsB;"
+                     . "touch progB.done) &");
+        } else {
+            mysystem("(rm -f progB.done;"
+                     . " > $name.stdoutB.out 2> $name.stderrB.out $progB $argsB;"
+                     . "touch progB.done)  &");
+        }
+    } else {
+        printf("%-16s valgrind $extraopts $vgopts $prog $args\n", "$name:");
+    }
     # Pass the appropriate --tool option for the directory (can be overridden
     # by an "args:" line, though).  Set both VALGRIND_LIB and
     # VALGRIND_LIB_INNER in case this Valgrind was configured with
@@ -363,6 +417,38 @@ sub do_one_test($$)
     (0 != scalar @stderr_exps) or die "Could not find `$name.stderr.exp*'\n";
     do_diffs($fullname, $name, "stderr", \@stderr_exps); 
 
+    if (defined $progB) {
+        # wait for the child to be finished
+        # tried things such as:
+        #   wait;
+        #   $SIG{CHLD} = sub { wait };
+        # but nothing worked:
+        # e.g. running mssnapshot.vgtest in a loop failed from time to time
+        # due to some missing output (not yet written?).
+        # So, we search progB.done during max 100 times 100 millisecond.
+        my $count;
+        for ($count = 1; $count <= 100; $count++) {
+            (-f "progB.done") or select(undef, undef, undef, 0.100);
+        }
+        # Filter stdout
+        if (defined $stdoutB_filter) {
+            mysystem("$stdoutB_filter < $name.stdoutB.out > $tmp");
+            rename($tmp, "$name.stdoutB.out");
+        }
+        # Find all the .stdoutB.exp files.  If none, use /dev/null.
+        my @stdoutB_exps = <$name.stdoutB.exp*>;
+        @stdoutB_exps = ( "/dev/null" ) if (0 == scalar @stdoutB_exps);
+        do_diffs($fullname, $name, "stdoutB", \@stdoutB_exps); 
+        
+        # Filter stderr
+        mysystem("$stderrB_filter < $name.stderrB.out > $tmp");
+        rename($tmp, "$name.stderrB.out");
+        # Find all the .stderrB.exp files.  At least one must exist.
+        my @stderrB_exps = <$name.stderrB.exp*>;
+        (0 != scalar @stderrB_exps) or die "Could not find `$name.stderrB.exp*'\n";
+        do_diffs($fullname, $name, "stderrB", \@stderrB_exps); 
+    }
+
     # Maybe do post-test check
     if (defined $post) {
        if (mysystem("$post > $name.post.out") != 0) {
@@ -449,10 +535,13 @@ sub summarise_results
     my $x = ( $num_tests_done == 1 ? "test" : "tests" );
     
     printf("\n== %d test%s, %d stderr failure%s, %d stdout failure%s, "
+                         . "%d stderrB failure%s, %d stdoutB failure%s, "
                          . "%d post failure%s ==\n", 
            $num_tests_done, plural($num_tests_done),
            $num_failures{"stderr"},   plural($num_failures{"stderr"}),
            $num_failures{"stdout"},   plural($num_failures{"stdout"}),
+           $num_failures{"stderrB"},  plural($num_failures{"stderrB"}),
+           $num_failures{"stdoutB"},  plural($num_failures{"stdoutB"}),
            $num_failures{"post"},     plural($num_failures{"post"}));
 
     foreach my $failure (@failures) {
@@ -508,6 +597,8 @@ if ($ENV{"EXTRA_REGTEST_OPTS"}) {
 
 if (0 == $num_failures{"stdout"} &&
     0 == $num_failures{"stderr"} &&
+    0 == $num_failures{"stdoutB"} &&
+    0 == $num_failures{"stderrB"} &&
     0 == $num_failures{"post"}) {
     exit 0;
 } else {