1130803Smarcel/* Machine independent support for QNX Neutrino /proc (process file system)
2130803Smarcel   for GDB.  Written by Colin Burgess at QNX Software Systems Limited.
3130803Smarcel
4130803Smarcel   Copyright 2003 Free Software Foundation, Inc.
5130803Smarcel
6130803Smarcel   Contributed by QNX Software Systems Ltd.
7130803Smarcel
8130803Smarcel   This file is part of GDB.
9130803Smarcel
10130803Smarcel   This program is free software; you can redistribute it and/or modify
11130803Smarcel   it under the terms of the GNU General Public License as published by
12130803Smarcel   the Free Software Foundation; either version 2 of the License, or
13130803Smarcel   (at your option) any later version.
14130803Smarcel
15130803Smarcel   This program is distributed in the hope that it will be useful,
16130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
17130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18130803Smarcel   GNU General Public License for more details.
19130803Smarcel
20130803Smarcel   You should have received a copy of the GNU General Public License
21130803Smarcel   along with this program; if not, write to the Free Software
22130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
23130803Smarcel   Boston, MA 02111-1307, USA.  */
24130803Smarcel
25130803Smarcel#include "defs.h"
26130803Smarcel
27130803Smarcel#include <fcntl.h>
28130803Smarcel#include <spawn.h>
29130803Smarcel#include <sys/debug.h>
30130803Smarcel#include <sys/procfs.h>
31130803Smarcel#include <sys/neutrino.h>
32130803Smarcel#include <sys/syspage.h>
33130803Smarcel#include "gdb_dirent.h"
34130803Smarcel#include <sys/netmgr.h>
35130803Smarcel
36130803Smarcel#include "gdb_string.h"
37130803Smarcel#include "gdbcore.h"
38130803Smarcel#include "inferior.h"
39130803Smarcel#include "target.h"
40130803Smarcel#include "objfiles.h"
41130803Smarcel#include "gdbthread.h"
42130803Smarcel#include "nto-tdep.h"
43130803Smarcel#include "command.h"
44130803Smarcel#include "regcache.h"
45130803Smarcel
46130803Smarcel#define NULL_PID		0
47130803Smarcel#define _DEBUG_FLAG_TRACE	(_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\
48130803Smarcel		_DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY)
49130803Smarcel
50130803Smarcelstatic struct target_ops procfs_ops;
51130803Smarcel
52130803Smarcelint ctl_fd;
53130803Smarcel
54130803Smarcelstatic void (*ofunc) ();
55130803Smarcel
56130803Smarcelstatic procfs_run run;
57130803Smarcel
58130803Smarcelstatic void procfs_open (char *, int);
59130803Smarcel
60130803Smarcelstatic int procfs_can_run (void);
61130803Smarcel
62130803Smarcelstatic ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
63130803Smarcel
64130803Smarcelstatic int procfs_xfer_memory (CORE_ADDR, char *, int, int,
65130803Smarcel			       struct mem_attrib *attrib,
66130803Smarcel			       struct target_ops *);
67130803Smarcel
68130803Smarcelstatic void procfs_fetch_registers (int);
69130803Smarcel
70130803Smarcelstatic void notice_signals (void);
71130803Smarcel
72130803Smarcelstatic void init_procfs_ops (void);
73130803Smarcel
74130803Smarcelstatic ptid_t do_attach (ptid_t ptid);
75130803Smarcel
76130803Smarcelstatic int procfs_can_use_hw_breakpoint (int, int, int);
77130803Smarcel
78130803Smarcelstatic int procfs_insert_hw_breakpoint (CORE_ADDR, char *);
79130803Smarcel
80130803Smarcelstatic int procfs_remove_hw_breakpoint (CORE_ADDR addr, char *);
81130803Smarcel
82130803Smarcelstatic int procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type);
83130803Smarcel
84130803Smarcelstatic int procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type);
85130803Smarcel
86130803Smarcelstatic int procfs_stopped_by_watchpoint (void);
87130803Smarcel
88130803Smarcel/* These two globals are only ever set in procfs_open(), but are
89130803Smarcel   referenced elsewhere.  'nto_procfs_node' is a flag used to say
90130803Smarcel   whether we are local, or we should get the current node descriptor
91130803Smarcel   for the remote QNX node.  */
92130803Smarcelstatic char nto_procfs_path[PATH_MAX] = { "/proc" };
93130803Smarcelstatic unsigned nto_procfs_node = ND_LOCAL_NODE;
94130803Smarcel
95130803Smarcel/* Return the current QNX Node, or error out.  This is a simple
96130803Smarcel   wrapper for the netmgr_strtond() function.  The reason this
97130803Smarcel   is required is because QNX node descriptors are transient so
98130803Smarcel   we have to re-acquire them every time.  */
99130803Smarcelstatic unsigned
100130803Smarcelnto_node(void)
101130803Smarcel{
102130803Smarcel  unsigned node;
103130803Smarcel
104130803Smarcel  if (ND_NODE_CMP(nto_procfs_node, ND_LOCAL_NODE) == 0)
105130803Smarcel    return ND_LOCAL_NODE;
106130803Smarcel
107130803Smarcel  node = netmgr_strtond(nto_procfs_path,0);
108130803Smarcel  if (node == -1)
109130803Smarcel      error ("Lost the QNX node.  Debug session probably over.");
110130803Smarcel
111130803Smarcel  return (node);
112130803Smarcel}
113130803Smarcel
114130803Smarcel/* This is called when we call 'target procfs <arg>' from the (gdb) prompt.
115130803Smarcel   For QNX6 (nto), the only valid arg will be a QNX node string,
116130803Smarcel   eg: "/net/some_node".  If arg is not a valid QNX node, we will
117130803Smarcel   default to local.  */
118130803Smarcelstatic void
119130803Smarcelprocfs_open (char *arg, int from_tty)
120130803Smarcel{
121130803Smarcel  char *nodestr;
122130803Smarcel  char *endstr;
123130803Smarcel  char buffer[50];
124130803Smarcel  int fd, total_size;
125130803Smarcel  procfs_sysinfo *sysinfo;
126130803Smarcel
127130803Smarcel  /* Set the default node used for spawning to this one,
128130803Smarcel     and only override it if there is a valid arg.  */
129130803Smarcel
130130803Smarcel  nto_procfs_node = ND_LOCAL_NODE;
131130803Smarcel  nodestr = arg ? xstrdup (arg) : arg;
132130803Smarcel
133130803Smarcel  init_thread_list ();
134130803Smarcel
135130803Smarcel  if (nodestr)
136130803Smarcel    {
137130803Smarcel      nto_procfs_node = netmgr_strtond (nodestr, &endstr);
138130803Smarcel      if (nto_procfs_node == -1)
139130803Smarcel	{
140130803Smarcel	  if (errno == ENOTSUP)
141130803Smarcel	    printf_filtered ("QNX Net Manager not found.\n");
142130803Smarcel	  printf_filtered ("Invalid QNX node %s: error %d (%s).\n", nodestr,
143130803Smarcel			   errno, safe_strerror (errno));
144130803Smarcel	  xfree (nodestr);
145130803Smarcel	  nodestr = NULL;
146130803Smarcel	  nto_procfs_node = ND_LOCAL_NODE;
147130803Smarcel	}
148130803Smarcel      else if (*endstr)
149130803Smarcel	{
150130803Smarcel	  if (*(endstr - 1) == '/')
151130803Smarcel	    *(endstr - 1) = 0;
152130803Smarcel	  else
153130803Smarcel	    *endstr = 0;
154130803Smarcel	}
155130803Smarcel    }
156130803Smarcel  snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s", nodestr ? nodestr : "", "/proc");
157130803Smarcel  if (nodestr)
158130803Smarcel    xfree (nodestr);
159130803Smarcel
160130803Smarcel  fd = open (nto_procfs_path, O_RDONLY);
161130803Smarcel  if (fd == -1)
162130803Smarcel    {
163130803Smarcel      printf_filtered ("Error opening %s : %d (%s)\n", nto_procfs_path, errno,
164130803Smarcel		       safe_strerror (errno));
165130803Smarcel      error ("Invalid procfs arg");
166130803Smarcel    }
167130803Smarcel
168130803Smarcel  sysinfo = (void *) buffer;
169130803Smarcel  if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK)
170130803Smarcel    {
171130803Smarcel      printf_filtered ("Error getting size: %d (%s)\n", errno,
172130803Smarcel		       safe_strerror (errno));
173130803Smarcel      close (fd);
174130803Smarcel      error ("Devctl failed.");
175130803Smarcel    }
176130803Smarcel  else
177130803Smarcel    {
178130803Smarcel      total_size = sysinfo->total_size;
179130803Smarcel      sysinfo = alloca (total_size);
180130803Smarcel      if (!sysinfo)
181130803Smarcel	{
182130803Smarcel	  printf_filtered ("Memory error: %d (%s)\n", errno,
183130803Smarcel			   safe_strerror (errno));
184130803Smarcel	  close (fd);
185130803Smarcel	  error ("alloca failed.");
186130803Smarcel	}
187130803Smarcel      else
188130803Smarcel	{
189130803Smarcel	  if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, total_size, 0) != EOK)
190130803Smarcel	    {
191130803Smarcel	      printf_filtered ("Error getting sysinfo: %d (%s)\n", errno,
192130803Smarcel			       safe_strerror (errno));
193130803Smarcel	      close (fd);
194130803Smarcel	      error ("Devctl failed.");
195130803Smarcel	    }
196130803Smarcel	  else
197130803Smarcel	    {
198130803Smarcel	      if (sysinfo->type !=
199130803Smarcel		  nto_map_arch_to_cputype (TARGET_ARCHITECTURE->arch_name))
200130803Smarcel		{
201130803Smarcel		  close (fd);
202130803Smarcel		  error ("Invalid target CPU.");
203130803Smarcel		}
204130803Smarcel	    }
205130803Smarcel	}
206130803Smarcel    }
207130803Smarcel  close (fd);
208130803Smarcel  printf_filtered ("Debugging using %s\n", nto_procfs_path);
209130803Smarcel}
210130803Smarcel
211130803Smarcelstatic void
212130803Smarcelprocfs_set_thread (ptid_t ptid)
213130803Smarcel{
214130803Smarcel  pid_t tid;
215130803Smarcel
216130803Smarcel  tid = ptid_get_tid (ptid);
217130803Smarcel  devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0);
218130803Smarcel}
219130803Smarcel
220130803Smarcel/*  Return nonzero if the thread TH is still alive.  */
221130803Smarcelstatic int
222130803Smarcelprocfs_thread_alive (ptid_t ptid)
223130803Smarcel{
224130803Smarcel  pid_t tid;
225130803Smarcel
226130803Smarcel  tid = ptid_get_tid (ptid);
227130803Smarcel  if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK)
228130803Smarcel    return 1;
229130803Smarcel  return 0;
230130803Smarcel}
231130803Smarcel
232130803Smarcelvoid
233130803Smarcelprocfs_find_new_threads (void)
234130803Smarcel{
235130803Smarcel  procfs_status status;
236130803Smarcel  pid_t pid;
237130803Smarcel  ptid_t ptid;
238130803Smarcel
239130803Smarcel  if (ctl_fd == -1)
240130803Smarcel    return;
241130803Smarcel
242130803Smarcel  pid = ptid_get_pid (inferior_ptid);
243130803Smarcel
244130803Smarcel  for (status.tid = 1;; ++status.tid)
245130803Smarcel    {
246130803Smarcel      if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0)
247130803Smarcel	  != EOK && status.tid != 0)
248130803Smarcel	break;
249130803Smarcel      ptid = ptid_build (pid, 0, status.tid);
250130803Smarcel      if (!in_thread_list (ptid))
251130803Smarcel	add_thread (ptid);
252130803Smarcel    }
253130803Smarcel  return;
254130803Smarcel}
255130803Smarcel
256130803Smarcelvoid
257130803Smarcelprocfs_pidlist (char *args, int from_tty)
258130803Smarcel{
259130803Smarcel  DIR *dp = NULL;
260130803Smarcel  struct dirent *dirp = NULL;
261130803Smarcel  int fd = -1;
262130803Smarcel  char buf[512];
263130803Smarcel  procfs_info *pidinfo = NULL;
264130803Smarcel  procfs_debuginfo *info = NULL;
265130803Smarcel  procfs_status *status = NULL;
266130803Smarcel  pid_t num_threads = 0;
267130803Smarcel  pid_t pid;
268130803Smarcel  char name[512];
269130803Smarcel
270130803Smarcel  dp = opendir (nto_procfs_path);
271130803Smarcel  if (dp == NULL)
272130803Smarcel    {
273130803Smarcel      fprintf_unfiltered (gdb_stderr, "failed to opendir \"%s\" - %d (%s)",
274130803Smarcel	      nto_procfs_path, errno, safe_strerror (errno));
275130803Smarcel      return;
276130803Smarcel    }
277130803Smarcel
278130803Smarcel  /* Start scan at first pid.  */
279130803Smarcel  rewinddir (dp);
280130803Smarcel
281130803Smarcel  do
282130803Smarcel    {
283130803Smarcel      /* Get the right pid and procfs path for the pid.  */
284130803Smarcel      do
285130803Smarcel	{
286130803Smarcel	  dirp = readdir (dp);
287130803Smarcel	  if (dirp == NULL)
288130803Smarcel	    {
289130803Smarcel	      closedir (dp);
290130803Smarcel	      return;
291130803Smarcel	    }
292130803Smarcel	  snprintf (buf, 511, "%s/%s/as", nto_procfs_path, dirp->d_name);
293130803Smarcel	  pid = atoi (dirp->d_name);
294130803Smarcel	}
295130803Smarcel      while (pid == 0);
296130803Smarcel
297130803Smarcel      /* Open the procfs path. */
298130803Smarcel      fd = open (buf, O_RDONLY);
299130803Smarcel      if (fd == -1)
300130803Smarcel	{
301130803Smarcel	  fprintf_unfiltered (gdb_stderr, "failed to open %s - %d (%s)\n",
302130803Smarcel		  buf, errno, safe_strerror (errno));
303130803Smarcel	  closedir (dp);
304130803Smarcel	  return;
305130803Smarcel	}
306130803Smarcel
307130803Smarcel      pidinfo = (procfs_info *) buf;
308130803Smarcel      if (devctl (fd, DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK)
309130803Smarcel	{
310130803Smarcel	  fprintf_unfiltered (gdb_stderr,
311130803Smarcel		  "devctl DCMD_PROC_INFO failed - %d (%s)\n", errno,
312130803Smarcel		  safe_strerror (errno));
313130803Smarcel	  break;
314130803Smarcel	}
315130803Smarcel      num_threads = pidinfo->num_threads;
316130803Smarcel
317130803Smarcel      info = (procfs_debuginfo *) buf;
318130803Smarcel      if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0) != EOK)
319130803Smarcel	strcpy (name, "unavailable");
320130803Smarcel      else
321130803Smarcel	strcpy (name, info->path);
322130803Smarcel
323130803Smarcel      /* Collect state info on all the threads.  */
324130803Smarcel      status = (procfs_status *) buf;
325130803Smarcel      for (status->tid = 1; status->tid <= num_threads; status->tid++)
326130803Smarcel	{
327130803Smarcel	  if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK
328130803Smarcel	      && status->tid != 0)
329130803Smarcel	    break;
330130803Smarcel	  if (status->tid != 0)
331130803Smarcel	    printf_filtered ("%s - %d/%d\n", name, pid, status->tid);
332130803Smarcel	}
333130803Smarcel      close (fd);
334130803Smarcel    }
335130803Smarcel  while (dirp != NULL);
336130803Smarcel
337130803Smarcel  close (fd);
338130803Smarcel  closedir (dp);
339130803Smarcel  return;
340130803Smarcel}
341130803Smarcel
342130803Smarcelvoid
343130803Smarcelprocfs_meminfo (char *args, int from_tty)
344130803Smarcel{
345130803Smarcel  procfs_mapinfo *mapinfos = NULL;
346130803Smarcel  static int num_mapinfos = 0;
347130803Smarcel  procfs_mapinfo *mapinfo_p, *mapinfo_p2;
348130803Smarcel  int flags = ~0, err, num, i, j;
349130803Smarcel
350130803Smarcel  struct
351130803Smarcel  {
352130803Smarcel    procfs_debuginfo info;
353130803Smarcel    char buff[_POSIX_PATH_MAX];
354130803Smarcel  } map;
355130803Smarcel
356130803Smarcel  struct info
357130803Smarcel  {
358130803Smarcel    unsigned addr;
359130803Smarcel    unsigned size;
360130803Smarcel    unsigned flags;
361130803Smarcel    unsigned debug_vaddr;
362130803Smarcel    unsigned long long offset;
363130803Smarcel  };
364130803Smarcel
365130803Smarcel  struct printinfo
366130803Smarcel  {
367130803Smarcel    unsigned long long ino;
368130803Smarcel    unsigned dev;
369130803Smarcel    struct info text;
370130803Smarcel    struct info data;
371130803Smarcel    char name[256];
372130803Smarcel  } printme;
373130803Smarcel
374130803Smarcel  /* Get the number of map entrys.  */
375130803Smarcel  err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num);
376130803Smarcel  if (err != EOK)
377130803Smarcel    {
378130803Smarcel      printf ("failed devctl num mapinfos - %d (%s)\n", err, safe_strerror (err));
379130803Smarcel      return;
380130803Smarcel    }
381130803Smarcel
382130803Smarcel  mapinfos = xmalloc (num * sizeof (procfs_mapinfo));
383130803Smarcel
384130803Smarcel  num_mapinfos = num;
385130803Smarcel  mapinfo_p = mapinfos;
386130803Smarcel
387130803Smarcel  /* Fill the map entrys.  */
388130803Smarcel  err = devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, num
389130803Smarcel		* sizeof (procfs_mapinfo), &num);
390130803Smarcel  if (err != EOK)
391130803Smarcel    {
392130803Smarcel      printf ("failed devctl mapinfos - %d (%s)\n", err, safe_strerror (err));
393130803Smarcel      xfree (mapinfos);
394130803Smarcel      return;
395130803Smarcel    }
396130803Smarcel
397130803Smarcel  num = min (num, num_mapinfos);
398130803Smarcel
399130803Smarcel  /* Run through the list of mapinfos, and store the data and text info
400130803Smarcel     so we can print it at the bottom of the loop.  */
401130803Smarcel  for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++)
402130803Smarcel    {
403130803Smarcel      if (!(mapinfo_p->flags & flags))
404130803Smarcel	mapinfo_p->ino = 0;
405130803Smarcel
406130803Smarcel      if (mapinfo_p->ino == 0)	/* Already visited.  */
407130803Smarcel	continue;
408130803Smarcel
409130803Smarcel      map.info.vaddr = mapinfo_p->vaddr;
410130803Smarcel
411130803Smarcel      err = devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
412130803Smarcel      if (err != EOK)
413130803Smarcel	continue;
414130803Smarcel
415130803Smarcel      memset (&printme, 0, sizeof printme);
416130803Smarcel      printme.dev = mapinfo_p->dev;
417130803Smarcel      printme.ino = mapinfo_p->ino;
418130803Smarcel      printme.text.addr = mapinfo_p->vaddr;
419130803Smarcel      printme.text.size = mapinfo_p->size;
420130803Smarcel      printme.text.flags = mapinfo_p->flags;
421130803Smarcel      printme.text.offset = mapinfo_p->offset;
422130803Smarcel      printme.text.debug_vaddr = map.info.vaddr;
423130803Smarcel      strcpy (printme.name, map.info.path);
424130803Smarcel
425130803Smarcel      /* Check for matching data.  */
426130803Smarcel      for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++)
427130803Smarcel	{
428130803Smarcel	  if (mapinfo_p2->vaddr != mapinfo_p->vaddr
429130803Smarcel	      && mapinfo_p2->ino == mapinfo_p->ino
430130803Smarcel	      && mapinfo_p2->dev == mapinfo_p->dev)
431130803Smarcel	    {
432130803Smarcel	      map.info.vaddr = mapinfo_p2->vaddr;
433130803Smarcel	      err =
434130803Smarcel		devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
435130803Smarcel	      if (err != EOK)
436130803Smarcel		continue;
437130803Smarcel
438130803Smarcel	      if (strcmp (map.info.path, printme.name))
439130803Smarcel		continue;
440130803Smarcel
441130803Smarcel	      /* Lower debug_vaddr is always text, if nessessary, swap.  */
442130803Smarcel	      if ((int) map.info.vaddr < (int) printme.text.debug_vaddr)
443130803Smarcel		{
444130803Smarcel		  memcpy (&(printme.data), &(printme.text),
445130803Smarcel			  sizeof (printme.data));
446130803Smarcel		  printme.text.addr = mapinfo_p2->vaddr;
447130803Smarcel		  printme.text.size = mapinfo_p2->size;
448130803Smarcel		  printme.text.flags = mapinfo_p2->flags;
449130803Smarcel		  printme.text.offset = mapinfo_p2->offset;
450130803Smarcel		  printme.text.debug_vaddr = map.info.vaddr;
451130803Smarcel		}
452130803Smarcel	      else
453130803Smarcel		{
454130803Smarcel		  printme.data.addr = mapinfo_p2->vaddr;
455130803Smarcel		  printme.data.size = mapinfo_p2->size;
456130803Smarcel		  printme.data.flags = mapinfo_p2->flags;
457130803Smarcel		  printme.data.offset = mapinfo_p2->offset;
458130803Smarcel		  printme.data.debug_vaddr = map.info.vaddr;
459130803Smarcel		}
460130803Smarcel	      mapinfo_p2->ino = 0;
461130803Smarcel	    }
462130803Smarcel	}
463130803Smarcel      mapinfo_p->ino = 0;
464130803Smarcel
465130803Smarcel      printf_filtered ("%s\n", printme.name);
466130803Smarcel      printf_filtered ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size,
467130803Smarcel		       printme.text.addr);
468130803Smarcel      printf_filtered ("\t\tflags=%08x\n", printme.text.flags);
469130803Smarcel      printf_filtered ("\t\tdebug=%08x\n", printme.text.debug_vaddr);
470130803Smarcel      printf_filtered ("\t\toffset=%016llx\n", printme.text.offset);
471130803Smarcel      if (printme.data.size)
472130803Smarcel	{
473130803Smarcel	  printf_filtered ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size,
474130803Smarcel			   printme.data.addr);
475130803Smarcel	  printf_filtered ("\t\tflags=%08x\n", printme.data.flags);
476130803Smarcel	  printf_filtered ("\t\tdebug=%08x\n", printme.data.debug_vaddr);
477130803Smarcel	  printf_filtered ("\t\toffset=%016llx\n", printme.data.offset);
478130803Smarcel	}
479130803Smarcel      printf_filtered ("\tdev=0x%x\n", printme.dev);
480130803Smarcel      printf_filtered ("\tino=0x%x\n", (unsigned int) printme.ino);
481130803Smarcel    }
482130803Smarcel  xfree (mapinfos);
483130803Smarcel  return;
484130803Smarcel}
485130803Smarcel
486130803Smarcel/* Print status information about what we're accessing.  */
487130803Smarcelstatic void
488130803Smarcelprocfs_files_info (struct target_ops *ignore)
489130803Smarcel{
490130803Smarcel  printf_unfiltered ("\tUsing the running image of %s %s via %s.\n",
491130803Smarcel		     attach_flag ? "attached" : "child",
492130803Smarcel		     target_pid_to_str (inferior_ptid), nto_procfs_path);
493130803Smarcel}
494130803Smarcel
495130803Smarcel/* Mark our target-struct as eligible for stray "run" and "attach" commands.  */
496130803Smarcelstatic int
497130803Smarcelprocfs_can_run (void)
498130803Smarcel{
499130803Smarcel  return 1;
500130803Smarcel}
501130803Smarcel
502130803Smarcel/* Attach to process PID, then initialize for debugging it.  */
503130803Smarcelstatic void
504130803Smarcelprocfs_attach (char *args, int from_tty)
505130803Smarcel{
506130803Smarcel  char *exec_file;
507130803Smarcel  int pid;
508130803Smarcel
509130803Smarcel  if (!args)
510130803Smarcel    error_no_arg ("process-id to attach");
511130803Smarcel
512130803Smarcel  pid = atoi (args);
513130803Smarcel
514130803Smarcel  if (pid == getpid ())
515130803Smarcel    error ("Attaching GDB to itself is not a good idea...");
516130803Smarcel
517130803Smarcel  if (from_tty)
518130803Smarcel    {
519130803Smarcel      exec_file = (char *) get_exec_file (0);
520130803Smarcel
521130803Smarcel      if (exec_file)
522130803Smarcel	printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
523130803Smarcel			   target_pid_to_str (pid_to_ptid (pid)));
524130803Smarcel      else
525130803Smarcel	printf_unfiltered ("Attaching to %s\n",
526130803Smarcel			   target_pid_to_str (pid_to_ptid (pid)));
527130803Smarcel
528130803Smarcel      gdb_flush (gdb_stdout);
529130803Smarcel    }
530130803Smarcel  inferior_ptid = do_attach (pid_to_ptid (pid));
531130803Smarcel  push_target (&procfs_ops);
532130803Smarcel}
533130803Smarcel
534130803Smarcelstatic void
535130803Smarcelprocfs_post_attach (pid_t pid)
536130803Smarcel{
537130803Smarcel#ifdef SOLIB_CREATE_INFERIOR_HOOK
538130803Smarcel  if (exec_bfd)
539130803Smarcel    SOLIB_CREATE_INFERIOR_HOOK (pid);
540130803Smarcel#endif
541130803Smarcel}
542130803Smarcel
543130803Smarcelstatic ptid_t
544130803Smarceldo_attach (ptid_t ptid)
545130803Smarcel{
546130803Smarcel  procfs_status status;
547130803Smarcel  struct sigevent event;
548130803Smarcel  char path[PATH_MAX];
549130803Smarcel
550130803Smarcel  snprintf (path, PATH_MAX - 1, "%s/%d/as", nto_procfs_path, PIDGET (ptid));
551130803Smarcel  ctl_fd = open (path, O_RDWR);
552130803Smarcel  if (ctl_fd == -1)
553130803Smarcel    error ("Couldn't open proc file %s, error %d (%s)", path, errno,
554130803Smarcel	   safe_strerror (errno));
555130803Smarcel  if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK)
556130803Smarcel    error ("Couldn't stop process");
557130803Smarcel
558130803Smarcel  /* Define a sigevent for process stopped notification.  */
559130803Smarcel  event.sigev_notify = SIGEV_SIGNAL_THREAD;
560130803Smarcel  event.sigev_signo = SIGUSR1;
561130803Smarcel  event.sigev_code = 0;
562130803Smarcel  event.sigev_value.sival_ptr = NULL;
563130803Smarcel  event.sigev_priority = -1;
564130803Smarcel  devctl (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
565130803Smarcel
566130803Smarcel  if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK
567130803Smarcel      && status.flags & _DEBUG_FLAG_STOPPED)
568130803Smarcel    SignalKill (nto_node(), PIDGET (ptid), 0, SIGCONT, 0, 0);
569130803Smarcel  attach_flag = 1;
570130803Smarcel  nto_init_solib_absolute_prefix ();
571130803Smarcel  return ptid;
572130803Smarcel}
573130803Smarcel
574130803Smarcel/* Ask the user what to do when an interrupt is received.  */
575130803Smarcelstatic void
576130803Smarcelinterrupt_query (void)
577130803Smarcel{
578130803Smarcel  target_terminal_ours ();
579130803Smarcel
580130803Smarcel  if (query ("Interrupted while waiting for the program.\n\
581130803SmarcelGive up (and stop debugging it)? "))
582130803Smarcel    {
583130803Smarcel      target_mourn_inferior ();
584130803Smarcel      throw_exception (RETURN_QUIT);
585130803Smarcel    }
586130803Smarcel
587130803Smarcel  target_terminal_inferior ();
588130803Smarcel}
589130803Smarcel
590130803Smarcel/* The user typed ^C twice.  */
591130803Smarcelstatic void
592130803Smarcelnto_interrupt_twice (int signo)
593130803Smarcel{
594130803Smarcel  signal (signo, ofunc);
595130803Smarcel  interrupt_query ();
596130803Smarcel  signal (signo, nto_interrupt_twice);
597130803Smarcel}
598130803Smarcel
599130803Smarcelstatic void
600130803Smarcelnto_interrupt (int signo)
601130803Smarcel{
602130803Smarcel  /* If this doesn't work, try more severe steps.  */
603130803Smarcel  signal (signo, nto_interrupt_twice);
604130803Smarcel
605130803Smarcel  target_stop ();
606130803Smarcel}
607130803Smarcel
608130803Smarcelstatic ptid_t
609130803Smarcelprocfs_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
610130803Smarcel{
611130803Smarcel  sigset_t set;
612130803Smarcel  siginfo_t info;
613130803Smarcel  procfs_status status;
614130803Smarcel  static int exit_signo = 0;	/* To track signals that cause termination.  */
615130803Smarcel
616130803Smarcel  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
617130803Smarcel
618130803Smarcel  if (ptid_equal (inferior_ptid, null_ptid))
619130803Smarcel    {
620130803Smarcel      ourstatus->kind = TARGET_WAITKIND_STOPPED;
621130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_0;
622130803Smarcel      exit_signo = 0;
623130803Smarcel      return null_ptid;
624130803Smarcel    }
625130803Smarcel
626130803Smarcel  sigemptyset (&set);
627130803Smarcel  sigaddset (&set, SIGUSR1);
628130803Smarcel
629130803Smarcel  devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
630130803Smarcel  while (!(status.flags & _DEBUG_FLAG_ISTOP))
631130803Smarcel    {
632130803Smarcel      ofunc = (void (*)()) signal (SIGINT, nto_interrupt);
633130803Smarcel      sigwaitinfo (&set, &info);
634130803Smarcel      signal (SIGINT, ofunc);
635130803Smarcel      devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
636130803Smarcel    }
637130803Smarcel
638130803Smarcel  if (status.flags & _DEBUG_FLAG_SSTEP)
639130803Smarcel    {
640130803Smarcel      ourstatus->kind = TARGET_WAITKIND_STOPPED;
641130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
642130803Smarcel    }
643130803Smarcel  /* Was it a breakpoint?  */
644130803Smarcel  else if (status.flags & _DEBUG_FLAG_TRACE)
645130803Smarcel    {
646130803Smarcel      ourstatus->kind = TARGET_WAITKIND_STOPPED;
647130803Smarcel      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
648130803Smarcel    }
649130803Smarcel  else if (status.flags & _DEBUG_FLAG_ISTOP)
650130803Smarcel    {
651130803Smarcel      switch (status.why)
652130803Smarcel	{
653130803Smarcel	case _DEBUG_WHY_SIGNALLED:
654130803Smarcel	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
655130803Smarcel	  ourstatus->value.sig =
656130803Smarcel	    target_signal_from_host (status.info.si_signo);
657130803Smarcel	  exit_signo = 0;
658130803Smarcel	  break;
659130803Smarcel	case _DEBUG_WHY_FAULTED:
660130803Smarcel	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
661130803Smarcel	  if (status.info.si_signo == SIGTRAP)
662130803Smarcel	    {
663130803Smarcel	      ourstatus->value.sig = 0;
664130803Smarcel	      exit_signo = 0;
665130803Smarcel	    }
666130803Smarcel	  else
667130803Smarcel	    {
668130803Smarcel	      ourstatus->value.sig =
669130803Smarcel		target_signal_from_host (status.info.si_signo);
670130803Smarcel	      exit_signo = ourstatus->value.sig;
671130803Smarcel	    }
672130803Smarcel	  break;
673130803Smarcel
674130803Smarcel	case _DEBUG_WHY_TERMINATED:
675130803Smarcel	  {
676130803Smarcel	    int waitval = 0;
677130803Smarcel
678130803Smarcel	    waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG);
679130803Smarcel	    if (exit_signo)
680130803Smarcel	      {
681130803Smarcel		/* Abnormal death.  */
682130803Smarcel		ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
683130803Smarcel		ourstatus->value.sig = exit_signo;
684130803Smarcel	      }
685130803Smarcel	    else
686130803Smarcel	      {
687130803Smarcel		/* Normal death.  */
688130803Smarcel		ourstatus->kind = TARGET_WAITKIND_EXITED;
689130803Smarcel		ourstatus->value.integer = WEXITSTATUS (waitval);
690130803Smarcel	      }
691130803Smarcel	    exit_signo = 0;
692130803Smarcel	    break;
693130803Smarcel	  }
694130803Smarcel
695130803Smarcel	case _DEBUG_WHY_REQUESTED:
696130803Smarcel	  /* We are assuming a requested stop is due to a SIGINT.  */
697130803Smarcel	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
698130803Smarcel	  ourstatus->value.sig = TARGET_SIGNAL_INT;
699130803Smarcel	  exit_signo = 0;
700130803Smarcel	  break;
701130803Smarcel	}
702130803Smarcel    }
703130803Smarcel
704130803Smarcel  return inferior_ptid;
705130803Smarcel}
706130803Smarcel
707130803Smarcel/* Read the current values of the inferior's registers, both the
708130803Smarcel   general register set and floating point registers (if supported)
709130803Smarcel   and update gdb's idea of their current values.  */
710130803Smarcelstatic void
711130803Smarcelprocfs_fetch_registers (int regno)
712130803Smarcel{
713130803Smarcel  union
714130803Smarcel  {
715130803Smarcel    procfs_greg greg;
716130803Smarcel    procfs_fpreg fpreg;
717130803Smarcel    procfs_altreg altreg;
718130803Smarcel  }
719130803Smarcel  reg;
720130803Smarcel  int regsize;
721130803Smarcel
722130803Smarcel  procfs_set_thread (inferior_ptid);
723130803Smarcel  if (devctl (ctl_fd, DCMD_PROC_GETGREG, &reg, sizeof (reg), &regsize) == EOK)
724130803Smarcel    nto_supply_gregset ((char *) &reg.greg);
725130803Smarcel  if (devctl (ctl_fd, DCMD_PROC_GETFPREG, &reg, sizeof (reg), &regsize)
726130803Smarcel      == EOK)
727130803Smarcel    nto_supply_fpregset ((char *) &reg.fpreg);
728130803Smarcel  if (devctl (ctl_fd, DCMD_PROC_GETALTREG, &reg, sizeof (reg), &regsize)
729130803Smarcel      == EOK)
730130803Smarcel    nto_supply_altregset ((char *) &reg.altreg);
731130803Smarcel}
732130803Smarcel
733130803Smarcel/* Copy LEN bytes to/from inferior's memory starting at MEMADDR
734130803Smarcel   from/to debugger memory starting at MYADDR.  Copy from inferior
735130803Smarcel   if DOWRITE is zero or to inferior if DOWRITE is nonzero.
736130803Smarcel
737130803Smarcel   Returns the length copied, which is either the LEN argument or
738130803Smarcel   zero.  This xfer function does not do partial moves, since procfs_ops
739130803Smarcel   doesn't allow memory operations to cross below us in the target stack
740130803Smarcel   anyway.  */
741130803Smarcelstatic int
742130803Smarcelprocfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
743130803Smarcel		    struct mem_attrib *attrib, struct target_ops *target)
744130803Smarcel{
745130803Smarcel  int nbytes = 0;
746130803Smarcel
747130803Smarcel  if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr)
748130803Smarcel    {
749130803Smarcel      if (dowrite)
750130803Smarcel	nbytes = write (ctl_fd, myaddr, len);
751130803Smarcel      else
752130803Smarcel	nbytes = read (ctl_fd, myaddr, len);
753130803Smarcel      if (nbytes < 0)
754130803Smarcel	nbytes = 0;
755130803Smarcel    }
756130803Smarcel  return (nbytes);
757130803Smarcel}
758130803Smarcel
759130803Smarcel/* Take a program previously attached to and detaches it.
760130803Smarcel   The program resumes execution and will no longer stop
761130803Smarcel   on signals, etc.  We'd better not have left any breakpoints
762130803Smarcel   in the program or it'll die when it hits one.  */
763130803Smarcelstatic void
764130803Smarcelprocfs_detach (char *args, int from_tty)
765130803Smarcel{
766130803Smarcel  int siggnal = 0;
767130803Smarcel
768130803Smarcel  if (from_tty)
769130803Smarcel    {
770130803Smarcel      char *exec_file = get_exec_file (0);
771130803Smarcel      if (exec_file == 0)
772130803Smarcel	exec_file = "";
773130803Smarcel      printf_unfiltered ("Detaching from program: %s %s\n",
774130803Smarcel			 exec_file, target_pid_to_str (inferior_ptid));
775130803Smarcel      gdb_flush (gdb_stdout);
776130803Smarcel    }
777130803Smarcel  if (args)
778130803Smarcel    siggnal = atoi (args);
779130803Smarcel
780130803Smarcel  if (siggnal)
781130803Smarcel    SignalKill (nto_node(), PIDGET (inferior_ptid), 0, siggnal, 0, 0);
782130803Smarcel
783130803Smarcel  close (ctl_fd);
784130803Smarcel  ctl_fd = -1;
785130803Smarcel  init_thread_list ();
786130803Smarcel  inferior_ptid = null_ptid;
787130803Smarcel  attach_flag = 0;
788130803Smarcel  unpush_target (&procfs_ops);	/* Pop out of handling an inferior.  */
789130803Smarcel}
790130803Smarcel
791130803Smarcelstatic int
792130803Smarcelprocfs_breakpoint (CORE_ADDR addr, int type, int size)
793130803Smarcel{
794130803Smarcel  procfs_break brk;
795130803Smarcel
796130803Smarcel  brk.type = type;
797130803Smarcel  brk.addr = addr;
798130803Smarcel  brk.size = size;
799130803Smarcel  errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
800130803Smarcel  if (errno != EOK)
801130803Smarcel    return 1;
802130803Smarcel  return 0;
803130803Smarcel}
804130803Smarcel
805130803Smarcelstatic int
806130803Smarcelprocfs_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
807130803Smarcel{
808130803Smarcel  return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, 0);
809130803Smarcel}
810130803Smarcel
811130803Smarcelstatic int
812130803Smarcelprocfs_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
813130803Smarcel{
814130803Smarcel  return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, -1);
815130803Smarcel}
816130803Smarcel
817130803Smarcelstatic int
818130803Smarcelprocfs_insert_hw_breakpoint (CORE_ADDR addr, char *contents_cache)
819130803Smarcel{
820130803Smarcel  return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0);
821130803Smarcel}
822130803Smarcel
823130803Smarcelstatic int
824130803Smarcelprocfs_remove_hw_breakpoint (CORE_ADDR addr, char *contents_cache)
825130803Smarcel{
826130803Smarcel  return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1);
827130803Smarcel}
828130803Smarcel
829130803Smarcelstatic void
830130803Smarcelprocfs_resume (ptid_t ptid, int step, enum target_signal signo)
831130803Smarcel{
832130803Smarcel  int signal_to_pass;
833130803Smarcel  procfs_status status;
834130803Smarcel
835130803Smarcel  if (ptid_equal (inferior_ptid, null_ptid))
836130803Smarcel    return;
837130803Smarcel
838130803Smarcel  procfs_set_thread (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid :
839130803Smarcel		     ptid);
840130803Smarcel
841130803Smarcel  run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
842130803Smarcel  if (step)
843130803Smarcel    run.flags |= _DEBUG_RUN_STEP;
844130803Smarcel
845130803Smarcel  sigemptyset ((sigset_t *) &run.fault);
846130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTBPT);
847130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTTRACE);
848130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTILL);
849130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTPRIV);
850130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTBOUNDS);
851130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTIOVF);
852130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTIZDIV);
853130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTFPE);
854130803Smarcel  /* Peter V will be changing this at some point.  */
855130803Smarcel  sigaddset ((sigset_t *) &run.fault, FLTPAGE);
856130803Smarcel
857130803Smarcel  run.flags |= _DEBUG_RUN_ARM;
858130803Smarcel
859130803Smarcel  sigemptyset (&run.trace);
860130803Smarcel  notice_signals ();
861130803Smarcel  signal_to_pass = target_signal_to_host (signo);
862130803Smarcel
863130803Smarcel  if (signal_to_pass)
864130803Smarcel    {
865130803Smarcel      devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
866130803Smarcel      signal_to_pass = target_signal_to_host (signo);
867130803Smarcel      if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
868130803Smarcel	{
869130803Smarcel	  if (signal_to_pass != status.info.si_signo)
870130803Smarcel	    {
871130803Smarcel	      SignalKill (nto_node(), PIDGET (inferior_ptid), 0, signal_to_pass,
872130803Smarcel			  0, 0);
873130803Smarcel	      run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
874130803Smarcel	    }
875130803Smarcel	  else			/* Let it kill the program without telling us.  */
876130803Smarcel	    sigdelset (&run.trace, signal_to_pass);
877130803Smarcel	}
878130803Smarcel    }
879130803Smarcel  else
880130803Smarcel    run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
881130803Smarcel
882130803Smarcel  errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
883130803Smarcel  if (errno != EOK)
884130803Smarcel    {
885130803Smarcel      perror ("run error!\n");
886130803Smarcel      return;
887130803Smarcel    }
888130803Smarcel}
889130803Smarcel
890130803Smarcelstatic void
891130803Smarcelprocfs_mourn_inferior (void)
892130803Smarcel{
893130803Smarcel  if (!ptid_equal (inferior_ptid, null_ptid))
894130803Smarcel    {
895130803Smarcel      SignalKill (nto_node(), PIDGET (inferior_ptid), 0, SIGKILL, 0, 0);
896130803Smarcel      close (ctl_fd);
897130803Smarcel    }
898130803Smarcel  inferior_ptid = null_ptid;
899130803Smarcel  init_thread_list ();
900130803Smarcel  unpush_target (&procfs_ops);
901130803Smarcel  generic_mourn_inferior ();
902130803Smarcel  attach_flag = 0;
903130803Smarcel}
904130803Smarcel
905130803Smarcel/* This function breaks up an argument string into an argument
906130803Smarcel   vector suitable for passing to execvp().
907130803Smarcel   E.g., on "run a b c d" this routine would get as input
908130803Smarcel   the string "a b c d", and as output it would fill in argv with
909130803Smarcel   the four arguments "a", "b", "c", "d".  The only additional
910130803Smarcel   functionality is simple quoting.  The gdb command:
911130803Smarcel  	run a "b c d" f
912130803Smarcel   will fill in argv with the three args "a", "b c d", "e".  */
913130803Smarcelstatic void
914130803Smarcelbreakup_args (char *scratch, char **argv)
915130803Smarcel{
916130803Smarcel  char *pp, *cp = scratch;
917130803Smarcel  char quoting = 0;
918130803Smarcel
919130803Smarcel  for (;;)
920130803Smarcel    {
921130803Smarcel      /* Scan past leading separators.  */
922130803Smarcel      quoting = 0;
923130803Smarcel      while (*cp == ' ' || *cp == '\t' || *cp == '\n')
924130803Smarcel	cp++;
925130803Smarcel
926130803Smarcel      /* Break if at end of string.  */
927130803Smarcel      if (*cp == '\0')
928130803Smarcel	break;
929130803Smarcel
930130803Smarcel      /* Take an arg.  */
931130803Smarcel      if (*cp == '"')
932130803Smarcel	{
933130803Smarcel	  cp++;
934130803Smarcel	  quoting = strchr (cp, '"') ? 1 : 0;
935130803Smarcel	}
936130803Smarcel
937130803Smarcel      *argv++ = cp;
938130803Smarcel
939130803Smarcel      /* Scan for next arg separator.  */
940130803Smarcel      pp = cp;
941130803Smarcel      if (quoting)
942130803Smarcel	cp = strchr (pp, '"');
943130803Smarcel      if ((cp == NULL) || (!quoting))
944130803Smarcel	cp = strchr (pp, ' ');
945130803Smarcel      if (cp == NULL)
946130803Smarcel	cp = strchr (pp, '\t');
947130803Smarcel      if (cp == NULL)
948130803Smarcel	cp = strchr (pp, '\n');
949130803Smarcel
950130803Smarcel      /* No separators => end of string => break.  */
951130803Smarcel      if (cp == NULL)
952130803Smarcel	{
953130803Smarcel	  pp = cp;
954130803Smarcel	  break;
955130803Smarcel	}
956130803Smarcel
957130803Smarcel      /* Replace the separator with a terminator.  */
958130803Smarcel      *cp++ = '\0';
959130803Smarcel    }
960130803Smarcel
961130803Smarcel  /* Execv requires a null-terminated arg vector.  */
962130803Smarcel  *argv = NULL;
963130803Smarcel}
964130803Smarcel
965130803Smarcelstatic void
966130803Smarcelprocfs_create_inferior (char *exec_file, char *allargs, char **env)
967130803Smarcel{
968130803Smarcel  struct inheritance inherit;
969130803Smarcel  pid_t pid;
970130803Smarcel  int flags, errn;
971130803Smarcel  char **argv, *args;
972130803Smarcel  char *in = "", *out = "", *err = "";
973130803Smarcel  int fd, fds[3];
974130803Smarcel  sigset_t set;
975130803Smarcel
976130803Smarcel  argv = xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) *
977130803Smarcel		  sizeof (*argv));
978130803Smarcel  argv[0] = get_exec_file (1);
979130803Smarcel  if (!argv[0])
980130803Smarcel    {
981130803Smarcel      if (exec_file)
982130803Smarcel	argv[0] = exec_file;
983130803Smarcel      else
984130803Smarcel	return;
985130803Smarcel    }
986130803Smarcel
987130803Smarcel  args = xstrdup (allargs);
988130803Smarcel  breakup_args (args, exec_file ? &argv[1] : &argv[0]);
989130803Smarcel
990130803Smarcel  argv = nto_parse_redirection (argv, &in, &out, &err);
991130803Smarcel
992130803Smarcel  fds[0] = STDIN_FILENO;
993130803Smarcel  fds[1] = STDOUT_FILENO;
994130803Smarcel  fds[2] = STDERR_FILENO;
995130803Smarcel
996130803Smarcel  /* If the user specified I/O via gdb's --tty= arg, use it, but only
997130803Smarcel     if the i/o is not also being specified via redirection.  */
998130803Smarcel  if (inferior_io_terminal)
999130803Smarcel    {
1000130803Smarcel      if (!in[0])
1001130803Smarcel	in = inferior_io_terminal;
1002130803Smarcel      if (!out[0])
1003130803Smarcel	out = inferior_io_terminal;
1004130803Smarcel      if (!err[0])
1005130803Smarcel	err = inferior_io_terminal;
1006130803Smarcel    }
1007130803Smarcel
1008130803Smarcel  if (in[0])
1009130803Smarcel    {
1010130803Smarcel      fd = open (in, O_RDONLY);
1011130803Smarcel      if (fd == -1)
1012130803Smarcel	perror (in);
1013130803Smarcel      else
1014130803Smarcel	fds[0] = fd;
1015130803Smarcel    }
1016130803Smarcel  if (out[0])
1017130803Smarcel    {
1018130803Smarcel      fd = open (out, O_WRONLY);
1019130803Smarcel      if (fd == -1)
1020130803Smarcel	perror (out);
1021130803Smarcel      else
1022130803Smarcel	fds[1] = fd;
1023130803Smarcel    }
1024130803Smarcel  if (err[0])
1025130803Smarcel    {
1026130803Smarcel      fd = open (err, O_WRONLY);
1027130803Smarcel      if (fd == -1)
1028130803Smarcel	perror (err);
1029130803Smarcel      else
1030130803Smarcel	fds[2] = fd;
1031130803Smarcel    }
1032130803Smarcel
1033130803Smarcel  /* Clear any pending SIGUSR1's but keep the behavior the same.  */
1034130803Smarcel  signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
1035130803Smarcel
1036130803Smarcel  sigemptyset (&set);
1037130803Smarcel  sigaddset (&set, SIGUSR1);
1038130803Smarcel  sigprocmask (SIG_UNBLOCK, &set, NULL);
1039130803Smarcel
1040130803Smarcel  memset (&inherit, 0, sizeof (inherit));
1041130803Smarcel
1042130803Smarcel  if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0)
1043130803Smarcel    {
1044130803Smarcel      inherit.nd = nto_node();
1045130803Smarcel      inherit.flags |= SPAWN_SETND;
1046130803Smarcel      inherit.flags &= ~SPAWN_EXEC;
1047130803Smarcel    }
1048130803Smarcel  inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
1049130803Smarcel  inherit.pgroup = SPAWN_NEWPGROUP;
1050130803Smarcel  pid = spawnp (argv[0], 3, fds, &inherit, argv,
1051130803Smarcel		ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0);
1052130803Smarcel  xfree (args);
1053130803Smarcel
1054130803Smarcel  sigprocmask (SIG_BLOCK, &set, NULL);
1055130803Smarcel
1056130803Smarcel  if (pid == -1)
1057130803Smarcel    error ("Error spawning %s: %d (%s)", argv[0], errno, safe_strerror (errno));
1058130803Smarcel
1059130803Smarcel  if (fds[0] != STDIN_FILENO)
1060130803Smarcel    close (fds[0]);
1061130803Smarcel  if (fds[1] != STDOUT_FILENO)
1062130803Smarcel    close (fds[1]);
1063130803Smarcel  if (fds[2] != STDERR_FILENO)
1064130803Smarcel    close (fds[2]);
1065130803Smarcel
1066130803Smarcel  inferior_ptid = do_attach (pid_to_ptid (pid));
1067130803Smarcel
1068130803Smarcel  attach_flag = 0;
1069130803Smarcel  flags = _DEBUG_FLAG_KLC;	/* Kill-on-Last-Close flag.  */
1070130803Smarcel  errn = devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0);
1071130803Smarcel  if (errn != EOK)
1072130803Smarcel    {
1073130803Smarcel      /* FIXME: expected warning?  */
1074130803Smarcel      /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n",
1075130803Smarcel         errn, strerror(errn) ); */
1076130803Smarcel    }
1077130803Smarcel  push_target (&procfs_ops);
1078130803Smarcel  target_terminal_init ();
1079130803Smarcel
1080130803Smarcel#ifdef SOLIB_CREATE_INFERIOR_HOOK
1081130803Smarcel  if (exec_bfd != NULL
1082130803Smarcel      || (symfile_objfile != NULL && symfile_objfile->obfd != NULL))
1083130803Smarcel    SOLIB_CREATE_INFERIOR_HOOK (pid);
1084130803Smarcel#endif
1085130803Smarcel}
1086130803Smarcel
1087130803Smarcelstatic void
1088130803Smarcelprocfs_stop (void)
1089130803Smarcel{
1090130803Smarcel  devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0);
1091130803Smarcel}
1092130803Smarcel
1093130803Smarcelstatic void
1094130803Smarcelprocfs_kill_inferior (void)
1095130803Smarcel{
1096130803Smarcel  target_mourn_inferior ();
1097130803Smarcel}
1098130803Smarcel
1099130803Smarcel/* Store register REGNO, or all registers if REGNO == -1, from the contents
1100130803Smarcel   of REGISTERS.  */
1101130803Smarcelstatic void
1102130803Smarcelprocfs_prepare_to_store (void)
1103130803Smarcel{
1104130803Smarcel}
1105130803Smarcel
1106130803Smarcel/* Fill buf with regset and return devctl cmd to do the setting.  Return
1107130803Smarcel   -1 if we fail to get the regset.  Store size of regset in regsize.  */
1108130803Smarcelstatic int
1109130803Smarcelget_regset (int regset, char *buf, int bufsize, int *regsize)
1110130803Smarcel{
1111130803Smarcel  int dev_get, dev_set;
1112130803Smarcel  switch (regset)
1113130803Smarcel    {
1114130803Smarcel    case NTO_REG_GENERAL:
1115130803Smarcel      dev_get = DCMD_PROC_GETGREG;
1116130803Smarcel      dev_set = DCMD_PROC_SETGREG;
1117130803Smarcel      break;
1118130803Smarcel
1119130803Smarcel    case NTO_REG_FLOAT:
1120130803Smarcel      dev_get = DCMD_PROC_GETFPREG;
1121130803Smarcel      dev_set = DCMD_PROC_SETFPREG;
1122130803Smarcel      break;
1123130803Smarcel
1124130803Smarcel    case NTO_REG_ALT:
1125130803Smarcel      dev_get = DCMD_PROC_GETALTREG;
1126130803Smarcel      dev_set = DCMD_PROC_SETALTREG;
1127130803Smarcel      break;
1128130803Smarcel
1129130803Smarcel    case NTO_REG_SYSTEM:
1130130803Smarcel    default:
1131130803Smarcel      return -1;
1132130803Smarcel    }
1133130803Smarcel  if (devctl (ctl_fd, dev_get, &buf, bufsize, regsize) != EOK)
1134130803Smarcel    return -1;
1135130803Smarcel
1136130803Smarcel  return dev_set;
1137130803Smarcel}
1138130803Smarcel
1139130803Smarcelvoid
1140130803Smarcelprocfs_store_registers (int regno)
1141130803Smarcel{
1142130803Smarcel  union
1143130803Smarcel  {
1144130803Smarcel    procfs_greg greg;
1145130803Smarcel    procfs_fpreg fpreg;
1146130803Smarcel    procfs_altreg altreg;
1147130803Smarcel  }
1148130803Smarcel  reg;
1149130803Smarcel  unsigned off;
1150130803Smarcel  int len, regset, regsize, dev_set, err;
1151130803Smarcel  char *data;
1152130803Smarcel
1153130803Smarcel  if (ptid_equal (inferior_ptid, null_ptid))
1154130803Smarcel    return;
1155130803Smarcel  procfs_set_thread (inferior_ptid);
1156130803Smarcel
1157130803Smarcel  if (regno == -1)
1158130803Smarcel    {
1159130803Smarcel      for (regset = NTO_REG_GENERAL; regset < NTO_REG_END; regset++)
1160130803Smarcel	{
1161130803Smarcel	  dev_set = get_regset (regset, (char *) &reg,
1162130803Smarcel				sizeof (reg), &regsize);
1163130803Smarcel	  if (dev_set == -1)
1164130803Smarcel	    continue;
1165130803Smarcel
1166130803Smarcel	  if (nto_regset_fill (regset, (char *) &reg) == -1)
1167130803Smarcel	    continue;
1168130803Smarcel
1169130803Smarcel	  err = devctl (ctl_fd, dev_set, &reg, regsize, 0);
1170130803Smarcel	  if (err != EOK)
1171130803Smarcel	    fprintf_unfiltered (gdb_stderr,
1172130803Smarcel				"Warning unable to write regset %d: %s\n",
1173130803Smarcel				regno, safe_strerror (err));
1174130803Smarcel	}
1175130803Smarcel    }
1176130803Smarcel  else
1177130803Smarcel    {
1178130803Smarcel      regset = nto_regset_id (regno);
1179130803Smarcel      if (regset == -1)
1180130803Smarcel	return;
1181130803Smarcel
1182130803Smarcel      dev_set = get_regset (regset, (char *) &reg, sizeof (reg), &regsize);
1183130803Smarcel      if (dev_set == -1)
1184130803Smarcel	return;
1185130803Smarcel
1186130803Smarcel      len = nto_register_area (regno, regset, &off);
1187130803Smarcel
1188130803Smarcel      if (len < 1)
1189130803Smarcel	return;
1190130803Smarcel
1191130803Smarcel      regcache_collect (regno, (char *) &reg + off);
1192130803Smarcel
1193130803Smarcel      err = devctl (ctl_fd, dev_set, &reg, regsize, 0);
1194130803Smarcel      if (err != EOK)
1195130803Smarcel	fprintf_unfiltered (gdb_stderr,
1196130803Smarcel			    "Warning unable to write regset %d: %s\n", regno,
1197130803Smarcel			    safe_strerror (err));
1198130803Smarcel    }
1199130803Smarcel}
1200130803Smarcel
1201130803Smarcelstatic void
1202130803Smarcelnotice_signals (void)
1203130803Smarcel{
1204130803Smarcel  int signo;
1205130803Smarcel
1206130803Smarcel  for (signo = 1; signo < NSIG; signo++)
1207130803Smarcel    {
1208130803Smarcel      if (signal_stop_state (target_signal_from_host (signo)) == 0
1209130803Smarcel	  && signal_print_state (target_signal_from_host (signo)) == 0
1210130803Smarcel	  && signal_pass_state (target_signal_from_host (signo)) == 1)
1211130803Smarcel	sigdelset (&run.trace, signo);
1212130803Smarcel      else
1213130803Smarcel	sigaddset (&run.trace, signo);
1214130803Smarcel    }
1215130803Smarcel}
1216130803Smarcel
1217130803Smarcel/* When the user changes the state of gdb's signal handling via the
1218130803Smarcel   "handle" command, this function gets called to see if any change
1219130803Smarcel   in the /proc interface is required.  It is also called internally
1220130803Smarcel   by other /proc interface functions to initialize the state of
1221130803Smarcel   the traced signal set.  */
1222130803Smarcelstatic void
1223130803Smarcelprocfs_notice_signals (ptid_t ptid)
1224130803Smarcel{
1225130803Smarcel  sigemptyset (&run.trace);
1226130803Smarcel  notice_signals ();
1227130803Smarcel}
1228130803Smarcel
1229130803Smarcelstatic struct tidinfo *
1230130803Smarcelprocfs_thread_info (pid_t pid, short tid)
1231130803Smarcel{
1232130803Smarcel/* NYI */
1233130803Smarcel  return NULL;
1234130803Smarcel}
1235130803Smarcel
1236130803Smarcelchar *
1237130803Smarcelprocfs_pid_to_str (ptid_t ptid)
1238130803Smarcel{
1239130803Smarcel  static char buf[1024];
1240130803Smarcel  int pid, tid, n;
1241130803Smarcel  struct tidinfo *tip;
1242130803Smarcel
1243130803Smarcel  pid = ptid_get_pid (ptid);
1244130803Smarcel  tid = ptid_get_tid (ptid);
1245130803Smarcel
1246130803Smarcel  n = snprintf (buf, 1023, "process %d", pid);
1247130803Smarcel
1248130803Smarcel#if 0				/* NYI */
1249130803Smarcel  tip = procfs_thread_info (pid, tid);
1250130803Smarcel  if (tip != NULL)
1251130803Smarcel    snprintf (&buf[n], 1023, " (state = 0x%02x)", tip->state);
1252130803Smarcel#endif
1253130803Smarcel
1254130803Smarcel  return buf;
1255130803Smarcel}
1256130803Smarcel
1257130803Smarcelstatic void
1258130803Smarcelinit_procfs_ops (void)
1259130803Smarcel{
1260130803Smarcel  procfs_ops.to_shortname = "procfs";
1261130803Smarcel  procfs_ops.to_longname = "QNX Neutrino procfs child process";
1262130803Smarcel  procfs_ops.to_doc =
1263130803Smarcel    "QNX Neutrino procfs child process (started by the \"run\" command).\n\
1264130803Smarcel	target procfs <node>";
1265130803Smarcel  procfs_ops.to_open = procfs_open;
1266130803Smarcel  procfs_ops.to_attach = procfs_attach;
1267130803Smarcel  procfs_ops.to_post_attach = procfs_post_attach;
1268130803Smarcel  procfs_ops.to_detach = procfs_detach;
1269130803Smarcel  procfs_ops.to_resume = procfs_resume;
1270130803Smarcel  procfs_ops.to_wait = procfs_wait;
1271130803Smarcel  procfs_ops.to_fetch_registers = procfs_fetch_registers;
1272130803Smarcel  procfs_ops.to_store_registers = procfs_store_registers;
1273130803Smarcel  procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
1274130803Smarcel  procfs_ops.to_xfer_memory = procfs_xfer_memory;
1275130803Smarcel  procfs_ops.to_files_info = procfs_files_info;
1276130803Smarcel  procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint;
1277130803Smarcel  procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint;
1278130803Smarcel  procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
1279130803Smarcel  procfs_ops.to_insert_hw_breakpoint = procfs_insert_hw_breakpoint;
1280130803Smarcel  procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint;
1281130803Smarcel  procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint;
1282130803Smarcel  procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint;
1283130803Smarcel  procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
1284130803Smarcel  procfs_ops.to_terminal_init = terminal_init_inferior;
1285130803Smarcel  procfs_ops.to_terminal_inferior = terminal_inferior;
1286130803Smarcel  procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
1287130803Smarcel  procfs_ops.to_terminal_ours = terminal_ours;
1288130803Smarcel  procfs_ops.to_terminal_info = child_terminal_info;
1289130803Smarcel  procfs_ops.to_kill = procfs_kill_inferior;
1290130803Smarcel  procfs_ops.to_create_inferior = procfs_create_inferior;
1291130803Smarcel  procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
1292130803Smarcel  procfs_ops.to_can_run = procfs_can_run;
1293130803Smarcel  procfs_ops.to_notice_signals = procfs_notice_signals;
1294130803Smarcel  procfs_ops.to_thread_alive = procfs_thread_alive;
1295130803Smarcel  procfs_ops.to_find_new_threads = procfs_find_new_threads;
1296130803Smarcel  procfs_ops.to_pid_to_str = procfs_pid_to_str;
1297130803Smarcel  procfs_ops.to_stop = procfs_stop;
1298130803Smarcel  procfs_ops.to_stratum = process_stratum;
1299130803Smarcel  procfs_ops.to_has_all_memory = 1;
1300130803Smarcel  procfs_ops.to_has_memory = 1;
1301130803Smarcel  procfs_ops.to_has_stack = 1;
1302130803Smarcel  procfs_ops.to_has_registers = 1;
1303130803Smarcel  procfs_ops.to_has_execution = 1;
1304130803Smarcel  procfs_ops.to_magic = OPS_MAGIC;
1305130803Smarcel  procfs_ops.to_have_continuable_watchpoint = 1;
1306130803Smarcel}
1307130803Smarcel
1308130803Smarcel#define OSTYPE_NTO 1
1309130803Smarcel
1310130803Smarcelvoid
1311130803Smarcel_initialize_procfs (void)
1312130803Smarcel{
1313130803Smarcel  sigset_t set;
1314130803Smarcel
1315130803Smarcel  init_procfs_ops ();
1316130803Smarcel  add_target (&procfs_ops);
1317130803Smarcel
1318130803Smarcel  /* We use SIGUSR1 to gain control after we block waiting for a process.
1319130803Smarcel     We use sigwaitevent to wait.  */
1320130803Smarcel  sigemptyset (&set);
1321130803Smarcel  sigaddset (&set, SIGUSR1);
1322130803Smarcel  sigprocmask (SIG_BLOCK, &set, NULL);
1323130803Smarcel
1324130803Smarcel  /* Set up trace and fault sets, as gdb expects them.  */
1325130803Smarcel  sigemptyset (&run.trace);
1326130803Smarcel  notice_signals ();
1327130803Smarcel
1328130803Smarcel  /* Stuff some information.  */
1329130803Smarcel  nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags;
1330130803Smarcel  nto_cpuinfo_valid = 1;
1331130803Smarcel
1332130803Smarcel  add_info ("pidlist", procfs_pidlist, "pidlist");
1333130803Smarcel  add_info ("meminfo", procfs_meminfo, "memory information");
1334130803Smarcel}
1335130803Smarcel
1336130803Smarcel
1337130803Smarcelstatic int
1338130803Smarcelprocfs_hw_watchpoint (int addr, int len, int type)
1339130803Smarcel{
1340130803Smarcel  procfs_break brk;
1341130803Smarcel
1342130803Smarcel  switch (type)
1343130803Smarcel    {
1344130803Smarcel    case 1:			/* Read.  */
1345130803Smarcel      brk.type = _DEBUG_BREAK_RD;
1346130803Smarcel      break;
1347130803Smarcel    case 2:			/* Read/Write.  */
1348130803Smarcel      brk.type = _DEBUG_BREAK_RW;
1349130803Smarcel      break;
1350130803Smarcel    default:			/* Modify.  */
1351130803Smarcel/* FIXME: brk.type = _DEBUG_BREAK_RWM gives EINVAL for some reason.  */
1352130803Smarcel      brk.type = _DEBUG_BREAK_RW;
1353130803Smarcel    }
1354130803Smarcel  brk.type |= _DEBUG_BREAK_HW;	/* Always ask for HW.  */
1355130803Smarcel  brk.addr = addr;
1356130803Smarcel  brk.size = len;
1357130803Smarcel
1358130803Smarcel  errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
1359130803Smarcel  if (errno != EOK)
1360130803Smarcel    {
1361130803Smarcel      perror ("Failed to set hardware watchpoint");
1362130803Smarcel      return -1;
1363130803Smarcel    }
1364130803Smarcel  return 0;
1365130803Smarcel}
1366130803Smarcel
1367130803Smarcelstatic int
1368130803Smarcelprocfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
1369130803Smarcel{
1370130803Smarcel  return 1;
1371130803Smarcel}
1372130803Smarcel
1373130803Smarcelstatic int
1374130803Smarcelprocfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
1375130803Smarcel{
1376130803Smarcel  return procfs_hw_watchpoint (addr, -1, type);
1377130803Smarcel}
1378130803Smarcel
1379130803Smarcelstatic int
1380130803Smarcelprocfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
1381130803Smarcel{
1382130803Smarcel  return procfs_hw_watchpoint (addr, len, type);
1383130803Smarcel}
1384130803Smarcel
1385130803Smarcelstatic int
1386130803Smarcelprocfs_stopped_by_watchpoint (void)
1387130803Smarcel{
1388130803Smarcel  return 0;
1389130803Smarcel}
1390