bfd/
[deliverable/binutils-gdb.git] / gdb / nto-procfs.c
CommitLineData
61bb466e
KW
1/* Machine independent support for QNX Neutrino /proc (process file system)
2 for GDB. Written by Colin Burgess at QNX Software Systems Limited.
3
4 Copyright 2003 Free Software Foundation, Inc.
5
6 Contributed by QNX Software Systems Ltd.
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
24
25#include "defs.h"
26
27#include <fcntl.h>
28#include <spawn.h>
29#include <sys/debug.h>
30#include <sys/procfs.h>
31#include <sys/neutrino.h>
32#include <sys/syspage.h>
5483d879 33#include "gdb_dirent.h"
61bb466e
KW
34#include <sys/netmgr.h>
35
60250e8b 36#include "exceptions.h"
61bb466e
KW
37#include "gdb_string.h"
38#include "gdbcore.h"
39#include "inferior.h"
40#include "target.h"
41#include "objfiles.h"
42#include "gdbthread.h"
43#include "nto-tdep.h"
44#include "command.h"
45#include "regcache.h"
46
47#define NULL_PID 0
48#define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\
49 _DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY)
50
51static struct target_ops procfs_ops;
52
53int ctl_fd;
54
55static void (*ofunc) ();
56
57static procfs_run run;
58
59static void procfs_open (char *, int);
60
61static int procfs_can_run (void);
62
63static ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
64
65static int procfs_xfer_memory (CORE_ADDR, char *, int, int,
66 struct mem_attrib *attrib,
67 struct target_ops *);
68
69static void procfs_fetch_registers (int);
70
71static void notice_signals (void);
72
73static void init_procfs_ops (void);
74
75static ptid_t do_attach (ptid_t ptid);
76
77static int procfs_can_use_hw_breakpoint (int, int, int);
78
79static int procfs_insert_hw_breakpoint (CORE_ADDR, char *);
80
81static int procfs_remove_hw_breakpoint (CORE_ADDR addr, char *);
82
83static int procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type);
84
85static int procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type);
86
87static int procfs_stopped_by_watchpoint (void);
88
89/* These two globals are only ever set in procfs_open(), but are
90 referenced elsewhere. 'nto_procfs_node' is a flag used to say
91 whether we are local, or we should get the current node descriptor
92 for the remote QNX node. */
93static char nto_procfs_path[PATH_MAX] = { "/proc" };
94static unsigned nto_procfs_node = ND_LOCAL_NODE;
95
96/* Return the current QNX Node, or error out. This is a simple
97 wrapper for the netmgr_strtond() function. The reason this
98 is required is because QNX node descriptors are transient so
99 we have to re-acquire them every time. */
100static unsigned
d737fd7f 101nto_node (void)
61bb466e
KW
102{
103 unsigned node;
104
d737fd7f 105 if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0)
61bb466e
KW
106 return ND_LOCAL_NODE;
107
d737fd7f 108 node = netmgr_strtond (nto_procfs_path, 0);
61bb466e 109 if (node == -1)
8a3fe4f8 110 error (_("Lost the QNX node. Debug session probably over."));
61bb466e
KW
111
112 return (node);
113}
114
d737fd7f
KW
115static enum gdb_osabi
116procfs_is_nto_target (bfd *abfd)
117{
118 return GDB_OSABI_QNXNTO;
119}
120
61bb466e
KW
121/* This is called when we call 'target procfs <arg>' from the (gdb) prompt.
122 For QNX6 (nto), the only valid arg will be a QNX node string,
123 eg: "/net/some_node". If arg is not a valid QNX node, we will
124 default to local. */
125static void
126procfs_open (char *arg, int from_tty)
127{
128 char *nodestr;
129 char *endstr;
130 char buffer[50];
131 int fd, total_size;
132 procfs_sysinfo *sysinfo;
133
d737fd7f
KW
134 nto_is_nto_target = procfs_is_nto_target;
135
61bb466e
KW
136 /* Set the default node used for spawning to this one,
137 and only override it if there is a valid arg. */
138
139 nto_procfs_node = ND_LOCAL_NODE;
140 nodestr = arg ? xstrdup (arg) : arg;
141
142 init_thread_list ();
143
144 if (nodestr)
145 {
146 nto_procfs_node = netmgr_strtond (nodestr, &endstr);
147 if (nto_procfs_node == -1)
148 {
149 if (errno == ENOTSUP)
150 printf_filtered ("QNX Net Manager not found.\n");
151 printf_filtered ("Invalid QNX node %s: error %d (%s).\n", nodestr,
dc5dd1eb 152 errno, safe_strerror (errno));
61bb466e
KW
153 xfree (nodestr);
154 nodestr = NULL;
155 nto_procfs_node = ND_LOCAL_NODE;
156 }
157 else if (*endstr)
158 {
159 if (*(endstr - 1) == '/')
160 *(endstr - 1) = 0;
161 else
162 *endstr = 0;
163 }
164 }
d737fd7f
KW
165 snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s", nodestr ? nodestr : "",
166 "/proc");
61bb466e
KW
167 if (nodestr)
168 xfree (nodestr);
169
170 fd = open (nto_procfs_path, O_RDONLY);
171 if (fd == -1)
172 {
173 printf_filtered ("Error opening %s : %d (%s)\n", nto_procfs_path, errno,
dc5dd1eb 174 safe_strerror (errno));
8a3fe4f8 175 error (_("Invalid procfs arg"));
61bb466e
KW
176 }
177
178 sysinfo = (void *) buffer;
179 if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK)
180 {
181 printf_filtered ("Error getting size: %d (%s)\n", errno,
dc5dd1eb 182 safe_strerror (errno));
61bb466e 183 close (fd);
8a3fe4f8 184 error (_("Devctl failed."));
61bb466e
KW
185 }
186 else
187 {
188 total_size = sysinfo->total_size;
189 sysinfo = alloca (total_size);
190 if (!sysinfo)
191 {
192 printf_filtered ("Memory error: %d (%s)\n", errno,
dc5dd1eb 193 safe_strerror (errno));
61bb466e 194 close (fd);
8a3fe4f8 195 error (_("alloca failed."));
61bb466e
KW
196 }
197 else
198 {
199 if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, total_size, 0) != EOK)
200 {
201 printf_filtered ("Error getting sysinfo: %d (%s)\n", errno,
dc5dd1eb 202 safe_strerror (errno));
61bb466e 203 close (fd);
8a3fe4f8 204 error (_("Devctl failed."));
61bb466e
KW
205 }
206 else
207 {
208 if (sysinfo->type !=
209 nto_map_arch_to_cputype (TARGET_ARCHITECTURE->arch_name))
210 {
211 close (fd);
8a3fe4f8 212 error (_("Invalid target CPU."));
61bb466e
KW
213 }
214 }
215 }
216 }
217 close (fd);
218 printf_filtered ("Debugging using %s\n", nto_procfs_path);
219}
220
221static void
222procfs_set_thread (ptid_t ptid)
223{
224 pid_t tid;
225
226 tid = ptid_get_tid (ptid);
227 devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0);
228}
229
230/* Return nonzero if the thread TH is still alive. */
231static int
232procfs_thread_alive (ptid_t ptid)
233{
234 pid_t tid;
235
236 tid = ptid_get_tid (ptid);
237 if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK)
238 return 1;
239 return 0;
240}
241
242void
243procfs_find_new_threads (void)
244{
245 procfs_status status;
246 pid_t pid;
247 ptid_t ptid;
248
249 if (ctl_fd == -1)
250 return;
251
252 pid = ptid_get_pid (inferior_ptid);
253
254 for (status.tid = 1;; ++status.tid)
255 {
256 if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0)
257 != EOK && status.tid != 0)
258 break;
259 ptid = ptid_build (pid, 0, status.tid);
260 if (!in_thread_list (ptid))
261 add_thread (ptid);
262 }
263 return;
264}
265
266void
267procfs_pidlist (char *args, int from_tty)
268{
269 DIR *dp = NULL;
270 struct dirent *dirp = NULL;
271 int fd = -1;
272 char buf[512];
273 procfs_info *pidinfo = NULL;
274 procfs_debuginfo *info = NULL;
275 procfs_status *status = NULL;
276 pid_t num_threads = 0;
277 pid_t pid;
278 char name[512];
279
280 dp = opendir (nto_procfs_path);
281 if (dp == NULL)
282 {
dc5dd1eb 283 fprintf_unfiltered (gdb_stderr, "failed to opendir \"%s\" - %d (%s)",
d737fd7f 284 nto_procfs_path, errno, safe_strerror (errno));
61bb466e
KW
285 return;
286 }
287
288 /* Start scan at first pid. */
289 rewinddir (dp);
290
291 do
292 {
293 /* Get the right pid and procfs path for the pid. */
294 do
295 {
296 dirp = readdir (dp);
297 if (dirp == NULL)
298 {
299 closedir (dp);
300 return;
301 }
dc5dd1eb 302 snprintf (buf, 511, "%s/%s/as", nto_procfs_path, dirp->d_name);
61bb466e
KW
303 pid = atoi (dirp->d_name);
304 }
305 while (pid == 0);
306
307 /* Open the procfs path. */
308 fd = open (buf, O_RDONLY);
309 if (fd == -1)
310 {
dc5dd1eb 311 fprintf_unfiltered (gdb_stderr, "failed to open %s - %d (%s)\n",
d737fd7f 312 buf, errno, safe_strerror (errno));
61bb466e
KW
313 closedir (dp);
314 return;
315 }
316
317 pidinfo = (procfs_info *) buf;
318 if (devctl (fd, DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK)
319 {
dc5dd1eb 320 fprintf_unfiltered (gdb_stderr,
d737fd7f
KW
321 "devctl DCMD_PROC_INFO failed - %d (%s)\n",
322 errno, safe_strerror (errno));
61bb466e
KW
323 break;
324 }
325 num_threads = pidinfo->num_threads;
326
327 info = (procfs_debuginfo *) buf;
328 if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0) != EOK)
329 strcpy (name, "unavailable");
330 else
331 strcpy (name, info->path);
332
333 /* Collect state info on all the threads. */
334 status = (procfs_status *) buf;
335 for (status->tid = 1; status->tid <= num_threads; status->tid++)
336 {
337 if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK
338 && status->tid != 0)
339 break;
340 if (status->tid != 0)
341 printf_filtered ("%s - %d/%d\n", name, pid, status->tid);
342 }
343 close (fd);
344 }
345 while (dirp != NULL);
346
347 close (fd);
348 closedir (dp);
349 return;
350}
351
352void
353procfs_meminfo (char *args, int from_tty)
354{
355 procfs_mapinfo *mapinfos = NULL;
356 static int num_mapinfos = 0;
357 procfs_mapinfo *mapinfo_p, *mapinfo_p2;
358 int flags = ~0, err, num, i, j;
359
360 struct
361 {
362 procfs_debuginfo info;
363 char buff[_POSIX_PATH_MAX];
364 } map;
365
366 struct info
367 {
368 unsigned addr;
369 unsigned size;
370 unsigned flags;
371 unsigned debug_vaddr;
372 unsigned long long offset;
373 };
374
375 struct printinfo
376 {
377 unsigned long long ino;
378 unsigned dev;
379 struct info text;
380 struct info data;
381 char name[256];
382 } printme;
383
384 /* Get the number of map entrys. */
385 err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num);
386 if (err != EOK)
387 {
d737fd7f
KW
388 printf ("failed devctl num mapinfos - %d (%s)\n", err,
389 safe_strerror (err));
61bb466e
KW
390 return;
391 }
392
393 mapinfos = xmalloc (num * sizeof (procfs_mapinfo));
394
395 num_mapinfos = num;
396 mapinfo_p = mapinfos;
397
398 /* Fill the map entrys. */
399 err = devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, num
400 * sizeof (procfs_mapinfo), &num);
401 if (err != EOK)
402 {
5483d879 403 printf ("failed devctl mapinfos - %d (%s)\n", err, safe_strerror (err));
61bb466e
KW
404 xfree (mapinfos);
405 return;
406 }
407
408 num = min (num, num_mapinfos);
409
410 /* Run through the list of mapinfos, and store the data and text info
411 so we can print it at the bottom of the loop. */
412 for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++)
413 {
414 if (!(mapinfo_p->flags & flags))
415 mapinfo_p->ino = 0;
416
417 if (mapinfo_p->ino == 0) /* Already visited. */
418 continue;
419
420 map.info.vaddr = mapinfo_p->vaddr;
421
422 err = devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
423 if (err != EOK)
424 continue;
425
426 memset (&printme, 0, sizeof printme);
427 printme.dev = mapinfo_p->dev;
428 printme.ino = mapinfo_p->ino;
429 printme.text.addr = mapinfo_p->vaddr;
430 printme.text.size = mapinfo_p->size;
431 printme.text.flags = mapinfo_p->flags;
432 printme.text.offset = mapinfo_p->offset;
433 printme.text.debug_vaddr = map.info.vaddr;
434 strcpy (printme.name, map.info.path);
435
436 /* Check for matching data. */
437 for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++)
438 {
439 if (mapinfo_p2->vaddr != mapinfo_p->vaddr
440 && mapinfo_p2->ino == mapinfo_p->ino
441 && mapinfo_p2->dev == mapinfo_p->dev)
442 {
443 map.info.vaddr = mapinfo_p2->vaddr;
444 err =
445 devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0);
446 if (err != EOK)
447 continue;
448
449 if (strcmp (map.info.path, printme.name))
450 continue;
451
452 /* Lower debug_vaddr is always text, if nessessary, swap. */
453 if ((int) map.info.vaddr < (int) printme.text.debug_vaddr)
454 {
455 memcpy (&(printme.data), &(printme.text),
456 sizeof (printme.data));
457 printme.text.addr = mapinfo_p2->vaddr;
458 printme.text.size = mapinfo_p2->size;
459 printme.text.flags = mapinfo_p2->flags;
460 printme.text.offset = mapinfo_p2->offset;
461 printme.text.debug_vaddr = map.info.vaddr;
462 }
463 else
464 {
465 printme.data.addr = mapinfo_p2->vaddr;
466 printme.data.size = mapinfo_p2->size;
467 printme.data.flags = mapinfo_p2->flags;
468 printme.data.offset = mapinfo_p2->offset;
469 printme.data.debug_vaddr = map.info.vaddr;
470 }
471 mapinfo_p2->ino = 0;
472 }
473 }
474 mapinfo_p->ino = 0;
475
476 printf_filtered ("%s\n", printme.name);
477 printf_filtered ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size,
478 printme.text.addr);
479 printf_filtered ("\t\tflags=%08x\n", printme.text.flags);
480 printf_filtered ("\t\tdebug=%08x\n", printme.text.debug_vaddr);
481 printf_filtered ("\t\toffset=%016llx\n", printme.text.offset);
482 if (printme.data.size)
483 {
484 printf_filtered ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size,
485 printme.data.addr);
486 printf_filtered ("\t\tflags=%08x\n", printme.data.flags);
487 printf_filtered ("\t\tdebug=%08x\n", printme.data.debug_vaddr);
488 printf_filtered ("\t\toffset=%016llx\n", printme.data.offset);
489 }
490 printf_filtered ("\tdev=0x%x\n", printme.dev);
491 printf_filtered ("\tino=0x%x\n", (unsigned int) printme.ino);
492 }
493 xfree (mapinfos);
494 return;
495}
496
497/* Print status information about what we're accessing. */
498static void
499procfs_files_info (struct target_ops *ignore)
500{
501 printf_unfiltered ("\tUsing the running image of %s %s via %s.\n",
502 attach_flag ? "attached" : "child",
503 target_pid_to_str (inferior_ptid), nto_procfs_path);
504}
505
506/* Mark our target-struct as eligible for stray "run" and "attach" commands. */
507static int
5483d879 508procfs_can_run (void)
61bb466e
KW
509{
510 return 1;
511}
512
513/* Attach to process PID, then initialize for debugging it. */
514static void
515procfs_attach (char *args, int from_tty)
516{
517 char *exec_file;
518 int pid;
519
520 if (!args)
e2e0b3e5 521 error_no_arg (_("process-id to attach"));
61bb466e
KW
522
523 pid = atoi (args);
524
525 if (pid == getpid ())
8a3fe4f8 526 error (_("Attaching GDB to itself is not a good idea..."));
61bb466e
KW
527
528 if (from_tty)
529 {
530 exec_file = (char *) get_exec_file (0);
531
532 if (exec_file)
533 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
534 target_pid_to_str (pid_to_ptid (pid)));
535 else
536 printf_unfiltered ("Attaching to %s\n",
537 target_pid_to_str (pid_to_ptid (pid)));
538
539 gdb_flush (gdb_stdout);
540 }
541 inferior_ptid = do_attach (pid_to_ptid (pid));
542 push_target (&procfs_ops);
543}
544
545static void
546procfs_post_attach (pid_t pid)
547{
548#ifdef SOLIB_CREATE_INFERIOR_HOOK
549 if (exec_bfd)
550 SOLIB_CREATE_INFERIOR_HOOK (pid);
551#endif
552}
553
554static ptid_t
555do_attach (ptid_t ptid)
556{
557 procfs_status status;
558 struct sigevent event;
dc5dd1eb 559 char path[PATH_MAX];
61bb466e 560
dc5dd1eb 561 snprintf (path, PATH_MAX - 1, "%s/%d/as", nto_procfs_path, PIDGET (ptid));
61bb466e
KW
562 ctl_fd = open (path, O_RDWR);
563 if (ctl_fd == -1)
8a3fe4f8 564 error (_("Couldn't open proc file %s, error %d (%s)"), path, errno,
dc5dd1eb 565 safe_strerror (errno));
61bb466e 566 if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK)
8a3fe4f8 567 error (_("Couldn't stop process"));
61bb466e
KW
568
569 /* Define a sigevent for process stopped notification. */
570 event.sigev_notify = SIGEV_SIGNAL_THREAD;
571 event.sigev_signo = SIGUSR1;
572 event.sigev_code = 0;
573 event.sigev_value.sival_ptr = NULL;
574 event.sigev_priority = -1;
575 devctl (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
576
577 if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK
578 && status.flags & _DEBUG_FLAG_STOPPED)
d737fd7f 579 SignalKill (nto_node (), PIDGET (ptid), 0, SIGCONT, 0, 0);
61bb466e
KW
580 attach_flag = 1;
581 nto_init_solib_absolute_prefix ();
582 return ptid;
583}
584
585/* Ask the user what to do when an interrupt is received. */
586static void
dc5dd1eb 587interrupt_query (void)
61bb466e
KW
588{
589 target_terminal_ours ();
590
591 if (query ("Interrupted while waiting for the program.\n\
592Give up (and stop debugging it)? "))
593 {
594 target_mourn_inferior ();
315a522e 595 deprecated_throw_reason (RETURN_QUIT);
61bb466e
KW
596 }
597
598 target_terminal_inferior ();
599}
600
601/* The user typed ^C twice. */
602static void
603nto_interrupt_twice (int signo)
604{
605 signal (signo, ofunc);
606 interrupt_query ();
607 signal (signo, nto_interrupt_twice);
608}
609
610static void
611nto_interrupt (int signo)
612{
613 /* If this doesn't work, try more severe steps. */
614 signal (signo, nto_interrupt_twice);
615
616 target_stop ();
617}
618
619static ptid_t
620procfs_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
621{
622 sigset_t set;
623 siginfo_t info;
624 procfs_status status;
625 static int exit_signo = 0; /* To track signals that cause termination. */
626
627 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
628
629 if (ptid_equal (inferior_ptid, null_ptid))
630 {
631 ourstatus->kind = TARGET_WAITKIND_STOPPED;
632 ourstatus->value.sig = TARGET_SIGNAL_0;
633 exit_signo = 0;
634 return null_ptid;
635 }
636
637 sigemptyset (&set);
638 sigaddset (&set, SIGUSR1);
639
640 devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
641 while (!(status.flags & _DEBUG_FLAG_ISTOP))
642 {
643 ofunc = (void (*)()) signal (SIGINT, nto_interrupt);
644 sigwaitinfo (&set, &info);
645 signal (SIGINT, ofunc);
646 devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
647 }
648
649 if (status.flags & _DEBUG_FLAG_SSTEP)
650 {
651 ourstatus->kind = TARGET_WAITKIND_STOPPED;
652 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
653 }
654 /* Was it a breakpoint? */
655 else if (status.flags & _DEBUG_FLAG_TRACE)
656 {
657 ourstatus->kind = TARGET_WAITKIND_STOPPED;
658 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
659 }
660 else if (status.flags & _DEBUG_FLAG_ISTOP)
661 {
662 switch (status.why)
663 {
664 case _DEBUG_WHY_SIGNALLED:
665 ourstatus->kind = TARGET_WAITKIND_STOPPED;
666 ourstatus->value.sig =
667 target_signal_from_host (status.info.si_signo);
668 exit_signo = 0;
669 break;
670 case _DEBUG_WHY_FAULTED:
671 ourstatus->kind = TARGET_WAITKIND_STOPPED;
672 if (status.info.si_signo == SIGTRAP)
673 {
674 ourstatus->value.sig = 0;
675 exit_signo = 0;
676 }
677 else
678 {
679 ourstatus->value.sig =
680 target_signal_from_host (status.info.si_signo);
681 exit_signo = ourstatus->value.sig;
682 }
683 break;
684
685 case _DEBUG_WHY_TERMINATED:
686 {
687 int waitval = 0;
688
689 waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG);
690 if (exit_signo)
691 {
692 /* Abnormal death. */
693 ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
694 ourstatus->value.sig = exit_signo;
695 }
696 else
697 {
698 /* Normal death. */
699 ourstatus->kind = TARGET_WAITKIND_EXITED;
700 ourstatus->value.integer = WEXITSTATUS (waitval);
701 }
702 exit_signo = 0;
703 break;
704 }
705
706 case _DEBUG_WHY_REQUESTED:
707 /* We are assuming a requested stop is due to a SIGINT. */
708 ourstatus->kind = TARGET_WAITKIND_STOPPED;
709 ourstatus->value.sig = TARGET_SIGNAL_INT;
710 exit_signo = 0;
711 break;
712 }
713 }
714
715 return inferior_ptid;
716}
717
718/* Read the current values of the inferior's registers, both the
719 general register set and floating point registers (if supported)
720 and update gdb's idea of their current values. */
721static void
722procfs_fetch_registers (int regno)
723{
724 union
725 {
726 procfs_greg greg;
727 procfs_fpreg fpreg;
728 procfs_altreg altreg;
729 }
730 reg;
731 int regsize;
732
733 procfs_set_thread (inferior_ptid);
734 if (devctl (ctl_fd, DCMD_PROC_GETGREG, &reg, sizeof (reg), &regsize) == EOK)
735 nto_supply_gregset ((char *) &reg.greg);
736 if (devctl (ctl_fd, DCMD_PROC_GETFPREG, &reg, sizeof (reg), &regsize)
737 == EOK)
738 nto_supply_fpregset ((char *) &reg.fpreg);
739 if (devctl (ctl_fd, DCMD_PROC_GETALTREG, &reg, sizeof (reg), &regsize)
740 == EOK)
741 nto_supply_altregset ((char *) &reg.altreg);
742}
743
744/* Copy LEN bytes to/from inferior's memory starting at MEMADDR
745 from/to debugger memory starting at MYADDR. Copy from inferior
746 if DOWRITE is zero or to inferior if DOWRITE is nonzero.
747
748 Returns the length copied, which is either the LEN argument or
749 zero. This xfer function does not do partial moves, since procfs_ops
750 doesn't allow memory operations to cross below us in the target stack
751 anyway. */
752static int
753procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
754 struct mem_attrib *attrib, struct target_ops *target)
755{
756 int nbytes = 0;
757
758 if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr)
759 {
760 if (dowrite)
761 nbytes = write (ctl_fd, myaddr, len);
762 else
763 nbytes = read (ctl_fd, myaddr, len);
764 if (nbytes < 0)
765 nbytes = 0;
766 }
767 return (nbytes);
768}
769
770/* Take a program previously attached to and detaches it.
771 The program resumes execution and will no longer stop
772 on signals, etc. We'd better not have left any breakpoints
773 in the program or it'll die when it hits one. */
774static void
775procfs_detach (char *args, int from_tty)
776{
777 int siggnal = 0;
778
779 if (from_tty)
780 {
781 char *exec_file = get_exec_file (0);
782 if (exec_file == 0)
783 exec_file = "";
784 printf_unfiltered ("Detaching from program: %s %s\n",
785 exec_file, target_pid_to_str (inferior_ptid));
786 gdb_flush (gdb_stdout);
787 }
788 if (args)
789 siggnal = atoi (args);
790
791 if (siggnal)
d737fd7f 792 SignalKill (nto_node (), PIDGET (inferior_ptid), 0, siggnal, 0, 0);
61bb466e
KW
793
794 close (ctl_fd);
795 ctl_fd = -1;
796 init_thread_list ();
797 inferior_ptid = null_ptid;
798 attach_flag = 0;
799 unpush_target (&procfs_ops); /* Pop out of handling an inferior. */
800}
801
802static int
803procfs_breakpoint (CORE_ADDR addr, int type, int size)
804{
805 procfs_break brk;
806
807 brk.type = type;
808 brk.addr = addr;
809 brk.size = size;
810 errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
811 if (errno != EOK)
812 return 1;
813 return 0;
814}
815
816static int
817procfs_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
818{
819 return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, 0);
820}
821
822static int
823procfs_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
824{
825 return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, -1);
826}
827
828static int
829procfs_insert_hw_breakpoint (CORE_ADDR addr, char *contents_cache)
830{
831 return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0);
832}
833
834static int
835procfs_remove_hw_breakpoint (CORE_ADDR addr, char *contents_cache)
836{
837 return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1);
838}
839
840static void
841procfs_resume (ptid_t ptid, int step, enum target_signal signo)
842{
843 int signal_to_pass;
844 procfs_status status;
845
846 if (ptid_equal (inferior_ptid, null_ptid))
847 return;
848
849 procfs_set_thread (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid :
850 ptid);
851
852 run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
853 if (step)
854 run.flags |= _DEBUG_RUN_STEP;
855
856 sigemptyset ((sigset_t *) &run.fault);
857 sigaddset ((sigset_t *) &run.fault, FLTBPT);
858 sigaddset ((sigset_t *) &run.fault, FLTTRACE);
859 sigaddset ((sigset_t *) &run.fault, FLTILL);
860 sigaddset ((sigset_t *) &run.fault, FLTPRIV);
861 sigaddset ((sigset_t *) &run.fault, FLTBOUNDS);
862 sigaddset ((sigset_t *) &run.fault, FLTIOVF);
863 sigaddset ((sigset_t *) &run.fault, FLTIZDIV);
864 sigaddset ((sigset_t *) &run.fault, FLTFPE);
865 /* Peter V will be changing this at some point. */
866 sigaddset ((sigset_t *) &run.fault, FLTPAGE);
867
868 run.flags |= _DEBUG_RUN_ARM;
869
870 sigemptyset (&run.trace);
871 notice_signals ();
872 signal_to_pass = target_signal_to_host (signo);
873
874 if (signal_to_pass)
875 {
876 devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
877 signal_to_pass = target_signal_to_host (signo);
878 if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
879 {
880 if (signal_to_pass != status.info.si_signo)
881 {
d737fd7f
KW
882 SignalKill (nto_node (), PIDGET (inferior_ptid), 0,
883 signal_to_pass, 0, 0);
61bb466e
KW
884 run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
885 }
886 else /* Let it kill the program without telling us. */
887 sigdelset (&run.trace, signal_to_pass);
888 }
889 }
890 else
891 run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
892
893 errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
894 if (errno != EOK)
895 {
896 perror ("run error!\n");
897 return;
898 }
899}
900
901static void
dc5dd1eb 902procfs_mourn_inferior (void)
61bb466e
KW
903{
904 if (!ptid_equal (inferior_ptid, null_ptid))
905 {
d737fd7f 906 SignalKill (nto_node (), PIDGET (inferior_ptid), 0, SIGKILL, 0, 0);
61bb466e
KW
907 close (ctl_fd);
908 }
909 inferior_ptid = null_ptid;
910 init_thread_list ();
911 unpush_target (&procfs_ops);
912 generic_mourn_inferior ();
913 attach_flag = 0;
914}
915
916/* This function breaks up an argument string into an argument
917 vector suitable for passing to execvp().
918 E.g., on "run a b c d" this routine would get as input
919 the string "a b c d", and as output it would fill in argv with
920 the four arguments "a", "b", "c", "d". The only additional
921 functionality is simple quoting. The gdb command:
922 run a "b c d" f
923 will fill in argv with the three args "a", "b c d", "e". */
924static void
925breakup_args (char *scratch, char **argv)
926{
927 char *pp, *cp = scratch;
928 char quoting = 0;
929
930 for (;;)
931 {
932 /* Scan past leading separators. */
933 quoting = 0;
934 while (*cp == ' ' || *cp == '\t' || *cp == '\n')
935 cp++;
936
937 /* Break if at end of string. */
938 if (*cp == '\0')
939 break;
940
941 /* Take an arg. */
942 if (*cp == '"')
943 {
944 cp++;
945 quoting = strchr (cp, '"') ? 1 : 0;
946 }
947
948 *argv++ = cp;
949
950 /* Scan for next arg separator. */
951 pp = cp;
952 if (quoting)
953 cp = strchr (pp, '"');
954 if ((cp == NULL) || (!quoting))
955 cp = strchr (pp, ' ');
956 if (cp == NULL)
957 cp = strchr (pp, '\t');
958 if (cp == NULL)
959 cp = strchr (pp, '\n');
960
961 /* No separators => end of string => break. */
962 if (cp == NULL)
963 {
964 pp = cp;
965 break;
966 }
967
968 /* Replace the separator with a terminator. */
969 *cp++ = '\0';
970 }
971
972 /* Execv requires a null-terminated arg vector. */
973 *argv = NULL;
974}
975
976static void
c27cda74
AC
977procfs_create_inferior (char *exec_file, char *allargs, char **env,
978 int from_tty)
61bb466e
KW
979{
980 struct inheritance inherit;
981 pid_t pid;
982 int flags, errn;
983 char **argv, *args;
3cb3b8df 984 const char *in = "", *out = "", *err = "";
61bb466e
KW
985 int fd, fds[3];
986 sigset_t set;
3cb3b8df 987 const char *inferior_io_terminal = get_inferior_io_terminal ();
61bb466e
KW
988
989 argv = xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) *
990 sizeof (*argv));
991 argv[0] = get_exec_file (1);
992 if (!argv[0])
993 {
994 if (exec_file)
995 argv[0] = exec_file;
996 else
997 return;
998 }
999
1000 args = xstrdup (allargs);
1001 breakup_args (args, exec_file ? &argv[1] : &argv[0]);
1002
1003 argv = nto_parse_redirection (argv, &in, &out, &err);
1004
1005 fds[0] = STDIN_FILENO;
1006 fds[1] = STDOUT_FILENO;
1007 fds[2] = STDERR_FILENO;
1008
1009 /* If the user specified I/O via gdb's --tty= arg, use it, but only
1010 if the i/o is not also being specified via redirection. */
1011 if (inferior_io_terminal)
1012 {
1013 if (!in[0])
1014 in = inferior_io_terminal;
1015 if (!out[0])
1016 out = inferior_io_terminal;
1017 if (!err[0])
1018 err = inferior_io_terminal;
1019 }
1020
1021 if (in[0])
1022 {
1023 fd = open (in, O_RDONLY);
1024 if (fd == -1)
1025 perror (in);
1026 else
1027 fds[0] = fd;
1028 }
1029 if (out[0])
1030 {
1031 fd = open (out, O_WRONLY);
1032 if (fd == -1)
1033 perror (out);
1034 else
1035 fds[1] = fd;
1036 }
1037 if (err[0])
1038 {
1039 fd = open (err, O_WRONLY);
1040 if (fd == -1)
1041 perror (err);
1042 else
1043 fds[2] = fd;
1044 }
1045
1046 /* Clear any pending SIGUSR1's but keep the behavior the same. */
1047 signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
1048
1049 sigemptyset (&set);
1050 sigaddset (&set, SIGUSR1);
1051 sigprocmask (SIG_UNBLOCK, &set, NULL);
1052
1053 memset (&inherit, 0, sizeof (inherit));
1054
1055 if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0)
1056 {
d737fd7f 1057 inherit.nd = nto_node ();
61bb466e
KW
1058 inherit.flags |= SPAWN_SETND;
1059 inherit.flags &= ~SPAWN_EXEC;
1060 }
1061 inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
1062 inherit.pgroup = SPAWN_NEWPGROUP;
1063 pid = spawnp (argv[0], 3, fds, &inherit, argv,
1064 ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0);
1065 xfree (args);
1066
1067 sigprocmask (SIG_BLOCK, &set, NULL);
1068
1069 if (pid == -1)
8a3fe4f8 1070 error (_("Error spawning %s: %d (%s)"), argv[0], errno,
d737fd7f 1071 safe_strerror (errno));
61bb466e
KW
1072
1073 if (fds[0] != STDIN_FILENO)
1074 close (fds[0]);
1075 if (fds[1] != STDOUT_FILENO)
1076 close (fds[1]);
1077 if (fds[2] != STDERR_FILENO)
1078 close (fds[2]);
1079
1080 inferior_ptid = do_attach (pid_to_ptid (pid));
1081
1082 attach_flag = 0;
1083 flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */
1084 errn = devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0);
1085 if (errn != EOK)
1086 {
1087 /* FIXME: expected warning? */
1088 /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n",
1089 errn, strerror(errn) ); */
1090 }
1091 push_target (&procfs_ops);
1092 target_terminal_init ();
1093
1094#ifdef SOLIB_CREATE_INFERIOR_HOOK
1095 if (exec_bfd != NULL
1096 || (symfile_objfile != NULL && symfile_objfile->obfd != NULL))
1097 SOLIB_CREATE_INFERIOR_HOOK (pid);
1098#endif
d737fd7f
KW
1099 stop_soon = 0;
1100 proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
61bb466e
KW
1101}
1102
1103static void
dc5dd1eb 1104procfs_stop (void)
61bb466e
KW
1105{
1106 devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0);
1107}
1108
1109static void
dc5dd1eb 1110procfs_kill_inferior (void)
61bb466e
KW
1111{
1112 target_mourn_inferior ();
1113}
1114
1115/* Store register REGNO, or all registers if REGNO == -1, from the contents
1116 of REGISTERS. */
1117static void
dc5dd1eb 1118procfs_prepare_to_store (void)
61bb466e
KW
1119{
1120}
1121
1122/* Fill buf with regset and return devctl cmd to do the setting. Return
1123 -1 if we fail to get the regset. Store size of regset in regsize. */
1124static int
1125get_regset (int regset, char *buf, int bufsize, int *regsize)
1126{
1127 int dev_get, dev_set;
1128 switch (regset)
1129 {
1130 case NTO_REG_GENERAL:
1131 dev_get = DCMD_PROC_GETGREG;
1132 dev_set = DCMD_PROC_SETGREG;
1133 break;
1134
1135 case NTO_REG_FLOAT:
1136 dev_get = DCMD_PROC_GETFPREG;
1137 dev_set = DCMD_PROC_SETFPREG;
1138 break;
1139
1140 case NTO_REG_ALT:
1141 dev_get = DCMD_PROC_GETALTREG;
1142 dev_set = DCMD_PROC_SETALTREG;
1143 break;
1144
1145 case NTO_REG_SYSTEM:
1146 default:
1147 return -1;
1148 }
1149 if (devctl (ctl_fd, dev_get, &buf, bufsize, regsize) != EOK)
1150 return -1;
1151
1152 return dev_set;
1153}
1154
1155void
1156procfs_store_registers (int regno)
1157{
1158 union
1159 {
1160 procfs_greg greg;
1161 procfs_fpreg fpreg;
1162 procfs_altreg altreg;
1163 }
1164 reg;
1165 unsigned off;
1166 int len, regset, regsize, dev_set, err;
1167 char *data;
1168
1169 if (ptid_equal (inferior_ptid, null_ptid))
1170 return;
1171 procfs_set_thread (inferior_ptid);
1172
1173 if (regno == -1)
1174 {
1175 for (regset = NTO_REG_GENERAL; regset < NTO_REG_END; regset++)
1176 {
1177 dev_set = get_regset (regset, (char *) &reg,
1178 sizeof (reg), &regsize);
1179 if (dev_set == -1)
1180 continue;
1181
1182 if (nto_regset_fill (regset, (char *) &reg) == -1)
1183 continue;
1184
1185 err = devctl (ctl_fd, dev_set, &reg, regsize, 0);
1186 if (err != EOK)
1187 fprintf_unfiltered (gdb_stderr,
1188 "Warning unable to write regset %d: %s\n",
dc5dd1eb 1189 regno, safe_strerror (err));
61bb466e
KW
1190 }
1191 }
1192 else
1193 {
1194 regset = nto_regset_id (regno);
1195 if (regset == -1)
1196 return;
1197
1198 dev_set = get_regset (regset, (char *) &reg, sizeof (reg), &regsize);
1199 if (dev_set == -1)
1200 return;
1201
1202 len = nto_register_area (regno, regset, &off);
1203
1204 if (len < 1)
1205 return;
1206
822c9732 1207 regcache_raw_collect (current_regcache, regno, (char *) &reg + off);
61bb466e
KW
1208
1209 err = devctl (ctl_fd, dev_set, &reg, regsize, 0);
1210 if (err != EOK)
1211 fprintf_unfiltered (gdb_stderr,
1212 "Warning unable to write regset %d: %s\n", regno,
dc5dd1eb 1213 safe_strerror (err));
61bb466e
KW
1214 }
1215}
1216
1217static void
1218notice_signals (void)
1219{
1220 int signo;
1221
1222 for (signo = 1; signo < NSIG; signo++)
1223 {
1224 if (signal_stop_state (target_signal_from_host (signo)) == 0
1225 && signal_print_state (target_signal_from_host (signo)) == 0
1226 && signal_pass_state (target_signal_from_host (signo)) == 1)
1227 sigdelset (&run.trace, signo);
1228 else
1229 sigaddset (&run.trace, signo);
1230 }
1231}
1232
1233/* When the user changes the state of gdb's signal handling via the
1234 "handle" command, this function gets called to see if any change
1235 in the /proc interface is required. It is also called internally
1236 by other /proc interface functions to initialize the state of
1237 the traced signal set. */
1238static void
1239procfs_notice_signals (ptid_t ptid)
1240{
1241 sigemptyset (&run.trace);
1242 notice_signals ();
1243}
1244
1245static struct tidinfo *
1246procfs_thread_info (pid_t pid, short tid)
1247{
1248/* NYI */
1249 return NULL;
1250}
1251
1252char *
1253procfs_pid_to_str (ptid_t ptid)
1254{
1255 static char buf[1024];
1256 int pid, tid, n;
1257 struct tidinfo *tip;
1258
1259 pid = ptid_get_pid (ptid);
1260 tid = ptid_get_tid (ptid);
1261
dc5dd1eb 1262 n = snprintf (buf, 1023, "process %d", pid);
61bb466e
KW
1263
1264#if 0 /* NYI */
1265 tip = procfs_thread_info (pid, tid);
1266 if (tip != NULL)
dc5dd1eb 1267 snprintf (&buf[n], 1023, " (state = 0x%02x)", tip->state);
61bb466e
KW
1268#endif
1269
1270 return buf;
1271}
1272
1273static void
dc5dd1eb 1274init_procfs_ops (void)
61bb466e
KW
1275{
1276 procfs_ops.to_shortname = "procfs";
1277 procfs_ops.to_longname = "QNX Neutrino procfs child process";
1278 procfs_ops.to_doc =
1279 "QNX Neutrino procfs child process (started by the \"run\" command).\n\
1280 target procfs <node>";
1281 procfs_ops.to_open = procfs_open;
1282 procfs_ops.to_attach = procfs_attach;
1283 procfs_ops.to_post_attach = procfs_post_attach;
1284 procfs_ops.to_detach = procfs_detach;
1285 procfs_ops.to_resume = procfs_resume;
1286 procfs_ops.to_wait = procfs_wait;
1287 procfs_ops.to_fetch_registers = procfs_fetch_registers;
1288 procfs_ops.to_store_registers = procfs_store_registers;
1289 procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
c8e73a31 1290 procfs_ops.deprecated_xfer_memory = procfs_xfer_memory;
61bb466e
KW
1291 procfs_ops.to_files_info = procfs_files_info;
1292 procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint;
1293 procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint;
1294 procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
1295 procfs_ops.to_insert_hw_breakpoint = procfs_insert_hw_breakpoint;
1296 procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint;
1297 procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint;
1298 procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint;
1299 procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
1300 procfs_ops.to_terminal_init = terminal_init_inferior;
1301 procfs_ops.to_terminal_inferior = terminal_inferior;
1302 procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
1303 procfs_ops.to_terminal_ours = terminal_ours;
1304 procfs_ops.to_terminal_info = child_terminal_info;
1305 procfs_ops.to_kill = procfs_kill_inferior;
1306 procfs_ops.to_create_inferior = procfs_create_inferior;
1307 procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
1308 procfs_ops.to_can_run = procfs_can_run;
1309 procfs_ops.to_notice_signals = procfs_notice_signals;
1310 procfs_ops.to_thread_alive = procfs_thread_alive;
1311 procfs_ops.to_find_new_threads = procfs_find_new_threads;
1312 procfs_ops.to_pid_to_str = procfs_pid_to_str;
1313 procfs_ops.to_stop = procfs_stop;
1314 procfs_ops.to_stratum = process_stratum;
1315 procfs_ops.to_has_all_memory = 1;
1316 procfs_ops.to_has_memory = 1;
1317 procfs_ops.to_has_stack = 1;
1318 procfs_ops.to_has_registers = 1;
1319 procfs_ops.to_has_execution = 1;
1320 procfs_ops.to_magic = OPS_MAGIC;
1321 procfs_ops.to_have_continuable_watchpoint = 1;
1322}
1323
1324#define OSTYPE_NTO 1
1325
1326void
dc5dd1eb 1327_initialize_procfs (void)
61bb466e
KW
1328{
1329 sigset_t set;
1330
1331 init_procfs_ops ();
1332 add_target (&procfs_ops);
1333
1334 /* We use SIGUSR1 to gain control after we block waiting for a process.
1335 We use sigwaitevent to wait. */
1336 sigemptyset (&set);
1337 sigaddset (&set, SIGUSR1);
1338 sigprocmask (SIG_BLOCK, &set, NULL);
1339
1340 /* Set up trace and fault sets, as gdb expects them. */
1341 sigemptyset (&run.trace);
61bb466e
KW
1342
1343 /* Stuff some information. */
1344 nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags;
1345 nto_cpuinfo_valid = 1;
1346
1bedd215
AC
1347 add_info ("pidlist", procfs_pidlist, _("pidlist"));
1348 add_info ("meminfo", procfs_meminfo, _("memory information"));
d737fd7f
KW
1349
1350 nto_is_nto_target = procfs_is_nto_target;
61bb466e
KW
1351}
1352
1353
1354static int
1355procfs_hw_watchpoint (int addr, int len, int type)
1356{
1357 procfs_break brk;
1358
1359 switch (type)
1360 {
1361 case 1: /* Read. */
1362 brk.type = _DEBUG_BREAK_RD;
1363 break;
1364 case 2: /* Read/Write. */
1365 brk.type = _DEBUG_BREAK_RW;
1366 break;
1367 default: /* Modify. */
1368/* FIXME: brk.type = _DEBUG_BREAK_RWM gives EINVAL for some reason. */
1369 brk.type = _DEBUG_BREAK_RW;
1370 }
1371 brk.type |= _DEBUG_BREAK_HW; /* Always ask for HW. */
1372 brk.addr = addr;
1373 brk.size = len;
1374
1375 errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0);
1376 if (errno != EOK)
1377 {
1378 perror ("Failed to set hardware watchpoint");
1379 return -1;
1380 }
1381 return 0;
1382}
1383
1384static int
1385procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
1386{
1387 return 1;
1388}
1389
1390static int
1391procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
1392{
1393 return procfs_hw_watchpoint (addr, -1, type);
1394}
1395
1396static int
1397procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
1398{
1399 return procfs_hw_watchpoint (addr, len, type);
1400}
1401
1402static int
1403procfs_stopped_by_watchpoint (void)
1404{
1405 return 0;
1406}
This page took 0.273576 seconds and 4 git commands to generate.