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: [RFA 3/3] gdbserver support for powerpc-lynxos (4.x)


Hi Joel.  Sorry for how long it took to get to this...

On Wednesday 23 June 2010 18:46:17, Joel Brobecker wrote:

> 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...

Are all lynxos archs going to need that?  Sound like you could add to this:

gdbserver/configure.ac:

if test "${srv_mingwce}" = "yes"; then
  LIBS="$LIBS -lws2"
elif test "${srv_mingw}" = "yes"; then
  LIBS="$LIBS -lws2_32"
elif test "${srv_qnx}" = "yes"; then
  LIBS="$LIBS -lsocket"
fi

> 
> 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.

This looks generaly okay.  It may need a couple of tweaks for
target_ops vector additions.  Quite honesly, the split out of
lynx-debug.c and lynx-ptrace.c looks overkill to me.  I'd prefer
getting rid of those (and their headers), and just put their
contents on top of lynx-low.c, and make the functions static.

I made a few comments inline below.

> 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);
> +}

Right, the remote serial protocol has no concept (as of yet) of lwp vs
tid, so we're using the lwp field for storing thread ids throughout
all ports currently.

> +
> +/* 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;

struct process_info *process.  Though, this variable appears to
be write only.


> +  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);

Please remove the unnecessary cast.

> +  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;
> +}

Make sure you don't need to handle EINTR here.  You may want to take
a look at linux-low.c:my_waitpid and see whether you could do something
of the sorts, to be able to get rid of the usleep.  

> +
> +/* 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);

This should go through target_signal_from_host.

> +      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 ();

These lynx_clear_inferiors calls should now move the the target_ops->mourn
callback.

> +      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)

`enum target_signal' vs host signal mixup continued.

> +    {
> +      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]