From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31806 invoked by alias); 23 Jun 2010 17:46:44 -0000 Received: (qmail 31152 invoked by uid 22791); 23 Jun 2010 17:46:35 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,TW_CP,TW_EG,TW_NX,TW_QX,TW_VF,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 23 Jun 2010 17:46:26 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 814202BACA8; Wed, 23 Jun 2010 13:46:24 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id t0NMIhfZ5YHT; Wed, 23 Jun 2010 13:46:24 -0400 (EDT) Received: from kwai.gnat.com (kwai.gnat.com [205.232.38.4]) by rock.gnat.com (Postfix) with ESMTP id 5143E2BACAC; Wed, 23 Jun 2010 13:46:24 -0400 (EDT) Received: by kwai.gnat.com (Postfix, from userid 4233) id 4C73492953; Wed, 23 Jun 2010 13:46:24 -0400 (EDT) From: Joel Brobecker To: gdb-patches@sourceware.org Cc: Joel Brobecker Subject: [RFA 3/3] gdbserver support for powerpc-lynxos (4.x) Date: Wed, 23 Jun 2010 17:46:00 -0000 Message-Id: <1277315177-17869-4-git-send-email-brobecker@adacore.com> In-Reply-To: <1277315177-17869-1-git-send-email-brobecker@adacore.com> References: <1277315177-17869-1-git-send-email-brobecker@adacore.com> 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-06/txt/msg00510.txt.bz2 This patch adds support for powerpc-lynxos. Note that I'm adding a new varialble "srv_extra_libs" in configure.srv. I need this because I need to link against -linet. Perhaps the right way of doing things might have been to use a configure check... gdbserver/ChangeLog: * gdbserver/lynx-debug.c, gdbserver/lynx-debug.h, gdbserver/lynx-low.c, gdbserver/lynx-low.h, gdbserver/lynx-ppc-low.c, gdbserver/lynx-ptrace.c, gdbserver/lynx-ptrace.h: New files. * Makefile.in (lynx_debug_h, lynx_ptrace_h, lynx_low_h): New variables. (lynx-debug.o, lynx-low.o, lynx-ppc-low.o, lynx-ptrace.o): New rules. * configure.ac: Add support for srv_extra_libs variable. * configure.srv: Add handling of powerpc-*-lynxos* targets. * configure: regenerate. -- Joel --- gdb/gdbserver/Makefile.in | 9 + gdb/gdbserver/configure | 4 + gdb/gdbserver/configure.ac | 4 + gdb/gdbserver/configure.srv | 4 + gdb/gdbserver/lynx-debug.c | 35 +++ gdb/gdbserver/lynx-debug.h | 26 ++ gdb/gdbserver/lynx-low.c | 531 ++++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/lynx-low.h | 57 +++++ gdb/gdbserver/lynx-ppc-low.c | 186 +++++++++++++++ gdb/gdbserver/lynx-ptrace.c | 262 +++++++++++++++++++++ gdb/gdbserver/lynx-ptrace.h | 26 ++ 11 files changed, 1144 insertions(+), 0 deletions(-) create mode 100644 gdb/gdbserver/lynx-debug.c create mode 100644 gdb/gdbserver/lynx-debug.h create mode 100644 gdb/gdbserver/lynx-low.c create mode 100644 gdb/gdbserver/lynx-low.h create mode 100644 gdb/gdbserver/lynx-ppc-low.c create mode 100644 gdb/gdbserver/lynx-ptrace.c create mode 100644 gdb/gdbserver/lynx-ptrace.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index c2e3ea2..7f6649d 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -293,6 +293,10 @@ server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ linux_low_h = $(srcdir)/linux-low.h +lynx_debug_h = $(srcdir)/lynx-debug.h $(srcdir)/server.h +lynx_ptrace_h = $(srcdir)/lynx-ptrace.h $(srcdir)/server.h +lynx_low_h = $(srcdir)/lynx-low.h $(srcdir)/server.h + nto_low_h = $(srcdir)/nto-low.h # Note, we only build the IPA if -fvisibility=hidden is supported in @@ -369,6 +373,11 @@ linux-x86-low.o: linux-x86-low.c $(linux_low_h) $(server_h) \ $(gdb_proc_service_h) $(i386_low_h) linux-xtensa-low.o: linux-xtensa-low.c xtensa-xtregs.c $(linux_low_h) $(server_h) +lynx-debug.o: lynx-debug.c $(lynx_debug_h) +lynx-low.o: lynx-low.c $(server_h) $(target_h) $(lynx_low_h) $(lynx_debug_h) \ + $(lynx_ptrace_h) +lynx-ppc-low.o: lynx-ppc-low.c $(server_h) $(lynx_low_h) +lynx-ptrace.o: lynx-ptrace.c $(server_h) $(lynx_ptrace_h) nto-low.o: nto-low.c $(server_h) $(nto_low_h) nto-x86-low.o: nto-x86-low.c $(server_h) $(nto_low_h) $(regdef_h) $(regcache_h) diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure index 2708f23..0521214 100755 --- a/gdb/gdbserver/configure +++ b/gdb/gdbserver/configure @@ -4563,6 +4563,10 @@ if test "$ipa_obj" != "" \ extra_libraries="libinproctrace.so" fi +if test "$srv_extra_libs" != ""; then + GDBSERVER_LIBS="$GDBSERVER_LIBS $srv_extra_libs" +fi + diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index 40d30c4..6d810fa 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -275,6 +275,10 @@ if test "$ipa_obj" != "" \ extra_libraries="libinproctrace.so" fi +if test "$srv_extra_libs" != ""; then + GDBSERVER_LIBS="$GDBSERVER_LIBS $srv_extra_libs" +fi + AC_SUBST(GDBSERVER_DEPFILES) AC_SUBST(GDBSERVER_LIBS) AC_SUBST(USE_THREAD_DB) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 99187a5..e1bb84a 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -200,6 +200,10 @@ case "${target}" in srv_linux_regsets=yes srv_linux_thread_db=yes ;; + powerpc-*-lynxos*) srv_regobj="powerpc-32.o" + srv_tgtobj="lynx-low.o lynx-ppc-low.o lynx-debug.o lynx-ptrace.o" + srv_extra_libs="-lnetinet" + ;; s390*-*-linux*) srv_regobj="s390-linux32.o" srv_regobj="${srv_regobj} s390-linux64.o" srv_regobj="${srv_regobj} s390x-linux64.o" diff --git a/gdb/gdbserver/lynx-debug.c b/gdb/gdbserver/lynx-debug.c new file mode 100644 index 0000000..aaca754 --- /dev/null +++ b/gdb/gdbserver/lynx-debug.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "lynx-debug.h" + +void +lynx_debug (char *string, ...) +{ + va_list args; + + if (!debug_threads) + return; + + va_start (args, string); + fprintf (stdout, "DEBUG(lynx): "); + vfprintf (stdout, string, args); + fprintf (stdout, "\n"); + va_end (args); +} + + diff --git a/gdb/gdbserver/lynx-debug.h b/gdb/gdbserver/lynx-debug.h new file mode 100644 index 0000000..396df2b --- /dev/null +++ b/gdb/gdbserver/lynx-debug.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#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); +} + +/* Return the process ID of the given PTID. + + This function has little reason to exist, it's just a wrapper around + ptid_get_pid. But since we have a getter function for the lynxos + ptid, it feels cleaner to have a getter for the pid as well. */ + +int +lynx_ptid_get_pid (ptid_t ptid) +{ + return ptid_get_pid (ptid); +} + +/* Return the LynxOS tid of the given PTID. */ + +long +lynx_ptid_get_tid (ptid_t ptid) +{ + /* See lynx_ptid_build: The LynxOS tid is stored inside the lwp field + of the ptid. */ + return ptid_get_lwp (ptid); +} + +/* Implement the create_inferior method of the target_ops vector. */ + +static int +lynx_create_inferior (char *program, char **allargs) +{ + void *new_process; + int pid; + + lynx_debug ("lynx_create_inferior ()"); + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + int pgrp; + + /* Switch child to its own process group so that signals won't + directly affect gdbserver. */ + pgrp = getpid(); + setpgid (0, pgrp); + ioctl (0, TIOCSPGRP, &pgrp); + lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0); + execv (program, allargs); + fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); + fflush (stderr); + _exit (0177); + } + + new_process = add_process (pid, 0); + /* Do not add the process thread just yet, as we do not know its tid. + We will add it later, during the wait for the STOP event corresponding + to the lynx_ptrace (PTRACE_TRACEME) call above. */ + return pid; +} + +/* Implement the attach target_ops method. */ + +static int +lynx_attach (unsigned long pid) +{ + struct process_info *new_process; + ptid_t ptid = lynx_ptid_build (pid, 0); + + if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0) + error ("Cannot attach to process %lu: %s (%d)\n", pid, + strerror (errno), errno); + + new_process = (struct process_info *) add_process (pid, 1); + add_thread (ptid, NULL); + + return 0; +} + +/* Implement the resume target_ops method. */ + +static void +lynx_resume (struct thread_resume *resume_info, size_t n) +{ + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + /* FIXME: Assume for now that n == 1. */ + const int request = (resume_info[0].kind == resume_step + ? PTRACE_SINGLESTEP : PTRACE_CONT); + const int signal = resume_info[0].sig; + int ret; + + regcache_invalidate (); + ret = lynx_ptrace (request, inferior_ptid, 1, signal, 0); +} + +/* Resume the execution of the given PTID. */ + +static void +lynx_continue (ptid_t ptid) +{ + struct thread_resume resume_info; + + resume_info.thread = ptid; + resume_info.kind = resume_continue; + resume_info.sig = 0; + + lynx_resume (&resume_info, 1); +} + +/* Remove all inferiors and associated threads. */ + +static void +lynx_clear_inferiors (void) +{ + /* We do not use private data, so nothing much to do except calling + clear_inferiors. */ + clear_inferiors (); +} + +/* A wrapper around waitpid that handles the various idiosyncrasies + of LynxOS' waitpid. */ + +static int +lynx_waitpid (int pid, int *stat_loc) +{ + int ret = 0; + + while (1) + { + ret = waitpid (pid, stat_loc, WNOHANG); + if (ret < 0) + { + /* An ECHILD error is not indicative of a real problem. + It happens for instance while waiting for the inferior + to stop after attaching to it. */ + if (errno != ECHILD) + perror_with_name ("waitpid (WNOHANG)"); + } + if (ret > 0) + break; + /* No event with WNOHANG. See if there is one with WUNTRACED. */ + ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED); + if (ret < 0) + { + /* An ECHILD error is not indicative of a real problem. + It happens for instance while waiting for the inferior + to stop after attaching to it. */ + if (errno != ECHILD) + perror_with_name ("waitpid (WNOHANG|WUNTRACED)"); + } + if (ret > 0) + break; + usleep (1000); + } + return ret; +} + +/* Implement the wait target_ops method. */ + +static ptid_t +lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options) +{ + int pid; + int ret; + int wstat; + ptid_t new_ptid; + + if (ptid_equal (ptid, minus_one_ptid)) + pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior)); + else + pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); + +retry: + + ret = lynx_waitpid (pid, &wstat); + new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid); + + /* If this is a new thread, then add it now. The reason why we do + this here instead of when handling new-thread events is because + we need to add the thread associated to the "main" thread - even + for non-threaded applications where the new-thread events are not + generated. */ + if (!find_thread_ptid (new_ptid)) + add_thread (new_ptid, NULL); + + if (WIFSTOPPED (wstat)) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.integer = WSTOPSIG (wstat); + lynx_debug ("process stopped with signal: %d", + status->value.integer); + } + else if (WIFEXITED (wstat)) + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = WEXITSTATUS (wstat); + lynx_clear_inferiors (); + lynx_debug ("process exited with code: %d", status->value.integer); + } + else if (WIFSIGNALED (wstat)) + { + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.integer = WTERMSIG (wstat); + lynx_clear_inferiors (); + lynx_debug ("process terminated with code: %d", + status->value.integer); + } + else + { + /* Not sure what happened if we get here, or whether we can + in fact get here. But if we do, handle the event the best + we can. */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.integer = 0; + lynx_debug ("unknown event ????"); + } + + /* SIGTRAP events are generated for situations other than single-step/ + breakpoint events (Eg. new-thread events). Handle those other types + of events, and resume the execution if necessary. */ + if (status->kind == TARGET_WAITKIND_STOPPED + && status->value.integer == SIGTRAP) + { + const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0); + + lynx_debug ("(realsig = %d)", realsig); + switch (realsig) + { + case SIGNEWTHREAD: + /* We just added the new thread above. No need to do anything + further. Just resume the execution again. */ + lynx_continue (ptid); + goto retry; + + case SIGTHREADEXIT: + remove_thread (find_thread_ptid (new_ptid)); + lynx_continue (ptid); + goto retry; + } + } + + return new_ptid; +} + +/* A wrapper around lynx_wait_1 that also prints debug traces when + such debug traces have been activated. */ + +static ptid_t +lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options) +{ + ptid_t new_ptid; + + lynx_debug ("lynx_wait (pid = %d, tid = %ld)", + lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); + new_ptid = lynx_wait_1 (ptid, status, options); + lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)", + lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid), + status->kind); + return new_ptid; +} + +/* Implement the kill target_ops method. */ + +static int +lynx_kill (int pid) +{ + ptid_t ptid = lynx_ptid_build (pid, 0); + struct target_waitstatus status; + + lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0); + lynx_wait (ptid, &status, 0); + return 0; +} + +/* Implement the detach target_ops method. */ + +static int +lynx_detach (int pid) +{ + ptid_t ptid = lynx_ptid_build (pid, 0); + + lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0); + return 0; +} + +/* Implement the join target_ops method. */ + +static void +lynx_join (int pid) +{ + /* The PTRACE_DETACH is sufficient to detach from the process. + So no need to do anything extra. */ +} + +/* Implement the thread_alive target_ops method. */ + +static int +lynx_thread_alive (ptid_t ptid) +{ + /* The list of threads is updated at the end of each wait, so it + should be up to date. No need to re-fetch it. */ + return (find_thread_ptid (ptid) != NULL); +} + +/* Implement the fetch_registers target_ops method. */ + +static void +lynx_fetch_registers (struct regcache *regcache, int regno) +{ + struct lynx_regset_info *regset = lynx_target_regsets; + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + + lynx_debug ("lynx_fetch_registers (regno = %d)", regno); + + while (regset->size >= 0) + { + void *buf; + int res; + + buf = xmalloc (regset->size); + res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); + if (res < 0) + perror ("ptrace"); + regset->store_function (regcache, buf); + free (buf); + regset++; + } +} + +/* Implement the store_registers target_ops method. */ + +static void +lynx_store_registers (struct regcache *regcache, int regno) +{ + struct lynx_regset_info *regset = lynx_target_regsets; + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + + lynx_debug ("lynx_store_registers (regno = %d)", regno); + + while (regset->size >= 0) + { + void *buf; + int res; + + buf = xmalloc (regset->size); + res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); + if (res == 0) + { + /* Then overlay our cached registers on that. */ + regset->fill_function (regcache, buf); + /* Only now do we write the register set. */ + res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf, + 0, 0); + } + if (res < 0) + perror ("ptrace"); + free (buf); + regset++; + } +} + +/* Implement the read_memory target_ops method. */ + +static int +lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + /* On LynxOS, memory reads needs to be performed in chunks the size + of int types, and they should also be aligned accordingly. */ + int buf; + const int xfer_size = sizeof (buf); + CORE_ADDR addr = memaddr & -(CORE_ADDR)xfer_size; + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + + while (addr < memaddr + len) + { + int skip = 0; + int truncate = 0; + + errno = 0; + if (addr < memaddr) + skip = memaddr - addr; + if (addr + xfer_size > memaddr + len) + truncate = addr + xfer_size - memaddr - len; + buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0); + if (errno) + return errno; + memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *)&buf + skip, + xfer_size - skip - truncate); + addr += xfer_size; + } + + return 0; +} + +/* Implement the write_memory target_ops method. */ + +static int +lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +{ + /* On LynxOS, memory writes needs to be performed in chunks the size + of int types, and they should also be aligned accordingly. */ + int buf; + const int xfer_size = sizeof (buf); + CORE_ADDR addr = memaddr & -(CORE_ADDR)xfer_size; + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + + while (addr < memaddr + len) + { + int skip = 0; + int truncate = 0; + + if (addr < memaddr) + skip = memaddr - addr; + if (addr + xfer_size > memaddr + len) + truncate = addr + xfer_size - memaddr - len; + if (skip > 0 || truncate > 0) + /* We need to read the memory at this address in order to preserve + the data that we are not overwriting. */ + lynx_read_memory (addr, (unsigned char *) &buf, xfer_size); + if (errno) + return errno; + memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip, + xfer_size - skip - truncate); + errno = 0; + lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0); + if (errno) + return errno; + addr += xfer_size; + } + + return 0; +} + +/* Implement the kill_request target_ops method. */ + +static void +lynx_request_interrupt (void) +{ + ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); + + kill (lynx_ptid_get_pid (inferior_ptid), SIGINT); +} + +/* The LynxOS target_ops vector. */ + +static struct target_ops lynx_target_ops = { + lynx_create_inferior, + lynx_attach, + lynx_kill, + lynx_detach, + NULL, /* mourn */ + lynx_join, + lynx_thread_alive, + lynx_resume, + lynx_wait, + lynx_fetch_registers, + lynx_store_registers, + lynx_read_memory, + lynx_write_memory, + NULL, /* look_up_symbols */ + lynx_request_interrupt, + NULL, /* read_auxv */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* read_offsets */ + NULL, /* get_tls_address */ + NULL, /* qxfer_spu */ + NULL, /* hostio_last_error */ + NULL, /* qxfer_osdata */ + NULL, /* qxfer_siginfo */ + NULL, /* supports_non_stop */ + NULL, /* async */ + NULL, /* start_non_stop */ + NULL, /* supports_multi_process */ + NULL, /* handle_monitor_command */ +}; + +void +initialize_low (void) +{ + set_target_ops (&lynx_target_ops); + the_low_target.arch_setup (); +} + diff --git a/gdb/gdbserver/lynx-low.h b/gdb/gdbserver/lynx-low.h new file mode 100644 index 0000000..9f2ce30 --- /dev/null +++ b/gdb/gdbserver/lynx-low.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#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