Implement a GDB server in Valgrind. See #214909.
(Philippe Waroquiers, philippe.waroquiers@skynet.be)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11727 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_gdbserver/target.c b/coregrind/m_gdbserver/target.c
new file mode 100644
index 0000000..ae61c94
--- /dev/null
+++ b/coregrind/m_gdbserver/target.c
@@ -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);
+}