From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14550 invoked by alias); 27 Jul 2010 16:13:45 -0000 Received: (qmail 14514 invoked by uid 22791); 27 Jul 2010 16:13:39 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,TW_CP,TW_EG,TW_NX,TW_QX,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 27 Jul 2010 16:13:27 +0000 Received: (qmail 15672 invoked from network); 27 Jul 2010 16:13:25 -0000 Received: from unknown (HELO orlando.localnet) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 27 Jul 2010 16:13:25 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Re: [RFA 3/3] gdbserver support for powerpc-lynxos (4.x) Date: Tue, 27 Jul 2010 16:13:00 -0000 User-Agent: KMail/1.13.2 (Linux/2.6.32-24-generic; KDE/4.4.2; x86_64; ; ) Cc: Joel Brobecker References: <1277315177-17869-1-git-send-email-brobecker@adacore.com> <1277315177-17869-4-git-send-email-brobecker@adacore.com> In-Reply-To: <1277315177-17869-4-git-send-email-brobecker@adacore.com> MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-15" Content-Transfer-Encoding: 7bit Message-Id: <201007271713.22677.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-07/txt/msg00429.txt.bz2 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 . */ > + > +#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 . */ > + > +#include "server.h" > +#include "target.h" > +#include "lynx-low.h" > +#include "lynx-debug.h" > +#include "lynx-ptrace.h" > + > +#include > +#include > +#include /* Provides PIDGET, TIDGET, BUILDPID, etc. */ > +#include > +#include > +#include > +#include > +#include > + > +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 . */ > + > +#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 . */ > + > +#include "server.h" > +#include "lynx-low.h" > + > +#include > +#include > +#include > +#include > + > +/* 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 . */ > + > +#include "server.h" > +#include "lynx-ptrace.h" > + > +#include > +#include > +#include /* 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 ""; > +} > + > +/* 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 . */ > + > +#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