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]

Re: [patch] gdbserver: Add qnx target


Pedro Alves wrote:
On Wednesday 17 June 2009 16:04:47, Aleksandar Ristovski wrote:

The patch is quite straight-forward.

Not quite.


2) gdbserver-ntotarget - ChangeLog

* configure.srv (i[34567]86-*-nto*): New target.
* nto-low.c, nto-low.h, nto-x86-low.c: New files.
* remote-utils.c (include sys/iomgr.h): New include for __QNX__ only.
(nto_comctrl): New function for __QNX__ only.
(enable_async_io, disable_async_io): Call nto_comcntrl for __QNX__ only.

I took a first look at this one.




> +void nto_trace (const char *fmt, ...)

Pedro: Function name at column 0.

Done.

> > +void nto_trace (const char *fmt, ...)
> > +{
> > +  va_list arg_list;
> > +
> > +  if (debug_threads == 0)
> > +    return;
> > +

Pedro: ^ spurious space.

Done.

> > +  printf ("nto:");
> > +  va_start (arg_list, fmt);
> > +  vprintf (fmt, arg_list);
> > +  va_end (arg_list);
> > +}

Pedro: This should go to stderr, not stdout.

Done.

> > +static void
> > +do_detach ()
              ^ (void)


> > + return ptid_build (0, 0, 0);


Pedro: This is null_ptid, although minus_one_ptid is
more common for returning errors.

Done

