Adding Neutrino gdbserver.
[deliverable/binutils-gdb.git] / gdb / gdbserver / nto-low.c
CommitLineData
ac8c974e
AR
1/* QNX Neutrino specific low level interface, for the remote server
2 for GDB.
3 Copyright (C) 2009
4 Free Software Foundation, Inc.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21
22#include "server.h"
23#include "nto-low.h"
24
25#include <limits.h>
26#include <fcntl.h>
27#include <spawn.h>
28#include <sys/procfs.h>
29#include <sys/auxv.h>
30#include <stdarg.h>
31#include <sys/iomgr.h>
32#include <sys/neutrino.h>
33
34
35extern int using_threads;
36int using_threads = 1;
37
38static void
39nto_trace (const char *fmt, ...)
40{
41 va_list arg_list;
42
43 if (debug_threads == 0)
44 return;
45 fprintf (stderr, "nto:");
46 va_start (arg_list, fmt);
47 vfprintf (stderr, fmt, arg_list);
48 va_end (arg_list);
49}
50
51#define TRACE nto_trace
52
53/* Structure holding neutrino specific information about
54 inferior. */
55
56struct nto_inferior
57{
58 char nto_procfs_path[PATH_MAX];
59 int ctl_fd;
60 pid_t pid;
61 int exit_signo; /* For tracking exit status. */
62};
63
64static struct nto_inferior nto_inferior;
65
66static void
67init_nto_inferior (struct nto_inferior *nto_inferior)
68{
69 memset (nto_inferior, 0, sizeof (struct nto_inferior));
70 nto_inferior->ctl_fd = -1;
71 nto_inferior->pid = -1;
72}
73
74static void
75do_detach (void)
76{
77 if (nto_inferior.ctl_fd != -1)
78 {
79 nto_trace ("Closing fd\n");
80 close (nto_inferior.ctl_fd);
81 init_nto_inferior (&nto_inferior);
82 }
83}
84
85/* Set current thread. Return 1 on success, 0 otherwise. */
86
87static int
88nto_set_thread (ptid_t ptid)
89{
90 int res = 0;
91
92 TRACE ("%s pid: %d tid: %ld\n", __func__, ptid_get_pid (ptid),
93 ptid_get_lwp (ptid));
94 if (nto_inferior.ctl_fd != -1
95 && !ptid_equal (ptid, null_ptid)
96 && !ptid_equal (ptid, minus_one_ptid))
97 {
98 pthread_t tid = ptid_get_lwp (ptid);
99
100 if (EOK == devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid,
101 sizeof (tid), 0))
102 res = 1;
103 else
104 TRACE ("%s: Error: failed to set current thread\n", __func__);
105 }
106 return res;
107}
108
109/* This function will determine all alive threads. Note that we do not list
110 dead but unjoined threads even though they are still in the process' thread
111 list.
112
113 NTO_INFERIOR must not be NULL. */
114
115static void
116nto_find_new_threads (struct nto_inferior *nto_inferior)
117{
118 pthread_t tid;
119
120 TRACE ("%s pid:%d\n", __func__, nto_inferior->pid);
121
122 if (nto_inferior->ctl_fd == -1)
123 return;
124
125 for (tid = 1;; ++tid)
126 {
127 procfs_status status;
128 ptid_t ptid;
129 int err;
130
131 status.tid = tid;
132 err = devctl (nto_inferior->ctl_fd, DCMD_PROC_TIDSTATUS, &status,
133 sizeof (status), 0);
134
135 if (err != EOK || status.tid == 0)
136 break;
137
138 /* All threads in between are gone. */
139 while (tid != status.tid || status.state == STATE_DEAD)
140 {
141 struct thread_info *ti;
142
143 ptid = ptid_build (nto_inferior->pid, tid, 0);
144 ti = find_thread_ptid (ptid);
145 if (ti != NULL)
146 {
147 TRACE ("Removing thread %d\n", tid);
148 remove_thread (ti);
149 }
150 if (tid == status.tid)
151 break;
152 ++tid;
153 }
154
155 if (status.state != STATE_DEAD)
156 {
157 TRACE ("Adding thread %d\n", tid);
158 ptid = ptid_build (nto_inferior->pid, tid, 0);
159 if (!find_thread_ptid (ptid))
160 add_thread (ptid, NULL);
161 }
162 }
163}
164
165/* Given pid, open procfs path. */
166
167static pid_t
168do_attach (pid_t pid)
169{
170 procfs_status status;
171 struct sigevent event;
172
173 if (nto_inferior.ctl_fd != -1)
174 {
175 close (nto_inferior.ctl_fd);
176 init_nto_inferior (&nto_inferior);
177 }
178 snprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", pid);
179 nto_inferior.ctl_fd = open (nto_inferior.nto_procfs_path, O_RDWR);
180 if (nto_inferior.ctl_fd == -1)
181 {
182 TRACE ("Failed to open %s\n", nto_inferior.nto_procfs_path);
183 init_nto_inferior (&nto_inferior);
184 return -1;
185 }
186 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0)
187 != EOK)
188 {
189 do_detach ();
190 return -1;
191 }
192 nto_inferior.pid = pid;
193 /* Define a sigevent for process stopped notification. */
194 event.sigev_notify = SIGEV_SIGNAL_THREAD;
195 event.sigev_signo = SIGUSR1;
196 event.sigev_code = 0;
197 event.sigev_value.sival_ptr = NULL;
198 event.sigev_priority = -1;
199 devctl (nto_inferior.ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
200
201 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
202 0) == EOK
203 && (status.flags & _DEBUG_FLAG_STOPPED))
204 {
205 ptid_t ptid;
206
207 kill (pid, SIGCONT);
208 ptid = ptid_build (status.pid, status.tid, 0);
209 the_low_target.arch_setup ();
210 add_process (status.pid, 1);
211 TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid,
212 ptid_get_lwp (ptid));
213 nto_find_new_threads (&nto_inferior);
214 }
215 else
216 {
217 do_detach ();
218 return -1;
219 }
220
221 return pid;
222}
223
224/* Read or write LEN bytes from/to inferior's MEMADDR memory address
225 into gdbservers's MYADDR buffer. Return number of bytes actually
226 transfered. */
227
228static int
229nto_xfer_memory (off_t memaddr, unsigned char *myaddr, int len,
230 int dowrite)
231{
232 int nbytes = 0;
233
234 if (lseek (nto_inferior.ctl_fd, memaddr, SEEK_SET) == memaddr)
235 {
236 if (dowrite)
237 nbytes = write (nto_inferior.ctl_fd, myaddr, len);
238 else
239 nbytes = read (nto_inferior.ctl_fd, myaddr, len);
240 if (nbytes < 0)
241 nbytes = 0;
242 }
243 if (nbytes == 0)
244 {
245 int e = errno;
246 TRACE ("Error in %s : errno=%d (%s)\n", __func__, e, strerror (e));
247 }
248 return nbytes;
249}
250
251/* Insert or remove breakpoint or watchpoint at address ADDR.
252 TYPE can be one of Neutrino breakpoint types. SIZE must be 0 for
253 inserting the point, -1 for removing it.
254
255 Return 0 on success, 1 otherwise. */
256
257static int
258nto_breakpoint (CORE_ADDR addr, int type, int size)
259{
260 procfs_break brk;
261
262 brk.type = type;
263 brk.addr = addr;
264 brk.size = size;
265 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)
266 != EOK)
267 return 1;
268 return 0;
269}
270
271/* Read auxiliary vector from inferior's initial stack into gdbserver's
272 MYADDR buffer, up to LEN bytes.
273
274 Return number of bytes read. */
275
276static int
277nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
278 unsigned char *myaddr,
279 unsigned int len)
280{
281 int data_ofs = 0;
282 int anint;
283 unsigned int len_read = 0;
284
285 /* Skip over argc, argv and envp... Comment from ldd.c:
286
287 The startup frame is set-up so that we have:
288 auxv
289 NULL
290 ...
291 envp2
292 envp1 <----- void *frame + (argc + 2) * sizeof(char *)
293 NULL
294 ...
295 argv2
296 argv1
297 argc <------ void * frame
298
299 On entry to ldd, frame gives the address of argc on the stack. */
300 if (nto_xfer_memory (initial_stack, (unsigned char *)&anint,
301 sizeof (anint), 0) != sizeof (anint))
302 return 0;
303
304 /* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */
305 data_ofs += (anint + 2) * sizeof (void *); /* + 2 comes from argc itself and
306 NULL terminating pointer in
307 argv. */
308
309 /* Now loop over env table: */
310 while (nto_xfer_memory (initial_stack + data_ofs,
311 (unsigned char *)&anint, sizeof (anint), 0)
312 == sizeof (anint))
313 {
314 data_ofs += sizeof (anint);
315 if (anint == 0)
316 break;
317 }
318 initial_stack += data_ofs;
319
320 memset (myaddr, 0, len);
321 while (len_read <= len - sizeof (auxv_t))
322 {
323 auxv_t *auxv = (auxv_t *)myaddr;
324
325 /* Search backwards until we have read AT_PHDR (num. 3),
326 AT_PHENT (num 4), AT_PHNUM (num 5) */
327 if (nto_xfer_memory (initial_stack, (unsigned char *)auxv,
328 sizeof (auxv_t), 0) == sizeof (auxv_t))
329 {
330 if (auxv->a_type != AT_NULL)
331 {
332 auxv++;
333 len_read += sizeof (auxv_t);
334 }
335 if (auxv->a_type == AT_PHNUM) /* That's all we need. */
336 break;
337 initial_stack += sizeof (auxv_t);
338 }
339 else
340 break;
341 }
342 TRACE ("auxv: len_read: %d\n", len_read);
343 return len_read;
344}
345
346/* Start inferior specified by PROGRAM passing arguments ALLARGS. */
347
348static int
349nto_create_inferior (char *program, char **allargs)
350{
351 struct inheritance inherit;
352 pid_t pid;
353 sigset_t set;
354
355 TRACE ("%s %s\n", __func__, program);
356 /* Clear any pending SIGUSR1's but keep the behavior the same. */
357 signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
358
359 sigemptyset (&set);
360 sigaddset (&set, SIGUSR1);
361 sigprocmask (SIG_UNBLOCK, &set, NULL);
362
363 memset (&inherit, 0, sizeof (inherit));
364 inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
365 inherit.pgroup = SPAWN_NEWPGROUP;
366 pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
367 sigprocmask (SIG_BLOCK, &set, NULL);
368
369 if (pid == -1)
370 return -1;
371
372 if (do_attach (pid) != pid)
373 return -1;
374
375 return pid;
376}
377
378/* Attach to process PID. */
379
380static int
381nto_attach (unsigned long pid)
382{
383 TRACE ("%s %ld\n", __func__, pid);
384 if (do_attach (pid) != pid)
385 error ("Unable to attach to %ld\n", pid);
386 return 0;
387}
388
389/* Send signal to process PID. */
390
391static int
392nto_kill (int pid)
393{
394 TRACE ("%s %d\n", __func__, pid);
395 kill (pid, SIGKILL);
396 do_detach ();
397 return 0;
398}
399
400/* Detach from process PID. */
401
402static int
403nto_detach (int pid)
404{
405 TRACE ("%s %d\n", __func__, pid);
406 do_detach ();
407 return 0;
408}
409
410/* Check if the given thread is alive.
411
412 Return 1 if alive, 0 otherwise. */
413
414static int
415nto_thread_alive (ptid_t ptid)
416{
417 int res;
418
419 TRACE ("%s pid:%d tid:%d\n", __func__, ptid_get_pid (ptid),
420 ptid_get_lwp (ptid));
421 if (SignalKill (0, ptid_get_pid (ptid), ptid_get_lwp (ptid),
422 0, 0, 0) == -1)
423 res = 0;
424 else
425 res = 1;
426 TRACE ("%s: %s\n", __func__, res ? "yes" : "no");
427 return res;
428}
429
430/* Resume inferior's execution. */
431
432static void
433nto_resume (struct thread_resume *resume_info, size_t n)
434{
435 /* We can only work in all-stop mode. */
436 procfs_status status;
437 procfs_run run;
438 int err;
439
440 TRACE ("%s\n", __func__);
441 /* Workaround for aliasing rules violation. */
442 sigset_t *run_fault = (sigset_t *) (void *) &run.fault;
443
444 nto_set_thread (resume_info->thread);
445
446 run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
447 if (resume_info->kind == resume_step)
448 run.flags |= _DEBUG_RUN_STEP;
449 run.flags |= _DEBUG_RUN_ARM;
450
451 sigemptyset (run_fault);
452 sigaddset (run_fault, FLTBPT);
453 sigaddset (run_fault, FLTTRACE);
454 sigaddset (run_fault, FLTILL);
455 sigaddset (run_fault, FLTPRIV);
456 sigaddset (run_fault, FLTBOUNDS);
457 sigaddset (run_fault, FLTIOVF);
458 sigaddset (run_fault, FLTIZDIV);
459 sigaddset (run_fault, FLTFPE);
460 sigaddset (run_fault, FLTPAGE);
461 sigaddset (run_fault, FLTSTACK);
462 sigaddset (run_fault, FLTACCESS);
463
464 sigemptyset (&run.trace);
465 if (resume_info->sig)
466 {
467 int signal_to_pass;
468
469 devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
470 0);
471 signal_to_pass = resume_info->sig;
472 if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
473 {
474 if (signal_to_pass != status.info.si_signo)
475 {
476 kill (status.pid, signal_to_pass);
477 run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
478 }
479 else /* Let it kill the program without telling us. */
480 sigdelset (&run.trace, signal_to_pass);
481 }
482 }
483 else
484 run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
485
486 sigfillset (&run.trace);
487
488 regcache_invalidate ();
489
490 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
491 if (err != EOK)
492 TRACE ("Error: %d \"%s\"\n", err, strerror (err));
493}
494
495/* Wait for inferior's event.
496
497 Return ptid of thread that caused the event. */
498
499static ptid_t
500nto_wait (ptid_t ptid,
501 struct target_waitstatus *ourstatus, int target_options)
502{
503 sigset_t set;
504 siginfo_t info;
505 procfs_status status;
506 const int trace_mask = (_DEBUG_FLAG_TRACE_EXEC | _DEBUG_FLAG_TRACE_RD
507 | _DEBUG_FLAG_TRACE_WR | _DEBUG_FLAG_TRACE_MODIFY);
508
509 TRACE ("%s\n", __func__);
510
511 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
512
513 sigemptyset (&set);
514 sigaddset (&set, SIGUSR1);
515
516 devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
517 while (!(status.flags & _DEBUG_FLAG_ISTOP))
518 {
519 sigwaitinfo (&set, &info);
520 devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
521 0);
522 }
523 nto_find_new_threads (&nto_inferior);
524
525 if (status.flags & _DEBUG_FLAG_SSTEP)
526 {
527 TRACE ("SSTEP\n");
528 ourstatus->kind = TARGET_WAITKIND_STOPPED;
529 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
530 }
531 /* Was it a breakpoint? */
532 else if (status.flags & trace_mask)
533 {
534 TRACE ("STOPPED\n");
535 ourstatus->kind = TARGET_WAITKIND_STOPPED;
536 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
537 }
538 else if (status.flags & _DEBUG_FLAG_ISTOP)
539 {
540 TRACE ("ISTOP\n");
541 switch (status.why)
542 {
543 case _DEBUG_WHY_SIGNALLED:
544 TRACE (" SIGNALLED\n");
545 ourstatus->kind = TARGET_WAITKIND_STOPPED;
546 ourstatus->value.sig =
547 target_signal_from_host (status.info.si_signo);
548 nto_inferior.exit_signo = ourstatus->value.sig;
549 break;
550 case _DEBUG_WHY_FAULTED:
551 TRACE (" FAULTED\n");
552 ourstatus->kind = TARGET_WAITKIND_STOPPED;
553 if (status.info.si_signo == SIGTRAP)
554 {
555 ourstatus->value.sig = 0;
556 nto_inferior.exit_signo = 0;
557 }
558 else
559 {
560 ourstatus->value.sig =
561 target_signal_from_host (status.info.si_signo);
562 nto_inferior.exit_signo = ourstatus->value.sig;
563 }
564 break;
565
566 case _DEBUG_WHY_TERMINATED:
567 {
568 int waitval = 0;
569
570 TRACE (" TERMINATED\n");
571 waitpid (ptid_get_pid (ptid), &waitval, WNOHANG);
572 if (nto_inferior.exit_signo)
573 {
574 /* Abnormal death. */
575 ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
576 ourstatus->value.sig = nto_inferior.exit_signo;
577 }
578 else
579 {
580 /* Normal death. */
581 ourstatus->kind = TARGET_WAITKIND_EXITED;
582 ourstatus->value.integer = WEXITSTATUS (waitval);
583 }
584 nto_inferior.exit_signo = 0;
585 break;
586 }
587
588 case _DEBUG_WHY_REQUESTED:
589 TRACE ("REQUESTED\n");
590 /* We are assuming a requested stop is due to a SIGINT. */
591 ourstatus->kind = TARGET_WAITKIND_STOPPED;
592 ourstatus->value.sig = TARGET_SIGNAL_INT;
593 nto_inferior.exit_signo = 0;
594 break;
595 }
596 }
597
598 return ptid_build (status.pid, status.tid, 0);
599}
600
601/* Fetch inferior's registers for currently selected thread (CURRENT_INFERIOR).
602 If REGNO is -1, fetch all registers, or REGNO register only otherwise. */
603
604static void
605nto_fetch_registers (int regno)
606{
607 int regsize;
608 procfs_greg greg;
609 ptid_t ptid;
610
611 TRACE ("%s (regno=%d)\n", __func__, regno);
612 if (regno >= the_low_target.num_regs)
613 return;
614
615 if (current_inferior == NULL)
616 {
617 TRACE ("current_inferior is NULL\n");
618 return;
619 }
620 ptid = thread_to_gdb_id (current_inferior);
621 if (!nto_set_thread (ptid))
622 return;
623
624 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg),
625 &regsize) == EOK)
626 {
627 if (regno == -1) /* All registers. */
628 {
629 for (regno = 0; regno != the_low_target.num_regs; ++regno)
630 {
631 const unsigned int registeroffset
632 = the_low_target.register_offset (regno);
633 supply_register (regno, ((char *)&greg) + registeroffset);
634 }
635 }
636 else
637 {
638 const unsigned int registeroffset
639 = the_low_target.register_offset (regno);
640 if (registeroffset == -1)
641 return;
642 supply_register (regno, ((char *)&greg) + registeroffset);
643 }
644 }
645 else
646 TRACE ("ERROR reading registers from inferior.\n");
647}
648
649/* Store registers for currently selected thread (CURRENT_INFERIOR).
650 We always store all registers, regardless of REGNO. */
651
652static void
653nto_store_registers (int regno)
654{
655 procfs_greg greg;
656 int err;
657 ptid_t ptid;
658
659 TRACE ("%s (regno:%d)\n", __func__, regno);
660
661 if (current_inferior == NULL)
662 {
663 TRACE ("current_inferior is NULL\n");
664 return;
665 }
666 ptid = thread_to_gdb_id (current_inferior);
667 if (!nto_set_thread (ptid))
668 return;
669
670 memset (&greg, 0, sizeof (greg));
671 for (regno = 0; regno != the_low_target.num_regs; ++regno)
672 {
673 const unsigned int regoffset
674 = the_low_target.register_offset (regno);
675 collect_register (regno, ((char *)&greg) + regoffset);
676 }
677 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg),
678 0);
679 if (err != EOK)
680 TRACE ("Error: setting registers.\n");
681}
682
683/* Read LEN bytes from inferior's memory address MEMADDR into
684 gdbserver's MYADDR buffer.
685
686 Return 0 on success -1 otherwise. */
687
688static int
689nto_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
690{
691 TRACE ("%s memaddr:0x%08lx, len:%d\n", __func__, memaddr, len);
692
693 if (nto_xfer_memory (memaddr, myaddr, len, 0) != len)
694 {
695 TRACE ("Failed to read memory\n");
696 return -1;
697 }
698
699 return 0;
700}
701
702/* Write LEN bytes from gdbserver's buffer MYADDR into inferior's
703 memory at address MEMADDR.
704
705 Return 0 on success -1 otherwise. */
706
707static int
708nto_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
709{
710 int len_written;
711
712 TRACE ("%s memaddr: 0x%08llx len: %d\n", __func__, memaddr, len);
713 if ((len_written = nto_xfer_memory (memaddr, (unsigned char *)myaddr, len,
714 1))
715 != len)
716 {
717 TRACE ("Wanted to write: %d but written: %d\n", len, len_written);
718 return -1;
719 }
720
721 return 0;
722}
723
724/* Stop inferior. We always stop all threads. */
725
726static void
727nto_request_interrupt (void)
728{
729 TRACE ("%s\n", __func__);
730 nto_set_thread (ptid_build (nto_inferior.pid, 1, 0));
731 if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0))
732 TRACE ("Error stopping inferior.\n");
733}
734
735/* Read auxiliary vector from inferior's memory into gdbserver's buffer
736 MYADDR. We always read whole auxv.
737
738 Return number of bytes stored in MYADDR buffer, 0 if OFFSET > 0
739 or -1 on error. */
740
741static int
742nto_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
743{
744 int err;
745 CORE_ADDR initial_stack;
746 procfs_info procinfo;
747
748 TRACE ("%s\n", __func__);
749 if (offset > 0)
750 return 0;
751
752 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_INFO, &procinfo,
753 sizeof procinfo, 0);
754 if (err != EOK)
755 return -1;
756
757 initial_stack = procinfo.initial_stack;
758
759 return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len);
760}
761
762/* Insert {break/watch}point at address ADDR.
763 TYPE must be in '0'..'4' range. LEN is not used. */
764
765static int
766nto_insert_point (char type, CORE_ADDR addr, int len)
767{
768 int wtype = _DEBUG_BREAK_HW; /* Always request HW. */
769
770 TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, len);
771 switch (type)
772 {
773 case '0': /* software-breakpoint */
774 wtype = _DEBUG_BREAK_EXEC;
775 break;
776 case '1': /* hardware-breakpoint */
777 wtype |= _DEBUG_BREAK_EXEC;
778 break;
779 case '2': /* write watchpoint */
780 wtype |= _DEBUG_BREAK_RW;
781 break;
782 case '3': /* read watchpoint */
783 wtype |= _DEBUG_BREAK_RD;
784 break;
785 case '4': /* access watchpoint */
786 wtype |= _DEBUG_BREAK_RW;
787 break;
788 default:
789 return 1; /* Not supported. */
790 }
791 return nto_breakpoint (addr, wtype, 0);
792}
793
794/* Remove {break/watch}point at address ADDR.
795 TYPE must be in '0'..'4' range. LEN is not used. */
796
797static int
798nto_remove_point (char type, CORE_ADDR addr, int len)
799{
800 int wtype = _DEBUG_BREAK_HW; /* Always request HW. */
801
802 TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, len);
803 switch (type)
804 {
805 case '0': /* software-breakpoint */
806 wtype = _DEBUG_BREAK_EXEC;
807 break;
808 case '1': /* hardware-breakpoint */
809 wtype |= _DEBUG_BREAK_EXEC;
810 break;
811 case '2': /* write watchpoint */
812 wtype |= _DEBUG_BREAK_RW;
813 break;
814 case '3': /* read watchpoint */
815 wtype |= _DEBUG_BREAK_RD;
816 break;
817 case '4': /* access watchpoint */
818 wtype |= _DEBUG_BREAK_RW;
819 break;
820 default:
821 return 1; /* Not supported. */
822 }
823 return nto_breakpoint (addr, wtype, -1);
824}
825
826/* Check if the reason of stop for current thread (CURRENT_INFERIOR) is
827 a watchpoint.
828
829 Return 1 if stopped by watchpoint, 0 otherwise. */
830
831static int
832nto_stopped_by_watchpoint (void)
833{
834 int ret = 0;
835
836 TRACE ("%s\n", __func__);
837 if (nto_inferior.ctl_fd != -1 && current_inferior != NULL)
838 {
839 ptid_t ptid;
840
841 ptid = thread_to_gdb_id (current_inferior);
842 if (nto_set_thread (ptid))
843 {
844 const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR
845 | _DEBUG_FLAG_TRACE_MODIFY;
846 procfs_status status;
847 int err;
848
849 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
850 sizeof (status), 0);
851 if (err == EOK && (status.flags & watchmask))
852 ret = 1;
853 }
854 }
855 TRACE ("%s: %s\n", __func__, ret ? "yes" : "no");
856 return ret;
857}
858
859/* Get instruction pointer for CURRENT_INFERIOR thread.
860
861 Return inferior's instruction pointer value, or 0 on error. */
862
863static CORE_ADDR
864nto_stopped_data_address (void)
865{
866 CORE_ADDR ret = (CORE_ADDR)0;
867
868 TRACE ("%s\n", __func__);
869 if (nto_inferior.ctl_fd != -1 && current_inferior != NULL)
870 {
871 ptid_t ptid;
872
873 ptid = thread_to_gdb_id (current_inferior);
874
875 if (nto_set_thread (ptid))
876 {
877 procfs_status status;
878
879 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
880 sizeof (status), 0) == EOK)
881 ret = status.ip;
882 }
883 }
884 TRACE ("%s: 0x%08lx\n", __func__, ret);
885 return ret;
886}
887
888/* We do not currently support non-stop. */
889
890static int
891nto_supports_non_stop (void)
892{
893 TRACE ("%s\n", __func__);
894 return 0;
895}
896
897
898
899static struct target_ops nto_target_ops = {
900 nto_create_inferior,
901 nto_attach,
902 nto_kill,
903 nto_detach,
904 NULL, /* nto_join */
905 nto_thread_alive,
906 nto_resume,
907 nto_wait,
908 nto_fetch_registers,
909 nto_store_registers,
910 nto_read_memory,
911 nto_write_memory,
912 NULL, /* nto_look_up_symbols */
913 nto_request_interrupt,
914 nto_read_auxv,
915 nto_insert_point,
916 nto_remove_point,
917 nto_stopped_by_watchpoint,
918 nto_stopped_data_address,
919 NULL, /* nto_read_offsets */
920 NULL, /* thread_db_set_tls_address */
921 NULL,
922 hostio_last_error_from_errno,
923 NULL, /* nto_qxfer_osdata */
924 NULL, /* xfer_siginfo */
925 nto_supports_non_stop,
926 NULL, /* async */
927 NULL /* start_non_stop */
928};
929
930
931/* Global function called by server.c. Initializes QNX Neutrino
932 gdbserver. */
933
934void
935initialize_low (void)
936{
937 sigset_t set;
938
939 TRACE ("%s\n", __func__);
940 set_target_ops (&nto_target_ops);
941 set_breakpoint_data (the_low_target.breakpoint,
942 the_low_target.breakpoint_len);
943
944 /* We use SIGUSR1 to gain control after we block waiting for a process.
945 We use sigwaitevent to wait. */
946 sigemptyset (&set);
947 sigaddset (&set, SIGUSR1);
948 sigprocmask (SIG_BLOCK, &set, NULL);
949}
950
This page took 0.057533 seconds and 4 git commands to generate.