From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26774 invoked by alias); 15 Jun 2003 16:09:38 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 26576 invoked from network); 15 Jun 2003 16:09:33 -0000 Received: from unknown (HELO hub.ott.qnx.com) (209.226.137.76) by sources.redhat.com with SMTP; 15 Jun 2003 16:09:33 -0000 Received: from smtp.ott.qnx.com (smtp.ott.qnx.com [10.0.2.158]) by hub.ott.qnx.com (8.9.3p2/8.9.3) with ESMTP id MAA12195; Sun, 15 Jun 2003 12:03:05 -0400 Received: from dash ([192.168.20.26]) by smtp.ott.qnx.com (8.8.8/8.6.12) with SMTP id MAA26760; Sun, 15 Jun 2003 12:09:29 -0400 Message-ID: <006001c33359$e6cd5c70$2a00a8c0@dash> From: "Kris Warkentin" To: "Mark Kettenis" Cc: "Gdb-Patches@Sources.Redhat.Com" References: <001a01c3261c$313284c0$0202040a@catdog> <86ptlfh67k.fsf@elgar.kettenis.dyndns.org> Subject: Re: [Patch] Native QNX Neutrino support Date: Sun, 15 Jun 2003 16:09:00 -0000 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106 X-SW-Source: 2003-06/txt/msg00514.txt.bz2 > > ==================================== > > nto.mt > > ==================================== > > # Host: Intel 386 running QNX. > > > > NAT_FILE= nm-nto.h > > > > NATDEPFILES= nto-procfs.o > > What? This file should be named nto.mh. You'll probably want to set > XM_FILE here too. The ChangeLog entry for this should be fixed too. > > ==================================== > > nm-nto.h > > ==================================== > > #ifndef _NM_NTO_H > > #define _NM_NTO_H > > > > /* This file needed to build a native debugger. */ > > > > #endif > > Too bad this is needed, but that's not your fault. OK. > > > > > ==================================== > > nto-procfs.c > > ==================================== > > /* Machine independent support for QNX Neutrino /proc (process file system) > > for GDB. Written by Colin Burgess at QNX Software Systems Limited. > > > > Copyright 2003 Free Software Foundation, Inc. > > > > Contributed by QNX Software Systems Ltd. > > > > 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 2 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, write to the Free Software > > Foundation, Inc., 59 Temple Place - Suite 330, > > Boston, MA 02111-1307, USA. */ > > > > > > #include "defs.h" > > > > #include > > #include > > #include > > #include > > #include > > #include > > #include > > #include > > > > #include "gdb_string.h" > > #include "gdbcore.h" > > #include "inferior.h" > > #include "target.h" > > #include "objfiles.h" > > #include "gdbthread.h" > > #include "nto-tdep.h" > > #include "command.h" > > #include "regcache.h" > > > > #define NULL_PID 0 > > #define _DEBUG_FLAG_TRACE > > (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|_DEBUG_FLAG_TRACE_WR|_DEBUG_FLA > > G_TRACE_MODIFY) > > That line is too long. There are more lines that are too long. They > should be at most 72-chars, or at least less than 80-chars. Please fix. > > > static struct target_ops procfs_ops; > > > > int ctl_fd; > > > > static void (*ofunc) (); > > > > static procfs_run run; > > > > static void procfs_open (char *, int); > > > > static int procfs_can_run (void); > > > > static ptid_t procfs_wait (ptid_t, struct target_waitstatus *); > > > > static int procfs_xfer_memory (CORE_ADDR, char *, int, int, > > struct mem_attrib * attrib, struct target_ops *); > > > > static void procfs_fetch_registers (int); > > > > static void notice_signals (void); > > > > static void init_procfs_ops (void); > > > > static ptid_t do_attach (ptid_t ptid); > > > > static int procfs_can_use_hw_breakpoint (int, int, int); > > > > static int procfs_insert_hw_breakpoint (CORE_ADDR, char *); > > > > static int procfs_remove_hw_breakpoint (CORE_ADDR addr, char *); > > > > static int procfs_insert_hw_watchpoint > > (CORE_ADDR addr, int len, int type); > > > > static int procfs_remove_hw_watchpoint > > (CORE_ADDR addr, int len, int type); > > > > static int procfs_stopped_by_watchpoint (void); > > > > /* These two globals are only ever set in procfs_open(), but are > > referenced elsewhere. 'nto_procfs_node' is a flag used to say > > whether we are local, or we should get the current node descriptor > > for the remote QNX node. */ > > static char nto_procfs_path[PATH_MAX] = { "/proc" }; > > static unsigned nto_procfs_node = ND_LOCAL_NODE; > > > > /* This is a simple wrapper for the netmgr_strtond() function. It is > > only called from the QNX_NODE macro declared below. The reason for > > the macro and function are because QNX node descriptors are transient, > > so we have to re-acquire them every time. */ > > static unsigned > > procfs_nto_node (unsigned node) > > { > > if (node == -1) > > { > > error ("Lost the QNX node. Debug session probably over."); > > } > > return (node); > > } > > The braces here are redundant. Oh, and in error messages I suppose > there only needs to be one space after the full stop. > > > /* This define returns the current QNX Node, or -1 on error. It calls the > > above > > function which is a simple wrapper for the error() call. */ > > #define QNX_NODE (ND_NODE_CMP(nto_procfs_node, ND_LOCAL_NODE) == 0 ? > > ND_LOCAL_NODE : \ > > procfs_nto_node(netmgr_strtond(nto_procfs_path, 0))) > > > > /* This is called when we call 'target procfs ' from the (gdb) prompt. > > For QNX6 (nto), the only valid arg will be a QNX node string, > > eg: "/net/some_node". If arg is not a valid QNX node, we will > > default to local. */ > > static void > > procfs_open (char *arg, int from_tty) > > { > > char *nodestr; > > char *endstr; > > char buffer[50]; > > int fd, total_size; > > procfs_sysinfo *sysinfo; > > > > /* Set the default node used for spawning to this one, > > and only override it if there is a valid arg. */ > > > > nto_procfs_node = ND_LOCAL_NODE; > > nodestr = arg ? strdup (arg) : arg; > > > > init_thread_list (); > > > > if (nodestr) > > { > > nto_procfs_node = netmgr_strtond (nodestr, &endstr); > > if (nto_procfs_node == -1) > > { > > if (errno == ENOTSUP) > > printf_filtered ("QNX Net Manager not found.\n"); > > printf_filtered ("Invalid QNX node %s: error %d (%s).\n", nodestr, > > errno, strerror (errno)); > > xfree (nodestr); > > nodestr = NULL; > > nto_procfs_node = ND_LOCAL_NODE; > > } > > The indentation is all wrong here. Hmm, the attached file is all-right here. Looks like you need to use a decent MUA ;-). > > > else if (*endstr) > > { > > if (*(endstr - 1) == '/') > > *(endstr - 1) = 0; > > else > > *endstr = 0; > > } > > } > > sprintf (nto_procfs_path, "%s%s", nodestr ? nodestr : "", "/proc"); > > if (nodestr) > > xfree (nodestr); > > > > fd = open (nto_procfs_path, O_RDONLY); > > if (fd == -1) > > { > > printf_filtered ("Error opening %s : %d (%s)\n", nto_procfs_path, > > errno, > > strerror (errno)); > > error ("Invalid procfs arg"); > > } > > > > sysinfo = (void *) buffer; > > if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK) > > { > > printf_filtered ("Error getting size: %d (%s)\n", errno, > > strerror (errno)); > > close (fd); > > error ("Devctl failed."); > > } > > else > > { > > total_size = sysinfo->total_size; > > if (!(sysinfo = alloca (total_size))) > > { > > printf_filtered ("Memory error: %d (%s)\n", errno, > > strerror (errno)); > > close (fd); > > error ("alloca failed."); > > } > > else > > { > > if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, total_size, 0) != EOK) > > { > > printf_filtered ("Error getting sysinfo: %d (%s)\n", errno, > > strerror (errno)); > > close (fd); > > error ("Devctl failed."); > > } > > else > > { > > if (sysinfo->type != > > nto_map_arch_to_cputype(TARGET_ARCHITECTURE->arch_name)) > > { > > close (fd); > > error ("Invalid target CPU."); > > } > > } > > } > > } > > close (fd); > > printf_filtered ("Debugging using %s\n", nto_procfs_path); > > > > } > > Please remove the whitespace before the closing brace. > > > > > static void > > procfs_set_thread (ptid_t ptid) > > { > > pid_t tid; > > > > tid = ptid_get_tid (ptid); > > devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0); > > } > > > > /* Return nonzero if the thread TH is still alive. */ > > static int > > procfs_thread_alive (ptid_t ptid) > > { > > pid_t tid; > > > > tid = ptid_get_tid (ptid); > > if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK) > > return 1; > > return 0; > > } > > > > > > void > > procfs_find_new_threads (void) > > { > > procfs_status status; > > pid_t pid; > > ptid_t ptid; > > > > if (ctl_fd == -1) > > return; > > > > pid = ptid_get_pid (inferior_ptid); > > > > for (status.tid = 1;; ++status.tid) > > { > > if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0) > > != > > EOK && status.tid != 0) > > { > > break; > > } > > ptid = ptid_build (pid, 0, status.tid); > > if (!in_thread_list (ptid)) > > add_thread (ptid); > > } > > return; > > } > > > > void > > procfs_pidlist (char *args, int from_tty) > > { > > static DIR *dp = NULL; > > Why is this static? > > > struct dirent *dirp = NULL; > > int fd = -1; > > char buf[512]; > > procfs_info *pidinfo = NULL; > > procfs_debuginfo *info = NULL; > > procfs_status *status = NULL; > > pid_t num_threads = 0; > > pid_t pid; > > char name[512]; > > > > dp = opendir (nto_procfs_path); > > if (dp == NULL) > > { > > printf ("failed to opendir \"%s\" - %d (%s)", nto_procfs_path, errno, > > strerror (errno)); > > return; > > } > > > > /* Start scan at first pid. */ > > rewinddir (dp); > > > > do > > { > > /* Get the right pid and procfs path for the pid. */ > > do > > { > > if ((dirp = readdir (dp)) == NULL) > > Please don't use assignments in if-statements. There are more places > where this is done. Please fix them all. > > > { > > closedir (dp); > > return; > > } > > strcat (strcat > > (strcat (strcpy (buf, nto_procfs_path), "/"), dirp->d_name), > > "/as"); > > } > > while ((pid = atoi (dirp->d_name)) == 0); > > > > /* Open the procfs path. */ > > if ((fd = open (buf, O_RDONLY)) == -1) > > { > > printf ("failed to open %s - %d (%s)\n", buf, errno, > > strerror (errno)); > > closedir (dp); > > return; > > } > > > > pidinfo = (procfs_info *) buf; > > if (devctl (fd, DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK) > > { > > printf ("devctl DCMD_PROC_INFO failed - %d (%s)\n", errno, > > strerror (errno)); > > break; > > } > > num_threads = pidinfo->num_threads; > > > > info = (procfs_debuginfo *) buf; > > if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0) != > > EOK) > > strcpy (name, "unavailable"); > > else > > strcpy (name, info->path); > > > > /* Collect state info on all the threads. */ > > status = (procfs_status *) buf; > > for (status->tid = 1; status->tid <= num_threads; status->tid++) > > { > > if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK > > && status->tid != 0) > > break; > > if (status->tid != 0) > > printf_filtered ("%s - %d/%d\n", name, pid, status->tid); > > } > > close (fd); > > } > > while (dirp != NULL); > > > > close (fd); > > closedir (dp); > > return; > > } > > > > > > void > > procfs_meminfo (char *args, int from_tty) > > { > > procfs_mapinfo *mapinfos = NULL; > > static int num_mapinfos = 0; > > procfs_mapinfo *mapinfo_p, *mapinfo_p2; > > int flags = ~0, err, num, i, j; > > > > struct > > { > > procfs_debuginfo info; > > char buff[_POSIX_PATH_MAX]; > > } map; > > > > struct info > > { > > unsigned addr; > > unsigned size; > > unsigned flags; > > unsigned debug_vaddr; > > unsigned long long offset; > > }; > > > > struct printinfo > > { > > unsigned long long ino; > > unsigned dev; > > struct info text; > > struct info data; > > char name[256]; > > } printme; > > > > > > A single line of whitespace is enough here. > > > /* Get the number of map entrys. */ > > if ((err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num)) != EOK) > > { > > printf ("failed devctl num mapinfos - %d (%s)\n", err, strerror > > (err)); > > return; > > } > > > > mapinfos = xmalloc (num * sizeof (procfs_mapinfo)); > > > > num_mapinfos = num; > > mapinfo_p = mapinfos; > > > > /* Fill the map entrys. */ > > if ((err = > > devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, > > num * sizeof (procfs_mapinfo), &num)) != EOK) > > Please remove the line-break after the `=' here. > > > { > > printf ("failed devctl mapinfos - %d (%s)\n", err, strerror (err)); > > xfree (mapinfos); > > return; > > } > > > > num = min (num, num_mapinfos); > > > > /* Run through the list of mapinfos, and store the data and text info > > so we can print it at the bottom of the loop. */ > > for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++) > > { > > if (!(mapinfo_p->flags & flags)) > > mapinfo_p->ino = 0; > > > > if (mapinfo_p->ino == 0) /* Already visited. */ > > continue; > > > > map.info.vaddr = mapinfo_p->vaddr; > > > > if ((err = > > devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0)) != EOK) > > continue; > > > > memset (&printme, 0, sizeof printme); > > printme.dev = mapinfo_p->dev; > > printme.ino = mapinfo_p->ino; > > printme.text.addr = mapinfo_p->vaddr; > > printme.text.size = mapinfo_p->size; > > printme.text.flags = mapinfo_p->flags; > > printme.text.offset = mapinfo_p->offset; > > printme.text.debug_vaddr = map.info.vaddr; > > strcpy (printme.name, map.info.path); > > > > /* Check for matching data. */ > > for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++) > > { > > if (mapinfo_p2->vaddr != mapinfo_p->vaddr && > > mapinfo_p2->ino == mapinfo_p->ino > > && mapinfo_p2->dev == mapinfo_p->dev) > > { > > The && at the end of the first line of the if-statement should be on > the next line. > > > map.info.vaddr = mapinfo_p2->vaddr; > > if ((err = > > devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), > > 0)) != EOK) > > continue; > > Again, please remove the line-break after the `='. > > > > > if (strcmp (map.info.path, printme.name)) > > { > > continue; > > } > > Redundant braces. > > > /* Lower debug_vaddr is always text, if nessessary, swap. */ > > if ((int) map.info.vaddr < (int) printme.text.debug_vaddr) > > { > > memcpy (&(printme.data), &(printme.text), > > sizeof (printme.data)); > > printme.text.addr = mapinfo_p2->vaddr; > > printme.text.size = mapinfo_p2->size; > > printme.text.flags = mapinfo_p2->flags; > > printme.text.offset = mapinfo_p2->offset; > > printme.text.debug_vaddr = map.info.vaddr; > > } > > else > > { > > printme.data.addr = mapinfo_p2->vaddr; > > printme.data.size = mapinfo_p2->size; > > printme.data.flags = mapinfo_p2->flags; > > printme.data.offset = mapinfo_p2->offset; > > printme.data.debug_vaddr = map.info.vaddr; > > } > > mapinfo_p2->ino = 0; > > } > > } > > mapinfo_p->ino = 0; > > > > printf_filtered ("%s\n", printme.name); > > printf_filtered ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size, > > printme.text.addr); > > printf_filtered ("\t\tflags=%08x\n", printme.text.flags); > > printf_filtered ("\t\tdebug=%08x\n", printme.text.debug_vaddr); > > printf_filtered ("\t\toffset=%016llx\n", printme.text.offset); > > if (printme.data.size) > > { > > printf_filtered ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size, > > printme.data.addr); > > printf_filtered ("\t\tflags=%08x\n", printme.data.flags); > > printf_filtered ("\t\tdebug=%08x\n", printme.data.debug_vaddr); > > printf_filtered ("\t\toffset=%016llx\n", printme.data.offset); > > } > > printf_filtered ("\tdev=0x%x\n", printme.dev); > > printf_filtered ("\tino=0x%x\n", (unsigned int) printme.ino); > > } > > xfree (mapinfos); > > return; > > } > > > > /* Print status information about what we're accessing. */ > > > > static void > > procfs_files_info (struct target_ops *ignore) > > { > > printf_unfiltered ("\tUsing the running image of %s %s via %s.\n", > > attach_flag ? "attached" : "child", > > target_pid_to_str (inferior_ptid), nto_procfs_path); > > } > > > > /* Mark our target-struct as eligible for stray "run" and "attach" commands. > > */ > > static int > > procfs_can_run () > > { > > return 1; > > } > > > > /* Attach to process PID, then initialize for debugging it. */ > > static void > > procfs_attach (char *args, int from_tty) > > { > > char *exec_file; > > int pid; > > > > if (!args) > > error_no_arg ("process-id to attach"); > > > > pid = atoi (args); > > > > if (pid == getpid ()) > > error ("Attaching GDB to itself is not a good idea..."); > > > > if (from_tty) > > { > > exec_file = (char *) get_exec_file (0); > > > > if (exec_file) > > printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, > > target_pid_to_str (pid_to_ptid (pid))); > > else > > printf_unfiltered ("Attaching to %s\n", > > target_pid_to_str (pid_to_ptid (pid))); > > > > gdb_flush (gdb_stdout); > > } > > inferior_ptid = do_attach (pid_to_ptid (pid)); > > push_target (&procfs_ops); > > } > > > > static void > > procfs_post_attach (pid_t pid) > > { > > #ifdef SOLIB_CREATE_INFERIOR_HOOK > > if (exec_bfd) > > SOLIB_CREATE_INFERIOR_HOOK (pid); > > #endif > > } > > > > static ptid_t > > do_attach (ptid_t ptid) > > { > > procfs_status status; > > struct sigevent event; > > char path[100]; > > > > sprintf (path, "%s/%d/as", nto_procfs_path, PIDGET (ptid)); > > ctl_fd = open (path, O_RDWR); > > if (ctl_fd == -1) > > { > > error ("Couldn't open proc file %s, error %d (%s)", path, errno, > > strerror (errno)); > > } > > if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK) > > { > > error ("Couldn't stop process"); > > } > > > > /* 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 (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0); > > > > if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK) > > { > > if (status.flags & _DEBUG_FLAG_STOPPED) > > { > > SignalKill (QNX_NODE, PIDGET (ptid), 0, SIGCONT, 0, 0); > > } > > } > > attach_flag = 1; > > nto_init_solib_absolute_prefix (); > > return ptid; > > } > > > > /* Ask the user what to do when an interrupt is received. */ > > static void > > interrupt_query () > > { > > target_terminal_ours (); > > > > if (query ("Interrupted while waiting for the program.\n\ > > Give up (and stop debugging it)? ")) > > { > > target_mourn_inferior (); > > throw_exception (RETURN_QUIT); > > } > > > > target_terminal_inferior (); > > } > > > > /* The user typed ^C twice. */ > > static void > > nto_interrupt_twice (int signo) > > { > > signal (signo, ofunc); > > interrupt_query (); > > signal (signo, nto_interrupt_twice); > > } > > > > static void > > nto_interrupt (int signo) > > { > > /* If this doesn't work, try more severe steps. */ > > signal (signo, nto_interrupt_twice); > > > > target_stop (); > > } > > > > static ptid_t > > procfs_wait (ptid_t ptid, struct target_waitstatus *ourstatus) > > { > > sigset_t set; > > siginfo_t info; > > procfs_status status; > > static int exit_signo = 0; /* Used to track signals that cause > > termination. */ > > > > ourstatus->kind = TARGET_WAITKIND_SPURIOUS; > > > > if (ptid_equal (inferior_ptid, null_ptid)) > > { > > ourstatus->kind = TARGET_WAITKIND_STOPPED; > > ourstatus->value.sig = TARGET_SIGNAL_0; > > exit_signo = 0; > > return null_ptid; > > } > > > > sigemptyset (&set); > > sigaddset (&set, SIGUSR1); > > > > devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); > > while (!(status.flags & _DEBUG_FLAG_ISTOP)) > > { > > ofunc = (void (*)()) signal (SIGINT, nto_interrupt); > > sigwaitinfo (&set, &info); > > signal (SIGINT, ofunc); > > devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); > > } > > > > if (status.flags & _DEBUG_FLAG_SSTEP) > > { > > ourstatus->kind = TARGET_WAITKIND_STOPPED; > > ourstatus->value.sig = TARGET_SIGNAL_TRAP; > > } > > /* Was it a breakpoint? */ > > else if (status.flags & _DEBUG_FLAG_TRACE) > > { > > ourstatus->kind = TARGET_WAITKIND_STOPPED; > > ourstatus->value.sig = TARGET_SIGNAL_TRAP; > > } > > else if (status.flags & _DEBUG_FLAG_ISTOP) > > { > > switch (status.why) > > { > > case _DEBUG_WHY_SIGNALLED: > > ourstatus->kind = TARGET_WAITKIND_STOPPED; > > ourstatus->value.sig = > > target_signal_from_host (status.info.si_signo); > > exit_signo = 0; > > break; > > case _DEBUG_WHY_FAULTED: > > 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; > > > > waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG); > > if (exit_signo) > > { > > ourstatus->kind = TARGET_WAITKIND_SIGNALLED; /* Abnormal death. */ > > ourstatus->value.sig = exit_signo; > > } > > else > > { > > ourstatus->kind = TARGET_WAITKIND_EXITED; /* Normal death. */ > > ourstatus->value.integer = WEXITSTATUS (waitval); > > } > > exit_signo = 0; > > break; > > } > > > > case _DEBUG_WHY_REQUESTED: > > /* 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 inferior_ptid; > > } > > > > /* Read the current values of the inferior's registers, both the > > general register set and floating point registers (if supported) > > and update gdb's idea of their current values. */ > > static void > > procfs_fetch_registers (int regno) > > { > > union > > { > > procfs_greg greg; > > procfs_fpreg fpreg; > > procfs_altreg altreg; > > } > > reg; > > int regsize; > > > > procfs_set_thread (inferior_ptid); > > if (devctl (ctl_fd, DCMD_PROC_GETGREG, ®, sizeof (reg), ®size) == > > EOK) > > { > > nto_supply_gregset ((char *)®.greg); > > } > > if (devctl (ctl_fd, DCMD_PROC_GETFPREG, ®, sizeof (reg), ®size) == > > EOK) > > { > > nto_supply_fpregset ((char *)®.fpreg); > > } > > if (devctl (ctl_fd, DCMD_PROC_GETALTREG, ®, sizeof (reg), ®size) == > > EOK) > > { > > nto_supply_altregset ((char *)®.altreg); > > } > > } > > > > /* Copy LEN bytes to/from inferior's memory starting at MEMADDR > > from/to debugger memory starting at MYADDR. Copy from inferior > > if DOWRITE is zero or to inferior if DOWRITE is nonzero. > > > > Returns the length copied, which is either the LEN argument or > > zero. This xfer function does not do partial moves, since procfs_ops > > doesn't allow memory operations to cross below us in the target stack > > anyway. */ > > > > static int > > procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite, > > struct mem_attrib *attrib, struct target_ops *target) > > { > > int nbytes = 0; > > > > if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr) > > { > > if (dowrite) > > { > > nbytes = write (ctl_fd, myaddr, len); > > } > > else > > { > > nbytes = read (ctl_fd, myaddr, len); > > } > > if (nbytes < 0) > > { > > nbytes = 0; > > } > > } > > return (nbytes); > > } > > > > /* Take a program previously attached to and detaches it. > > The program resumes execution and will no longer stop > > on signals, etc. We'd better not have left any breakpoints > > in the program or it'll die when it hits one. */ > > static void > > procfs_detach (char *args, int from_tty) > > { > > int siggnal = 0; > > > > if (from_tty) > > { > > char *exec_file = get_exec_file (0); > > if (exec_file == 0) > > exec_file = ""; > > printf_unfiltered ("Detaching from program: %s %s\n", > > exec_file, target_pid_to_str (inferior_ptid)); > > gdb_flush (gdb_stdout); > > } > > if (args) > > siggnal = atoi (args); > > > > if (siggnal) > > SignalKill (QNX_NODE, PIDGET (inferior_ptid), 0, siggnal, 0, 0); > > > > close (ctl_fd); > > ctl_fd = -1; > > init_thread_list (); > > inferior_ptid = null_ptid; > > attach_flag = 0; > > unpush_target (&procfs_ops); /* Pop out of handling an inferior. */ > > } > > > > static int > > procfs_breakpoint (CORE_ADDR addr, int type, int size) > > { > > procfs_break brk; > > > > brk.type = type; > > brk.addr = addr; > > brk.size = size; > > if ((errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)) != > > EOK) > > { > > return 1; > > } > > return 0; > > } > > > > static int > > procfs_insert_breakpoint (CORE_ADDR addr, char *contents_cache) > > { > > return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, 0); > > } > > > > static int > > procfs_remove_breakpoint (CORE_ADDR addr, char *contents_cache) > > { > > return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, -1); > > } > > > > static int > > procfs_insert_hw_breakpoint (CORE_ADDR addr, char *contents_cache) > > { > > return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0); > > } > > > > static int > > procfs_remove_hw_breakpoint (CORE_ADDR addr, char *contents_cache) > > { > > return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1); > > } > > > > static void > > procfs_resume (ptid_t ptid, int step, enum target_signal signo) > > { > > int signal_to_pass; > > procfs_status status; > > > > if (ptid_equal (inferior_ptid, null_ptid)) > > return; > > > > procfs_set_thread (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid : > > ptid); > > > > run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE; > > if (step) > > run.flags |= _DEBUG_RUN_STEP; > > > > sigemptyset ((sigset_t *) & run.fault); > > sigaddset ((sigset_t *) & run.fault, FLTBPT); > > sigaddset ((sigset_t *) & run.fault, FLTTRACE); > > sigaddset ((sigset_t *) & run.fault, FLTILL); > > sigaddset ((sigset_t *) & run.fault, FLTPRIV); > > sigaddset ((sigset_t *) & run.fault, FLTBOUNDS); > > sigaddset ((sigset_t *) & run.fault, FLTIOVF); > > sigaddset ((sigset_t *) & run.fault, FLTIZDIV); > > sigaddset ((sigset_t *) & run.fault, FLTFPE); > > /* Peter V will be changing this at some point. */ > > sigaddset ((sigset_t *) & run.fault, FLTPAGE); > > > > run.flags |= _DEBUG_RUN_ARM; > > > > sigemptyset (&run.trace); > > notice_signals (); > > signal_to_pass = target_signal_to_host (signo); > > > > if (signal_to_pass) > > { > > devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); > > signal_to_pass = target_signal_to_host (signo); > > if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED)) > > { > > if (signal_to_pass != status.info.si_signo) > > { > > SignalKill (QNX_NODE, PIDGET (inferior_ptid), 0, signal_to_pass, > > 0, 0); > > 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; > > } > > if ((errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0)) != > > EOK) > > { > > perror ("run error!\n"); > > return; > > } > > } > > > > static void > > procfs_mourn_inferior () > > { > > if (!ptid_equal (inferior_ptid, null_ptid)) > > { > > SignalKill (QNX_NODE, PIDGET (inferior_ptid), 0, SIGKILL, 0, 0); > > close (ctl_fd); > > } > > inferior_ptid = null_ptid; > > init_thread_list (); > > unpush_target (&procfs_ops); > > generic_mourn_inferior (); > > attach_flag = 0; > > } > > > > /* This function breaks up an argument string into an argument > > vector suitable for passing to execvp(). > > E.g., on "run a b c d" this routine would get as input > > the string "a b c d", and as output it would fill in argv with > > the four arguments "a", "b", "c", "d". The only additional > > functionality is simple quoting. The gdb command: > > run a "b c d" f > > will fill in argv with the three args "a", "b c d", "e". */ > > static void > > breakup_args (char *scratch, char **argv) > > { > > char *pp, *cp = scratch; > > char quoting = 0; > > > > for (;;) > > { > > > > Please remove the whitespace here... > > > /* Scan past leading separators. */ > > quoting = 0; > > while (*cp == ' ' || *cp == '\t' || *cp == '\n') > > { > > cp++; > > } > > > > /* Break if at end of string. */ > > if (*cp == '\0') > > break; > > > > /* Take an arg. */ > > if (*cp == '"') > > { > > cp++; > > quoting = strchr (cp, '"') ? 1 : 0; > > } > > > > *argv++ = cp; > > > > /* Scan for next arg separator. */ > > pp = cp; > > if (quoting) > > cp = strchr (pp, '"'); > > if ((cp == NULL) || (!quoting)) > > cp = strchr (pp, ' '); > > if (cp == NULL) > > cp = strchr (pp, '\t'); > > if (cp == NULL) > > cp = strchr (pp, '\n'); > > > > /* No separators => end of string => break. */ > > if (cp == NULL) > > { > > pp = cp; > > break; > > } > > > > /* Replace the separator with a terminator. */ > > *cp++ = '\0'; > > } > > > > /* Execv requires a null-terminated arg vector. */ > > *argv = NULL; > > > > } > > ... and here. > > > > > static void > > procfs_create_inferior (char *exec_file, char *allargs, char **env) > > { > > struct inheritance inherit; > > pid_t pid; > > int flags, errn; > > char **argv, *args; > > char *in = "", *out = "", *err = ""; > > int fd, fds[3]; > > sigset_t set; > > > > argv = > > (char **) xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) * > > sizeof (*argv)); > > argv[0] = get_exec_file (1); > > if (!argv[0]) > > { > > if (exec_file) > > argv[0] = exec_file; > > else > > return; > > } > > > > args = strdup (allargs); > > breakup_args (args, exec_file ? &argv[1] : &argv[0]); > > > > argv = nto_parse_redirection (argv, &in, &out, &err); > > > > fds[0] = STDIN_FILENO; > > fds[1] = STDOUT_FILENO; > > fds[2] = STDERR_FILENO; > > > > /* If the user specified I/O via gdb's --tty= arg, use it, but only > > if the i/o is not also being specified via redirection. */ > > if (inferior_io_terminal) > > { > > if (!in[0]) > > in = inferior_io_terminal; > > if (!out[0]) > > out = inferior_io_terminal; > > if (!err[0]) > > err = inferior_io_terminal; > > } > > > > if (in[0]) > > { > > if ((fd = open (in, O_RDONLY)) == -1) > > { > > perror (in); > > } > > else > > fds[0] = fd; > > } > > if (out[0]) > > { > > if ((fd = open (out, O_WRONLY)) == -1) > > { > > perror (out); > > } > > else > > fds[1] = fd; > > } > > if (err[0]) > > { > > if ((fd = open (err, O_WRONLY)) == -1) > > { > > perror (err); > > } > > else > > fds[2] = fd; > > } > > > > /* 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)); > > > > if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0) > > { > > inherit.nd = QNX_NODE; > > inherit.flags |= SPAWN_SETND; > > inherit.flags &= ~SPAWN_EXEC; > > } > > inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD; > > inherit.pgroup = SPAWN_NEWPGROUP; > > pid = > > spawnp (argv[0], 3, fds, &inherit, argv, > > ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0); > > xfree (args); > > > > sigprocmask (SIG_BLOCK, &set, NULL); > > > > if (pid == -1) > > error ("Error spawning %s: %d (%s)", argv[0], errno, strerror (errno)); > > > > if (fds[0] != STDIN_FILENO) > > close (fds[0]); > > if (fds[1] != STDOUT_FILENO) > > close (fds[1]); > > if (fds[2] != STDERR_FILENO) > > close (fds[2]); > > > > inferior_ptid = do_attach (pid_to_ptid (pid)); > > > > attach_flag = 0; > > flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */ > > if ((errn = > > devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0)) != > > EOK) > > { > > /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n", > > errn, strerror(errn) ); */ > > } > > push_target (&procfs_ops); > > target_terminal_init (); > > > > #ifdef SOLIB_CREATE_INFERIOR_HOOK > > if (exec_bfd != NULL > > || (symfile_objfile != NULL && symfile_objfile->obfd != NULL)) > > SOLIB_CREATE_INFERIOR_HOOK (pid); > > #endif > > } > > > > static void > > procfs_stop () > > { > > devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0); > > } > > > > static void > > procfs_kill_inferior () > > { > > target_mourn_inferior (); > > } > > > > /* Store register REGNO, or all registers if REGNO == -1, from the contents > > of REGISTERS. */ > > > > static void > > procfs_prepare_to_store () > > { > > } > > > > /* Fill buf with regset and return devctl cmd to do the setting. Return > > -1 if we fail to get the regset. Store size of regset in regsize. */ > > static int > > get_regset(int regset, char *buf, int bufsize, int *regsize) > > { > > int dev_get, dev_set; > > switch(regset){ > > case NTO_REG_GENERAL: > > dev_get = DCMD_PROC_GETGREG; > > dev_set = DCMD_PROC_SETGREG; > > break; > > > > case NTO_REG_FLOAT: > > dev_get = DCMD_PROC_GETFPREG; > > dev_set = DCMD_PROC_SETFPREG; > > break; > > > > case NTO_REG_ALT: > > dev_get = DCMD_PROC_GETALTREG; > > dev_set = DCMD_PROC_SETALTREG; > > break; > > > > case NTO_REG_SYSTEM: > > default: > > return -1; > > } > > if(devctl(ctl_fd, dev_get, &buf, bufsize, regsize) != EOK) > > return -1; > > > > return dev_set; > > } > > > > void > > procfs_store_registers (int regno) > > { > > union > > { > > procfs_greg greg; > > procfs_fpreg fpreg; > > procfs_altreg altreg; > > } > > reg; > > unsigned off; > > int len, regset, regsize, dev_set, err; > > char *data; > > > > if (ptid_equal (inferior_ptid, null_ptid)) > > return; > > procfs_set_thread (inferior_ptid); > > > > if (regno == -1) { > > for(regset = NTO_REG_GENERAL; regset < NTO_REG_END ; regset++){ > > if((dev_set = get_regset(regset, (char *)®, sizeof(reg), > > ®size)) == -1) > > continue; > > > > if(nto_regset_fill(regset, (char *)®) == -1) > > continue; > > > > if((err = devctl(ctl_fd, dev_set, ®, regsize, 0)) != EOK) > > fprintf_unfiltered(gdb_stderr, "Warning unable to write regset %d: > > %s\n", regno, strerror(err)); > > } > > } > > else{ > > if((regset = nto_regset_id(regno)) == -1) > > return; > > > > if((dev_set = get_regset(regset, (char *)®, sizeof(reg), ®size)) > > == -1) > > return; > > > > len = nto_register_area(regno, regset, &off); > > > > if(len < 1) > > return; > > > > regcache_collect(regno, (char *)® + off); > > > > if((err = devctl(ctl_fd, dev_set, ®, regsize, 0)) != EOK) > > fprintf_unfiltered(gdb_stderr, "Warning unable to write regset %d: > > %s\n", regno, strerror(err)); > > } > > } > > > > static void > > notice_signals (void) > > { > > int signo; > > > > for (signo = 1; signo < NSIG; signo++) > > { > > if (signal_stop_state (target_signal_from_host (signo)) == 0 && > > signal_print_state (target_signal_from_host (signo)) == 0 && > > signal_pass_state (target_signal_from_host (signo)) == 1) > > The &&'s should be moved to the next line. > > > { > > sigdelset (&run.trace, signo); > > } > > else > > { > > sigaddset (&run.trace, signo); > > } > > } > > } > > > > /* When the user changes the state of gdb's signal handling via the > > "handle" command, this function gets called to see if any change > > in the /proc interface is required. It is also called internally > > by other /proc interface functions to initialize the state of > > the traced signal set. */ > > static void > > procfs_notice_signals (ptid_t ptid) > > { > > sigemptyset (&run.trace); > > notice_signals (); > > } > > > > static struct tidinfo * > > procfs_thread_info (pid_t pid, short tid) > > { > > /* NYI */ > > return NULL; > > } > > > > char * > > procfs_pid_to_str (ptid_t ptid) > > { > > static char buf[1024]; > > int pid, tid, n; > > struct tidinfo *tip; > > > > pid = ptid_get_pid (ptid); > > tid = ptid_get_tid (ptid); > > > > n = sprintf (buf, "process %d", pid); > > > > #if 0 /* NYI */ > > tip = procfs_thread_info (pid, tid); > > if (tip != NULL) > > sprintf (&buf[n], " (state = 0x%02x)", tip->state); > > #endif > > > > return buf; > > } > > > > static void > > init_procfs_ops () > > { > > procfs_ops.to_shortname = "procfs"; > > procfs_ops.to_longname = "QNX Neutrino procfs child process"; > > procfs_ops.to_doc = > > "QNX Neutrino procfs child process (started by the \"run\" command).\n\ > > target procfs "; > > procfs_ops.to_open = procfs_open; > > procfs_ops.to_attach = procfs_attach; > > procfs_ops.to_post_attach = procfs_post_attach; > > procfs_ops.to_detach = procfs_detach; > > procfs_ops.to_resume = procfs_resume; > > procfs_ops.to_wait = procfs_wait; > > procfs_ops.to_fetch_registers = procfs_fetch_registers; > > procfs_ops.to_store_registers = procfs_store_registers; > > procfs_ops.to_prepare_to_store = procfs_prepare_to_store; > > procfs_ops.to_xfer_memory = procfs_xfer_memory; > > procfs_ops.to_files_info = procfs_files_info; > > procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint; > > procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint; > > procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint; > > procfs_ops.to_insert_hw_breakpoint = procfs_insert_hw_breakpoint; > > procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint; > > procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint; > > procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint; > > procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint; > > procfs_ops.to_terminal_init = terminal_init_inferior; > > procfs_ops.to_terminal_inferior = terminal_inferior; > > procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output; > > procfs_ops.to_terminal_ours = terminal_ours; > > procfs_ops.to_terminal_info = child_terminal_info; > > procfs_ops.to_kill = procfs_kill_inferior; > > procfs_ops.to_create_inferior = procfs_create_inferior; > > procfs_ops.to_mourn_inferior = procfs_mourn_inferior; > > procfs_ops.to_can_run = procfs_can_run; > > procfs_ops.to_notice_signals = procfs_notice_signals; > > procfs_ops.to_thread_alive = procfs_thread_alive; > > procfs_ops.to_find_new_threads = procfs_find_new_threads; > > procfs_ops.to_pid_to_str = procfs_pid_to_str; > > procfs_ops.to_stop = procfs_stop; > > procfs_ops.to_stratum = process_stratum; > > procfs_ops.to_has_all_memory = 1; > > procfs_ops.to_has_memory = 1; > > procfs_ops.to_has_stack = 1; > > procfs_ops.to_has_registers = 1; > > procfs_ops.to_has_execution = 1; > > procfs_ops.to_magic = OPS_MAGIC; > > procfs_ops.to_have_continuable_watchpoint = 1; > > } > > > > #define OSTYPE_NTO 1 > > > > void > > _initialize_procfs () > > { > > sigset_t set; > > > > init_procfs_ops (); > > add_target (&procfs_ops); > > > > /* 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); > > > > /* Set up trace and fault sets, as gdb expects them. */ > > sigemptyset (&run.trace); > > notice_signals (); > > > > /* Stuff some information. */ > > nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags; > > nto_cpuinfo_valid = 1; > > > > add_info ("pidlist", procfs_pidlist, "pidlist"); > > add_info ("meminfo", procfs_meminfo, "memory information"); > > } > > > > > > static int > > procfs_hw_watchpoint (int addr, int len, int type) > > { > > procfs_break brk; > > int err; > > > > switch (type) > > { > > case 1: /* Read. */ > > brk.type = _DEBUG_BREAK_RD; > > break; > > case 2: /* Read/Write. */ > > brk.type = _DEBUG_BREAK_RW; > > break; > > default: /* Modify. */ > > /* brk.type = _DEBUG_BREAK_RWM; This should work, shouldn't it? I get > > EINVAL */ > > brk.type = _DEBUG_BREAK_RW; > > } > > brk.type |= _DEBUG_BREAK_HW; /* Always ask for HW. */ > > brk.addr = addr; > > brk.size = len; > > > > if ((err = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)) != > > EOK) > > { > > errno = err; > > perror ("Failed to set hardware watchpoint"); > > return -1; > > } > > return 0; > > } > > > > static int > > procfs_can_use_hw_breakpoint (int type, int cnt, int othertype) > > { > > return 1; > > } > > > > static int > > procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type) > > { > > return procfs_hw_watchpoint (addr, -1, type); > > } > > > > static int > > procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type) > > { > > return procfs_hw_watchpoint (addr, len, type); > > } > > > > static int > > procfs_stopped_by_watchpoint (void) > > { > > return 0; > > } > > Mark >