> > +/* Given pid, open procfs path. Return ptid built from pid,0,tid. */
> > +
> > +static ptid_t
> > +do_attach (ptid_t ptid)
> > +{


Pedro: It would simpler and clearer if this took a
simple `int pid' as argument.

Done.

> > +
> > +static void
> > +nto_resume (struct thread_resume *resume_info, size_t n)
> > +{

Pedro: OOC, there's really no way to resume only one thread in
nto then? (scheduler-locking).

Not for now, but it will soon.

> > +  regcache_invalidate ();
> > +}

Pedro: You should flush the register cache *before* resuming, not
after...



Done.


> > +static void nto_fetch_registers (int regno);

Pedro: Can you reorder the code so that forward declarations
aren't needed?

This forward decl was not necessary. Removed.

> > +static ptid_t
> > +nto_wait (ptid_t ptid,
> > + struct target_waitstatus *ourstatus, int target_options)
> > +{
> > + sigset_t set;
> > + siginfo_t info;
> > + procfs_status status;
> > + static int exit_signo = 0; /* For tracking exit status. */


Pedro: Why is this static?

We first register that signal has hit the inferior, but it hasn't died just yet. We set exit_signo and return TARGET_WAITKIND_STOPPED. On next resume it really terminates, we set recorded signal from the static.

It should really go into "nto_inferior" structure. I plan to support multiple processes so there will be a chance for cleanups.

> > +
> > +  TRACE ("%s\n", __func__);
> > +
> > +  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
> > +
> > +  if (ptid_equal (ptid, null_ptid))
> > +    {
> > +      ourstatus->kind = TARGET_WAITKIND_STOPPED;
> > +      ourstatus->value.sig = TARGET_SIGNAL_0;
> > +      exit_signo = 0;
> > +      TRACE ("null_ptid...\n");
> > +      return null_ptid;
> > +    }

Pedro: Is this checking on null_ptid really needed?  I'd prefer
to not carry dead code from gdb into gdbserver...

Removed.

> > +
> > +  regcache_invalidate ();
> > +

Pedro: It is bogus to flush the regcache here to the inferior
here, instead of just before resuming.

Ok, moved before resume.

> > +
> > +  return ptid_build (status.pid, status.tid, 0);
> > +}
> > +

Pedro: AFAICS, nowhere have you set the current_inferior.

add_thread will set it (see inferiors.c:184)


> > + > > +static void > > +nto_fetch_registers (int regno) > > +{

> > + const unsigned int registeroffset
> > + = the_low_target.register_offset (regno);


Pedro: ^^^ bad indentation.

Changed.


> > + const unsigned int registeroffset > > + = the_low_target.register_offset (regno);

Pedro: Likewise. Spurious space after registeroffset.

Removed.


> > +static void
> > +nto_store_registers (int regno)
> > +{
> > + int reg;
> > + procfs_greg greg;
> > + int err;
> > +
> > + memset (&greg, 0, sizeof (greg));
> > +
> > + TRACE ("%s (regno:%d)\n", __func__, regno);
> > + for (reg = 0; reg != the_low_target.num_regs; ++reg)
> > + {
> > + const unsigned int regoffset
> > + = the_low_target.register_offset (regno);
> > + collect_register (reg, ((char *)&greg) + regoffset);
> > + }
> > + if (greg.x86.eip != 0)
> > + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg),
> > + 0);
> > + reg = greg.x86.eip;
> > + TRACE ("eip=0x%08x\n", reg);
> > + if (err != EOK)
> > + TRACE ("Error: setting registers.\n");
> > +}


Pedro: Okay, I'm confused. You're referencing x86 things here, in the
nto-low.c file.


No wonder you are confused :-) It was a leftover from my debugging. Removed.

> > +static int
> > +nto_stopped_by_watchpoint (void)
> > +{
> > + procfs_status status;
> > + int ret = 0;
> > +
> > + TRACE ("%s...", __func__);
> > + if (nto_inferior.ctl_fd != -1)
> > + {
> > + devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
> > + 0);
> > + if (status.flags & _DEBUG_FLAG_ISTOP)
> > + ret = 1;
> > + }
> > + ret = 0;


Pedro: ^^^^^^^ this seems bogus...

Another leftover.. Removed.

> > +  TRACE ("%s\n", ret ? "yes" : "no");
> > +  return ret;
> > +}
> > +


> > +#ifdef __QNX__
> > +static void
> > +nto_comctrl (int enable)
> > +{
> > + struct sigevent event;
> > +
> > + if (enable)
> > + {
> > + event.sigev_notify = SIGEV_SIGNAL_THREAD;
> > + event.sigev_signo = SIGIO;
> > + event.sigev_code = 0;
> > + event.sigev_value.sival_ptr = NULL;
> > + event.sigev_priority = -1;
> > + ionotify (remote_desc, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT,
> > + &event);
> > + }
> > + else
> > + ionotify (remote_desc, _NOTIFY_ACTION_POLL, _NOTIFY_COND_INPUT, NULL);
> > +}
> > +#endif /* __QNX__ */
> > +
> > +


> > @@ -828,6 +854,9 @@ enable_async_io (void)
> >    signal (SIGIO, input_interrupt);
> >  #endif
> >    async_io_enabled = 1;
> > +#ifdef __QNX__
> > +  nto_comctrl (1);
> > +#endif /* __QNX__ */
> >  }

> >
> >  /* Disable asynchronous I/O.  */
> > @@ -841,6 +870,10 @@ disable_async_io (void)
> >    signal (SIGIO, SIG_IGN);
> >  #endif
> >    async_io_enabled = 0;
> > +#ifdef __QNX__
> > +  nto_comctrl (0);
> > +#endif /* __QNX__ */
> > +
> >  }
> >

Pedro: I don't really know a thing about nto/qnx apis, but,
do you really need this nto_comctrl enable/disable calls?
Can't you just do what nto_comctrl does once unconditionaly,
and then rely on signal (SIGIO, SIG_IGN|input_interrupt),
as you seem to already ?


Unfortunately, I couldn't find a way. Whatever I looked at requires that handle is present. The problem here is that while we are blocked, we will not receive SIGIO signal unless we explicitly setup an event. And we need to do it every time before we go into sigwaitinfo.



I added support for watchpoints.


Thanks,

--
Aleksandar Ristovski
QNX Software Systems

ChangeLog remains the same:


* configure.srv (i[34567]86-*-nto*): New target.
* nto-low.c, nto-low.h, nto-x86-low.c: New files.
* remote-utils.c (include sys/iomgr.h): New include for __QNX__ only.
(nto_comctrl): New function for __QNX__ only.
(enable_async_io, disable_async_io): Call nto_comcntrl for __QNX__ only.
diff -upN -x CVS -x '.*' -x '*.bak' ../../../srcclean/gdb/gdbserver/configure.srv ./configure.srv
--- ../../../srcclean/gdb/gdbserver/configure.srv	2009-05-26 09:56:20.000000000 -0400
+++ ./configure.srv	2009-06-17 10:39:25.000000000 -0400
@@ -74,6 +74,10 @@ case "${target}" in
 			srv_tgtobj="win32-low.o win32-i386-low.o"
 			srv_mingw=yes
 			;;
+  i[34567]86-*-nto*)	srv_regobj=reg-i386.o
+			srv_tgtobj="nto-low.o nto-x86-low.o"
+			extra_srv_libs=-lsocket
+			;;
   ia64-*-linux*)	srv_regobj=reg-ia64.o
 			srv_tgtobj="linux-low.o linux-ia64-low.o"
 			srv_linux_usrregs=yes
diff -upN -x CVS -x '.*' -x '*.bak' ../../../srcclean/gdb/gdbserver/nto-low.c ./nto-low.c
--- ../../../srcclean/gdb/gdbserver/nto-low.c	1969-12-31 19:00:00.000000000 -0500
+++ ./nto-low.c	2009-06-19 15:42:47.000000000 -0400
@@ -0,0 +1,766 @@
+/* QNX Neutrino specific low level interface, for the remote server
+   for GDB.
+   Copyright (C) 2009
+   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 "nto-low.h"
+
+#include <limits.h>
+#include <fcntl.h>
+#include <spawn.h>
+#include <sys/procfs.h>
+#include <sys/auxv.h>
+#include <stdarg.h>
+#include <sys/iomgr.h>
+
+#define _DEBUG_FLAG_TRACE	(_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\
+		_DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY)
+
+
+extern int using_threads;
+int using_threads = 1;
+
+static void
+nto_trace (const char *fmt, ...)
+{
+  va_list arg_list;
+
+  if (debug_threads == 0)
+    return;
+  fprintf (stderr, "nto:");
+  va_start (arg_list, fmt);
+  vfprintf (stderr, fmt, arg_list);
+  va_end (arg_list);
+}
+
+#define TRACE nto_trace
+
+struct nto_inferior
+{
+  char nto_procfs_path[PATH_MAX];
+  int ctl_fd;
+};
+
+static struct nto_inferior nto_inferior;
+
+static void
+do_detach ()
+{
+  if (nto_inferior.ctl_fd != -1)
+    {
+      nto_trace ("Closing fd\n");
+      close (nto_inferior.ctl_fd);
+      nto_inferior.ctl_fd = -1;
+    }
+}
+
+/* Given pid, open procfs path.  Return ptid built from pid,0,tid.  */
+
+static pid_t
+do_attach (pid_t pid)
+{
+  procfs_status status;
+  struct sigevent event;
+
+  if (nto_inferior.ctl_fd != -1)
+    {
+      close (nto_inferior.ctl_fd);
+      nto_inferior.ctl_fd = -1;
+    }
+  snprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", pid);
+  nto_inferior.ctl_fd = open (nto_inferior.nto_procfs_path, O_RDWR);
+  if (nto_inferior.ctl_fd == -1)
+    {
+      TRACE ("Failed to open %s\n", nto_inferior.nto_procfs_path);
+      return -1;
+    }
+  if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0)
+      != EOK)
+    {
+      do_detach ();
+      return -1;
+    }
+  /* Define a sigevent for process stopped notification.  */
+  event.sigev_notify = SIGEV_SIGNAL_THREAD;
+  event.sigev_signo = SIGUSR1;
+  event.sigev_code = 0;
+  event.sigev_value.sival_ptr = NULL;
+  event.sigev_priority = -1;
+  devctl (nto_inferior.ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
+
+  if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
+	      0) == EOK
+      && (status.flags & _DEBUG_FLAG_STOPPED))
+    {
+      ptid_t ptid;
+
+      kill (pid, SIGCONT);
+      ptid = ptid_build (status.pid, status.tid, 0);
+      the_low_target.arch_setup ();
+      add_process (status.pid, 1);
+      TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid,
+	     ptid_get_lwp (ptid));
+      add_thread (ptid, NULL);
+    }
+  else
+    {
+      do_detach ();
+      return -1;
+    }
+
+  return pid;
+}
+
+static void
+nto_set_thread (ptid_t ptid)
+{
+  pid_t tid;
+
+  TRACE ("%s pid: %d tid: %ld\n", __func__, ptid_get_pid (ptid),
+	 ptid_get_lwp (ptid));
+
+  if (nto_inferior.ctl_fd != -1)
+    {
+      tid = ptid_get_lwp (ptid);
+      if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid,
+			 sizeof (tid), 0))
+	TRACE ("ERROR: setting current thread\n");
+    }
+}
+
+static int
+nto_xfer_memory (off_t memaddr, unsigned char *myaddr, int len,
+		 int dowrite)
+{
+  int nbytes = 0;
+
+  if (lseek (nto_inferior.ctl_fd, memaddr, SEEK_SET) == memaddr)
+    {
+      if (dowrite)
+	nbytes = write (nto_inferior.ctl_fd, myaddr, len);
+      else
+	nbytes = read (nto_inferior.ctl_fd, myaddr, len);
+      if (nbytes < 0)
+	nbytes = 0;
+    }
+  if (nbytes == 0)
+    {
+      int e = errno;
+      TRACE ("Error in %s : errno=%d (%s)\n", __func__, e, strerror (e));
+    }
+  return (nbytes);
+}
+
+static int
+nto_breakpoint (CORE_ADDR addr, int type, int size)
+{
+  procfs_break brk;
+
+  brk.type = type;
+  brk.addr = addr;
+  brk.size = size;
+  errno = devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
+  if (errno != EOK)
+    return 1;
+  return 0;
+}
+
+/* Read AUXV from initial_stack.  */
+static int
+nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
+				  unsigned char *myaddr,
+				  unsigned int len)
+{
+  int data_ofs = 0;
+  int anint;
+  unsigned int len_read = 0;
+
+  /* Skip over argc, argv and envp... (see comment in ldd.c)  */
+  if (nto_xfer_memory (initial_stack, (unsigned char *)&anint,
+		       sizeof (anint), 0) != sizeof (anint))
+    return 0;
+
+  /* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */
+  data_ofs += (anint + 2) * sizeof (void *); /* + 2 comes from argc itself and
+						NULL terminating pointer in
+						argv.  */
+
+  /* Now loop over env table:  */
+  while (nto_xfer_memory (initial_stack + data_ofs,
+			  (unsigned char *)&anint, sizeof (anint), 0)
+	 == sizeof (anint))
+    {
+      data_ofs += sizeof (anint);
+      if (anint == 0)
+	break;
+    }
+  initial_stack += data_ofs;
+
+  memset (myaddr, 0, len);
+  while (len_read <= len - sizeof (auxv_t))
+    {
+      auxv_t *auxv = (auxv_t *)myaddr;
+
+      /* Search backwards until we have read AT_PHDR (num. 3),
+	 AT_PHENT (num 4), AT_PHNUM (num 5)  */
+      if (nto_xfer_memory (initial_stack, (unsigned char *)auxv,
+			   sizeof (auxv_t), 0) == sizeof (auxv_t))
+	{
+	  if (auxv->a_type != AT_NULL)
+	    {
+	      auxv++;
+	      len_read += sizeof (auxv_t);
+	    }
+	  if (auxv->a_type == AT_PHNUM) /* That's all we need.  */
+	    break;
+	  initial_stack += sizeof (auxv_t);
+	}
+      else
+	break;
+    }
+  TRACE ("auxv: len_read: %d\n", len_read);
+  return len_read;
+}
+
+/* Start inferior specified by PROGRAM passing arguments ALLARGS.  */
+
+static int
+nto_create_inferior (char *program, char **allargs)
+{
+  struct inheritance inherit;
+  pid_t pid;
+  sigset_t set;
+
+  TRACE ("%s %s\n", __func__, program);
+  /* Clear any pending SIGUSR1's but keep the behavior the same.  */
+  signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
+
+  sigemptyset (&set);
+  sigaddset (&set, SIGUSR1);
+  sigprocmask (SIG_UNBLOCK, &set, NULL);
+
+  memset (&inherit, 0, sizeof (inherit));
+  inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
+  inherit.pgroup = SPAWN_NEWPGROUP;
+  pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
+  sigprocmask (SIG_BLOCK, &set, NULL);
+
+  if (pid == -1)
+    return -1;
+
+  if (do_attach (pid) != pid)
+    return -1;
+
+  return pid;
+}
+
+static int
+nto_attach (unsigned long pid)
+{
+  TRACE ("%s %ld\n", __func__, pid);
+  if (do_attach (pid) != pid)
+    error ("Unable to attach to %ld\n", pid);
+  return 0;
+}
+
+static int
+nto_kill (int pid)
+{
+  TRACE ("%s %d\n", __func__, pid);
+  kill (pid, SIGKILL);
+  do_detach ();
+  return 0;
+}
+
+static int
+nto_detach (int pid)
+{
+  TRACE ("%s %d\n", __func__, pid);
+  do_detach ();
+  return 0;
+}
+
+static int
+nto_thread_alive (ptid_t ptid)
+{
+  pid_t tid;
+
+  tid = ptid_get_lwp (ptid);
+  TRACE ("%s %d\n", __func__, tid);
+  if (devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0)
+      == EOK)
+    return 1;
+  return 0;
+}
+
+static void
+nto_resume (struct thread_resume *resume_info, size_t n)
+{
+  /* We can only work in all-stop mode.  */
+  procfs_status status;
+  procfs_run run;
+  int err;
+
+  TRACE ("%s\n", __func__);
+  /* Workaround for aliasing rules violation. */
+  sigset_t *run_fault = (sigset_t *) (void *) &run.fault;
+  nto_set_thread (resume_info->thread);
+
+  run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
+  if (resume_info->kind == resume_step)
+    run.flags |= _DEBUG_RUN_STEP;
+  run.flags |= _DEBUG_RUN_ARM;
+
+  sigemptyset (run_fault);
+  sigaddset (run_fault, FLTBPT);
+  sigaddset (run_fault, FLTTRACE);
+  sigaddset (run_fault, FLTILL);
+  sigaddset (run_fault, FLTPRIV);
+  sigaddset (run_fault, FLTBOUNDS);
+  sigaddset (run_fault, FLTIOVF);
+  sigaddset (run_fault, FLTIZDIV);
+  sigaddset (run_fault, FLTFPE);
+  sigaddset (run_fault, FLTPAGE);
+
+  sigemptyset (&run.trace);
+  if (resume_info->sig)
+    {
+      int signal_to_pass;
+
+      devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
+	      0);
+      signal_to_pass = resume_info->sig;
+      if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
+	{
+	  if (signal_to_pass != status.info.si_signo)
+	    {
+	      kill (status.pid, signal_to_pass);
+	      run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
+	    }
+	  else		/* Let it kill the program without telling us.  */
+	    sigdelset (&run.trace, signal_to_pass);
+	}
+    }
+  else
+    run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
+
+  regcache_invalidate ();
+
+  err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
+  if (err != EOK)
+    TRACE ("Error: %d \"%s\"\n", err);
+}
+
+static ptid_t
+nto_wait (ptid_t ptid,
+	  struct target_waitstatus *ourstatus, int target_options)
+{
+  sigset_t set;
+  siginfo_t info;
+  procfs_status status;
+  static int exit_signo = 0; /* For tracking exit status.  */
+
+  TRACE ("%s\n", __func__);
+
+  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+
+
+  sigemptyset (&set);
+  sigaddset (&set, SIGUSR1);
+
+  devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
+  while (!(status.flags & _DEBUG_FLAG_ISTOP))
+    {
+      sigwaitinfo (&set, &info);
+      devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
+	      0);
+    }
+
+  if (status.flags & _DEBUG_FLAG_SSTEP)
+    {
+      TRACE ("SSTEP\n");
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+    }
+  /* Was it a breakpoint?  */
+  else if (status.flags & _DEBUG_FLAG_TRACE)
+    {
+      TRACE ("STOPPED\n");
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+    }
+  else if (status.flags & _DEBUG_FLAG_ISTOP)
+    {
+      TRACE ("ISTOP\n");
+      switch (status.why)
+	{
+	case _DEBUG_WHY_SIGNALLED:
+	  TRACE ("  SIGNALLED\n");
+	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+	  ourstatus->value.sig =
+	    target_signal_from_host (status.info.si_signo);
+	  exit_signo = 0;
+	  break;
+	case _DEBUG_WHY_FAULTED:
+	  TRACE ("  FAULTED\n");
+	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+	  if (status.info.si_signo == SIGTRAP)
+	    {
+	      ourstatus->value.sig = 0;
+	      exit_signo = 0;
+	    }
+	  else
+	    {
+	      ourstatus->value.sig =
+		target_signal_from_host (status.info.si_signo);
+	      exit_signo = ourstatus->value.sig;
+	    }
+	  break;
+
+	case _DEBUG_WHY_TERMINATED:
+	  {
+	    int waitval = 0;
+
+	    TRACE ("  TERMINATED\n");
+	    waitpid (ptid_get_pid (ptid), &waitval, WNOHANG);
+	    if (exit_signo)
+	      {
+		/* Abnormal death.  */
+		ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+		ourstatus->value.sig = exit_signo;
+	      }
+	    else
+	      {
+		/* Normal death.  */
+		ourstatus->kind = TARGET_WAITKIND_EXITED;
+		ourstatus->value.integer = WEXITSTATUS (waitval);
+	      }
+	    exit_signo = 0;
+	    break;
+	  }
+
+	case _DEBUG_WHY_REQUESTED:
+	  TRACE ("REQUESTED\n");
+	  /* We are assuming a requested stop is due to a SIGINT.  */
+	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+	  ourstatus->value.sig = TARGET_SIGNAL_INT;
+	  exit_signo = 0;
+	  break;
+	}
+    }
+
+  return ptid_build (status.pid, status.tid, 0);
+}
+
+static void
+nto_fetch_registers (int regno)
+{
+  int regsize;
+  procfs_greg greg;
+
+  TRACE ("%s (regno=%d)\n", __func__, regno);
+  if (regno >= the_low_target.num_regs)
+    return;
+
+  if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg),
+	      &regsize) == EOK)
+    {
+      if (regno == -1) /* All registers. */
+	{
+	  for (regno = 0; regno != the_low_target.num_regs; ++regno)
+	    {
+	      const unsigned int registeroffset
+		= the_low_target.register_offset (regno);
+	      supply_register (regno, ((char *)&greg) + registeroffset);
+	    }
+	}
+      else
+	{
+	  const unsigned int registeroffset
+	    = the_low_target.register_offset (regno);
+
+	  if (registeroffset == -1)
+	    return;
+	  supply_register (regno, ((char *)&greg) + registeroffset);
+	}
+    }
+  else
+    TRACE ("ERROR reading registers from inferior.\n");
+}
+
+static void
+nto_store_registers (int regno)
+{
+  procfs_greg greg;
+  int err;
+
+  TRACE ("%s (regno:%d)\n", __func__, regno);
+  memset (&greg, 0, sizeof (greg));
+  for  (regno = 0; regno != the_low_target.num_regs; ++regno)
+    {
+      const unsigned int regoffset
+	= the_low_target.register_offset (regno);
+      collect_register (regno, ((char *)&greg) + regoffset);
+    }
+  err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg),
+		0);
+  if (err != EOK)
+    TRACE ("Error: setting registers.\n");
+}
+
+static int
+nto_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+  TRACE ("%s\n", __func__);
+
+  if (nto_xfer_memory (memaddr, myaddr, len, 0) != len)
+    {
+      TRACE ("Failed to read memory\n");
+      return -1;
+    }
+
+  return 0;
+}
+
+static int
+nto_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+  int len_written;
+
+  TRACE ("%s memaddr: 0x%08llx len: %d\n", __func__, memaddr, len);
+  if ((len_written = nto_xfer_memory (memaddr, (unsigned char *)myaddr, len,
+				      1))
+      != len)
+    {
+      TRACE ("Wanted to write: %d but written: %d\n", len, len_written);
+      return -1;
+    }
+
+  return 0;
+}
+
+static void
+nto_request_interrupt (void)
+{
+  TRACE (__func__);
+  devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0);
+}
+
+static int
+nto_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
+{
+  int err;
+  CORE_ADDR initial_stack;
+  procfs_info procinfo;
+
+  TRACE ("%s\n", __func__);
+  if (offset > 0)
+    return 0;
+
+  err = devctl (nto_inferior.ctl_fd, DCMD_PROC_INFO, &procinfo,
+		sizeof procinfo, 0);
+  if (err != EOK)
+    return -1;
+
+  /* Similar as in the case of a core file, we read auxv from
+     initial_stack.  */
+  initial_stack = procinfo.initial_stack;
+
+  /* procfs is always 'self-hosted', no byte-order manipulation. */
+  return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len);
+}
+
+static int
+nto_insert_breakpoint (char type, CORE_ADDR addr)
+{
+  TRACE ("%s\n", __func__);
+  switch (type)
+    {
+    case '0': /* software-breakpoint */
+      return nto_breakpoint (addr, _DEBUG_BREAK_EXEC, 0);
+    case '1': /* hardware-breakpoint */
+      return nto_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0);
+    }
+  return 1; /* Not supported.  */
+}
+
+static int
+nto_remove_breakpoint (char type, CORE_ADDR addr)
+{
+  TRACE ("%s\n", __func__);
+  switch (type)
+    {
+    case '0': /* software-breakpoint */
+      return nto_breakpoint (addr, _DEBUG_BREAK_EXEC, -1);
+    case '1': /* hardware-breakpoint */
+      return nto_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1);
+    }
+  /* Not supported.  */
+  return 1;
+}
+
+static int
+nto_insert_watchpoint (char type, CORE_ADDR addr, int len)
+{
+  int wtype = _DEBUG_BREAK_HW; /* Always request HW.  */
+
+  TRACE ("%s type:%c\n", __func__, type);
+  switch (type)
+    {
+    case '2':  /* write watchpoint */
+      wtype |= _DEBUG_BREAK_RW;
+      break;
+    case '3':  /* read watchpoint */
+      wtype |= _DEBUG_BREAK_RD
+      break;
+    case '4':  /* access watchpoint */
+      wtype |= _DEBUG_BREAK_RW;
+      break;
+    default:
+      return 1; /* Not supported.  */
+    }
+  return nto_breakpoint (addr, wtype, 0);
+}
+
+static int
+nto_remove_watchpoint (char type, CORE_ADDR addr, int len)
+{
+  int wtype = _DEBUG_BREAK_HW; /* Always request HW.  */
+
+  TRACE ("%s type:%c\n", __func__, type);
+  switch (type)
+    {
+    case '2':  /* write watchpoint */
+      wtype |= _DEBUG_BREAK_RW;
+      break;
+    case '3':  /* read watchpoint */
+      wtype |= _DEBUG_BREAK_RD;
+      break;
+    case '4':  /* access watchpoint */
+      wtype |= _DEBUG_BREAK_RW;
+      break;
+    default:
+      return 1; /* Not supported.  */
+    }
+  return nto_breakpoint (addr, wtype, -1);
+}
+
+static int
+nto_stopped_by_watchpoint (void)
+{
+  procfs_status status;
+  int ret = 0;
+  const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR
+			| _DEBUG_FLAG_TRACE_MODIFY;
+
+  TRACE ("%s...", __func__);
+  if (nto_inferior.ctl_fd != -1)
+    {
+      int err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
+		        sizeof (status), 0);
+      if (err == EOK && (status.flags & watchmask))
+	ret = 1;
+    }
+  TRACE ("%s\n", ret ? "yes" : "no");
+  return ret;
+}
+
+static CORE_ADDR
+nto_stopped_data_address (void)
+{
+  procfs_status status;
+  CORE_ADDR ret = (CORE_ADDR)0;
+
+  TRACE ("%s...", __func__);
+  if (nto_inferior.ctl_fd != -1)
+    {
+      int err;
+      err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
+		    sizeof (status), 0);
+      if (err == EOK)
+	ret = status.ip;
+    }
+  return ret;
+}
+
+
+static int
+nto_supports_non_stop (void)
+{
+  TRACE ("%s\n", __func__);
+  return 0;
+}
+
+
+
+static struct target_ops nto_target_ops = {
+  nto_create_inferior,
+  nto_attach,
+  nto_kill,
+  nto_detach,
+  NULL, /* nto_join */
+  nto_thread_alive,
+  nto_resume,
+  nto_wait,
+  nto_fetch_registers,
+  nto_store_registers,
+  nto_read_memory,
+  nto_write_memory,
+  NULL, /* nto_look_up_symbols */
+  nto_request_interrupt,
+  nto_read_auxv,
+  nto_insert_breakpoint,
+  nto_remove_breakpoint,
+  nto_insert_watchpoint,
+  nto_remove_watchpoint,
+  nto_stopped_by_watchpoint,
+  nto_stopped_data_address,
+  NULL, /* nto_read_offsets */
+  NULL, /* thread_db_set_tls_address */
+  NULL,
+  hostio_last_error_from_errno,
+  NULL, /* nto_qxfer_osdata */
+  NULL, /* xfer_siginfo */
+  nto_supports_non_stop,
+  NULL, /* async */
+  NULL  /* start_non_stop */
+};
+
+
+/* Global function called by server.c.  Initializes QNX Neutrino
+   gdbserver.  */
+
+void
+initialize_low (void)
+{
+  sigset_t set;
+
+  TRACE ("%s\n", __func__);
+  set_target_ops (&nto_target_ops);
+  set_breakpoint_data (the_low_target.breakpoint,
+		       the_low_target.breakpoint_len);
+
+  /* We use SIGUSR1 to gain control after we block waiting for a process.
+     We use sigwaitevent to wait.  */
+  sigemptyset (&set);
+  sigaddset (&set, SIGUSR1);
+  sigprocmask (SIG_BLOCK, &set, NULL);
+}
+
diff -upN -x CVS -x '.*' -x '*.bak' ../../../srcclean/gdb/gdbserver/nto-low.h ./nto-low.h
--- ../../../srcclean/gdb/gdbserver/nto-low.h	1969-12-31 19:00:00.000000000 -0500
+++ ./nto-low.h	2009-06-17 10:35:04.000000000 -0400
@@ -0,0 +1,50 @@
+/* Internal interfaces for the QNX Neutrino specific target code for gdbserver.
+   Copyright (C) 2009
+   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 NTO_LOW_H
+#define NTO_LOW_H
+
+enum regset_type
+{
+  NTO_REG_GENERAL,
+  NTO_REG_FLOAT,
+  NTO_REG_SYSTEM,
+  NTO_REG_ALT,
+  NTO_REG_END
+};
+
+struct nto_target_ops
+{
+  /* Architecture specific setup.  */
+  void (*arch_setup) (void);
+
+  int num_regs;
+  int (*register_offset)(int gdbregno);
+  const unsigned char *breakpoint;
+  int breakpoint_len;
+};
+
+extern struct nto_target_ops the_low_target;
+
+
+/* Activated by env. variable GDBSERVER_DEBUG.  */
+extern int nto_debug;
+
+#endif
+
diff -upN -x CVS -x '.*' -x '*.bak' ../../../srcclean/gdb/gdbserver/nto-x86-low.c ./nto-x86-low.c
--- ../../../srcclean/gdb/gdbserver/nto-x86-low.c	1969-12-31 19:00:00.000000000 -0500
+++ ./nto-x86-low.c	2009-06-17 10:35:04.000000000 -0400
@@ -0,0 +1,108 @@
+/* QNX Neutrino specific low level interface, for the remote server
+   for GDB.
+   Copyright (C) 2009
+   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 "nto-low.h"
+#include "regdef.h"
+#include "regcache.h"
+
+#include <x86/context.h>
+
+
+/* Definition auto generated from reg-i386.dep.  */
+extern void init_registers_i386 ();
+extern struct reg *regs_i386;
+
+const unsigned char x86_breakpoint[] = { 0xCC };
+#define x86_breakpoint_len 1
+
+/* Returns offset in appropriate Neutrino's context structure.
+   Defined in x86/context.h.
+   GDBREGNO is index into regs_i386 array.  It is autogenerated and
+   hopefully doesn't change.  */
+static int
+nto_x86_register_offset (int gdbregno)
+{
+  if (gdbregno >= 0 && gdbregno < 16)
+    {
+      X86_CPU_REGISTERS *dummy = (void*)0;
+      /* GPRs  */
+      switch (gdbregno)
+	{
+	case 0: 
+	  return (int)&(dummy->eax);
+	case 1:
+	  return (int)&(dummy->ecx);
+	case 2:
+	  return (int)&(dummy->edx);
+	case 3:
+	  return (int)&(dummy->ebx);
+	case 4:
+	  return (int)&(dummy->esp);
+	case 5:
+	  return (int)&(dummy->ebp);
+	case 6:
+	  return (int)&(dummy->esi);
+	case 7:
+	  return (int)&(dummy->edi);
+	case 8:
+	  return (int)&(dummy->eip);
+	case 9:
+	  return (int)&(dummy->efl);
+	case 10:
+	  return (int)&(dummy->cs);
+	case 11:
+	  return (int)&(dummy->ss);
+#ifdef __SEGMENTS__
+	case 12:
+	  return (int)&(dummy->ds);
+	case 13:
+	  return (int)&(dummy->es);
+	case 14:
+	  return (int)&(dummy->fs);
+	case 15:
+	  return (int)&(dummy->gs);
+#endif
+	default:
+	  return -1;
+	}
+    }
+  //TODO: FPU, XMM registers
+  return -1;
+}
+
+static void
+nto_x86_arch_setup (void)
+{
+  init_registers_i386 ();
+  the_low_target.num_regs = 16;
+}
+
+struct nto_target_ops the_low_target =
+{
+  nto_x86_arch_setup,
+  0, /* num_regs */
+  nto_x86_register_offset,
+  x86_breakpoint,
+  x86_breakpoint_len
+};
+
+
+
diff -upN -x CVS -x '.*' -x '*.bak' ../../../srcclean/gdb/gdbserver/remote-utils.c ./remote-utils.c
--- ../../../srcclean/gdb/gdbserver/remote-utils.c	2009-05-26 09:56:20.000000000 -0400
+++ ./remote-utils.c	2009-06-17 10:35:04.000000000 -0400
@@ -66,6 +66,10 @@
 #include <winsock.h>
 #endif
 
+#if __QNX__
+#include <sys/iomgr.h>
+#endif /* __QNX__ */
+
 #ifndef HAVE_SOCKLEN_T
 typedef int socklen_t;
 #endif
@@ -814,6 +818,28 @@ unblock_async_io (void)
 #endif
 }
 
+#ifdef __QNX__
+static void
+nto_comctrl (int enable)
+{
+  struct sigevent event;
+
+  if (enable)
+    {
+      event.sigev_notify = SIGEV_SIGNAL_THREAD;
+      event.sigev_signo = SIGIO;
+      event.sigev_code = 0;
+      event.sigev_value.sival_ptr = NULL;
+      event.sigev_priority = -1;
+      ionotify (remote_desc, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT,
+		&event);
+    }
+  else
+    ionotify (remote_desc, _NOTIFY_ACTION_POLL, _NOTIFY_COND_INPUT, NULL);
+}
+#endif /* __QNX__ */
+
+
 /* Current state of asynchronous I/O.  */
 static int async_io_enabled;
 
@@ -828,6 +854,9 @@ enable_async_io (void)
   signal (SIGIO, input_interrupt);
 #endif
   async_io_enabled = 1;
+#ifdef __QNX__
+  nto_comctrl (1);
+#endif /* __QNX__ */
 }
 
 /* Disable asynchronous I/O.  */
@@ -841,6 +870,10 @@ disable_async_io (void)
   signal (SIGIO, SIG_IGN);
 #endif
   async_io_enabled = 0;
+#ifdef __QNX__
+  nto_comctrl (0);
+#endif /* __QNX__ */
+
 }
 
 void

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