From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5994 invoked by alias); 17 Jun 2009 15:05:18 -0000 Received: (qmail 5962 invoked by uid 22791); 17 Jun 2009 15:05:15 -0000 X-SWARE-Spam-Status: No, hits=-1.0 required=5.0 tests=AWL,BAYES_00,HK_OBFDOM,J_CHICKENPOX_34,J_CHICKENPOX_35,J_CHICKENPOX_63,J_CHICKENPOX_75,J_CHICKENPOX_92,J_CHICKENPOX_93,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from main.gmane.org (HELO ciao.gmane.org) (80.91.229.2) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 17 Jun 2009 15:05:05 +0000 Received: from list by ciao.gmane.org with local (Exim 4.43) id 1MGwhA-0007lc-Mw for gdb-patches@sources.redhat.com; Wed, 17 Jun 2009 15:05:00 +0000 Received: from mobius.qnx.com ([209.226.137.108]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Wed, 17 Jun 2009 15:05:00 +0000 Received: from aristovski by mobius.qnx.com with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Wed, 17 Jun 2009 15:05:00 +0000 To: gdb-patches@sources.redhat.com From: Aleksandar Ristovski Subject: [patch] gdbserver: Add qnx target Date: Wed, 17 Jun 2009 15:05:00 -0000 Message-ID: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------000505050904010709030208" User-Agent: Thunderbird 2.0.0.21 (Windows/20090302) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-06/txt/msg00435.txt.bz2 This is a multi-part message in MIME format. --------------000505050904010709030208 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1092 Hello, This patch adds QNX Neutrino gdbserver. The server is in working order. It does not support multiprocess. Patch depends on http://sourceware.org/ml/gdb-patches/2009-06/msg00428.html The patch is quite straight-forward. The only more invasive change is the change to configure.ac and Makefile.in. This is why I am attaching two patches and two change logs. 1) gdbserver-extra_srv_libs - ChangeLog (Note: this patch is not complete, I could not regenerate configure since I do not have autoconf version 2.59, I would appreciate if someone could generate if for me). * Makefile.in (gdbreplay): Add $(GDBSERVER_LIBS) to linking step. * configure.ac (GDBSERVER_LIBS): Add $extra_srv_libs. 2) gdbserver-ntotarget - ChangeLog * configure.srv (i[34567]86-*-nto*): New target. * nto-low.c, nto-low.h, nto-x86-low.c: New files. * remote-utils.c (include sys/iomgr.h): New include for __QNX__ only. (nto_comctrl): New function for __QNX__ only. (enable_async_io, disable_async_io): Call nto_comcntrl for __QNX__ only. Thank you, -- Aleksandar Ristovski QNX Software Systems --------------000505050904010709030208 Content-Type: text/x-patch; name="gdbserver-extra_srv_libs-20090617.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gdbserver-extra_srv_libs-20090617.diff" Content-length: 1248 Index: Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v retrieving revision 1.74 diff -u -p -r1.74 Makefile.in --- Makefile.in 12 May 2009 22:25:00 -0000 1.74 +++ Makefile.in 17 Jun 2009 14:45:09 -0000 @@ -181,7 +181,7 @@ gdbserver$(EXEEXT): $(OBS) ${ADD_DEPS} $ gdbreplay$(EXEEXT): $(GDBREPLAY_OBS) rm -f gdbreplay$(EXEEXT) ${CC-LD} $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) -o gdbreplay$(EXEEXT) $(GDBREPLAY_OBS) \ - $(XM_CLIBS) + $(GDBSERVER_LIBS) $(XM_CLIBS) # Put the proper machine-specific files first, so M-. on a machine # specific routine gets the one for the correct machine. Index: configure.ac =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v retrieving revision 1.25 diff -u -p -r1.25 configure.ac --- configure.ac 22 Mar 2009 23:57:10 -0000 1.25 +++ configure.ac 17 Jun 2009 14:45:09 -0000 @@ -182,7 +182,7 @@ if test "$srv_xmlfiles" != ""; then fi GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_hostio_err_objs $srv_thread_depfiles" -GDBSERVER_LIBS="$srv_libs" +GDBSERVER_LIBS="$srv_libs $extra_srv_libs" AC_SUBST(GDBSERVER_DEPFILES) AC_SUBST(GDBSERVER_LIBS) --------------000505050904010709030208 Content-Type: text/x-patch; name="gdbserver-ntotarget-20090617.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gdbserver-ntotarget-20090617.diff" Content-length: 24991 diff -upN ../../../srcclean/gdb/gdbserver/configure.srv ./configure.srv --- ../../../srcclean/gdb/gdbserver/configure.srv 2009-05-26 09:56:20.000000000 -0400 +++ ./configure.srv 2009-06-15 12:51:09.000000000 -0400 @@ -74,6 +74,10 @@ case "${target}" in srv_tgtobj="win32-low.o win32-i386-low.o" srv_mingw=yes ;; + i[34567]86-*-nto*) srv_regobj=reg-i386.o + srv_tgtobj="nto-low.o nto-x86-low.o" + extra_srv_libs=-lsocket + ;; ia64-*-linux*) srv_regobj=reg-ia64.o srv_tgtobj="linux-low.o linux-ia64-low.o" srv_linux_usrregs=yes diff -upN ../../../srcclean/gdb/gdbserver/nto-low.c ./nto-low.c --- ../../../srcclean/gdb/gdbserver/nto-low.c 1969-12-31 19:00:00.000000000 -0500 +++ ./nto-low.c 2009-06-17 10:24:02.000000000 -0400 @@ -0,0 +1,761 @@ +/* QNX Neutrino specific low level interface, for the remote server + for GDB. + Copyright (C) 2009 + 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 "nto-low.h" + +#include +#include +#include +#include +#include +#include +#include + +#define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\ + _DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY) + + +extern int using_threads; +int using_threads = 1; + +void nto_trace (const char *fmt, ...) +{ + va_list arg_list; + + if (debug_threads == 0) + return; + + printf ("nto:"); + va_start (arg_list, fmt); + vprintf (fmt, arg_list); + va_end (arg_list); +} + +#define TRACE nto_trace + +struct nto_inferior +{ + char nto_procfs_path[PATH_MAX]; + int ctl_fd; +}; + +static struct nto_inferior nto_inferior; + +static void +do_detach () +{ + if (nto_inferior.ctl_fd != -1) + { + nto_trace ("Closing fd\n"); + close (nto_inferior.ctl_fd); + nto_inferior.ctl_fd = -1; + } +} + +/* Given pid, open procfs path. Return ptid built from pid,0,tid. */ + +static ptid_t +do_attach (ptid_t ptid) +{ + procfs_status status; + struct sigevent event; + + if (nto_inferior.ctl_fd != -1) + { + close (nto_inferior.ctl_fd); + nto_inferior.ctl_fd = -1; + } + + snprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", + ptid_get_pid (ptid)); + 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); + return ptid_build (0, 0, 0); + } + + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) + != EOK) + { + do_detach (); + return ptid_build (0, 0, 0); + } + + /* 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)) + { + kill (ptid_get_pid (ptid), SIGCONT); + ptid = ptid_build (status.pid, status.tid, 0); + the_low_target.arch_setup (); + add_process (status.pid, 1); + TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid, + ptid_get_lwp (ptid)); + add_thread (ptid, NULL); + } + else + { + do_detach (); + ptid = ptid_build (0, 0, 0); + } + + return ptid; +} + +static void +nto_set_thread (ptid_t ptid) +{ + pid_t tid; + + TRACE ("%s pid: %d tid: %ld\n", __func__, ptid_get_pid (ptid), + ptid_get_lwp (ptid)); + + if (nto_inferior.ctl_fd != -1) + { + tid = ptid_get_lwp (ptid); + if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid, + sizeof (tid), 0)) + TRACE ("ERROR: setting current thread\n"); + } +} + +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, strerror (e)); + } + return (nbytes); +} + +static int +nto_breakpoint (CORE_ADDR addr, int type, int size) +{ + procfs_break brk; + + brk.type = type; + brk.addr = addr; + brk.size = size; + errno = devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0); + if (errno != EOK) + return 1; + return 0; +} + + +/* Read AUXV from initial_stack. */ +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... (see comment in ldd.c) */ + 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 passing arguments ALLARGS. */ + +static int +nto_create_inferior (char *program, char **allargs) +{ + 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, allargs, 0); + sigprocmask (SIG_BLOCK, &set, NULL); + + if (pid == -1) + return 0; + + do_attach (ptid_build (pid, 0, 0)); + + return pid; +} + +static int +nto_attach (unsigned long pid) +{ + TRACE ("%s %ld\n", __func__, pid); + do_attach (ptid_build (pid, 0, 0)); + return 0; +} + +static int +nto_kill (int pid) +{ + TRACE ("%s %d\n", __func__, pid); + kill (pid, SIGKILL); + do_detach (); + return 0; +} + +static int +nto_detach (int pid) +{ + TRACE ("%s %d\n", __func__, pid); + do_detach (); + return 0; +} + +static int +nto_thread_alive (ptid_t ptid) +{ + pid_t tid; + + tid = ptid_get_lwp (ptid); + TRACE ("%s %d\n", __func__, tid); + if (devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) + == EOK) + return 1; + return 0; +} + +static void +nto_resume (struct thread_resume *resume_info, size_t n) +{ + /* We can only work in all-stop mode. */ + procfs_status status; + procfs_run run; + int err; + + /* Workaround for aliasing rules violation. */ + sigset_t *run_fault = (sigset_t *) (void *) &run.fault; + + TRACE ("%s\n", __func__); + + 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; + + 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); + + run.flags |= _DEBUG_RUN_ARM; + + 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; + + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0); + if (err != EOK) + TRACE ("Error: %d\n", err); + regcache_invalidate (); +} + +static void nto_fetch_registers (int regno); + +static ptid_t +nto_wait (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) +{ + sigset_t set; + siginfo_t info; + procfs_status status; + static int exit_signo = 0; /* For tracking exit status. */ + + TRACE ("%s\n", __func__); + + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + + if (ptid_equal (ptid, null_ptid)) + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_SIGNAL_0; + exit_signo = 0; + TRACE ("null_ptid...\n"); + return null_ptid; + } + + regcache_invalidate (); + + 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); + } + + if (status.flags & _DEBUG_FLAG_SSTEP) + { + TRACE ("SSTEP\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_SIGNAL_TRAP; + } + /* Was it a breakpoint? */ + else if (status.flags & _DEBUG_FLAG_TRACE) + { + TRACE ("STOPPED\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = TARGET_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 = + target_signal_from_host (status.info.si_signo); + exit_signo = 0; + break; + case _DEBUG_WHY_FAULTED: + TRACE (" FAULTED\n"); + ourstatus->kind = TARGET_WAITKIND_STOPPED; + if (status.info.si_signo == SIGTRAP) + { + ourstatus->value.sig = 0; + exit_signo = 0; + } + else + { + ourstatus->value.sig = + target_signal_from_host (status.info.si_signo); + exit_signo = ourstatus->value.sig; + } + break; + + case _DEBUG_WHY_TERMINATED: + { + int waitval = 0; + + TRACE (" TERMINATED\n"); + waitpid (ptid_get_pid (ptid), &waitval, WNOHANG); + if (exit_signo) + { + /* Abnormal death. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = exit_signo; + } + else + { + /* Normal death. */ + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (waitval); + } + 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 = TARGET_SIGNAL_INT; + exit_signo = 0; + break; + } + } + + return ptid_build (status.pid, status.tid, 0); +} + +static void +nto_fetch_registers (int regno) +{ + int regsize; + procfs_greg greg; + + TRACE ("%s (regno=%d)\n", __func__, regno); + if (regno >= the_low_target.num_regs) + 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 (regno, ((char *)&greg) + registeroffset); + if (regno == 8) + TRACE ("eip=0x%08x\n", greg.x86.eip); + } + } + else + { + const unsigned int registeroffset + = the_low_target.register_offset (regno); + if (registeroffset == -1) + return; + supply_register (regno, ((char *)&greg) + registeroffset); + } + } + else + { + TRACE ("ERROR reading registers from inferior.\n"); + } +} + +static void +nto_store_registers (int regno) +{ + int reg; + procfs_greg greg; + int err; + + memset (&greg, 0, sizeof (greg)); + + TRACE ("%s (regno:%d)\n", __func__, regno); + for (reg = 0; reg != the_low_target.num_regs; ++reg) + { + const unsigned int regoffset + = the_low_target.register_offset (regno); + collect_register (reg, ((char *)&greg) + regoffset); + } + if (greg.x86.eip != 0) + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg), + 0); + reg = greg.x86.eip; + TRACE ("eip=0x%08x\n", reg); + if (err != EOK) + TRACE ("Error: setting registers.\n"); +} + +static int +nto_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + TRACE ("%s\n", __func__); + + if (nto_xfer_memory (memaddr, myaddr, len, 0) != len) + { + TRACE ("Failed to read memory\n"); + return -1; + } + + return 0; +} + +static int +nto_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; +} + +static void +nto_request_interrupt (void) +{ + procfs_status status; + + TRACE (__func__); + devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0); +} + +static int +nto_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; + + /* Similar as in the case of a core file, we read auxv from + initial_stack. */ + initial_stack = procinfo.initial_stack; + + /* procfs is always 'self-hosted', no byte-order manipulation. */ + return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len); +} + +static int +nto_insert_watchpoint (char type, CORE_ADDR addr, int len) +{ + TRACE ("%s type:%c\n", __func__, type); + switch (type) + { + case '0': /* software-breakpoint */ + return nto_breakpoint (addr, _DEBUG_BREAK_EXEC, 0); + case '1': /* hardware-breakpoint */ + return nto_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0); + } + /* Not supported */ + return 1; +} + +static int +nto_remove_watchpoint (char type, CORE_ADDR addr, int len) +{ + TRACE ("%s\n", __func__); + switch (type) + { + case '0': /* software-breakpoint */ + return nto_breakpoint (addr, _DEBUG_BREAK_EXEC, -1); + case '1': /* hardware-breakpoint */ + return nto_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1); + } + /* Not supported. */ + return 1; +} + +static int +nto_stopped_by_watchpoint (void) +{ + procfs_status status; + int ret = 0; + + TRACE ("%s...", __func__); + if (nto_inferior.ctl_fd != -1) + { + devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), + 0); + if (status.flags & _DEBUG_FLAG_ISTOP) + ret = 1; + } + ret = 0; + TRACE ("%s\n", ret ? "yes" : "no"); + return ret; +} + +static int +nto_insert_breakpoint (char type, CORE_ADDR addr) +{ + TRACE ("%s\n", __func__); + + return nto_insert_watchpoint (type, addr, 1); +} + +static int +nto_remove_breakpoint (char type, CORE_ADDR addr) +{ + TRACE ("%s\n", __func__); + + return nto_remove_watchpoint (type, addr, 1); +} + +static CORE_ADDR +nto_stopped_data_address (void) +{ + procfs_status status; + CORE_ADDR ret = (CORE_ADDR)0; + + TRACE ("%s...", __func__); + if (nto_inferior.ctl_fd != -1) + { + int err; + err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, + sizeof (status), 0); + if (err == EOK) + ret = status.ip; + } + return ret; +} + + +static int +nto_supports_non_stop (void) +{ + TRACE ("%s\n", __func__); + return 0; +} + + + +static struct target_ops nto_target_ops = { + nto_create_inferior, + nto_attach, + nto_kill, + nto_detach, + NULL, /* nto_join */ + nto_thread_alive, + nto_resume, + nto_wait, + nto_fetch_registers, + nto_store_registers, + nto_read_memory, + nto_write_memory, + NULL, /* nto_look_up_symbols */ + nto_request_interrupt, + nto_read_auxv, + nto_insert_watchpoint, + nto_remove_watchpoint, + nto_stopped_by_watchpoint, + nto_insert_breakpoint, + nto_remove_breakpoint, + nto_stopped_data_address, + NULL, /* nto_read_offsets */ + NULL, /* thread_db_set_tls_address */ + NULL, + hostio_last_error_from_errno, + NULL, /* nto_qxfer_osdata */ + NULL, /* xfer_siginfo */ + nto_supports_non_stop, + NULL, /* async */ + NULL /* start_non_stop */ +}; + + +/* Global function called by server.c. Initializes QNX Neutrino + gdbserver. */ + +void +initialize_low (void) +{ + sigset_t set; + + TRACE ("%s\n", __func__); + set_target_ops (&nto_target_ops); + set_breakpoint_data (the_low_target.breakpoint, + the_low_target.breakpoint_len); + + /* 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); +} + diff -upN ../../../srcclean/gdb/gdbserver/nto-low.h ./nto-low.h --- ../../../srcclean/gdb/gdbserver/nto-low.h 1969-12-31 19:00:00.000000000 -0500 +++ ./nto-low.h 2009-06-16 21:55:47.000000000 -0400 @@ -0,0 +1,50 @@ +/* Internal interfaces for the QNX Neutrino specific target code for gdbserver. + Copyright (C) 2009 + 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 NTO_LOW_H +#define NTO_LOW_H + +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; + + +/* Activated by env. variable GDBSERVER_DEBUG. */ +extern int nto_debug; + +#endif + diff -upN ../../../srcclean/gdb/gdbserver/nto-x86-low.c ./nto-x86-low.c --- ../../../srcclean/gdb/gdbserver/nto-x86-low.c 1969-12-31 19:00:00.000000000 -0500 +++ ./nto-x86-low.c 2009-06-15 23:29:51.000000000 -0400 @@ -0,0 +1,108 @@ +/* QNX Neutrino specific low level interface, for the remote server + for GDB. + Copyright (C) 2009 + 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 "nto-low.h" +#include "regdef.h" +#include "regcache.h" + +#include + + +/* Definition auto generated from reg-i386.dep. */ +extern void init_registers_i386 (); +extern struct reg *regs_i386; + +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; + } + } + //TODO: FPU, XMM registers + return -1; +} + +static void +nto_x86_arch_setup (void) +{ + init_registers_i386 (); + the_low_target.num_regs = 16; +} + +struct nto_target_ops the_low_target = +{ + nto_x86_arch_setup, + 0, /* num_regs */ + nto_x86_register_offset, + x86_breakpoint, + x86_breakpoint_len +}; + + + diff -upN ../../../srcclean/gdb/gdbserver/remote-utils.c ./remote-utils.c --- ../../../srcclean/gdb/gdbserver/remote-utils.c 2009-05-26 09:56:20.000000000 -0400 +++ ./remote-utils.c 2009-06-17 10:31:17.000000000 -0400 @@ -66,6 +66,10 @@ #include #endif +#if __QNX__ +#include +#endif /* __QNX__ */ + #ifndef HAVE_SOCKLEN_T typedef int socklen_t; #endif @@ -814,6 +818,28 @@ unblock_async_io (void) #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. */ static int async_io_enabled; @@ -828,6 +854,9 @@ enable_async_io (void) signal (SIGIO, input_interrupt); #endif async_io_enabled = 1; +#ifdef __QNX__ + nto_comctrl (1); +#endif /* __QNX__ */ } /* Disable asynchronous I/O. */ @@ -841,6 +870,10 @@ disable_async_io (void) signal (SIGIO, SIG_IGN); #endif async_io_enabled = 0; +#ifdef __QNX__ + nto_comctrl (0); +#endif /* __QNX__ */ + } void --------------000505050904010709030208--