Browse Source

gdbserver: remove support for LynxOS

This port has been unmaintained for years, remove it.

gdbserver/ChangeLog:

	* configure: Re-generate.
	* configure.ac: Remove srv_lynxos test.
	* configure.srv: Remove lynxos cases.
	* lynx-i386-low.cc, lynx-low.cc, lynx-low.h, lynx-ppc-low.c:
	Remove.

Change-Id: I239d1cf1fc7b4c7a174251bc7981707eaba7d972
binutils-2_35-branch
Simon Marchi 6 years ago
parent
commit
fdb95bf546
  1. 8
      gdbserver/ChangeLog
  2. 2
      gdbserver/configure
  3. 2
      gdbserver/configure.ac
  4. 13
      gdbserver/configure.srv
  5. 358
      gdbserver/lynx-i386-low.cc
  6. 747
      gdbserver/lynx-low.cc
  7. 102
      gdbserver/lynx-low.h
  8. 185
      gdbserver/lynx-ppc-low.cc

8
gdbserver/ChangeLog

@ -1,3 +1,11 @@
2020-06-12 Simon Marchi <simon.marchi@efficios.com>
* configure: Re-generate.
* configure.ac: Remove srv_lynxos test.
* configure.srv: Remove lynxos cases.
* lynx-i386-low.cc, lynx-low.cc, lynx-low.h, lynx-ppc-low.c:
Remove.
2020-06-12 Simon Marchi <simon.marchi@efficios.com>
* README: Fix a few outdated or incoherent things.

2
gdbserver/configure

@ -10254,8 +10254,6 @@ elif test "${srv_mingw}" = "yes"; then
LIBS="$LIBS $WIN32APILIBS"
elif test "${srv_qnx}" = "yes"; then
LIBS="$LIBS -lsocket"
elif test "${srv_lynxos}" = "yes"; then
LIBS="$LIBS -lnetinet"
fi
if test "${srv_linux_usrregs}" = "yes"; then

2
gdbserver/configure.ac

@ -227,8 +227,6 @@ elif test "${srv_mingw}" = "yes"; then
LIBS="$LIBS $WIN32APILIBS"
elif test "${srv_qnx}" = "yes"; then
LIBS="$LIBS -lsocket"
elif test "${srv_lynxos}" = "yes"; then
LIBS="$LIBS -lnetinet"
fi
if test "${srv_linux_usrregs}" = "yes"; then

13
gdbserver/configure.srv

@ -117,12 +117,6 @@ case "${gdbserver_host}" in
ipa_obj="linux-i386-ipa.o linux-x86-tdesc-ipa.o"
ipa_obj="${ipa_obj} arch/i386-ipa.o"
;;
i[34567]86-*-lynxos*) srv_regobj=""
srv_tgtobj="lynx-low.o lynx-i386-low.o fork-child.o"
srv_tgtobj="${srv_tgtobj} nat/fork-inferior.o"
srv_tgtobj="${srv_tgtobj} arch/i386.o"
srv_lynxos=yes
;;
i[34567]86-*-mingw32ce*)
srv_regobj=""
srv_tgtobj="x86-low.o nat/x86-dregs.o win32-low.o"
@ -274,13 +268,6 @@ case "${gdbserver_host}" in
srv_linux_thread_db=yes
ipa_obj="${ipa_ppc_linux_regobj} linux-ppc-ipa.o"
;;
powerpc-*-lynxos*) srv_regobj="powerpc-32.o"
srv_tgtobj="lynx-low.o lynx-ppc-low.o"
srv_xmlfiles="rs6000/powerpc-32.xml"
srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml"
srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml"
srv_lynxos=yes
;;
riscv*-*-linux*) srv_tgtobj="arch/riscv.o nat/riscv-linux-tdesc.o"
srv_tgtobj="${srv_tgtobj} linux-riscv-low.o"
srv_tgtobj="${srv_tgtobj} ${srv_linux_obj}"

358
gdbserver/lynx-i386-low.cc

