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