gdbserver: remove support for Neutrino
This port has been unmaintained for years, remove it. gdbserver/ChangeLog: * configure: Re-generate. * configure.ac: Remove srv_qnx test. * configure.srv: Remove nto case. * nto-low.cc, nto-low.h, nto-x86-low.cc: Remove. * remote-utils.c: Remove __QNX__-guarded code. Change-Id: I8a1ad9c740a69352da1f6993778dbf951eebb22f
This commit is contained in:
parent
fdb95bf546
commit
613f149a90
|
@ -1,3 +1,11 @@
|
||||||
|
2020-06-12 Simon Marchi <simon.marchi@efficios.com>
|
||||||
|
|
||||||
|
* configure: Re-generate.
|
||||||
|
* configure.ac: Remove srv_qnx test.
|
||||||
|
* configure.srv: Remove nto case.
|
||||||
|
* nto-low.cc, nto-low.h, nto-x86-low.cc: Remove.
|
||||||
|
* remote-utils.c: Remove __QNX__-guarded code.
|
||||||
|
|
||||||
2020-06-12 Simon Marchi <simon.marchi@efficios.com>
|
2020-06-12 Simon Marchi <simon.marchi@efficios.com>
|
||||||
|
|
||||||
* configure: Re-generate.
|
* configure: Re-generate.
|
||||||
|
|
|
@ -10252,8 +10252,6 @@ if test "${srv_mingwce}" = "yes"; then
|
||||||
elif test "${srv_mingw}" = "yes"; then
|
elif test "${srv_mingw}" = "yes"; then
|
||||||
# WIN32APILIBS is set by GDB_AC_COMMON.
|
# WIN32APILIBS is set by GDB_AC_COMMON.
|
||||||
LIBS="$LIBS $WIN32APILIBS"
|
LIBS="$LIBS $WIN32APILIBS"
|
||||||
elif test "${srv_qnx}" = "yes"; then
|
|
||||||
LIBS="$LIBS -lsocket"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "${srv_linux_usrregs}" = "yes"; then
|
if test "${srv_linux_usrregs}" = "yes"; then
|
||||||
|
|
|
@ -225,8 +225,6 @@ if test "${srv_mingwce}" = "yes"; then
|
||||||
elif test "${srv_mingw}" = "yes"; then
|
elif test "${srv_mingw}" = "yes"; then
|
||||||
# WIN32APILIBS is set by GDB_AC_COMMON.
|
# WIN32APILIBS is set by GDB_AC_COMMON.
|
||||||
LIBS="$LIBS $WIN32APILIBS"
|
LIBS="$LIBS $WIN32APILIBS"
|
||||||
elif test "${srv_qnx}" = "yes"; then
|
|
||||||
LIBS="$LIBS -lsocket"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "${srv_linux_usrregs}" = "yes"; then
|
if test "${srv_linux_usrregs}" = "yes"; then
|
||||||
|
|
|
@ -136,10 +136,6 @@ case "${gdbserver_host}" in
|
||||||
srv_tgtobj="${srv_tgtobj} arch/i386.o"
|
srv_tgtobj="${srv_tgtobj} arch/i386.o"
|
||||||
srv_mingw=yes
|
srv_mingw=yes
|
||||||
;;
|
;;
|
||||||
i[34567]86-*-nto*) srv_regobj=""
|
|
||||||
srv_tgtobj="nto-low.o nto-x86-low.o arch/i386.o"
|
|
||||||
srv_qnx="yes"
|
|
||||||
;;
|
|
||||||
ia64-*-linux*) srv_regobj=reg-ia64.o
|
ia64-*-linux*) srv_regobj=reg-ia64.o
|
||||||
srv_tgtobj="$srv_linux_obj linux-ia64-low.o"
|
srv_tgtobj="$srv_linux_obj linux-ia64-low.o"
|
||||||
srv_linux_usrregs=yes
|
srv_linux_usrregs=yes
|
||||||
|
|
|
@ -1,965 +0,0 @@
|
||||||
/* QNX Neutrino specific low level interface, for the remote server
|
|
||||||
for GDB.
|
|
||||||
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 "gdbthread.h"
|
|
||||||
#include "nto-low.h"
|
|
||||||
#include "hostio.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <spawn.h>
|
|
||||||
#include <sys/procfs.h>
|
|
||||||
#include <sys/auxv.h>
|
|
||||||
#include <sys/iomgr.h>
|
|
||||||
#include <sys/neutrino.h>
|
|
||||||
|
|
||||||
|
|
||||||
int using_threads = 1;
|
|
||||||
|
|
||||||
const struct target_desc *nto_tdesc;
|
|
||||||
|
|
||||||
static void
|
|
||||||
nto_trace (const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list arg_list;
|
|
||||||
|
|
||||||
if (debug_threads == 0)
|
|
||||||
return;
|
|
||||||
fprintf (stderr, "nto:");
|
|
||||||
va_start (arg_list, fmt);
|
|
||||||
vfprintf (stderr, fmt, arg_list);
|
|
||||||
va_end (arg_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TRACE nto_trace
|
|
||||||
|
|
||||||
/* Structure holding neutrino specific information about
|
|
||||||
inferior. */
|
|
||||||
|
|
||||||
struct nto_inferior
|
|
||||||
{
|
|
||||||
char nto_procfs_path[PATH_MAX];
|
|
||||||
int ctl_fd;
|
|
||||||
pid_t pid;
|
|
||||||
int exit_signo; /* For tracking exit status. */
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct nto_inferior nto_inferior;
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_nto_inferior (struct nto_inferior *nto_inferior)
|
|
||||||
{
|
|
||||||
memset (nto_inferior, 0, sizeof (struct nto_inferior));
|
|
||||||
nto_inferior->ctl_fd = -1;
|
|
||||||
nto_inferior->pid = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
do_detach (void)
|
|
||||||
{
|
|
||||||
if (nto_inferior.ctl_fd != -1)
|
|
||||||
{
|
|
||||||
nto_trace ("Closing fd\n");
|
|
||||||
close (nto_inferior.ctl_fd);
|
|
||||||
init_nto_inferior (&nto_inferior);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set current thread. Return 1 on success, 0 otherwise. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
nto_set_thread (ptid_t ptid)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
TRACE ("%s pid: %d tid: %ld\n", __func__, ptid.pid (),
|
|
||||||
ptid.lwp ());
|
|
||||||
if (nto_inferior.ctl_fd != -1
|
|
||||||
&& ptid != null_ptid
|
|
||||||
&& ptid != minus_one_ptid)
|
|
||||||
{
|
|
||||||
pthread_t tid = ptid.lwp ();
|
|
||||||
|
|
||||||
if (EOK == devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid,
|
|
||||||
sizeof (tid), 0))
|
|
||||||
res = 1;
|
|
||||||
else
|
|
||||||
TRACE ("%s: Error: failed to set current thread\n", __func__);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function will determine all alive threads. Note that we do not list
|
|
||||||
dead but unjoined threads even though they are still in the process' thread
|
|
||||||
list.
|
|
||||||
|
|
||||||
NTO_INFERIOR must not be NULL. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
nto_find_new_threads (struct nto_inferior *nto_inferior)
|
|
||||||
{
|
|
||||||
pthread_t tid;
|
|
||||||
|
|
||||||
TRACE ("%s pid:%d\n", __func__, nto_inferior->pid);
|
|
||||||
|
|
||||||
if (nto_inferior->ctl_fd == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (tid = 1;; ++tid)
|
|
||||||
{
|
|
||||||
procfs_status status;
|
|
||||||
ptid_t ptid;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
status.tid = tid;
|
|
||||||
err = devctl (nto_inferior->ctl_fd, DCMD_PROC_TIDSTATUS, &status,
|
|
||||||
sizeof (status), 0);
|
|
||||||
|
|
||||||
if (err != EOK || status.tid == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* All threads in between are gone. */
|
|
||||||
while (tid != status.tid || status.state == STATE_DEAD)
|
|
||||||
{
|
|
||||||
struct thread_info *ti;
|
|
||||||
|
|
||||||
ptid = ptid_t (nto_inferior->pid, tid, 0);
|
|
||||||
ti = find_thread_ptid (ptid);
|
|
||||||
if (ti != NULL)
|
|
||||||
{
|
|
||||||
TRACE ("Removing thread %d\n", tid);
|
|
||||||
remove_thread (ti);
|
|
||||||
}
|
|
||||||
if (tid == status.tid)
|
|
||||||
break;
|
|
||||||
++tid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.state != STATE_DEAD)
|
|
||||||
{
|
|
||||||
TRACE ("Adding thread %d\n", tid);
|
|
||||||
ptid = ptid_t (nto_inferior->pid, tid, 0);
|
|
||||||
if (!find_thread_ptid (ptid))
|
|
||||||
add_thread (ptid, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given pid, open procfs path. */
|
|
||||||
|
|
||||||
static pid_t
|
|
||||||
do_attach (pid_t pid)
|
|
||||||
{
|
|
||||||
procfs_status status;
|
|
||||||
struct sigevent event;
|
|
||||||
|
|
||||||
if (nto_inferior.ctl_fd != -1)
|
|
||||||
{
|
|
||||||
close (nto_inferior.ctl_fd);
|
|
||||||
init_nto_inferior (&nto_inferior);
|
|
||||||
}
|
|
||||||
xsnprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", pid);
|
|
||||||
nto_inferior.ctl_fd = open (nto_inferior.nto_procfs_path, O_RDWR);
|
|
||||||
if (nto_inferior.ctl_fd == -1)
|
|
||||||
{
|
|
||||||
TRACE ("Failed to open %s\n", nto_inferior.nto_procfs_path);
|
|
||||||
init_nto_inferior (&nto_inferior);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0)
|
|
||||||
!= EOK)
|
|
||||||
{
|
|
||||||
do_detach ();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
nto_inferior.pid = pid;
|
|
||||||
/* Define a sigevent for process stopped notification. */
|
|
||||||
event.sigev_notify = SIGEV_SIGNAL_THREAD;
|
|
||||||
event.sigev_signo = SIGUSR1;
|
|
||||||
event.sigev_code = 0;
|
|
||||||
event.sigev_value.sival_ptr = NULL;
|
|
||||||
event.sigev_priority = -1;
|
|
||||||
devctl (nto_inferior.ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
|
|
||||||
|
|
||||||
if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
|
|
||||||
0) == EOK
|
|
||||||
&& (status.flags & _DEBUG_FLAG_STOPPED))
|
|
||||||
{
|
|
||||||
ptid_t ptid;
|
|
||||||
struct process_info *proc;
|
|
||||||
|
|
||||||
kill (pid, SIGCONT);
|
|
||||||
ptid = ptid_t (status.pid, status.tid, 0);
|
|
||||||
the_low_target.arch_setup ();
|
|
||||||
proc = add_process (status.pid, 1);
|
|
||||||
proc->tdesc = nto_tdesc;
|
|
||||||
TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid,
|
|
||||||
ptid.lwp ());
|
|
||||||
nto_find_new_threads (&nto_inferior);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do_detach ();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read or write LEN bytes from/to inferior's MEMADDR memory address
|
|
||||||
into gdbservers's MYADDR buffer. Return number of bytes actually
|
|
||||||
transfered. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
nto_xfer_memory (off_t memaddr, unsigned char *myaddr, int len,
|
|
||||||
int dowrite)
|
|
||||||
{
|
|
||||||
int nbytes = 0;
|
|
||||||
|
|
||||||
if (lseek (nto_inferior.ctl_fd, memaddr, SEEK_SET) == memaddr)
|
|
||||||
{
|
|
||||||
if (dowrite)
|
|
||||||
nbytes = write (nto_inferior.ctl_fd, myaddr, len);
|
|
||||||
else
|
|
||||||
nbytes = read (nto_inferior.ctl_fd, myaddr, len);
|
|
||||||
if (nbytes < 0)
|
|
||||||
nbytes = 0;
|
|
||||||
}
|
|
||||||
if (nbytes == 0)
|
|
||||||
{
|
|
||||||
int e = errno;
|
|
||||||
TRACE ("Error in %s : errno=%d (%s)\n", __func__, e, safe_strerror (e));
|
|
||||||
}
|
|
||||||
return nbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert or remove breakpoint or watchpoint at address ADDR.
|
|
||||||
TYPE can be one of Neutrino breakpoint types. SIZE must be 0 for
|
|
||||||
inserting the point, -1 for removing it.
|
|
||||||
|
|
||||||
Return 0 on success, 1 otherwise. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
nto_breakpoint (CORE_ADDR addr, int type, int size)
|
|
||||||
{
|
|
||||||
procfs_break brk;
|
|
||||||
|
|
||||||
brk.type = type;
|
|
||||||
brk.addr = addr;
|
|
||||||
brk.size = size;
|
|
||||||
if (devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)
|
|
||||||
!= EOK)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read auxiliary vector from inferior's initial stack into gdbserver's
|
|
||||||
MYADDR buffer, up to LEN bytes.
|
|
||||||
|
|
||||||
Return number of bytes read. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
|
|
||||||
unsigned char *myaddr,
|
|
||||||
unsigned int len)
|
|
||||||
{
|
|
||||||
int data_ofs = 0;
|
|
||||||
int anint;
|
|
||||||
unsigned int len_read = 0;
|
|
||||||
|
|
||||||
/* Skip over argc, argv and envp... Comment from ldd.c:
|
|
||||||
|
|
||||||
The startup frame is set-up so that we have:
|
|
||||||
auxv
|
|
||||||
NULL
|
|
||||||
...
|
|
||||||
envp2
|
|
||||||
envp1 <----- void *frame + (argc + 2) * sizeof(char *)
|
|
||||||
NULL
|
|
||||||
...
|
|
||||||
argv2
|
|
||||||
argv1
|
|
||||||
argc <------ void * frame
|
|
||||||
|
|
||||||
On entry to ldd, frame gives the address of argc on the stack. */
|
|
||||||
if (nto_xfer_memory (initial_stack, (unsigned char *)&anint,
|
|
||||||
sizeof (anint), 0) != sizeof (anint))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */
|
|
||||||
data_ofs += (anint + 2) * sizeof (void *); /* + 2 comes from argc itself and
|
|
||||||
NULL terminating pointer in
|
|
||||||
argv. */
|
|
||||||
|
|
||||||
/* Now loop over env table: */
|
|
||||||
while (nto_xfer_memory (initial_stack + data_ofs,
|
|
||||||
(unsigned char *)&anint, sizeof (anint), 0)
|
|
||||||
== sizeof (anint))
|
|
||||||
{
|
|
||||||
data_ofs += sizeof (anint);
|
|
||||||
if (anint == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
initial_stack += data_ofs;
|
|
||||||
|
|
||||||
memset (myaddr, 0, len);
|
|
||||||
while (len_read <= len - sizeof (auxv_t))
|
|
||||||
{
|
|
||||||
auxv_t *auxv = (auxv_t *)myaddr;
|
|
||||||
|
|
||||||
/* Search backwards until we have read AT_PHDR (num. 3),
|
|
||||||
AT_PHENT (num 4), AT_PHNUM (num 5) */
|
|
||||||
if (nto_xfer_memory (initial_stack, (unsigned char *)auxv,
|
|
||||||
sizeof (auxv_t), 0) == sizeof (auxv_t))
|
|
||||||
{
|
|
||||||
if (auxv->a_type != AT_NULL)
|
|
||||||
{
|
|
||||||
auxv++;
|
|
||||||
len_read += sizeof (auxv_t);
|
|
||||||
}
|
|
||||||
if (auxv->a_type == AT_PHNUM) /* That's all we need. */
|
|
||||||
break;
|
|
||||||
initial_stack += sizeof (auxv_t);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TRACE ("auxv: len_read: %d\n", len_read);
|
|
||||||
return len_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start inferior specified by PROGRAM, using PROGRAM_ARGS as its
|
|
||||||
arguments. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::create_inferior (const char *program,
|
|
||||||
const std::vector<char *> &program_args)
|
|
||||||
{
|
|
||||||
struct inheritance inherit;
|
|
||||||
pid_t pid;
|
|
||||||
sigset_t set;
|
|
||||||
|
|
||||||
TRACE ("%s %s\n", __func__, program);
|
|
||||||
/* Clear any pending SIGUSR1's but keep the behavior the same. */
|
|
||||||
signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
|
|
||||||
|
|
||||||
sigemptyset (&set);
|
|
||||||
sigaddset (&set, SIGUSR1);
|
|
||||||
sigprocmask (SIG_UNBLOCK, &set, NULL);
|
|
||||||
|
|
||||||
memset (&inherit, 0, sizeof (inherit));
|
|
||||||
inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
|
|
||||||
inherit.pgroup = SPAWN_NEWPGROUP;
|
|
||||||
pid = spawnp (program, 0, NULL, &inherit,
|
|
||||||
program_args.data (), 0);
|
|
||||||
sigprocmask (SIG_BLOCK, &set, NULL);
|
|
||||||
|
|
||||||
if (pid == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (do_attach (pid) != pid)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attach to process PID. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::attach (unsigned long pid)
|
|
||||||
{
|
|
||||||
TRACE ("%s %ld\n", __func__, pid);
|
|
||||||
if (do_attach (pid) != pid)
|
|
||||||
error ("Unable to attach to %ld\n", pid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send signal to process PID. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::kill (process_info *proc)
|
|
||||||
{
|
|
||||||
int pid = proc->pid;
|
|
||||||
|
|
||||||
TRACE ("%s %d\n", __func__, pid);
|
|
||||||
kill (pid, SIGKILL);
|
|
||||||
do_detach ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detach from process PID. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::detach (process_info *proc)
|
|
||||||
{
|
|
||||||
TRACE ("%s %d\n", __func__, proc->pid);
|
|
||||||
do_detach ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nto_process_target::mourn (struct process_info *process)
|
|
||||||
{
|
|
||||||
remove_process (process);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nto_process_target::join (int pid)
|
|
||||||
{
|
|
||||||
error (_("nto target does not implement the join op"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the given thread is alive.
|
|
||||||
|
|
||||||
Return true if alive, false otherwise. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
nto_process_target::thread_alive (ptid_t ptid)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
TRACE ("%s pid:%d tid:%d\n", __func__, ptid.pid (),
|
|
||||||
ptid.lwp ());
|
|
||||||
if (SignalKill (0, ptid.pid (), ptid.lwp (),
|
|
||||||
0, 0, 0) == -1)
|
|
||||||
res = 0;
|
|
||||||
else
|
|
||||||
res = 1;
|
|
||||||
TRACE ("%s: %s\n", __func__, res ? "yes" : "no");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume inferior's execution. */
|
|
||||||
|
|
||||||
void
|
|
||||||
nto_process_target::resume (thread_resume *resume_info, size_t n)
|
|
||||||
{
|
|
||||||
/* We can only work in all-stop mode. */
|
|
||||||
procfs_status status;
|
|
||||||
procfs_run run;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
/* Workaround for aliasing rules violation. */
|
|
||||||
sigset_t *run_fault = (sigset_t *) (void *) &run.fault;
|
|
||||||
|
|
||||||
nto_set_thread (resume_info->thread);
|
|
||||||
|
|
||||||
run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
|
|
||||||
if (resume_info->kind == resume_step)
|
|
||||||
run.flags |= _DEBUG_RUN_STEP;
|
|
||||||
run.flags |= _DEBUG_RUN_ARM;
|
|
||||||
|
|
||||||
sigemptyset (run_fault);
|
|
||||||
sigaddset (run_fault, FLTBPT);
|
|
||||||
sigaddset (run_fault, FLTTRACE);
|
|
||||||
sigaddset (run_fault, FLTILL);
|
|
||||||
sigaddset (run_fault, FLTPRIV);
|
|
||||||
sigaddset (run_fault, FLTBOUNDS);
|
|
||||||
sigaddset (run_fault, FLTIOVF);
|
|
||||||
sigaddset (run_fault, FLTIZDIV);
|
|
||||||
sigaddset (run_fault, FLTFPE);
|
|
||||||
sigaddset (run_fault, FLTPAGE);
|
|
||||||
sigaddset (run_fault, FLTSTACK);
|
|
||||||
sigaddset (run_fault, FLTACCESS);
|
|
||||||
|
|
||||||
sigemptyset (&run.trace);
|
|
||||||
if (resume_info->sig)
|
|
||||||
{
|
|
||||||
int signal_to_pass;
|
|
||||||
|
|
||||||
devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
|
|
||||||
0);
|
|
||||||
signal_to_pass = resume_info->sig;
|
|
||||||
if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
|
|
||||||
{
|
|
||||||
if (signal_to_pass != status.info.si_signo)
|
|
||||||
{
|
|
||||||
kill (status.pid, signal_to_pass);
|
|
||||||
run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
|
|
||||||
}
|
|
||||||
else /* Let it kill the program without telling us. */
|
|
||||||
sigdelset (&run.trace, signal_to_pass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
|
|
||||||
|
|
||||||
sigfillset (&run.trace);
|
|
||||||
|
|
||||||
regcache_invalidate ();
|
|
||||||
|
|
||||||
err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
|
|
||||||
if (err != EOK)
|
|
||||||
TRACE ("Error: %d \"%s\"\n", err, safe_strerror (err));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for inferior's event.
|
|
||||||
|
|
||||||
Return ptid of thread that caused the event. */
|
|
||||||
|
|
||||||
ptid_t
|
|
||||||
nto_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
|
|
||||||
int target_options)
|
|
||||||
{
|
|
||||||
sigset_t set;
|
|
||||||
siginfo_t info;
|
|
||||||
procfs_status status;
|
|
||||||
const int trace_mask = (_DEBUG_FLAG_TRACE_EXEC | _DEBUG_FLAG_TRACE_RD
|
|
||||||
| _DEBUG_FLAG_TRACE_WR | _DEBUG_FLAG_TRACE_MODIFY);
|
|
||||||
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
|
||||||
|
|
||||||
sigemptyset (&set);
|
|
||||||
sigaddset (&set, SIGUSR1);
|
|
||||||
|
|
||||||
devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
|
|
||||||
while (!(status.flags & _DEBUG_FLAG_ISTOP))
|
|
||||||
{
|
|
||||||
sigwaitinfo (&set, &info);
|
|
||||||
devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
nto_find_new_threads (&nto_inferior);
|
|
||||||
|
|
||||||
if (status.flags & _DEBUG_FLAG_SSTEP)
|
|
||||||
{
|
|
||||||
TRACE ("SSTEP\n");
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
||||||
ourstatus->value.sig = GDB_SIGNAL_TRAP;
|
|
||||||
}
|
|
||||||
/* Was it a breakpoint? */
|
|
||||||
else if (status.flags & trace_mask)
|
|
||||||
{
|
|
||||||
TRACE ("STOPPED\n");
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
||||||
ourstatus->value.sig = GDB_SIGNAL_TRAP;
|
|
||||||
}
|
|
||||||
else if (status.flags & _DEBUG_FLAG_ISTOP)
|
|
||||||
{
|
|
||||||
TRACE ("ISTOP\n");
|
|
||||||
switch (status.why)
|
|
||||||
{
|
|
||||||
case _DEBUG_WHY_SIGNALLED:
|
|
||||||
TRACE (" SIGNALLED\n");
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
||||||
ourstatus->value.sig =
|
|
||||||
gdb_signal_from_host (status.info.si_signo);
|
|
||||||
nto_inferior.exit_signo = ourstatus->value.sig;
|
|
||||||
break;
|
|
||||||
case _DEBUG_WHY_FAULTED:
|
|
||||||
TRACE (" FAULTED\n");
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
||||||
if (status.info.si_signo == SIGTRAP)
|
|
||||||
{
|
|
||||||
ourstatus->value.sig = 0;
|
|
||||||
nto_inferior.exit_signo = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ourstatus->value.sig =
|
|
||||||
gdb_signal_from_host (status.info.si_signo);
|
|
||||||
nto_inferior.exit_signo = ourstatus->value.sig;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case _DEBUG_WHY_TERMINATED:
|
|
||||||
{
|
|
||||||
int waitval = 0;
|
|
||||||
|
|
||||||
TRACE (" TERMINATED\n");
|
|
||||||
waitpid (ptid.pid (), &waitval, WNOHANG);
|
|
||||||
if (nto_inferior.exit_signo)
|
|
||||||
{
|
|
||||||
/* Abnormal death. */
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
|
|
||||||
ourstatus->value.sig = nto_inferior.exit_signo;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Normal death. */
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_EXITED;
|
|
||||||
ourstatus->value.integer = WEXITSTATUS (waitval);
|
|
||||||
}
|
|
||||||
nto_inferior.exit_signo = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case _DEBUG_WHY_REQUESTED:
|
|
||||||
TRACE ("REQUESTED\n");
|
|
||||||
/* We are assuming a requested stop is due to a SIGINT. */
|
|
||||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
|
||||||
ourstatus->value.sig = GDB_SIGNAL_INT;
|
|
||||||
nto_inferior.exit_signo = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptid_t (status.pid, status.tid, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fetch inferior's registers for currently selected thread (CURRENT_INFERIOR).
|
|
||||||
If REGNO is -1, fetch all registers, or REGNO register only otherwise. */
|
|
||||||
|
|
||||||
void
|
|
||||||
nto_process_target::fetch_registers (regcache *regcache, int regno)
|
|
||||||
{
|
|
||||||
int regsize;
|
|
||||||
procfs_greg greg;
|
|
||||||
|
|
||||||
TRACE ("%s (regno=%d)\n", __func__, regno);
|
|
||||||
if (regno >= the_low_target.num_regs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (current_thread == NULL)
|
|
||||||
{
|
|
||||||
TRACE ("current_thread is NULL\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ptid_t ptid = ptid_of (current_thread);
|
|
||||||
if (!nto_set_thread (ptid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg),
|
|
||||||
®size) == EOK)
|
|
||||||
{
|
|
||||||
if (regno == -1) /* All registers. */
|
|
||||||
{
|
|
||||||
for (regno = 0; regno != the_low_target.num_regs; ++regno)
|
|
||||||
{
|
|
||||||
const unsigned int registeroffset
|
|
||||||
= the_low_target.register_offset (regno);
|
|
||||||
supply_register (regcache, regno,
|
|
||||||
((char *)&greg) + registeroffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const unsigned int registeroffset
|
|
||||||
= the_low_target.register_offset (regno);
|
|
||||||
if (registeroffset == -1)
|
|
||||||
return;
|
|
||||||
supply_register (regcache, regno, ((char *)&greg) + registeroffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
TRACE ("ERROR reading registers from inferior.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store registers for currently selected thread (CURRENT_INFERIOR).
|
|
||||||
We always store all registers, regardless of REGNO. */
|
|
||||||
|
|
||||||
void
|
|
||||||
nto_process_target::store_registers (regcache *regcache, int regno)
|
|
||||||
{
|
|
||||||
procfs_greg greg;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
TRACE ("%s (regno:%d)\n", __func__, regno);
|
|
||||||
|
|
||||||
if (current_thread == NULL)
|
|
||||||
{
|
|
||||||
TRACE ("current_thread is NULL\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ptid_t ptid = ptid_of (current_thread);
|
|
||||||
if (!nto_set_thread (ptid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
memset (&greg, 0, sizeof (greg));
|
|
||||||
for (regno = 0; regno != the_low_target.num_regs; ++regno)
|
|
||||||
{
|
|
||||||
const unsigned int regoffset
|
|
||||||
= the_low_target.register_offset (regno);
|
|
||||||
collect_register (regcache, regno, ((char *)&greg) + regoffset);
|
|
||||||
}
|
|
||||||
err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg),
|
|
||||||
0);
|
|
||||||
if (err != EOK)
|
|
||||||
TRACE ("Error: setting registers.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read LEN bytes from inferior's memory address MEMADDR into
|
|
||||||
gdbserver's MYADDR buffer.
|
|
||||||
|
|
||||||
Return 0 on success -1 otherwise. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::read_memory (CORE_ADDR memaddr, unsigned char *myaddr,
|
|
||||||
int len)
|
|
||||||
{
|
|
||||||
TRACE ("%s memaddr:0x%08lx, len:%d\n", __func__, memaddr, len);
|
|
||||||
|
|
||||||
if (nto_xfer_memory (memaddr, myaddr, len, 0) != len)
|
|
||||||
{
|
|
||||||
TRACE ("Failed to read memory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write LEN bytes from gdbserver's buffer MYADDR into inferior's
|
|
||||||
memory at address MEMADDR.
|
|
||||||
|
|
||||||
Return 0 on success -1 otherwise. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::write_memory (CORE_ADDR memaddr,
|
|
||||||
const unsigned char *myaddr, int len)
|
|
||||||
{
|
|
||||||
int len_written;
|
|
||||||
|
|
||||||
TRACE ("%s memaddr: 0x%08llx len: %d\n", __func__, memaddr, len);
|
|
||||||
if ((len_written = nto_xfer_memory (memaddr, (unsigned char *)myaddr, len,
|
|
||||||
1))
|
|
||||||
!= len)
|
|
||||||
{
|
|
||||||
TRACE ("Wanted to write: %d but written: %d\n", len, len_written);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop inferior. We always stop all threads. */
|
|
||||||
|
|
||||||
void
|
|
||||||
nto_process_target::request_interrupt ()
|
|
||||||
{
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
nto_set_thread (ptid_t (nto_inferior.pid, 1, 0));
|
|
||||||
if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0))
|
|
||||||
TRACE ("Error stopping inferior.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
nto_process_target::supports_read_auxv ()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read auxiliary vector from inferior's memory into gdbserver's buffer
|
|
||||||
MYADDR. We always read whole auxv.
|
|
||||||
|
|
||||||
Return number of bytes stored in MYADDR buffer, 0 if OFFSET > 0
|
|
||||||
or -1 on error. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::read_auxv (CORE_ADDR offset, unsigned char *myaddr,
|
|
||||||
unsigned int len)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
CORE_ADDR initial_stack;
|
|
||||||
procfs_info procinfo;
|
|
||||||
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
if (offset > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err = devctl (nto_inferior.ctl_fd, DCMD_PROC_INFO, &procinfo,
|
|
||||||
sizeof procinfo, 0);
|
|
||||||
if (err != EOK)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
initial_stack = procinfo.initial_stack;
|
|
||||||
|
|
||||||
return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
nto_process_target::supports_z_point_type (char z_type)
|
|
||||||
{
|
|
||||||
switch (z_type)
|
|
||||||
{
|
|
||||||
case Z_PACKET_SW_BP:
|
|
||||||
case Z_PACKET_HW_BP:
|
|
||||||
case Z_PACKET_WRITE_WP:
|
|
||||||
case Z_PACKET_READ_WP:
|
|
||||||
case Z_PACKET_ACCESS_WP:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert {break/watch}point at address ADDR. SIZE is not used. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
|
|
||||||
int size, raw_breakpoint *bp)
|
|
||||||
{
|
|
||||||
int wtype = _DEBUG_BREAK_HW; /* Always request HW. */
|
|
||||||
|
|
||||||
TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, size);
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case raw_bkpt_type_sw:
|
|
||||||
wtype = _DEBUG_BREAK_EXEC;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_hw:
|
|
||||||
wtype |= _DEBUG_BREAK_EXEC;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_write_wp:
|
|
||||||
wtype |= _DEBUG_BREAK_RW;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_read_wp:
|
|
||||||
wtype |= _DEBUG_BREAK_RD;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_access_wp:
|
|
||||||
wtype |= _DEBUG_BREAK_RW;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 1; /* Not supported. */
|
|
||||||
}
|
|
||||||
return nto_breakpoint (addr, wtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove {break/watch}point at address ADDR. SIZE is not used. */
|
|
||||||
|
|
||||||
int
|
|
||||||
nto_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
|
|
||||||
int size, raw_breakpoint *bp)
|
|
||||||
{
|
|
||||||
int wtype = _DEBUG_BREAK_HW; /* Always request HW. */
|
|
||||||
|
|
||||||
TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, size);
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case raw_bkpt_type_sw:
|
|
||||||
wtype = _DEBUG_BREAK_EXEC;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_hw:
|
|
||||||
wtype |= _DEBUG_BREAK_EXEC;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_write_wp:
|
|
||||||
wtype |= _DEBUG_BREAK_RW;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_read_wp:
|
|
||||||
wtype |= _DEBUG_BREAK_RD;
|
|
||||||
break;
|
|
||||||
case raw_bkpt_type_access_wp:
|
|
||||||
wtype |= _DEBUG_BREAK_RW;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 1; /* Not supported. */
|
|
||||||
}
|
|
||||||
return nto_breakpoint (addr, wtype, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
nto_process_target::supports_hardware_single_step ()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the reason of stop for current thread (CURRENT_INFERIOR) is
|
|
||||||
a watchpoint.
|
|
||||||
|
|
||||||
Return true if stopped by watchpoint, false otherwise. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
nto_process_target::stopped_by_watchpoint ()
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
if (nto_inferior.ctl_fd != -1 && current_thread != NULL)
|
|
||||||
{
|
|
||||||
ptid_t ptid = ptid_of (current_thread);
|
|
||||||
if (nto_set_thread (ptid))
|
|
||||||
{
|
|
||||||
const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR
|
|
||||||
| _DEBUG_FLAG_TRACE_MODIFY;
|
|
||||||
procfs_status status;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
|
|
||||||
sizeof (status), 0);
|
|
||||||
if (err == EOK && (status.flags & watchmask))
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TRACE ("%s: %s\n", __func__, ret ? "yes" : "no");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get instruction pointer for CURRENT_INFERIOR thread.
|
|
||||||
|
|
||||||
Return inferior's instruction pointer value, or 0 on error. */
|
|
||||||
|
|
||||||
CORE_ADDR
|
|
||||||
nto_process_target::stopped_data_address ()
|
|
||||||
{
|
|
||||||
CORE_ADDR ret = (CORE_ADDR)0;
|
|
||||||
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
if (nto_inferior.ctl_fd != -1 && current_thread != NULL)
|
|
||||||
{
|
|
||||||
ptid_t ptid = ptid_of (current_thread);
|
|
||||||
|
|
||||||
if (nto_set_thread (ptid))
|
|
||||||
{
|
|
||||||
procfs_status status;
|
|
||||||
|
|
||||||
if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
|
|
||||||
sizeof (status), 0) == EOK)
|
|
||||||
ret = status.ip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TRACE ("%s: 0x%08lx\n", __func__, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implementation of the target_ops method "sw_breakpoint_from_kind". */
|
|
||||||
|
|
||||||
const gdb_byte *
|
|
||||||
nto_process_target::sw_breakpoint_from_kind (int kind, int *size)
|
|
||||||
{
|
|
||||||
*size = the_low_target.breakpoint_len;
|
|
||||||
return the_low_target.breakpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The QNX Neutrino target ops object. */
|
|
||||||
|
|
||||||
static nto_process_target the_nto_target;
|
|
||||||
|
|
||||||
/* Global function called by server.c. Initializes QNX Neutrino
|
|
||||||
gdbserver. */
|
|
||||||
|
|
||||||
void
|
|
||||||
initialize_low (void)
|
|
||||||
{
|
|
||||||
sigset_t set;
|
|
||||||
|
|
||||||
TRACE ("%s\n", __func__);
|
|
||||||
set_target_ops (&the_nto_target);
|
|
||||||
|
|
||||||
/* We use SIGUSR1 to gain control after we block waiting for a process.
|
|
||||||
We use sigwaitevent to wait. */
|
|
||||||
sigemptyset (&set);
|
|
||||||
sigaddset (&set, SIGUSR1);
|
|
||||||
sigprocmask (SIG_BLOCK, &set, NULL);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
/* Internal interfaces for the QNX Neutrino specific target code for gdbserver.
|
|
||||||
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/>. */
|
|
||||||
|
|
||||||
#ifndef GDBSERVER_NTO_LOW_H
|
|
||||||
#define GDBSERVER_NTO_LOW_H
|
|
||||||
|
|
||||||
struct target_desc;
|
|
||||||
|
|
||||||
enum regset_type
|
|
||||||
{
|
|
||||||
NTO_REG_GENERAL,
|
|
||||||
NTO_REG_FLOAT,
|
|
||||||
NTO_REG_SYSTEM,
|
|
||||||
NTO_REG_ALT,
|
|
||||||
NTO_REG_END
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nto_target_ops
|
|
||||||
{
|
|
||||||
/* Architecture specific setup. */
|
|
||||||
void (*arch_setup) (void);
|
|
||||||
int num_regs;
|
|
||||||
int (*register_offset) (int gdbregno);
|
|
||||||
const unsigned char *breakpoint;
|
|
||||||
int breakpoint_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct nto_target_ops the_low_target;
|
|
||||||
|
|
||||||
/* Target ops definitions for a QNX Neutrino target. */
|
|
||||||
|
|
||||||
class nto_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_read_auxv () override;
|
|
||||||
|
|
||||||
int read_auxv (CORE_ADDR offset, unsigned char *myaddr,
|
|
||||||
unsigned int len) override;
|
|
||||||
|
|
||||||
bool supports_z_point_type (char z_type) override;
|
|
||||||
|
|
||||||
int insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
|
|
||||||
int size, raw_breakpoint *bp) override;
|
|
||||||
|
|
||||||
int remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
|
|
||||||
int size, raw_breakpoint *bp) override;
|
|
||||||
|
|
||||||
bool supports_hardware_single_step () override;
|
|
||||||
|
|
||||||
bool stopped_by_watchpoint () override;
|
|
||||||
|
|
||||||
CORE_ADDR stopped_data_address () 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 *nto_tdesc;
|
|
||||||
|
|
||||||
#endif /* GDBSERVER_NTO_LOW_H */
|
|
|
@ -1,109 +0,0 @@
|
||||||
/* QNX Neutrino specific low level interface, for the remote server
|
|
||||||
for GDB.
|
|
||||||
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 "nto-low.h"
|
|
||||||
#include "regdef.h"
|
|
||||||
#include "regcache.h"
|
|
||||||
|
|
||||||
#include <x86/context.h>
|
|
||||||
#include "gdbsupport/x86-xstate.h"
|
|
||||||
#include "arch/i386.h"
|
|
||||||
#include "x86-tdesc.h"
|
|
||||||
|
|
||||||
const unsigned char x86_breakpoint[] = { 0xCC };
|
|
||||||
#define x86_breakpoint_len 1
|
|
||||||
|
|
||||||
/* Returns offset in appropriate Neutrino's context structure.
|
|
||||||
Defined in x86/context.h.
|
|
||||||
GDBREGNO is index into regs_i386 array. It is autogenerated and
|
|
||||||
hopefully doesn't change. */
|
|
||||||
static int
|
|
||||||
nto_x86_register_offset (int gdbregno)
|
|
||||||
{
|
|
||||||
if (gdbregno >= 0 && gdbregno < 16)
|
|
||||||
{
|
|
||||||
X86_CPU_REGISTERS *dummy = (void*)0;
|
|
||||||
/* GPRs */
|
|
||||||
switch (gdbregno)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return (int)&(dummy->eax);
|
|
||||||
case 1:
|
|
||||||
return (int)&(dummy->ecx);
|
|
||||||
case 2:
|
|
||||||
return (int)&(dummy->edx);
|
|
||||||
case 3:
|
|
||||||
return (int)&(dummy->ebx);
|
|
||||||
case 4:
|
|
||||||
return (int)&(dummy->esp);
|
|
||||||
case 5:
|
|
||||||
return (int)&(dummy->ebp);
|
|
||||||
case 6:
|
|
||||||
return (int)&(dummy->esi);
|
|
||||||
case 7:
|
|
||||||
return (int)&(dummy->edi);
|
|
||||||
case 8:
|
|
||||||
return (int)&(dummy->eip);
|
|
||||||
case 9:
|
|
||||||
return (int)&(dummy->efl);
|
|
||||||
case 10:
|
|
||||||
return (int)&(dummy->cs);
|
|
||||||
case 11:
|
|
||||||
return (int)&(dummy->ss);
|
|
||||||
#ifdef __SEGMENTS__
|
|
||||||
case 12:
|
|
||||||
return (int)&(dummy->ds);
|
|
||||||
case 13:
|
|
||||||
return (int)&(dummy->es);
|
|
||||||
case 14:
|
|
||||||
return (int)&(dummy->fs);
|
|
||||||
case 15:
|
|
||||||
return (int)&(dummy->gs);
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nto_x86_arch_setup (void)
|
|
||||||
{
|
|
||||||
the_low_target.num_regs = 16;
|
|
||||||
struct target_desc *tdesc
|
|
||||||
= i386_create_target_description (X86_XSTATE_SSE_MASK, false, false);
|
|
||||||
|
|
||||||
init_target_desc (tdesc, i386_expedite_regs);
|
|
||||||
|
|
||||||
nto_tdesc = tdesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct nto_target_ops the_low_target =
|
|
||||||
{
|
|
||||||
nto_x86_arch_setup,
|
|
||||||
0, /* num_regs */
|
|
||||||
nto_x86_register_offset,
|
|
||||||
x86_breakpoint,
|
|
||||||
x86_breakpoint_len
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,6 @@
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __QNX__
|
|
||||||
#include <sys/iomgr.h>
|
|
||||||
#endif /* __QNX__ */
|
|
||||||
|
|
||||||
#ifndef HAVE_SOCKLEN_T
|
#ifndef HAVE_SOCKLEN_T
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
#endif
|
#endif
|
||||||
|
@ -804,28 +800,6 @@ block_unblock_async_io (int block)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __QNX__
|
|
||||||
static void
|
|
||||||
nto_comctrl (int enable)
|
|
||||||
{
|
|
||||||
struct sigevent event;
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
{
|
|
||||||
event.sigev_notify = SIGEV_SIGNAL_THREAD;
|
|
||||||
event.sigev_signo = SIGIO;
|
|
||||||
event.sigev_code = 0;
|
|
||||||
event.sigev_value.sival_ptr = NULL;
|
|
||||||
event.sigev_priority = -1;
|
|
||||||
ionotify (remote_desc, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT,
|
|
||||||
&event);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ionotify (remote_desc, _NOTIFY_ACTION_POLL, _NOTIFY_COND_INPUT, NULL);
|
|
||||||
}
|
|
||||||
#endif /* __QNX__ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Current state of asynchronous I/O. */
|
/* Current state of asynchronous I/O. */
|
||||||
static int async_io_enabled;
|
static int async_io_enabled;
|
||||||
|
|
||||||
|
@ -839,9 +813,6 @@ enable_async_io (void)
|
||||||
block_unblock_async_io (0);
|
block_unblock_async_io (0);
|
||||||
|
|
||||||
async_io_enabled = 1;
|
async_io_enabled = 1;
|
||||||
#ifdef __QNX__
|
|
||||||
nto_comctrl (1);
|
|
||||||
#endif /* __QNX__ */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable asynchronous I/O. */
|
/* Disable asynchronous I/O. */
|
||||||
|
@ -854,10 +825,6 @@ disable_async_io (void)
|
||||||
block_unblock_async_io (1);
|
block_unblock_async_io (1);
|
||||||
|
|
||||||
async_io_enabled = 0;
|
async_io_enabled = 0;
|
||||||
#ifdef __QNX__
|
|
||||||
nto_comctrl (0);
|
|
||||||
#endif /* __QNX__ */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in New Issue