@ -1,358 +0,0 @@
/* Copyright (C) 2010-2020 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 <limits.h>
#include <sys/ptrace.h>
#include "gdbsupport/x86-xstate.h"
#include "arch/i386.h"
#include "x86-tdesc.h"
/* The following two typedefs are defined in a .h file which is not
in the standard include path (/sys/include/family/x86/ucontext.h),
so we just duplicate them here.
Unfortunately for us, the definition of this structure differs between
LynxOS 5.x and LynxOS 178. Rather than duplicate the code, we use
different definitions depending on the target. */
#ifdef VMOS_DEV
#define LYNXOS_178
#endif
/* General register context */
typedef struct usr_econtext {
uint32_t uec_fault;
uint32_t uec_es;
uint32_t uec_ds;
uint32_t uec_edi;
uint32_t uec_esi;
uint32_t uec_ebp;
uint32_t uec_temp;
uint32_t uec_ebx;
uint32_t uec_edx;
uint32_t uec_ecx;
uint32_t uec_eax;
uint32_t uec_inum;
uint32_t uec_ecode;
uint32_t uec_eip;
uint32_t uec_cs;
uint32_t uec_eflags;
uint32_t uec_esp;
uint32_t uec_ss;
uint32_t uec_fs;
uint32_t uec_gs;
} usr_econtext_t;
#if defined(LYNXOS_178)
/* Floating point register context */
typedef struct usr_fcontext {
uint32_t ufc_control;
uint32_t ufc_status;
uint32_t ufc_tag;
uint8_t *ufc_inst_off;
uint32_t ufc_inst_sel;
uint8_t *ufc_data_off;
uint32_t ufc_data_sel;
struct ufp387_real {
uint16_t umant4;
uint16_t umant3;
uint16_t umant2;
uint16_t umant1;
uint16_t us_and_e;
} ufc_reg[8];
} usr_fcontext_t;
#else /* This is LynxOS 5.x. */
/* Floating point and SIMD register context */
typedef struct usr_fcontext {
uint16_t ufc_control;
uint16_t ufc_status;
uint16_t ufc_tag;
uint16_t ufc_opcode;
uint8_t *ufc_inst_off;
uint32_t ufc_inst_sel;
uint8_t *ufc_data_off;
uint32_t ufc_data_sel;
uint32_t usse_mxcsr;
uint32_t usse_mxcsr_mask;
struct ufp387_real {
uint16_t umant4;
uint16_t umant3;
uint16_t umant2;
uint16_t umant1;
uint16_t us_and_e;
uint16_t ureserved_1;
uint16_t ureserved_2;
uint16_t ureserved_3;
} ufc_reg[8];
struct uxmm_register {
uint16_t uchunk_1;
uint16_t uchunk_2;
uint16_t uchunk_3;
uint16_t uchunk_4;
uint16_t uchunk_5;
uint16_t uchunk_6;
uint16_t uchunk_7;
uint16_t uchunk_8;
} uxmm_reg[8];
char ureserved[16][14];
} usr_fcontext_t;
#endif
/* The index of various registers inside the regcache. */
enum lynx_i386_gdb_regnum
{
I386_EAX_REGNUM,
I386_ECX_REGNUM,
I386_EDX_REGNUM,
I386_EBX_REGNUM,
I386_ESP_REGNUM,
I386_EBP_REGNUM,
I386_ESI_REGNUM,
I386_EDI_REGNUM,
I386_EIP_REGNUM,
I386_EFLAGS_REGNUM,
I386_CS_REGNUM,
I386_SS_REGNUM,
I386_DS_REGNUM,
I386_ES_REGNUM,
I386_FS_REGNUM,
I386_GS_REGNUM,
I386_ST0_REGNUM,
I386_FCTRL_REGNUM = I386_ST0_REGNUM + 8,
I386_FSTAT_REGNUM,
I386_FTAG_REGNUM,
I386_FISEG_REGNUM,
I386_FIOFF_REGNUM,
I386_FOSEG_REGNUM,
I386_FOOFF_REGNUM,
I386_FOP_REGNUM,
I386_XMM0_REGNUM = 32,
I386_MXCSR_REGNUM = I386_XMM0_REGNUM + 8,
I386_SENTINEL_REGUM
};
/* The fill_function for the general-purpose register set. */
static void
lynx_i386_fill_gregset (struct regcache *regcache, char *buf)
{
#define lynx_i386_collect_gp(regnum, fld) \
collect_register (regcache, regnum, \
buf + offsetof (usr_econtext_t, uec_##fld))
lynx_i386_collect_gp (I386_EAX_REGNUM, eax);
lynx_i386_collect_gp (I386_ECX_REGNUM, ecx);
lynx_i386_collect_gp (I386_EDX_REGNUM, edx);
lynx_i386_collect_gp (I386_EBX_REGNUM, ebx);
lynx_i386_collect_gp (I386_ESP_REGNUM, esp);
lynx_i386_collect_gp (I386_EBP_REGNUM, ebp);
lynx_i386_collect_gp (I386_ESI_REGNUM, esi);
lynx_i386_collect_gp (I386_EDI_REGNUM, edi);
lynx_i386_collect_gp (I386_EIP_REGNUM, eip);
lynx_i386_collect_gp (I386_EFLAGS_REGNUM, eflags);
lynx_i386_collect_gp (I386_CS_REGNUM, cs);
lynx_i386_collect_gp (I386_SS_REGNUM, ss);
lynx_i386_collect_gp (I386_DS_REGNUM, ds);
lynx_i386_collect_gp (I386_ES_REGNUM, es);
lynx_i386_collect_gp (I386_FS_REGNUM, fs);
lynx_i386_collect_gp (I386_GS_REGNUM, gs);
}
/* The store_function for the general-purpose register set. */
static void
lynx_i386_store_gregset (struct regcache *regcache, const char *buf)
{
#define lynx_i386_supply_gp(regnum, fld) \
supply_register (regcache, regnum, \
buf + offsetof (usr_econtext_t, uec_##fld))
lynx_i386_supply_gp (I386_EAX_REGNUM, eax);
lynx_i386_supply_gp (I386_ECX_REGNUM, ecx);
lynx_i386_supply_gp (I386_EDX_REGNUM, edx);
lynx_i386_supply_gp (I386_EBX_REGNUM, ebx);
lynx_i386_supply_gp (I386_ESP_REGNUM, esp);
lynx_i386_supply_gp (I386_EBP_REGNUM, ebp);
lynx_i386_supply_gp (I386_ESI_REGNUM, esi);
lynx_i386_supply_gp (I386_EDI_REGNUM, edi);
lynx_i386_supply_gp (I386_EIP_REGNUM, eip);
lynx_i386_supply_gp (I386_EFLAGS_REGNUM, eflags);
lynx_i386_supply_gp (I386_CS_REGNUM, cs);
lynx_i386_supply_gp (I386_SS_REGNUM, ss);
lynx_i386_supply_gp (I386_DS_REGNUM, ds);
lynx_i386_supply_gp (I386_ES_REGNUM, es);
lynx_i386_supply_gp (I386_FS_REGNUM, fs);
lynx_i386_supply_gp (I386_GS_REGNUM, gs);
}
/* Extract the first 16 bits of register REGNUM in the REGCACHE,
and store these 2 bytes at DEST.
This is useful to collect certain 16bit registers which are known
by GDBserver as 32bit registers (such as the Control Register
for instance). */
static void
collect_16bit_register (struct regcache *regcache, int regnum, char *dest)
{
gdb_byte word[4];
collect_register (regcache, regnum, word);
memcpy (dest, word, 2);
}
/* The fill_function for the floating-point register set. */
static void
lynx_i386_fill_fpregset (struct regcache *regcache, char *buf)
{
int i;
/* Collect %st0 .. %st7. */
for (i = 0; i < 8; i++)
collect_register (regcache, I386_ST0_REGNUM + i,
buf + offsetof (usr_fcontext_t, ufc_reg)
+ i * sizeof (struct ufp387_real));
/* Collect the other FPU registers. */
collect_16bit_register (regcache, I386_FCTRL_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_control));
collect_16bit_register (regcache, I386_FSTAT_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_status));
collect_16bit_register (regcache, I386_FTAG_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_tag));
collect_register (regcache, I386_FISEG_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_inst_sel));
collect_register (regcache, I386_FIOFF_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_inst_off));
collect_register (regcache, I386_FOSEG_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_data_sel));
collect_register (regcache, I386_FOOFF_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_data_off));
#if !defined(LYNXOS_178)
collect_16bit_register (regcache, I386_FOP_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_opcode));
/* Collect the XMM registers. */
for (i = 0; i < 8; i++)
collect_register (regcache, I386_XMM0_REGNUM + i,
buf + offsetof (usr_fcontext_t, uxmm_reg)
+ i * sizeof (struct uxmm_register));
collect_register (regcache, I386_MXCSR_REGNUM,
buf + offsetof (usr_fcontext_t, usse_mxcsr));
#endif
}
/* This is the supply counterpart for collect_16bit_register:
It extracts a 2byte value from BUF, and uses that value to
set REGNUM's value in the regcache.
This is useful to supply the value of certain 16bit registers
which are known by GDBserver as 32bit registers (such as the Control
Register for instance). */
static void
supply_16bit_register (struct regcache *regcache, int regnum, const char *buf)
{
gdb_byte word[4];
memcpy (word, buf, 2);
memset (word + 2, 0, 2);
supply_register (regcache, regnum, word);
}
/* The store_function for the floating-point register set. */
static void
lynx_i386_store_fpregset (struct regcache *regcache, const char *buf)
{
int i;
/* Store the %st0 .. %st7 registers. */
for (i = 0; i < 8; i++)
supply_register (regcache, I386_ST0_REGNUM + i,
buf + offsetof (usr_fcontext_t, ufc_reg)
+ i * sizeof (struct ufp387_real));
/* Store the other FPU registers. */
supply_16bit_register (regcache, I386_FCTRL_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_control));
supply_16bit_register (regcache, I386_FSTAT_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_status));
supply_16bit_register (regcache, I386_FTAG_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_tag));
supply_register (regcache, I386_FISEG_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_inst_sel));
supply_register (regcache, I386_FIOFF_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_inst_off));
supply_register (regcache, I386_FOSEG_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_data_sel));
supply_register (regcache, I386_FOOFF_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_data_off));
#if !defined(LYNXOS_178)
supply_16bit_register (regcache, I386_FOP_REGNUM,
buf + offsetof (usr_fcontext_t, ufc_opcode));
/* Store the XMM registers. */
for (i = 0; i < 8; i++)
supply_register (regcache, I386_XMM0_REGNUM + i,
buf + offsetof (usr_fcontext_t, uxmm_reg)
+ i * sizeof (struct uxmm_register));
supply_register (regcache, I386_MXCSR_REGNUM,
buf + offsetof (usr_fcontext_t, usse_mxcsr));
#endif
}
/* Implements the lynx_target_ops.arch_setup routine. */
static void
lynx_i386_arch_setup (void)
{
struct target_desc *tdesc
= i386_create_target_description (X86_XSTATE_SSE_MASK, false, false);
init_target_desc (tdesc, i386_expedite_regs);
lynx_tdesc = tdesc;
}
/* Description of all the x86-lynx register sets. */
struct lynx_regset_info lynx_target_regsets[] = {
/* General Purpose Registers. */
{PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t),
lynx_i386_fill_gregset, lynx_i386_store_gregset},
/* Floating Point Registers. */
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t),
lynx_i386_fill_fpregset, lynx_i386_store_fpregset },
/* End of list marker. */
{0, 0, -1, NULL, NULL }
};
/* The lynx_target_ops vector for x86-lynx. */
struct lynx_target_ops the_low_target = {
lynx_i386_arch_setup,
};

