This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA 3/3] gdbserver support for powerpc-lynxos (4.x)


This patch adds support for powerpc-lynxos.

Note that I'm adding a new varialble "srv_extra_libs" in configure.srv.
I need this because I need to link against -linet. Perhaps the right way
of doing things might have been to use a configure check...

gdbserver/ChangeLog:

        * gdbserver/lynx-debug.c, gdbserver/lynx-debug.h,
        gdbserver/lynx-low.c, gdbserver/lynx-low.h, gdbserver/lynx-ppc-low.c,
        gdbserver/lynx-ptrace.c, gdbserver/lynx-ptrace.h: New files.
        * Makefile.in (lynx_debug_h, lynx_ptrace_h, lynx_low_h): New variables.
        (lynx-debug.o, lynx-low.o, lynx-ppc-low.o, lynx-ptrace.o): New rules.
        * configure.ac: Add support for srv_extra_libs variable.
        * configure.srv: Add handling of powerpc-*-lynxos* targets.
        * configure: regenerate.

-- 
Joel

---
 gdb/gdbserver/Makefile.in    |    9 +
 gdb/gdbserver/configure      |    4 +
 gdb/gdbserver/configure.ac   |    4 +
 gdb/gdbserver/configure.srv  |    4 +
 gdb/gdbserver/lynx-debug.c   |   35 +++
 gdb/gdbserver/lynx-debug.h   |   26 ++
 gdb/gdbserver/lynx-low.c     |  531 ++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/lynx-low.h     |   57 +++++
 gdb/gdbserver/lynx-ppc-low.c |  186 +++++++++++++++
 gdb/gdbserver/lynx-ptrace.c  |  262 +++++++++++++++++++++
 gdb/gdbserver/lynx-ptrace.h  |   26 ++
 11 files changed, 1144 insertions(+), 0 deletions(-)
 create mode 100644 gdb/gdbserver/lynx-debug.c
 create mode 100644 gdb/gdbserver/lynx-debug.h
 create mode 100644 gdb/gdbserver/lynx-low.c
 create mode 100644 gdb/gdbserver/lynx-low.h
 create mode 100644 gdb/gdbserver/lynx-ppc-low.c
 create mode 100644 gdb/gdbserver/lynx-ptrace.c
 create mode 100644 gdb/gdbserver/lynx-ptrace.h

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index c2e3ea2..7f6649d 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -293,6 +293,10 @@ server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \
 
 linux_low_h = $(srcdir)/linux-low.h
 
+lynx_debug_h = $(srcdir)/lynx-debug.h $(srcdir)/server.h
+lynx_ptrace_h = $(srcdir)/lynx-ptrace.h $(srcdir)/server.h
+lynx_low_h = $(srcdir)/lynx-low.h $(srcdir)/server.h
+
 nto_low_h = $(srcdir)/nto-low.h
 
 # Note, we only build the IPA if -fvisibility=hidden is supported in
@@ -369,6 +373,11 @@ linux-x86-low.o: linux-x86-low.c $(linux_low_h) $(server_h) \
 	$(gdb_proc_service_h) $(i386_low_h)
 linux-xtensa-low.o: linux-xtensa-low.c xtensa-xtregs.c $(linux_low_h) $(server_h)
 
+lynx-debug.o: lynx-debug.c $(lynx_debug_h)
+lynx-low.o: lynx-low.c $(server_h) $(target_h) $(lynx_low_h) $(lynx_debug_h) \
+	$(lynx_ptrace_h)
+lynx-ppc-low.o: lynx-ppc-low.c $(server_h) $(lynx_low_h)
+lynx-ptrace.o: lynx-ptrace.c $(server_h) $(lynx_ptrace_h)
 nto-low.o: nto-low.c $(server_h) $(nto_low_h)
 nto-x86-low.o: nto-x86-low.c $(server_h) $(nto_low_h) $(regdef_h) $(regcache_h)
 
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index 2708f23..0521214 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -4563,6 +4563,10 @@ if test "$ipa_obj" != "" \
    extra_libraries="libinproctrace.so"
 fi
 
+if test "$srv_extra_libs" != ""; then
+   GDBSERVER_LIBS="$GDBSERVER_LIBS $srv_extra_libs"
+fi
+
 
 
 
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 40d30c4..6d810fa 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -275,6 +275,10 @@ if test "$ipa_obj" != "" \
    extra_libraries="libinproctrace.so"
 fi
 
+if test "$srv_extra_libs" != ""; then
+   GDBSERVER_LIBS="$GDBSERVER_LIBS $srv_extra_libs"
+fi
+
 AC_SUBST(GDBSERVER_DEPFILES)
 AC_SUBST(GDBSERVER_LIBS)
 AC_SUBST(USE_THREAD_DB)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 99187a5..e1bb84a 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -200,6 +200,10 @@ case "${target}" in
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
 			;;
