[LynxOS] Include sys/ptrace.h instead of ptrace.h.
[deliverable/binutils-gdb.git] / gdb / gdbserver / lynx-low.c
1 /* Copyright (C) 2009, 2010 Free Software Foundation, Inc.
2
3 This file is part of GDB.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "server.h"
19 #include "target.h"
20 #include "lynx-low.h"
21
22 #include <limits.h>
23 #include <sys/ptrace.h>
24 #include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc. */
25 #include <unistd.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <signal.h>
30
31 int using_threads = 1;
32
33 /* Print a debug trace on standard output if debug_threads is set. */
34
35 static void
36 lynx_debug (char *string, ...)
37 {
38 va_list args;
39
40 if (!debug_threads)
41 return;
42
43 va_start (args, string);
44 fprintf (stderr, "DEBUG(lynx): ");
45 vfprintf (stderr, string, args);
46 fprintf (stderr, "\n");
47 va_end (args);
48 }
49
50 /* Build a ptid_t given a PID and a LynxOS TID. */
51
52 static ptid_t
53 lynx_ptid_build (int pid, long tid)
54 {
55 /* brobecker/2010-06-21: It looks like the LWP field in ptids
56 should be distinct for each thread (see write_ptid where it
57 writes the thread ID from the LWP). So instead of storing
58 the LynxOS tid in the tid field of the ptid, we store it in
59 the lwp field. */
60 return ptid_build (pid, tid, 0);
61 }
62
63 /* Return the process ID of the given PTID.
64
65 This function has little reason to exist, it's just a wrapper around
66 ptid_get_pid. But since we have a getter function for the lynxos
67 ptid, it feels cleaner to have a getter for the pid as well. */
68
69 static int
70 lynx_ptid_get_pid (ptid_t ptid)
71 {
72 return ptid_get_pid (ptid);
73 }
74
75 /* Return the LynxOS tid of the given PTID. */
76
77 static long
78 lynx_ptid_get_tid (ptid_t ptid)
79 {
80 /* See lynx_ptid_build: The LynxOS tid is stored inside the lwp field
81 of the ptid. */
82 return ptid_get_lwp (ptid);
83 }
84
85 /* For a given PTID, return the associated PID as known by the LynxOS
86 ptrace layer. */
87
88 static int
89 lynx_ptrace_pid_from_ptid (ptid_t ptid)
90 {
91 return BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
92 }
93
94 /* Return a string image of the ptrace REQUEST number. */
95
96 static char *
97 ptrace_request_to_str (int request)
98 {
99 switch (request)
100 {
101 case PTRACE_TRACEME:
102 return "PTRACE_TRACEME";
103 break;
104 case PTRACE_PEEKTEXT:
105 return "PTRACE_PEEKTEXT";
106 break;
107 case PTRACE_PEEKDATA:
108 return "PTRACE_PEEKDATA";
109 break;
110 case PTRACE_PEEKUSER:
111 return "PTRACE_PEEKUSER";
112 break;
113 case PTRACE_POKETEXT:
114 return "PTRACE_POKETEXT";
115 break;
116 case PTRACE_POKEDATA:
117 return "PTRACE_POKEDATA";
118 break;
119 case PTRACE_POKEUSER:
120 return "PTRACE_POKEUSER";
121 break;
122 case PTRACE_CONT:
123 return "PTRACE_CONT";
124 break;
125 case PTRACE_KILL:
126 return "PTRACE_KILL";
127 break;
128 case PTRACE_SINGLESTEP:
129 return "PTRACE_SINGLESTEP";
130 break;
131 case PTRACE_ATTACH:
132 return "PTRACE_ATTACH";
133 break;
134 case PTRACE_DETACH:
135 return "PTRACE_DETACH";
136 break;
137 case PTRACE_GETREGS:
138 return "PTRACE_GETREGS";
139 break;
140 case PTRACE_SETREGS:
141 return "PTRACE_SETREGS";
142 break;
143 case PTRACE_GETFPREGS:
144 return "PTRACE_GETFPREGS";
145 break;
146 case PTRACE_SETFPREGS:
147 return "PTRACE_SETFPREGS";
148 break;
149 case PTRACE_READDATA:
150 return "PTRACE_READDATA";
151 break;
152 case PTRACE_WRITEDATA:
153 return "PTRACE_WRITEDATA";
154 break;
155 case PTRACE_READTEXT:
156 return "PTRACE_READTEXT";
157 break;
158 case PTRACE_WRITETEXT:
159 return "PTRACE_WRITETEXT";
160 break;
161 case PTRACE_GETFPAREGS:
162 return "PTRACE_GETFPAREGS";
163 break;
164 case PTRACE_SETFPAREGS:
165 return "PTRACE_SETFPAREGS";
166 break;
167 case PTRACE_GETWINDOW:
168 return "PTRACE_GETWINDOW";
169 break;
170 case PTRACE_SETWINDOW:
171 return "PTRACE_SETWINDOW";
172 break;
173 case PTRACE_SYSCALL:
174 return "PTRACE_SYSCALL";
175 break;
176 case PTRACE_DUMPCORE:
177 return "PTRACE_DUMPCORE";
178 break;
179 case PTRACE_SETWRBKPT:
180 return "PTRACE_SETWRBKPT";
181 break;
182 case PTRACE_SETACBKPT:
183 return "PTRACE_SETACBKPT";
184 break;
185 case PTRACE_CLRBKPT:
186 return "PTRACE_CLRBKPT";
187 break;
188 case PTRACE_GET_UCODE:
189 return "PTRACE_GET_UCODE";
190 break;
191 #ifdef PT_READ_GPR
192 case PT_READ_GPR:
193 return "PT_READ_GPR";
194 break;
195 #endif
196 #ifdef PT_WRITE_GPR
197 case PT_WRITE_GPR:
198 return "PT_WRITE_GPR";
199 break;
200 #endif
201 #ifdef PT_READ_FPR
202 case PT_READ_FPR:
203 return "PT_READ_FPR";
204 break;
205 #endif
206 #ifdef PT_WRITE_FPR
207 case PT_WRITE_FPR:
208 return "PT_WRITE_FPR";
209 break;
210 #endif
211 #ifdef PTRACE_GETVECREGS
212 case PTRACE_GETVECREGS:
213 return "PTRACE_GETVECREGS";
214 break;
215 #endif
216 #ifdef PTRACE_SETVECREGS
217 case PTRACE_SETVECREGS:
218 return "PTRACE_SETVECREGS";
219 break;
220 #endif
221 #ifdef PT_READ_VPR
222 case PT_READ_VPR:
223 return "PT_READ_VPR";
224 break;
225 #endif
226 #ifdef PT_WRITE_VPR
227 case PT_WRITE_VPR:
228 return "PT_WRITE_VPR";
229 break;
230 #endif
231 #ifdef PTRACE_PEEKUSP
232 case PTRACE_PEEKUSP:
233 return "PTRACE_PEEKUSP";
234 break;
235 #endif
236 #ifdef PTRACE_POKEUSP
237 case PTRACE_POKEUSP:
238 return "PTRACE_POKEUSP";
239 break;
240 #endif
241 case PTRACE_PEEKTHREAD:
242 return "PTRACE_PEEKTHREAD";
243 break;
244 case PTRACE_THREADUSER:
245 return "PTRACE_THREADUSER";
246 break;
247 case PTRACE_FPREAD:
248 return "PTRACE_FPREAD";
249 break;
250 case PTRACE_FPWRITE:
251 return "PTRACE_FPWRITE";
252 break;
253 case PTRACE_SETSIG:
254 return "PTRACE_SETSIG";
255 break;
256 case PTRACE_CONT_ONE:
257 return "PTRACE_CONT_ONE";
258 break;
259 case PTRACE_KILL_ONE:
260 return "PTRACE_KILL_ONE";
261 break;
262 case PTRACE_SINGLESTEP_ONE:
263 return "PTRACE_SINGLESTEP_ONE";
264 break;
265 case PTRACE_GETLOADINFO:
266 return "PTRACE_GETLOADINFO";
267 break;
268 case PTRACE_GETTHREADLIST:
269 return "PTRACE_GETTHREADLIST";
270 break;
271 case PTRACE_POSTSYSCALL:
272 return "PTRACE_POSTSYSCALL";
273 break;
274 case PTRACE_USE_SIGEXECED:
275 return "PTRACE_USE_SIGEXECED";
276 break;
277 case PTRACE_GETTRACESIG:
278 return "PTRACE_GETTRACESIG";
279 break;
280 case PTRACE_GETCWD:
281 return "PTRACE_GETCWD";
282 break;
283 case PTRACE_TRAPFORK:
284 return "PTRACE_TRAPFORK";
285 break;
286 case PTRACE_GETCHILDPID:
287 return "PTRACE_GETCHILDPID";
288 break;
289 case PTRACE_SYSCALL_ONE:
290 return "PTRACE_SYSCALL_ONE";
291 break;
292 case PTRACE_SIGMASK:
293 return "PTRACE_SIGMASK";
294 break;
295 case PTRACE_GETIWD:
296 return "PTRACE_GETIWD";
297 break;
298 case PTRACE_GETEXECFILE:
299 return "PTRACE_GETEXECFILE";
300 break;
301 }
302 return "<unknown-request>";
303 }
304
305 /* A wrapper around ptrace that allows us to print debug traces of
306 ptrace calls if debug traces are activated. */
307
308 static int
309 lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
310 {
311 int result;
312 const int pid = lynx_ptrace_pid_from_ptid (ptid);
313 int saved_errno;
314
315 if (debug_threads)
316 fprintf (stderr, "PTRACE (%s, pid=%d(pid=%d, tid=%d), addr=0x%x, "
317 "data=0x%x, addr2=0x%x)",
318 ptrace_request_to_str (request), pid, PIDGET (pid), TIDGET (pid),
319 addr, data, addr2);
320 result = ptrace (request, pid, addr, data, addr2);
321 saved_errno = errno;
322 if (debug_threads)
323 fprintf (stderr, " -> %d (=0x%x)\n", result, result);
324
325 errno = saved_errno;
326 return result;
327 }
328
329 /* Implement the create_inferior method of the target_ops vector. */
330
331 static int
332 lynx_create_inferior (char *program, char **allargs)
333 {
334 struct process_info *new_process;
335 int pid;
336
337 lynx_debug ("lynx_create_inferior ()");
338
339 pid = fork ();
340 if (pid < 0)
341 perror_with_name ("fork");
342
343 if (pid == 0)
344 {
345 int pgrp;
346
347 /* Switch child to its own process group so that signals won't
348 directly affect gdbserver. */
349 pgrp = getpid();
350 setpgid (0, pgrp);
351 ioctl (0, TIOCSPGRP, &pgrp);
352 lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
353 execv (program, allargs);
354 fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
355 fflush (stderr);
356 _exit (0177);
357 }
358
359 new_process = add_process (pid, 0);
360 /* Do not add the process thread just yet, as we do not know its tid.
361 We will add it later, during the wait for the STOP event corresponding
362 to the lynx_ptrace (PTRACE_TRACEME) call above. */
363 return pid;
364 }
365
366 /* Implement the attach target_ops method. */
367
368 static int
369 lynx_attach (unsigned long pid)
370 {
371 struct process_info *new_process;
372 ptid_t ptid = lynx_ptid_build (pid, 0);
373
374 if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0)
375 error ("Cannot attach to process %lu: %s (%d)\n", pid,
376 strerror (errno), errno);
377
378 new_process = add_process (pid, 1);
379 add_thread (ptid, NULL);
380
381 return 0;
382 }
383
384 /* Implement the resume target_ops method. */
385
386 static void
387 lynx_resume (struct thread_resume *resume_info, size_t n)
388 {
389 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
390 /* FIXME: Assume for now that n == 1. */
391 const int request = (resume_info[0].kind == resume_step
392 ? PTRACE_SINGLESTEP : PTRACE_CONT);
393 const int signal = resume_info[0].sig;
394 int ret;
395
396 regcache_invalidate ();
397 ret = lynx_ptrace (request, inferior_ptid, 1, signal, 0);
398 }
399
400 /* Resume the execution of the given PTID. */
401
402 static void
403 lynx_continue (ptid_t ptid)
404 {
405 struct thread_resume resume_info;
406
407 resume_info.thread = ptid;
408 resume_info.kind = resume_continue;
409 resume_info.sig = 0;
410
411 lynx_resume (&resume_info, 1);
412 }
413
414 /* Remove all inferiors and associated threads. */
415
416 static void
417 lynx_clear_inferiors (void)
418 {
419 /* We do not use private data, so nothing much to do except calling
420 clear_inferiors. */
421 clear_inferiors ();
422 }
423
424 /* A wrapper around waitpid that handles the various idiosyncrasies
425 of LynxOS' waitpid. */
426
427 static int
428 lynx_waitpid (int pid, int *stat_loc)
429 {
430 int ret = 0;
431
432 while (1)
433 {
434 ret = waitpid (pid, stat_loc, WNOHANG);
435 if (ret < 0)
436 {
437 /* An ECHILD error is not indicative of a real problem.
438 It happens for instance while waiting for the inferior
439 to stop after attaching to it. */
440 if (errno != ECHILD)
441 perror_with_name ("waitpid (WNOHANG)");
442 }
443 if (ret > 0)
444 break;
445 /* No event with WNOHANG. See if there is one with WUNTRACED. */
446 ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED);
447 if (ret < 0)
448 {
449 /* An ECHILD error is not indicative of a real problem.
450 It happens for instance while waiting for the inferior
451 to stop after attaching to it. */
452 if (errno != ECHILD)
453 perror_with_name ("waitpid (WNOHANG|WUNTRACED)");
454 }
455 if (ret > 0)
456 break;
457 usleep (1000);
458 }
459 return ret;
460 }
461
462 /* Implement the wait target_ops method. */
463
464 static ptid_t
465 lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options)
466 {
467 int pid;
468 int ret;
469 int wstat;
470 ptid_t new_ptid;
471
472 if (ptid_equal (ptid, minus_one_ptid))
473 pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior));
474 else
475 pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
476
477 retry:
478
479 ret = lynx_waitpid (pid, &wstat);
480 new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
481
482 /* If this is a new thread, then add it now. The reason why we do
483 this here instead of when handling new-thread events is because
484 we need to add the thread associated to the "main" thread - even
485 for non-threaded applications where the new-thread events are not
486 generated. */
487 if (!find_thread_ptid (new_ptid))
488 add_thread (new_ptid, NULL);
489
490 if (WIFSTOPPED (wstat))
491 {
492 status->kind = TARGET_WAITKIND_STOPPED;
493 status->value.integer = target_signal_from_host (WSTOPSIG (wstat));
494 lynx_debug ("process stopped with signal: %d",
495 status->value.integer);
496 }
497 else if (WIFEXITED (wstat))
498 {
499 status->kind = TARGET_WAITKIND_EXITED;
500 status->value.integer = WEXITSTATUS (wstat);
501 lynx_debug ("process exited with code: %d", status->value.integer);
502 }
503 else if (WIFSIGNALED (wstat))
504 {
505 status->kind = TARGET_WAITKIND_SIGNALLED;
506 status->value.integer = target_signal_from_host (WTERMSIG (wstat));
507 lynx_debug ("process terminated with code: %d",
508 status->value.integer);
509 }
510 else
511 {
512 /* Not sure what happened if we get here, or whether we can
513 in fact get here. But if we do, handle the event the best
514 we can. */
515 status->kind = TARGET_WAITKIND_STOPPED;
516 status->value.integer = target_signal_from_host (0);
517 lynx_debug ("unknown event ????");
518 }
519
520 /* SIGTRAP events are generated for situations other than single-step/
521 breakpoint events (Eg. new-thread events). Handle those other types
522 of events, and resume the execution if necessary. */
523 if (status->kind == TARGET_WAITKIND_STOPPED
524 && status->value.integer == TARGET_SIGNAL_TRAP)
525 {
526 const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0);
527
528 lynx_debug ("(realsig = %d)", realsig);
529 switch (realsig)
530 {
531 case SIGNEWTHREAD:
532 /* We just added the new thread above. No need to do anything
533 further. Just resume the execution again. */
534 lynx_continue (ptid);
535 goto retry;
536
537 case SIGTHREADEXIT:
538 remove_thread (find_thread_ptid (new_ptid));
539 lynx_continue (ptid);
540 goto retry;
541 }
542 }
543
544 return new_ptid;
545 }
546
547 /* A wrapper around lynx_wait_1 that also prints debug traces when
548 such debug traces have been activated. */
549
550 static ptid_t
551 lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options)
552 {
553 ptid_t new_ptid;
554
555 lynx_debug ("lynx_wait (pid = %d, tid = %ld)",
556 lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
557 new_ptid = lynx_wait_1 (ptid, status, options);
558 lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)",
559 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid),
560 status->kind);
561 return new_ptid;
562 }
563
564 /* Implement the kill target_ops method. */
565
566 static int
567 lynx_kill (int pid)
568 {
569 ptid_t ptid = lynx_ptid_build (pid, 0);
570 struct target_waitstatus status;
571 struct process_info *process;
572
573 process = find_process_pid (pid);
574 if (process == NULL)
575 return -1;
576
577 lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0);
578 lynx_wait (ptid, &status, 0);
579 the_target->mourn (process);
580 return 0;
581 }
582
583 /* Implement the detach target_ops method. */
584
585 static int
586 lynx_detach (int pid)
587 {
588 ptid_t ptid = lynx_ptid_build (pid, 0);
589 struct process_info *process;
590
591 process = find_process_pid (pid);
592 if (process == NULL)
593 return -1;
594
595 lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0);
596 the_target->mourn (process);
597 return 0;
598 }
599
600 /* Implement the mourn target_ops method. */
601
602 static void
603 lynx_mourn (struct process_info *proc)
604 {
605 lynx_clear_inferiors ();
606 }
607
608 /* Implement the join target_ops method. */
609
610 static void
611 lynx_join (int pid)
612 {
613 /* The PTRACE_DETACH is sufficient to detach from the process.
614 So no need to do anything extra. */
615 }
616
617 /* Implement the thread_alive target_ops method. */
618
619 static int
620 lynx_thread_alive (ptid_t ptid)
621 {
622 /* The list of threads is updated at the end of each wait, so it
623 should be up to date. No need to re-fetch it. */
624 return (find_thread_ptid (ptid) != NULL);
625 }
626
627 /* Implement the fetch_registers target_ops method. */
628
629 static void
630 lynx_fetch_registers (struct regcache *regcache, int regno)
631 {
632 struct lynx_regset_info *regset = lynx_target_regsets;
633 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
634
635 lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
636
637 while (regset->size >= 0)
638 {
639 char *buf;
640 int res;
641
642 buf = xmalloc (regset->size);
643 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
644 if (res < 0)
645 perror ("ptrace");
646 regset->store_function (regcache, buf);
647 free (buf);
648 regset++;
649 }
650 }
651
652 /* Implement the store_registers target_ops method. */
653
654 static void
655 lynx_store_registers (struct regcache *regcache, int regno)
656 {
657 struct lynx_regset_info *regset = lynx_target_regsets;
658 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
659
660 lynx_debug ("lynx_store_registers (regno = %d)", regno);
661
662 while (regset->size >= 0)
663 {
664 char *buf;
665 int res;
666
667 buf = xmalloc (regset->size);
668 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
669 if (res == 0)
670 {
671 /* Then overlay our cached registers on that. */
672 regset->fill_function (regcache, buf);
673 /* Only now do we write the register set. */
674 res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf,
675 0, 0);
676 }
677 if (res < 0)
678 perror ("ptrace");
679 free (buf);
680 regset++;
681 }
682 }
683
684 /* Implement the read_memory target_ops method. */
685
686 static int
687 lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
688 {
689 /* On LynxOS, memory reads needs to be performed in chunks the size
690 of int types, and they should also be aligned accordingly. */
691 int buf;
692 const int xfer_size = sizeof (buf);
693 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
694 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
695
696 while (addr < memaddr + len)
697 {
698 int skip = 0;
699 int truncate = 0;
700
701 errno = 0;
702 if (addr < memaddr)
703 skip = memaddr - addr;
704 if (addr + xfer_size > memaddr + len)
705 truncate = addr + xfer_size - memaddr - len;
706 buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0);
707 if (errno)
708 return errno;
709 memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip,
710 xfer_size - skip - truncate);
711 addr += xfer_size;
712 }
713
714 return 0;
715 }
716
717 /* Implement the write_memory target_ops method. */
718
719 static int
720 lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
721 {
722 /* On LynxOS, memory writes needs to be performed in chunks the size
723 of int types, and they should also be aligned accordingly. */
724 int buf;
725 const int xfer_size = sizeof (buf);
726 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
727 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
728
729 while (addr < memaddr + len)
730 {
731 int skip = 0;
732 int truncate = 0;
733
734 if (addr < memaddr)
735 skip = memaddr - addr;
736 if (addr + xfer_size > memaddr + len)
737 truncate = addr + xfer_size - memaddr - len;
738 if (skip > 0 || truncate > 0)
739 /* We need to read the memory at this address in order to preserve
740 the data that we are not overwriting. */
741 lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
742 if (errno)
743 return errno;
744 memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
745 xfer_size - skip - truncate);
746 errno = 0;
747 lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0);
748 if (errno)
749 return errno;
750 addr += xfer_size;
751 }
752
753 return 0;
754 }
755
756 /* Implement the kill_request target_ops method. */
757
758 static void
759 lynx_request_interrupt (void)
760 {
761 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
762
763 kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
764 }
765
766 /* The LynxOS target_ops vector. */
767
768 static struct target_ops lynx_target_ops = {
769 lynx_create_inferior,
770 lynx_attach,
771 lynx_kill,
772 lynx_detach,
773 lynx_mourn,
774 lynx_join,
775 lynx_thread_alive,
776 lynx_resume,
777 lynx_wait,
778 lynx_fetch_registers,
779 lynx_store_registers,
780 NULL, /* prepare_to_access_memory */
781 NULL, /* done_accessing_memory */
782 lynx_read_memory,
783 lynx_write_memory,
784 NULL, /* look_up_symbols */
785 lynx_request_interrupt,
786 NULL, /* read_auxv */
787 NULL, /* insert_point */
788 NULL, /* remove_point */
789 NULL, /* stopped_by_watchpoint */
790 NULL, /* stopped_data_address */
791 NULL, /* read_offsets */
792 NULL, /* get_tls_address */
793 NULL, /* qxfer_spu */
794 NULL, /* hostio_last_error */
795 NULL, /* qxfer_osdata */
796 NULL, /* qxfer_siginfo */
797 NULL, /* supports_non_stop */
798 NULL, /* async */
799 NULL, /* start_non_stop */
800 NULL, /* supports_multi_process */
801 NULL, /* handle_monitor_command */
802 };
803
804 void
805 initialize_low (void)
806 {
807 set_target_ops (&lynx_target_ops);
808 the_low_target.arch_setup ();
809 }
810
This page took 0.054752 seconds and 5 git commands to generate.