747
gdbserver/lynx-low.cc

@ -1,747 +0,0 @@
/* Copyright (C) 2009-2020 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 <limits.h>
#include <sys/ptrace.h>
#include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc. */
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include "gdbsupport/gdb_wait.h"
#include <signal.h>
#include "gdbsupport/filestuff.h"
#include "gdbsupport/common-inferior.h"
#include "nat/fork-inferior.h"
int using_threads = 1;
const struct target_desc *lynx_tdesc;
/* Per-process private data. */
struct process_info_private
{
/* The PTID obtained from the last wait performed on this process.
Initialized to null_ptid until the first wait is performed. */
ptid_t last_wait_event_ptid;
};
/* Print a debug trace on standard output if debug_threads is set. */
static void
lynx_debug (char *string, ...)
{
va_list args;
if (!debug_threads)
return;
va_start (args, string);
fprintf (stderr, "DEBUG(lynx): ");
vfprintf (stderr, string, args);
fprintf (stderr, "\n");
va_end (args);
}
/* Build a ptid_t given a PID and a LynxOS TID. */
static ptid_t
lynx_ptid_t (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_t (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. */
static int
lynx_ptid_get_pid (ptid_t ptid)
{
return ptid.pid ();
}
/* Return the LynxOS tid of the given PTID. */
static long
lynx_ptid_get_tid (ptid_t ptid)
{
/* See lynx_ptid_t: The LynxOS tid is stored inside the lwp field
of the ptid. */
return ptid.lwp ();
}
/* For a given PTID, return the associated PID as known by the LynxOS
ptrace layer. */
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)
{
#define CASE(X) case X: return #X
switch (request)
{
CASE(PTRACE_TRACEME);
CASE(PTRACE_PEEKTEXT);
CASE(PTRACE_PEEKDATA);
CASE(PTRACE_PEEKUSER);
CASE(PTRACE_POKETEXT);
CASE(PTRACE_POKEDATA);
CASE(PTRACE_POKEUSER);
CASE(PTRACE_CONT);
CASE(PTRACE_KILL);
CASE(PTRACE_SINGLESTEP);
CASE(PTRACE_ATTACH);
CASE(PTRACE_DETACH);
CASE(PTRACE_GETREGS);
CASE(PTRACE_SETREGS);
CASE(PTRACE_GETFPREGS);
CASE(PTRACE_SETFPREGS);
CASE(PTRACE_READDATA);
CASE(PTRACE_WRITEDATA);
CASE(PTRACE_READTEXT);
CASE(PTRACE_WRITETEXT);
CASE(PTRACE_GETFPAREGS);
CASE(PTRACE_SETFPAREGS);
CASE(PTRACE_GETWINDOW);
CASE(PTRACE_SETWINDOW);
CASE(PTRACE_SYSCALL);
CASE(PTRACE_DUMPCORE);
CASE(PTRACE_SETWRBKPT);
CASE(PTRACE_SETACBKPT);
CASE(PTRACE_CLRBKPT);
CASE(PTRACE_GET_UCODE);
#ifdef PT_READ_GPR
CASE(PT_READ_GPR);
#endif
#ifdef PT_WRITE_GPR
CASE(PT_WRITE_GPR);
#endif
#ifdef PT_READ_FPR
CASE(PT_READ_FPR);
#endif
#ifdef PT_WRITE_FPR
CASE(PT_WRITE_FPR);
#endif
#ifdef PT_READ_VPR
CASE(PT_READ_VPR);
#endif
#ifdef PT_WRITE_VPR
CASE(PT_WRITE_VPR);
#endif
#ifdef PTRACE_PEEKUSP
CASE(PTRACE_PEEKUSP);
#endif
#ifdef PTRACE_POKEUSP
CASE(PTRACE_POKEUSP);
#endif
CASE(PTRACE_PEEKTHREAD);
CASE(PTRACE_THREADUSER);
CASE(PTRACE_FPREAD);
CASE(PTRACE_FPWRITE);
CASE(PTRACE_SETSIG);
CASE(PTRACE_CONT_ONE);
CASE(PTRACE_KILL_ONE);
CASE(PTRACE_SINGLESTEP_ONE);
CASE(PTRACE_GETLOADINFO);
CASE(PTRACE_GETTRACESIG);
#ifdef PTRACE_GETTHREADLIST
CASE(PTRACE_GETTHREADLIST);
#endif
}
#undef CASE
return "<unknown-request>";
}
/* A wrapper around ptrace that allows us to print debug traces of
ptrace calls if debug traces are activated. */
static 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);
int saved_errno;
if (debug_threads)
fprintf (stderr, "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);
saved_errno = errno;
if (debug_threads)
fprintf (stderr, " -> %d (=0x%x)\n", result, result);
errno = saved_errno;
return result;
}
/* Call add_process with the given parameters, and initializes
the process' private data. */
static struct process_info *
lynx_add_process (int pid, int attached)
{
struct process_info *proc;
proc = add_process (pid, attached);
proc->tdesc = lynx_tdesc;
proc->priv = XCNEW (struct process_info_private);
proc->priv->last_wait_event_ptid = null_ptid;
return proc;
}
/* Callback used by fork_inferior to start tracing the inferior. */
static void
lynx_ptrace_fun ()
{
int pgrp;
/* Switch child to its own process group so that signals won't
directly affect GDBserver. */
pgrp = getpid();
if (pgrp < 0)
trace_start_error_with_name ("pgrp");
if (setpgid (0, pgrp) < 0)
trace_start_error_with_name ("setpgid");
if (ioctl (0, TIOCSPGRP, &pgrp) < 0)
trace_start_error_with_name ("ioctl");
if (lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0) < 0)
trace_start_error_with_name ("lynx_ptrace");
}
/* Implement the create_inferior method of the target_ops vector. */
int
lynx_process_target::create_inferior (const char *program,
const std::vector<char *> &program_args)
{
int pid;
std::string str_program_args = construct_inferior_arguments (program_args);
lynx_debug ("create_inferior ()");
pid = fork_inferior (program,
str_program_args.c_str (),
get_environ ()->envp (), lynx_ptrace_fun,
NULL, NULL, NULL, NULL);
post_fork_inferior (pid, program);
lynx_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;
}
/* Assuming we've just attached to a running inferior whose pid is PID,
add all threads running in that process. */
static void
lynx_add_threads_after_attach (int pid)
{
/* Ugh! There appears to be no way to get the list of threads
in the program we just attached to. So get the list by calling
the "ps" command. This is only needed now, as we will then
keep the thread list up to date thanks to thread creation and
exit notifications. */
FILE *f;
char buf[256];
int thread_pid, thread_tid;
f = popen ("ps atx", "r");
if (f == NULL)
perror_with_name ("Cannot get thread list");
while (fgets (buf, sizeof (buf), f) != NULL)
if ((sscanf (buf, "%d %d", &thread_pid, &thread_tid) == 2
&& thread_pid == pid))
{
ptid_t thread_ptid = lynx_ptid_t (pid, thread_tid);
if (!find_thread_ptid (thread_ptid))
{
lynx_debug ("New thread: (pid = %d, tid = %d)",
pid, thread_tid);
add_thread (thread_ptid, NULL);
}
}
pclose (f);
}
/* Implement the attach target_ops method. */
int
lynx_process_target::attach (unsigned long pid)
{
ptid_t ptid = lynx_ptid_t (pid, 0);
if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0)
error ("Cannot attach to process %lu: %s (%d)\n", pid,
safe_strerror (errno), errno);
lynx_add_process (pid, 1);
lynx_add_threads_after_attach (pid);
return 0;
}
/* Implement the resume target_ops method. */
void
lynx_process_target::resume (thread_resume *resume_info, size_t n)
{
ptid_t ptid = resume_info[0].thread;
const int request
= (resume_info[0].kind == resume_step
? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP)
: PTRACE_CONT);
const int signal = resume_info[0].sig;
/* If given a minus_one_ptid, then try using the current_process'
private->last_wait_event_ptid. On most LynxOS versions,
using any of the process' thread works well enough, but
LynxOS 178 is a little more sensitive, and triggers some
unexpected signals (Eg SIG61) when we resume the inferior
using a different thread. */
if (ptid == minus_one_ptid)
ptid = current_process()->priv->last_wait_event_ptid;
/* The ptid might still be minus_one_ptid; this can happen between
the moment we create the inferior or attach to a process, and
the moment we resume its execution for the first time. It is
fine to use the current_thread's ptid in those cases. */
if (ptid == minus_one_ptid)
ptid = ptid_of (current_thread);
regcache_invalidate_pid (ptid.pid ());
errno = 0;
lynx_ptrace (request, ptid, 1, signal, 0);
if (errno)
perror_with_name ("ptrace");
}
/* 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);
}
/* 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 == minus_one_ptid)
pid = lynx_ptid_get_pid (ptid_of (current_thread));
else
pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
retry:
ret = lynx_waitpid (pid, &wstat);
new_ptid = lynx_ptid_t (ret, ((union wait *) &wstat)->w_tid);
find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid;
/* 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))
{
lynx_debug ("New thread: (pid = %d, tid = %d)",
lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid));
add_thread (new_ptid, NULL);
}
if (WIFSTOPPED (wstat))
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.integer = gdb_signal_from_host (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_debug ("process exited with code: %d", status->value.integer);
}
else if (WIFSIGNALED (wstat))
{
status->kind = TARGET_WAITKIND_SIGNALLED;
status->value.integer = gdb_signal_from_host (WTERMSIG (wstat));
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 = gdb_signal_from_host (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 == GDB_SIGNAL_TRAP)
{
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 (new_ptid);
goto retry;
case SIGTHREADEXIT:
remove_thread (find_thread_ptid (new_ptid));
lynx_continue (new_ptid);
goto retry;
}
}
return new_ptid;
}
/* A wrapper around lynx_wait_1 that also prints debug traces when
such debug traces have been activated. */
ptid_t
lynx_process_target::wait (ptid_t ptid, target_waitstatus *status,
int options)
{
ptid_t new_ptid;
lynx_debug ("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. */
int
lynx_process_target::kill (process_info *process)
{
ptid_t ptid = lynx_ptid_t (process->pid, 0);
struct target_waitstatus status;
lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0);
lynx_wait (ptid, &status, 0);
mourn (process);
return 0;
}
/* Implement the detach target_ops method. */
int
lynx_process_target::detach (process_info *process)
{
ptid_t ptid = lynx_ptid_t (process->pid, 0);
lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0);
mourn (process);
return 0;
}
/* Implement the mourn target_ops method. */
void
lynx_process_target::mourn (struct process_info *proc)
{
for_each_thread (proc->pid, remove_thread);
/* Free our private data. */
free (proc->priv);
proc->priv = NULL;
remove_process (proc);
}
/* Implement the join target_ops method. */
void
lynx_process_target::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. */
bool
lynx_process_target::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. */
void
lynx_process_target::fetch_registers (regcache *regcache, int regno)
{
struct lynx_regset_info *regset = lynx_target_regsets;
ptid_t inferior_ptid = ptid_of (current_thread);
lynx_debug ("fetch_registers (regno = %d)", regno);
while (regset->size >= 0)
{
char *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. */
void
lynx_process_target::store_registers (regcache *regcache, int regno)
{
struct lynx_regset_info *regset = lynx_target_regsets;
ptid_t inferior_ptid = ptid_of (current_thread);
lynx_debug ("store_registers (regno = %d)", regno);
while (regset->size >= 0)
{
char *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. */
int
lynx_process_target::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 = ptid_of (current_thread);
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. */
int
lynx_process_target::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 = ptid_of (current_thread);
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. */
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. */
void
lynx_process_target::request_interrupt ()
{
ptid_t inferior_ptid = ptid_of (get_first_thread ());
kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
}
bool
lynx_process_target::supports_hardware_single_step ()
{
return true;
}
const gdb_byte *
lynx_process_target::sw_breakpoint_from_kind (int kind, int *size)
{
error (_("Target does not implement the sw_breakpoint_from_kind op"));
}
/* The LynxOS target ops object. */
static lynx_process_target the_lynx_target;
void
initialize_low (void)
{
set_target_ops (&the_lynx_target);
the_low_target.arch_setup ();
}

102
gdbserver/lynx-low.h

@ -1,102 +0,0 @@
/* Copyright (C) 2010-2020 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 GDBSERVER_LYNX_LOW_H
#define GDBSERVER_LYNX_LOW_H
struct regcache;
struct target_desc;
/* 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, char *buf);
/* Store the register value in BUF in the given REGCACHE. */
void (*store_function) (struct regcache *regcache, const char *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;
/* Target ops definitions for a LynxOS target. */
class lynx_process_target : public process_stratum_target
{
public:
int create_inferior (const char *program,
const std::vector<char *> &program_args) override;
int attach (unsigned long pid) override;
int kill (process_info *proc) override;
int detach (process_info *proc) override;
void mourn (process_info *proc) override;
void join (int pid) override;
bool thread_alive (ptid_t pid) override;
void resume (thread_resume *resume_info, size_t n) override;
ptid_t wait (ptid_t ptid, target_waitstatus *status,
int options) override;
void fetch_registers (regcache *regcache, int regno) override;
void store_registers (regcache *regcache, int regno) override;
int read_memory (CORE_ADDR memaddr, unsigned char *myaddr,
int len) override;
int write_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
int len) override;
void request_interrupt () override;
bool supports_hardware_single_step () override;
const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
};
/* The inferior's target description. This is a global because the
LynxOS ports support neither bi-arch nor multi-process. */
extern const struct target_desc *lynx_tdesc;
#endif /* GDBSERVER_LYNX_LOW_H */

185
gdbserver/lynx-ppc-low.cc

@ -1,185 +0,0 @@
/* Copyright (C) 2009-2020 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 <limits.h>
#include <sys/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);
extern const struct target_desc *tdesc_powerpc_32;
/* The fill_function for the general-purpose register set. */
static void
lynx_ppc_fill_gregset (struct regcache *regcache, char *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 char *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, char *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 char *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 ();
lynx_tdesc = tdesc_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,
};
Loading…
Cancel
Save