Add ptrace error handling in lynx_resume
[deliverable/binutils-gdb.git] / gdb / gdbserver / lynx-low.c
CommitLineData
28e7fd62 1/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
8ed54b31
JB
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>
1adfc54d 23#include <sys/ptrace.h>
8ed54b31
JB
24#include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc. */
25#include <unistd.h>
26#include <sys/ioctl.h>
27#include <sys/types.h>
8bdce1ff 28#include "gdb_wait.h"
8ed54b31
JB
29#include <signal.h>
30
31int using_threads = 1;
32
33/* Print a debug trace on standard output if debug_threads is set. */
34
35static void
36lynx_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
52static ptid_t
53lynx_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
69static int
70lynx_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
77static long
78lynx_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
88static int
89lynx_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
96static char *
97ptrace_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
8ed54b31
JB
211#ifdef PT_READ_VPR
212 case PT_READ_VPR:
213 return "PT_READ_VPR";
214 break;
215#endif
216#ifdef PT_WRITE_VPR
217 case PT_WRITE_VPR:
218 return "PT_WRITE_VPR";
219 break;
220#endif
221#ifdef PTRACE_PEEKUSP
222 case PTRACE_PEEKUSP:
223 return "PTRACE_PEEKUSP";
224 break;
225#endif
226#ifdef PTRACE_POKEUSP
227 case PTRACE_POKEUSP:
228 return "PTRACE_POKEUSP";
229 break;
230#endif
231 case PTRACE_PEEKTHREAD:
232 return "PTRACE_PEEKTHREAD";
233 break;
234 case PTRACE_THREADUSER:
235 return "PTRACE_THREADUSER";
236 break;
237 case PTRACE_FPREAD:
238 return "PTRACE_FPREAD";
239 break;
240 case PTRACE_FPWRITE:
241 return "PTRACE_FPWRITE";
242 break;
243 case PTRACE_SETSIG:
244 return "PTRACE_SETSIG";
245 break;
246 case PTRACE_CONT_ONE:
247 return "PTRACE_CONT_ONE";
248 break;
249 case PTRACE_KILL_ONE:
250 return "PTRACE_KILL_ONE";
251 break;
252 case PTRACE_SINGLESTEP_ONE:
253 return "PTRACE_SINGLESTEP_ONE";
254 break;
255 case PTRACE_GETLOADINFO:
256 return "PTRACE_GETLOADINFO";
257 break;
037335a7
JB
258 case PTRACE_GETTRACESIG:
259 return "PTRACE_GETTRACESIG";
260 break;
78cbc024 261#ifdef PTRACE_GETTHREADLIST
8ed54b31
JB
262 case PTRACE_GETTHREADLIST:
263 return "PTRACE_GETTHREADLIST";
264 break;
78cbc024 265#endif
8ed54b31
JB
266 }
267 return "<unknown-request>";
268}
269
270/* A wrapper around ptrace that allows us to print debug traces of
271 ptrace calls if debug traces are activated. */
272
273static int
274lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
275{
276 int result;
277 const int pid = lynx_ptrace_pid_from_ptid (ptid);
278 int saved_errno;
279
280 if (debug_threads)
281 fprintf (stderr, "PTRACE (%s, pid=%d(pid=%d, tid=%d), addr=0x%x, "
282 "data=0x%x, addr2=0x%x)",
283 ptrace_request_to_str (request), pid, PIDGET (pid), TIDGET (pid),
284 addr, data, addr2);
285 result = ptrace (request, pid, addr, data, addr2);
286 saved_errno = errno;
287 if (debug_threads)
288 fprintf (stderr, " -> %d (=0x%x)\n", result, result);
289
290 errno = saved_errno;
291 return result;
292}
293
294/* Implement the create_inferior method of the target_ops vector. */
295
296static int
297lynx_create_inferior (char *program, char **allargs)
298{
8ed54b31
JB
299 int pid;
300
301 lynx_debug ("lynx_create_inferior ()");
302
303 pid = fork ();
304 if (pid < 0)
305 perror_with_name ("fork");
306
307 if (pid == 0)
308 {
309 int pgrp;
310
311 /* Switch child to its own process group so that signals won't
312 directly affect gdbserver. */
313 pgrp = getpid();
314 setpgid (0, pgrp);
315 ioctl (0, TIOCSPGRP, &pgrp);
316 lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0);
317 execv (program, allargs);
318 fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
319 fflush (stderr);
320 _exit (0177);
321 }
322
ab8f6ca9 323 add_process (pid, 0);
8ed54b31
JB
324 /* Do not add the process thread just yet, as we do not know its tid.
325 We will add it later, during the wait for the STOP event corresponding
326 to the lynx_ptrace (PTRACE_TRACEME) call above. */
327 return pid;
328}
329
330/* Implement the attach target_ops method. */
331
332static int
333lynx_attach (unsigned long pid)
334{
8ed54b31
JB
335 ptid_t ptid = lynx_ptid_build (pid, 0);
336
337 if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0)
338 error ("Cannot attach to process %lu: %s (%d)\n", pid,
339 strerror (errno), errno);
340
52d4cbd8 341 add_process (pid, 1);
8ed54b31
JB
342 add_thread (ptid, NULL);
343
344 return 0;
345}
346
347/* Implement the resume target_ops method. */
348
349static void
350lynx_resume (struct thread_resume *resume_info, size_t n)
351{
8ed54b31 352 /* FIXME: Assume for now that n == 1. */
3f6e77ef 353 ptid_t ptid = resume_info[0].thread;
8ed54b31
JB
354 const int request = (resume_info[0].kind == resume_step
355 ? PTRACE_SINGLESTEP : PTRACE_CONT);
356 const int signal = resume_info[0].sig;
8ed54b31 357
3f6e77ef
JB
358 if (ptid_equal (ptid, minus_one_ptid))
359 ptid = thread_to_gdb_id (current_inferior);
360
8ed54b31 361 regcache_invalidate ();
9044dee2
JB
362
363 errno = 0;
3f6e77ef 364 lynx_ptrace (request, ptid, 1, signal, 0);
9044dee2
JB
365 if (errno)
366 perror_with_name ("ptrace");
8ed54b31
JB
367}
368
369/* Resume the execution of the given PTID. */
370
371static void
372lynx_continue (ptid_t ptid)
373{
374 struct thread_resume resume_info;
375
376 resume_info.thread = ptid;
377 resume_info.kind = resume_continue;
378 resume_info.sig = 0;
379
380 lynx_resume (&resume_info, 1);
381}
382
383/* Remove all inferiors and associated threads. */
384
385static void
386lynx_clear_inferiors (void)
387{
388 /* We do not use private data, so nothing much to do except calling
389 clear_inferiors. */
390 clear_inferiors ();
391}
392
393/* A wrapper around waitpid that handles the various idiosyncrasies
394 of LynxOS' waitpid. */
395
396static int
397lynx_waitpid (int pid, int *stat_loc)
398{
399 int ret = 0;
400
401 while (1)
402 {
403 ret = waitpid (pid, stat_loc, WNOHANG);
404 if (ret < 0)
405 {
406 /* An ECHILD error is not indicative of a real problem.
407 It happens for instance while waiting for the inferior
408 to stop after attaching to it. */
409 if (errno != ECHILD)
410 perror_with_name ("waitpid (WNOHANG)");
411 }
412 if (ret > 0)
413 break;
414 /* No event with WNOHANG. See if there is one with WUNTRACED. */
415 ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED);
416 if (ret < 0)
417 {
418 /* An ECHILD error is not indicative of a real problem.
419 It happens for instance while waiting for the inferior
420 to stop after attaching to it. */
421 if (errno != ECHILD)
422 perror_with_name ("waitpid (WNOHANG|WUNTRACED)");
423 }
424 if (ret > 0)
425 break;
426 usleep (1000);
427 }
428 return ret;
429}
430
431/* Implement the wait target_ops method. */
432
433static ptid_t
434lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options)
435{
436 int pid;
437 int ret;
438 int wstat;
439 ptid_t new_ptid;
440
441 if (ptid_equal (ptid, minus_one_ptid))
442 pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior));
443 else
444 pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
445
446retry:
447
448 ret = lynx_waitpid (pid, &wstat);
449 new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
450
451 /* If this is a new thread, then add it now. The reason why we do
452 this here instead of when handling new-thread events is because
453 we need to add the thread associated to the "main" thread - even
454 for non-threaded applications where the new-thread events are not
455 generated. */
456 if (!find_thread_ptid (new_ptid))
8b93d60f
JB
457 {
458 lynx_debug ("New thread: (pid = %d, tid = %d)",
459 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid));
460 add_thread (new_ptid, NULL);
461 }
8ed54b31
JB
462
463 if (WIFSTOPPED (wstat))
464 {
465 status->kind = TARGET_WAITKIND_STOPPED;
2ea28649 466 status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat));
8ed54b31
JB
467 lynx_debug ("process stopped with signal: %d",
468 status->value.integer);
469 }
470 else if (WIFEXITED (wstat))
471 {
472 status->kind = TARGET_WAITKIND_EXITED;
473 status->value.integer = WEXITSTATUS (wstat);
474 lynx_debug ("process exited with code: %d", status->value.integer);
475 }
476 else if (WIFSIGNALED (wstat))
477 {
478 status->kind = TARGET_WAITKIND_SIGNALLED;
2ea28649 479 status->value.integer = gdb_signal_from_host (WTERMSIG (wstat));
8ed54b31
JB
480 lynx_debug ("process terminated with code: %d",
481 status->value.integer);
482 }
483 else
484 {
485 /* Not sure what happened if we get here, or whether we can
486 in fact get here. But if we do, handle the event the best
487 we can. */
488 status->kind = TARGET_WAITKIND_STOPPED;
2ea28649 489 status->value.integer = gdb_signal_from_host (0);
8ed54b31
JB
490 lynx_debug ("unknown event ????");
491 }
492
493 /* SIGTRAP events are generated for situations other than single-step/
494 breakpoint events (Eg. new-thread events). Handle those other types
495 of events, and resume the execution if necessary. */
496 if (status->kind == TARGET_WAITKIND_STOPPED
a493e3e2 497 && status->value.integer == GDB_SIGNAL_TRAP)
8ed54b31
JB
498 {
499 const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0);
500
501 lynx_debug ("(realsig = %d)", realsig);
502 switch (realsig)
503 {
504 case SIGNEWTHREAD:
505 /* We just added the new thread above. No need to do anything
506 further. Just resume the execution again. */
3f6e77ef 507 lynx_continue (new_ptid);
8ed54b31
JB
508 goto retry;
509
510 case SIGTHREADEXIT:
511 remove_thread (find_thread_ptid (new_ptid));
3f6e77ef 512 lynx_continue (new_ptid);
8ed54b31
JB
513 goto retry;
514 }
515 }
516
517 return new_ptid;
518}
519
520/* A wrapper around lynx_wait_1 that also prints debug traces when
521 such debug traces have been activated. */
522
523static ptid_t
524lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options)
525{
526 ptid_t new_ptid;
527
528 lynx_debug ("lynx_wait (pid = %d, tid = %ld)",
529 lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
530 new_ptid = lynx_wait_1 (ptid, status, options);
531 lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)",
532 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid),
533 status->kind);
534 return new_ptid;
535}
536
537/* Implement the kill target_ops method. */
538
539static int
540lynx_kill (int pid)
541{
542 ptid_t ptid = lynx_ptid_build (pid, 0);
543 struct target_waitstatus status;
544 struct process_info *process;
545
546 process = find_process_pid (pid);
547 if (process == NULL)
548 return -1;
549
550 lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0);
551 lynx_wait (ptid, &status, 0);
552 the_target->mourn (process);
553 return 0;
554}
555
556/* Implement the detach target_ops method. */
557
558static int
559lynx_detach (int pid)
560{
561 ptid_t ptid = lynx_ptid_build (pid, 0);
562 struct process_info *process;
563
564 process = find_process_pid (pid);
565 if (process == NULL)
566 return -1;
567
568 lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0);
569 the_target->mourn (process);
570 return 0;
571}
572
573/* Implement the mourn target_ops method. */
574
575static void
576lynx_mourn (struct process_info *proc)
577{
578 lynx_clear_inferiors ();
579}
580
581/* Implement the join target_ops method. */
582
583static void
584lynx_join (int pid)
585{
586 /* The PTRACE_DETACH is sufficient to detach from the process.
587 So no need to do anything extra. */
588}
589
590/* Implement the thread_alive target_ops method. */
591
592static int
593lynx_thread_alive (ptid_t ptid)
594{
595 /* The list of threads is updated at the end of each wait, so it
596 should be up to date. No need to re-fetch it. */
597 return (find_thread_ptid (ptid) != NULL);
598}
599
600/* Implement the fetch_registers target_ops method. */
601
602static void
603lynx_fetch_registers (struct regcache *regcache, int regno)
604{
605 struct lynx_regset_info *regset = lynx_target_regsets;
606 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
607
608 lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
609
610 while (regset->size >= 0)
611 {
612 char *buf;
613 int res;
614
615 buf = xmalloc (regset->size);
616 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
617 if (res < 0)
618 perror ("ptrace");
619 regset->store_function (regcache, buf);
620 free (buf);
621 regset++;
622 }
623}
624
625/* Implement the store_registers target_ops method. */
626
627static void
628lynx_store_registers (struct regcache *regcache, int regno)
629{
630 struct lynx_regset_info *regset = lynx_target_regsets;
631 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
632
633 lynx_debug ("lynx_store_registers (regno = %d)", regno);
634
635 while (regset->size >= 0)
636 {
637 char *buf;
638 int res;
639
640 buf = xmalloc (regset->size);
641 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
642 if (res == 0)
643 {
644 /* Then overlay our cached registers on that. */
645 regset->fill_function (regcache, buf);
646 /* Only now do we write the register set. */
647 res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf,
648 0, 0);
649 }
650 if (res < 0)
651 perror ("ptrace");
652 free (buf);
653 regset++;
654 }
655}
656
657/* Implement the read_memory target_ops method. */
658
659static int
660lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
661{
662 /* On LynxOS, memory reads needs to be performed in chunks the size
663 of int types, and they should also be aligned accordingly. */
664 int buf;
665 const int xfer_size = sizeof (buf);
666 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
667 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
668
669 while (addr < memaddr + len)
670 {
671 int skip = 0;
672 int truncate = 0;
673
674 errno = 0;
675 if (addr < memaddr)
676 skip = memaddr - addr;
677 if (addr + xfer_size > memaddr + len)
678 truncate = addr + xfer_size - memaddr - len;
679 buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0);
680 if (errno)
681 return errno;
682 memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip,
683 xfer_size - skip - truncate);
684 addr += xfer_size;
685 }
686
687 return 0;
688}
689
690/* Implement the write_memory target_ops method. */
691
692static int
693lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
694{
695 /* On LynxOS, memory writes needs to be performed in chunks the size
696 of int types, and they should also be aligned accordingly. */
697 int buf;
698 const int xfer_size = sizeof (buf);
699 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
700 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
701
702 while (addr < memaddr + len)
703 {
704 int skip = 0;
705 int truncate = 0;
706
707 if (addr < memaddr)
708 skip = memaddr - addr;
709 if (addr + xfer_size > memaddr + len)
710 truncate = addr + xfer_size - memaddr - len;
711 if (skip > 0 || truncate > 0)
712 /* We need to read the memory at this address in order to preserve
713 the data that we are not overwriting. */
714 lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
715 if (errno)
716 return errno;
717 memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
718 xfer_size - skip - truncate);
719 errno = 0;
720 lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0);
721 if (errno)
722 return errno;
723 addr += xfer_size;
724 }
725
726 return 0;
727}
728
729/* Implement the kill_request target_ops method. */
730
731static void
732lynx_request_interrupt (void)
733{
734 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
735
736 kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
737}
738
739/* The LynxOS target_ops vector. */
740
741static struct target_ops lynx_target_ops = {
742 lynx_create_inferior,
743 lynx_attach,
744 lynx_kill,
745 lynx_detach,
746 lynx_mourn,
747 lynx_join,
748 lynx_thread_alive,
749 lynx_resume,
750 lynx_wait,
751 lynx_fetch_registers,
752 lynx_store_registers,
753 NULL, /* prepare_to_access_memory */
754 NULL, /* done_accessing_memory */
755 lynx_read_memory,
756 lynx_write_memory,
757 NULL, /* look_up_symbols */
758 lynx_request_interrupt,
759 NULL, /* read_auxv */
760 NULL, /* insert_point */
761 NULL, /* remove_point */
762 NULL, /* stopped_by_watchpoint */
763 NULL, /* stopped_data_address */
764 NULL, /* read_offsets */
765 NULL, /* get_tls_address */
766 NULL, /* qxfer_spu */
767 NULL, /* hostio_last_error */
768 NULL, /* qxfer_osdata */
769 NULL, /* qxfer_siginfo */
770 NULL, /* supports_non_stop */
771 NULL, /* async */
772 NULL, /* start_non_stop */
773 NULL, /* supports_multi_process */
774 NULL, /* handle_monitor_command */
775};
776
777void
778initialize_low (void)
779{
780 set_target_ops (&lynx_target_ops);
781 the_low_target.arch_setup ();
782}
783
This page took 0.243316 seconds and 4 git commands to generate.