+  powerpc-*-lynxos*)	srv_regobj="powerpc-32.o"
+			srv_tgtobj="lynx-low.o lynx-ppc-low.o lynx-debug.o lynx-ptrace.o"
+			srv_extra_libs="-lnetinet"
+			;;
   s390*-*-linux*)	srv_regobj="s390-linux32.o"
 			srv_regobj="${srv_regobj} s390-linux64.o"
 			srv_regobj="${srv_regobj} s390x-linux64.o"
diff --git a/gdb/gdbserver/lynx-debug.c b/gdb/gdbserver/lynx-debug.c
new file mode 100644
index 0000000..aaca754
--- /dev/null
+++ b/gdb/gdbserver/lynx-debug.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "lynx-debug.h"
+
+void
+lynx_debug (char *string, ...)
+{
+  va_list args;
+
+  if (!debug_threads)
+    return;
+
+  va_start (args, string);
+  fprintf (stdout, "DEBUG(lynx): ");
+  vfprintf (stdout, string, args);
+  fprintf (stdout, "\n");
+  va_end (args);
+}
+
+
diff --git a/gdb/gdbserver/lynx-debug.h b/gdb/gdbserver/lynx-debug.h
new file mode 100644
index 0000000..396df2b
--- /dev/null
+++ b/gdb/gdbserver/lynx-debug.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef LYNX_DEBUG_H
+#define LYNX_DEBUG_H
+
+#include "server.h"
+
+/* Print a debug trace on standard output if debug_threads is set.  */
+extern void lynx_debug (char *string, ...) ATTR_FORMAT (printf, 1, 2);
+
+#endif
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
new file mode 100644
index 0000000..50cc26a
--- /dev/null
+++ b/gdb/gdbserver/lynx-low.c
@@ -0,0 +1,531 @@
+/* Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include "target.h"
+#include "lynx-low.h"
+#include "lynx-debug.h"
+#include "lynx-ptrace.h"
+
+#include <limits.h>
+#include <ptrace.h>
+#include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc.  */
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+int using_threads = 1;
+
+/* Build a ptid_t given a PID and a LynxOS TID.  */
+
+ptid_t
+lynx_ptid_build (int pid, long tid)
+{
+  /* brobecker/2010-06-21: It looks like the LWP field in ptids
+     should be distinct for each thread (see write_ptid where it
+     writes the thread ID from the LWP).  So instead of storing
+     the LynxOS tid in the tid field of the ptid, we store it in
+     the lwp field.  */
+  return ptid_build (pid, tid, 0);
+}
+
+/* Return the process ID of the given PTID.
+
+   This function has little reason to exist, it's just a wrapper around
+   ptid_get_pid.  But since we have a getter function for the lynxos
+   ptid, it feels cleaner to have a getter for the pid as well.  */
+
+int
+lynx_ptid_get_pid (ptid_t ptid)
+{
+  return ptid_get_pid (ptid);
+}
+
+/* Return the LynxOS tid of the given PTID.  */
+
+long
+lynx_ptid_get_tid (ptid_t ptid)
+{
+  /* See lynx_ptid_build: The LynxOS tid is stored inside the lwp field
+     of the ptid.  */
+  return ptid_get_lwp (ptid);
+}
+
+/* Implement the create_inferior method of the target_ops vector.  */
+
+static int
+lynx_create_inferior (char *program, char **allargs)
+{
+  void *new_process;
+  int pid;
+
+  lynx_debug ("lynx_create_inferior ()");
+
+  pid = fork ();
+  if (pid < 0)
+    perror_with_name ("fork");
+
+  if (pid == 0)
+    {
+      int pgrp;
+
+      /* Switch child to its own process group so that signals won't
+         directly affect gdbserver. */
+      pgrp = getpid();
+      setpgid (0, pgrp);
+      ioctl (0, TIOCSPGRP, &pgrp);
+      lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
+      execv (program, allargs);
+      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  new_process = add_process (pid, 0);
+  /* Do not add the process thread just yet, as we do not know its tid.
+     We will add it later, during the wait for the STOP event corresponding
+     to the lynx_ptrace (PTRACE_TRACEME) call above.  */
+  return pid;
+}
+
+/* Implement the attach target_ops method.  */
+
+static int
+lynx_attach (unsigned long pid)
+{
+  struct process_info *new_process;
+  ptid_t ptid = lynx_ptid_build (pid, 0);
+
+  if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0)
+    error ("Cannot attach to process %lu: %s (%d)\n", pid,
+	   strerror (errno), errno);
+
+  new_process = (struct process_info *) add_process (pid, 1);
+  add_thread (ptid, NULL);
+
+  return 0;
+}
+
+/* Implement the resume target_ops method.  */
+
+static void
+lynx_resume (struct thread_resume *resume_info, size_t n)
+{
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  /* FIXME: Assume for now that n == 1.  */
+  const int request = (resume_info[0].kind == resume_step
+                       ? PTRACE_SINGLESTEP : PTRACE_CONT);
+  const int signal = resume_info[0].sig;
+  int ret;
+
+  regcache_invalidate ();
+  ret = lynx_ptrace (request, inferior_ptid, 1, signal, 0);
+}
+
+/* Resume the execution of the given PTID.  */
+
+static void
+lynx_continue (ptid_t ptid)
+{
+  struct thread_resume resume_info;
+
+  resume_info.thread = ptid;
+  resume_info.kind = resume_continue;
+  resume_info.sig = 0;
+
+  lynx_resume (&resume_info, 1);
+}
+
+/* Remove all inferiors and associated threads.  */
+
+static void
+lynx_clear_inferiors (void)
+{
+  /* We do not use private data, so nothing much to do except calling
+     clear_inferiors.  */
+  clear_inferiors ();
+}
+
+/* A wrapper around waitpid that handles the various idiosyncrasies
+   of LynxOS' waitpid.  */
+
+static int
+lynx_waitpid (int pid, int *stat_loc)
+{
+  int ret = 0;
+
+  while (1)
+    {
+      ret = waitpid (pid, stat_loc, WNOHANG);
+      if (ret < 0)
+        {
+	  /* An ECHILD error is not indicative of a real problem.
+	     It happens for instance while waiting for the inferior
+	     to stop after attaching to it.  */
+	  if (errno != ECHILD)
+	    perror_with_name ("waitpid (WNOHANG)");
+	}
+      if (ret > 0)
+        break;
+      /* No event with WNOHANG.  See if there is one with WUNTRACED.  */
+      ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED);
+      if (ret < 0)
+        {
+	  /* An ECHILD error is not indicative of a real problem.
+	     It happens for instance while waiting for the inferior
+	     to stop after attaching to it.  */
+	  if (errno != ECHILD)
+	    perror_with_name ("waitpid (WNOHANG|WUNTRACED)");
+	}
+      if (ret > 0)
+        break;
+      usleep (1000);
+    }
+  return ret;
+}
+
+/* Implement the wait target_ops method.  */
+
+static ptid_t
+lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options)
+{
+  int pid;
+  int ret;
+  int wstat;
+  ptid_t new_ptid;
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior));
+  else
+    pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
+
+retry:
+
+  ret = lynx_waitpid (pid, &wstat);
+  new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
+
+  /* If this is a new thread, then add it now.  The reason why we do
+     this here instead of when handling new-thread events is because
+     we need to add the thread associated to the "main" thread - even
+     for non-threaded applications where the new-thread events are not
+     generated.  */
+  if (!find_thread_ptid (new_ptid))
+    add_thread (new_ptid, NULL);
+
+  if (WIFSTOPPED (wstat))
+    {
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.integer = WSTOPSIG (wstat);
+      lynx_debug ("process stopped with signal: %d",
+                  status->value.integer);
+    }
+  else if (WIFEXITED (wstat))
+    {
+      status->kind = TARGET_WAITKIND_EXITED;
+      status->value.integer = WEXITSTATUS (wstat);
+      lynx_clear_inferiors ();
+      lynx_debug ("process exited with code: %d", status->value.integer);
+    }
+  else if (WIFSIGNALED (wstat))
+    {
+      status->kind = TARGET_WAITKIND_SIGNALLED;
+      status->value.integer = WTERMSIG (wstat);
+      lynx_clear_inferiors ();
+      lynx_debug ("process terminated with code: %d",
+                  status->value.integer);
+    }
+  else
+    {
+      /* Not sure what happened if we get here, or whether we can
+	 in fact get here.  But if we do, handle the event the best
+	 we can.  */
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.integer = 0;
+      lynx_debug ("unknown event ????");
+    }
+
+  /* SIGTRAP events are generated for situations other than single-step/
+     breakpoint events (Eg. new-thread events).  Handle those other types
+     of events, and resume the execution if necessary.  */
+  if (status->kind == TARGET_WAITKIND_STOPPED
+      && status->value.integer == SIGTRAP)
+    {
+      const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0);
+
+      lynx_debug ("(realsig = %d)", realsig);
+      switch (realsig)
+	{
+	  case SIGNEWTHREAD:
+	    /* We just added the new thread above.  No need to do anything
+	       further.  Just resume the execution again.  */
+	    lynx_continue (ptid);
+	    goto retry;
+
+	  case SIGTHREADEXIT:
+	    remove_thread (find_thread_ptid (new_ptid));
+	    lynx_continue (ptid);
+	    goto retry;
+	}
+    }
+
+  return new_ptid;
+}
+
+/* A wrapper around lynx_wait_1 that also prints debug traces when
+   such debug traces have been activated.  */
+
+static ptid_t
+lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options)
+{
+  ptid_t new_ptid;
+
+  lynx_debug ("lynx_wait (pid = %d, tid = %ld)",
+              lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
+  new_ptid = lynx_wait_1 (ptid, status, options);
+  lynx_debug ("          -> (pid=%d, tid=%ld, status->kind = %d)",
+	      lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid),
+	      status->kind);
+  return new_ptid;
+}
+
+/* Implement the kill target_ops method.  */
+
+static int
+lynx_kill (int pid)
+{
+  ptid_t ptid = lynx_ptid_build (pid, 0);
+  struct target_waitstatus status;
+
+  lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0);
+  lynx_wait (ptid, &status, 0);
+  return 0;
+}
+
+/* Implement the detach target_ops method.  */
+
+static int
+lynx_detach (int pid)
+{
+  ptid_t ptid = lynx_ptid_build (pid, 0);
+
+  lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0);
+  return 0;
+}
+
+/* Implement the join target_ops method.  */
+
+static void
+lynx_join (int pid)
+{
+  /* The PTRACE_DETACH is sufficient to detach from the process.
+     So no need to do anything extra.  */
+}
+
+/* Implement the thread_alive target_ops method.  */
+
+static int
+lynx_thread_alive (ptid_t ptid)
+{
+  /* The list of threads is updated at the end of each wait, so it
+     should be up to date.  No need to re-fetch it.  */
+  return (find_thread_ptid (ptid) != NULL);
+}
+
+/* Implement the fetch_registers target_ops method.  */
+
+static void
+lynx_fetch_registers (struct regcache *regcache, int regno)
+{
+  struct lynx_regset_info *regset = lynx_target_regsets;
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+
+  lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
+
+  while (regset->size >= 0)
+    {
+      void *buf;
+      int res;
+
+      buf = xmalloc (regset->size);
+      res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
+      if (res < 0)
+        perror ("ptrace");
+      regset->store_function (regcache, buf);
+      free (buf);
+      regset++;
+    }
+}
+
+/* Implement the store_registers target_ops method.  */
+
+static void
+lynx_store_registers (struct regcache *regcache, int regno)
+{
+  struct lynx_regset_info *regset = lynx_target_regsets;
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+
+  lynx_debug ("lynx_store_registers (regno = %d)", regno);
+
+  while (regset->size >= 0)
+    {
+      void *buf;
+      int res;
+
+      buf = xmalloc (regset->size);
+      res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
+      if (res == 0)
+        {
+	  /* Then overlay our cached registers on that.  */
+	  regset->fill_function (regcache, buf);
+	  /* Only now do we write the register set.  */
+	  res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf,
+			     0, 0);
+        }
+      if (res < 0)
+        perror ("ptrace");
+      free (buf);
+      regset++;
+    }
+}
+
+/* Implement the read_memory target_ops method.  */
+
+static int
+lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+  /* On LynxOS, memory reads needs to be performed in chunks the size
+     of int types, and they should also be aligned accordingly.  */
+  int buf;
+  const int xfer_size = sizeof (buf);
+  CORE_ADDR addr = memaddr & -(CORE_ADDR)xfer_size;
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+
+  while (addr < memaddr + len)
+    {
+      int skip = 0;
+      int truncate = 0;
+
+      errno = 0;
+      if (addr < memaddr)
+        skip = memaddr - addr;
+      if (addr + xfer_size > memaddr + len)
+        truncate = addr + xfer_size - memaddr - len;
+      buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0);
+      if (errno)
+        return errno;
+      memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *)&buf + skip,
+              xfer_size - skip - truncate);
+      addr += xfer_size;
+    }
+
+  return 0;
+}
+
+/* Implement the write_memory target_ops method.  */
+
+static int
+lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+  /* On LynxOS, memory writes needs to be performed in chunks the size
+     of int types, and they should also be aligned accordingly.  */
+  int buf;
+  const int xfer_size = sizeof (buf);
+  CORE_ADDR addr = memaddr & -(CORE_ADDR)xfer_size;
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+
+  while (addr < memaddr + len)
+    {
+      int skip = 0;
+      int truncate = 0;
+
+      if (addr < memaddr)
+        skip = memaddr - addr;
+      if (addr + xfer_size > memaddr + len)
+        truncate = addr + xfer_size - memaddr - len;
+      if (skip > 0 || truncate > 0)
+        /* We need to read the memory at this address in order to preserve
+           the data that we are not overwriting.  */
+        lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
+        if (errno)
+          return errno;
+      memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
+              xfer_size - skip - truncate);
+      errno = 0;
+      lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0);
+      if (errno)
+        return errno;
+      addr += xfer_size;
+    }
+
+  return 0;
+}
+
+/* Implement the kill_request target_ops method.  */
+
+static void
+lynx_request_interrupt (void)
+{
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+
+  kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
+}
+
+/* The LynxOS target_ops vector.  */
+
+static struct target_ops lynx_target_ops = {
+  lynx_create_inferior,
+  lynx_attach,
+  lynx_kill,
+  lynx_detach,
+  NULL,  /* mourn */
+  lynx_join,
+  lynx_thread_alive,
+  lynx_resume,
+  lynx_wait,
+  lynx_fetch_registers,
+  lynx_store_registers,
+  lynx_read_memory,
+  lynx_write_memory,
+  NULL,  /* look_up_symbols */
+  lynx_request_interrupt,
+  NULL,  /* read_auxv */
+  NULL,  /* insert_point */
+  NULL,  /* remove_point */
+  NULL,  /* stopped_by_watchpoint */
+  NULL,  /* stopped_data_address */
+  NULL,  /* read_offsets */
+  NULL,  /* get_tls_address */
+  NULL,  /* qxfer_spu */
+  NULL,  /* hostio_last_error */
+  NULL,  /* qxfer_osdata */
+  NULL,  /* qxfer_siginfo */
+  NULL,  /* supports_non_stop */
+  NULL,  /* async */
+  NULL,  /* start_non_stop */
+  NULL,  /* supports_multi_process */
+  NULL,  /* handle_monitor_command */
+};
+
+void
+initialize_low (void)
+{
+  set_target_ops (&lynx_target_ops);
+  the_low_target.arch_setup ();
+}
+
diff --git a/gdb/gdbserver/lynx-low.h b/gdb/gdbserver/lynx-low.h
new file mode 100644
index 0000000..9f2ce30
--- /dev/null
+++ b/gdb/gdbserver/lynx-low.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+
+struct regcache;
+
+/*  Some information relative to a given register set.   */
+
+struct lynx_regset_info
+{
+  /* The ptrace request needed to get/set registers of this set.  */
+  int get_request, set_request;
+  /* The size of the register set.  */
+  int size;
+  /* Fill the buffer BUF from the contents of the given REGCACHE.  */
+  void (*fill_function) (struct regcache *regcache, void *buf);
+  /* Store the register value in BUF in the given REGCACHE.  */
+  void (*store_function) (struct regcache *regcache, const void *buf);
+};
+
+/* A list of regsets for the target being debugged, terminated by an entry
+   where the size is negative.
+
+   This list should be created by the target-specific code.  */
+
+extern struct lynx_regset_info lynx_target_regsets[];
+
+/* The target-specific operations for LynxOS support.  */
+
+struct lynx_target_ops
+{
+  /* Architecture-specific setup.  */
+  void (*arch_setup) (void);
+};
+
+extern struct lynx_target_ops the_low_target;
+
+/* LynxOS-specific ptid handling.  */
+
+ptid_t lynx_ptid_build (int pid, long tid);
+int lynx_ptid_get_pid (ptid_t ptid);
+long lynx_ptid_get_tid (ptid_t ptid);
diff --git a/gdb/gdbserver/lynx-ppc-low.c b/gdb/gdbserver/lynx-ppc-low.c
new file mode 100644
index 0000000..6002060
--- /dev/null
+++ b/gdb/gdbserver/lynx-ppc-low.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include "lynx-low.h"
+
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ptrace.h>
+
+/* The following two typedefs are defined in a .h file which is not
+   in the standard include path (/sys/include/family/ppc/ucontext.h),
+   so we just duplicate them here.  */
+
+/* General register context */
+typedef struct usr_econtext_s
+{
+        uint32_t        uec_iregs[32];
+        uint32_t        uec_inum;
+        uint32_t        uec_srr0;
+        uint32_t        uec_srr1;
+        uint32_t        uec_lr;
+        uint32_t        uec_ctr;
+        uint32_t        uec_cr;
+        uint32_t        uec_xer;
+        uint32_t        uec_dar;
+        uint32_t        uec_mq;
+        uint32_t        uec_msr;
+        uint32_t        uec_sregs[16];
+        uint32_t        uec_ss_count;
+        uint32_t        uec_ss_addr1;
+        uint32_t        uec_ss_addr2;
+        uint32_t        uec_ss_code1;
+        uint32_t        uec_ss_code2;
+} usr_econtext_t;
+
+/* Floating point register context */
+typedef struct usr_fcontext_s
+{
+        uint64_t        ufc_freg[32];
+        uint32_t        ufc_fpscr[2];
+} usr_fcontext_t;
+
+/* Index of for various registers inside the regcache.  */
+#define R0_REGNUM    0
+#define F0_REGNUM    32
+#define PC_REGNUM    64
+#define MSR_REGNUM   65
+#define CR_REGNUM    66
+#define LR_REGNUM    67
+#define CTR_REGNUM   68
+#define XER_REGNUM   69
+#define FPSCR_REGNUM 70
+
+/* Defined in auto-generated file powerpc-32.c.  */
+extern void init_registers_powerpc_32 (void);
+
+/* The fill_function for the general-purpose register set.  */
+
+static void
+lynx_ppc_fill_gregset (struct regcache *regcache, void *buf)
+{
+  int i;
+
+  /* r0 - r31 */
+  for (i = 0; i < 32; i++)
+    collect_register (regcache, R0_REGNUM + i,
+                      buf + offsetof (usr_econtext_t, uec_iregs[i]));
+
+  /* The other registers provided in the GP register context.  */
+  collect_register (regcache, PC_REGNUM,
+                    buf + offsetof (usr_econtext_t, uec_srr0));
+  collect_register (regcache, MSR_REGNUM,
+                    buf + offsetof (usr_econtext_t, uec_srr1));
+  collect_register (regcache, CR_REGNUM,
+                    buf + offsetof (usr_econtext_t, uec_cr));
+  collect_register (regcache, LR_REGNUM,
+                    buf + offsetof (usr_econtext_t, uec_lr));
+  collect_register (regcache, CTR_REGNUM,
+                    buf + offsetof (usr_econtext_t, uec_ctr));
+  collect_register (regcache, XER_REGNUM,
+                    buf + offsetof (usr_econtext_t, uec_xer));
+}
+
+/* The store_function for the general-purpose register set.  */
+
+static void
+lynx_ppc_store_gregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+
+  /* r0 - r31 */
+  for (i = 0; i < 32; i++)
+    supply_register (regcache, R0_REGNUM + i,
+                      buf + offsetof (usr_econtext_t, uec_iregs[i]));
+
+  /* The other registers provided in the GP register context.  */
+  supply_register (regcache, PC_REGNUM,
+                   buf + offsetof (usr_econtext_t, uec_srr0));
+  supply_register (regcache, MSR_REGNUM,
+                   buf + offsetof (usr_econtext_t, uec_srr1));
+  supply_register (regcache, CR_REGNUM,
+                   buf + offsetof (usr_econtext_t, uec_cr));
+  supply_register (regcache, LR_REGNUM,
+                   buf + offsetof (usr_econtext_t, uec_lr));
+  supply_register (regcache, CTR_REGNUM,
+                   buf + offsetof (usr_econtext_t, uec_ctr));
+  supply_register (regcache, XER_REGNUM,
+                   buf + offsetof (usr_econtext_t, uec_xer));
+}
+
+/* The fill_function for the floating-point register set.  */
+
+static void
+lynx_ppc_fill_fpregset (struct regcache *regcache, void *buf)
+{
+  int i;
+
+  /* f0 - f31 */
+  for (i = 0; i < 32; i++)
+    collect_register (regcache, F0_REGNUM + i,
+                      buf + offsetof (usr_fcontext_t, ufc_freg[i]));
+
+  /* fpscr */
+  collect_register (regcache, FPSCR_REGNUM,
+                    buf + offsetof (usr_fcontext_t, ufc_fpscr));
+}
+
+/* The store_function for the floating-point register set.  */
+
+static void
+lynx_ppc_store_fpregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+
+  /* f0 - f31 */
+  for (i = 0; i < 32; i++)
+    supply_register (regcache, F0_REGNUM + i,
+                     buf + offsetof (usr_fcontext_t, ufc_freg[i]));
+
+  /* fpscr */
+  supply_register (regcache, FPSCR_REGNUM,
+                   buf + offsetof (usr_fcontext_t, ufc_fpscr));
+}
+
+/* Implements the lynx_target_ops.arch_setup routine.  */
+
+static void
+lynx_ppc_arch_setup (void)
+{
+  init_registers_powerpc_32 ();
+}
+
+/* Description of all the powerpc-lynx register sets.  */
+
+struct lynx_regset_info lynx_target_regsets[] = {
+  /* General Purpose Registers.  */
+  {PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t),
+   lynx_ppc_fill_gregset, lynx_ppc_store_gregset},
+  /* Floating Point Registers.  */
+  { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t),
+    lynx_ppc_fill_fpregset, lynx_ppc_store_fpregset },
+  /* End of list marker.  */
+  {0, 0, -1, NULL, NULL }
+};
+
+/* The lynx_target_ops vector for powerpc-lynxos.  */
+
+struct lynx_target_ops the_low_target = {
+  lynx_ppc_arch_setup,
+};
diff --git a/gdb/gdbserver/lynx-ptrace.c b/gdb/gdbserver/lynx-ptrace.c
new file mode 100644
index 0000000..9654cd6
--- /dev/null
+++ b/gdb/gdbserver/lynx-ptrace.c
@@ -0,0 +1,262 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include "lynx-ptrace.h"
+
+#include <limits.h>
+#include <ptrace.h>
+#include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc.  */
+
+static int
+lynx_ptrace_pid_from_ptid (ptid_t ptid)
+{
+  return BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
+}
+
+/* Return a string image of the ptrace REQUEST number.  */
+
+static char *
+ptrace_request_to_str (int request)
+{
+  switch (request)
+    {
+      case PTRACE_TRACEME:
+        return "PTRACE_TRACEME";
+        break;
+      case PTRACE_PEEKTEXT:
+        return "PTRACE_PEEKTEXT";
+        break;
+      case PTRACE_PEEKDATA:
+        return "PTRACE_PEEKDATA";
+        break;
+      case PTRACE_PEEKUSER:
+        return "PTRACE_PEEKUSER";
+        break;
+      case PTRACE_POKETEXT:
+        return "PTRACE_POKETEXT";
+        break;
+      case PTRACE_POKEDATA:
+        return "PTRACE_POKEDATA";
+        break;
+      case PTRACE_POKEUSER:
+        return "PTRACE_POKEUSER";
+        break;
+      case PTRACE_CONT:
+        return "PTRACE_CONT";
+        break;
+      case PTRACE_KILL:
+        return "PTRACE_KILL";
+        break;
+      case PTRACE_SINGLESTEP:
+        return "PTRACE_SINGLESTEP";
+        break;
+      case PTRACE_ATTACH:
+        return "PTRACE_ATTACH";
+        break;
+      case PTRACE_DETACH:
+        return "PTRACE_DETACH";
+        break;
+      case PTRACE_GETREGS:
+        return "PTRACE_GETREGS";
+        break;
+      case PTRACE_SETREGS:
+        return "PTRACE_SETREGS";
+        break;
+      case PTRACE_GETFPREGS:
+        return "PTRACE_GETFPREGS";
+        break;
+      case PTRACE_SETFPREGS:
+        return "PTRACE_SETFPREGS";
+        break;
+      case PTRACE_READDATA:
+        return "PTRACE_READDATA";
+        break;
+      case PTRACE_WRITEDATA:
+        return "PTRACE_WRITEDATA";
+        break;
+      case PTRACE_READTEXT:
+        return "PTRACE_READTEXT";
+        break;
+      case PTRACE_WRITETEXT:
+        return "PTRACE_WRITETEXT";
+        break;
+      case PTRACE_GETFPAREGS:
+        return "PTRACE_GETFPAREGS";
+        break;
+      case PTRACE_SETFPAREGS:
+        return "PTRACE_SETFPAREGS";
+        break;
+      case PTRACE_GETWINDOW:
+        return "PTRACE_GETWINDOW";
+        break;
+      case PTRACE_SETWINDOW:
+        return "PTRACE_SETWINDOW";
+        break;
+      case PTRACE_SYSCALL:
+        return "PTRACE_SYSCALL";
+        break;
+      case PTRACE_DUMPCORE:
+        return "PTRACE_DUMPCORE";
+        break;
+      case PTRACE_SETWRBKPT:
+        return "PTRACE_SETWRBKPT";
+        break;
+      case PTRACE_SETACBKPT:
+        return "PTRACE_SETACBKPT";
+        break;
+      case PTRACE_CLRBKPT:
+        return "PTRACE_CLRBKPT";
+        break;
+      case PTRACE_GET_UCODE:
+        return "PTRACE_GET_UCODE";
+        break;
+#ifdef PT_READ_GPR
+      case PT_READ_GPR:
+        return "PT_READ_GPR";
+        break;
+#endif
+#ifdef PT_WRITE_GPR
+      case PT_WRITE_GPR:
+        return "PT_WRITE_GPR";
+        break;
+#endif
+#ifdef PT_READ_FPR
+      case PT_READ_FPR:
+        return "PT_READ_FPR";
+        break;
+#endif
+#ifdef PT_WRITE_FPR
+      case PT_WRITE_FPR:
+        return "PT_WRITE_FPR";
+        break;
+#endif
+#ifdef PTRACE_GETVECREGS
+      case PTRACE_GETVECREGS:
+        return "PTRACE_GETVECREGS";
+        break;
+#endif
+#ifdef PTRACE_SETVECREGS
+      case PTRACE_SETVECREGS:
+        return "PTRACE_SETVECREGS";
+        break;
+#endif
+#ifdef PT_READ_VPR
+      case PT_READ_VPR:
+        return "PT_READ_VPR";
+        break;
+#endif
+#ifdef PT_WRITE_VPR
+      case PT_WRITE_VPR:
+        return "PT_WRITE_VPR";
+        break;
+#endif
+#ifdef PTRACE_PEEKUSP
+      case PTRACE_PEEKUSP:
+        return "PTRACE_PEEKUSP";
+        break;
+#endif
+#ifdef PTRACE_POKEUSP
+      case PTRACE_POKEUSP:
+        return "PTRACE_POKEUSP";
+        break;
+#endif
+      case PTRACE_PEEKTHREAD:
+        return "PTRACE_PEEKTHREAD";
+        break;
+      case PTRACE_THREADUSER:
+        return "PTRACE_THREADUSER";
+        break;
+      case PTRACE_FPREAD:
+        return "PTRACE_FPREAD";
+        break;
+      case PTRACE_FPWRITE:
+        return "PTRACE_FPWRITE";
+        break;
+      case PTRACE_SETSIG:
+        return "PTRACE_SETSIG";
+        break;
+      case PTRACE_CONT_ONE:
+        return "PTRACE_CONT_ONE";
+        break;
+      case PTRACE_KILL_ONE:
+        return "PTRACE_KILL_ONE";
+        break;
+      case PTRACE_SINGLESTEP_ONE:
+        return "PTRACE_SINGLESTEP_ONE";
+        break;
+      case PTRACE_GETLOADINFO:
+        return "PTRACE_GETLOADINFO";
+        break;
+      case PTRACE_GETTHREADLIST:
+        return "PTRACE_GETTHREADLIST";
+        break;
+      case PTRACE_POSTSYSCALL:
+        return "PTRACE_POSTSYSCALL";
+        break;
+      case PTRACE_USE_SIGEXECED:
+        return "PTRACE_USE_SIGEXECED";
+        break;
+      case PTRACE_GETTRACESIG:
+        return "PTRACE_GETTRACESIG";
+        break;
+      case PTRACE_GETCWD:
+        return "PTRACE_GETCWD";
+        break;
+      case PTRACE_TRAPFORK:
+        return "PTRACE_TRAPFORK";
+        break;
+      case PTRACE_GETCHILDPID:
+        return "PTRACE_GETCHILDPID";
+        break;
+      case PTRACE_SYSCALL_ONE:
+        return "PTRACE_SYSCALL_ONE";
+        break;
+      case PTRACE_SIGMASK:
+        return "PTRACE_SIGMASK";
+        break;
+      case PTRACE_GETIWD:
+        return "PTRACE_GETIWD";
+        break;
+      case PTRACE_GETEXECFILE:
+        return "PTRACE_GETEXECFILE";
+        break;
+    }
+  return "<unknown-request>";
+}
+
+/* A wrapper around ptrace that allows us to print debug traces of
+   ptrace calls if debug traces are activated.  */
+
+int
+lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
+{
+  int result;
+  const int pid = lynx_ptrace_pid_from_ptid (ptid);
+
+  if (debug_threads)
+    printf ("PTRACE (%s, pid=%d(pid=%d, tid=%d), addr=0x%x, data=0x%x, "
+            "addr2=0x%x)",
+            ptrace_request_to_str (request), pid, PIDGET (pid), TIDGET (pid),
+            addr, data, addr2);
+  result = ptrace (request, pid, addr, data, addr2);
+  if (debug_threads)
+    printf (" -> %d (=0x%x)\n", result, result);
+
+  return result;
+}
+
diff --git a/gdb/gdbserver/lynx-ptrace.h b/gdb/gdbserver/lynx-ptrace.h
new file mode 100644
index 0000000..dc39550
--- /dev/null
+++ b/gdb/gdbserver/lynx-ptrace.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef LYNX_PTRACE_H
+#define LYNX_PTRACE_H
+
+#include "server.h"
+
+int lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2);
+
+#endif
+
-- 
1.7.0.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]