Update years in copyright notice for the GDB files.
[deliverable/binutils-gdb.git] / gdb / gdbserver / lynx-low.c
1 /* Copyright (C) 2009-2013 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 "gdb_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 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;
258 case PTRACE_GETTRACESIG:
259 return "PTRACE_GETTRACESIG";
260 break;
261 #ifdef PTRACE_GETTHREADLIST
262 case PTRACE_GETTHREADLIST:
263 return "PTRACE_GETTHREADLIST";
264 break;
265 #endif
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
273 static int
274 lynx_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
296 static int
297 lynx_create_inferior (char *program, char **allargs)
298 {
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
323 add_process (pid, 0);
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
332 static int
333 lynx_attach (unsigned long pid)
334 {
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
341 add_process (pid, 1);
342 add_thread (ptid, NULL);
343
344 return 0;
345 }
346
347 /* Implement the resume target_ops method. */
348
349 static void
350 lynx_resume (struct thread_resume *resume_info, size_t n)
351 {
352 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
353 /* FIXME: Assume for now that n == 1. */
354 const int request = (resume_info[0].kind == resume_step
355 ? PTRACE_SINGLESTEP : PTRACE_CONT);
356 const int signal = resume_info[0].sig;
357 int ret;
358
359 regcache_invalidate ();
360 ret = lynx_ptrace (request, inferior_ptid, 1, signal, 0);
361 }
362
363 /* Resume the execution of the given PTID. */
364
365 static void
366 lynx_continue (ptid_t ptid)
367 {
368 struct thread_resume resume_info;
369
370 resume_info.thread = ptid;
371 resume_info.kind = resume_continue;
372 resume_info.sig = 0;
373
374 lynx_resume (&resume_info, 1);
375 }
376
377 /* Remove all inferiors and associated threads. */
378
379 static void
380 lynx_clear_inferiors (void)
381 {
382 /* We do not use private data, so nothing much to do except calling
383 clear_inferiors. */
384 clear_inferiors ();
385 }
386
387 /* A wrapper around waitpid that handles the various idiosyncrasies
388 of LynxOS' waitpid. */
389
390 static int
391 lynx_waitpid (int pid, int *stat_loc)
392 {
393 int ret = 0;
394
395 while (1)
396 {
397 ret = waitpid (pid, stat_loc, WNOHANG);
398 if (ret < 0)
399 {
400 /* An ECHILD error is not indicative of a real problem.
401 It happens for instance while waiting for the inferior
402 to stop after attaching to it. */
403 if (errno != ECHILD)
404 perror_with_name ("waitpid (WNOHANG)");
405 }
406 if (ret > 0)
407 break;
408 /* No event with WNOHANG. See if there is one with WUNTRACED. */
409 ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED);
410 if (ret < 0)
411 {
412 /* An ECHILD error is not indicative of a real problem.
413 It happens for instance while waiting for the inferior
414 to stop after attaching to it. */
415 if (errno != ECHILD)
416 perror_with_name ("waitpid (WNOHANG|WUNTRACED)");
417 }
418 if (ret > 0)
419 break;
420 usleep (1000);
421 }
422 return ret;
423 }
424
425 /* Implement the wait target_ops method. */
426
427 static ptid_t
428 lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options)
429 {
430 int pid;
431 int ret;
432 int wstat;
433 ptid_t new_ptid;
434
435 if (ptid_equal (ptid, minus_one_ptid))
436 pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior));
437 else
438 pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
439
440 retry:
441
442 ret = lynx_waitpid (pid, &wstat);
443 new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
444
445 /* If this is a new thread, then add it now. The reason why we do
446 this here instead of when handling new-thread events is because
447 we need to add the thread associated to the "main" thread - even
448 for non-threaded applications where the new-thread events are not
449 generated. */
450 if (!find_thread_ptid (new_ptid))
451 {
452 lynx_debug ("New thread: (pid = %d, tid = %d)",
453 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid));
454 add_thread (new_ptid, NULL);
455 }
456
457 if (WIFSTOPPED (wstat))
458 {
459 status->kind = TARGET_WAITKIND_STOPPED;
460 status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat));
461 lynx_debug ("process stopped with signal: %d",
462 status->value.integer);
463 }
464 else if (WIFEXITED (wstat))
465 {
466 status->kind = TARGET_WAITKIND_EXITED;
467 status->value.integer = WEXITSTATUS (wstat);
468 lynx_debug ("process exited with code: %d", status->value.integer);
469 }
470 else if (WIFSIGNALED (wstat))
471 {
472 status->kind = TARGET_WAITKIND_SIGNALLED;
473 status->value.integer = gdb_signal_from_host (WTERMSIG (wstat));
474 lynx_debug ("process terminated with code: %d",
475 status->value.integer);
476 }
477 else
478 {
479 /* Not sure what happened if we get here, or whether we can
480 in fact get here. But if we do, handle the event the best
481 we can. */
482 status->kind = TARGET_WAITKIND_STOPPED;
483 status->value.integer = gdb_signal_from_host (0);
484 lynx_debug ("unknown event ????");
485 }
486
487 /* SIGTRAP events are generated for situations other than single-step/
488 breakpoint events (Eg. new-thread events). Handle those other types
489 of events, and resume the execution if necessary. */
490 if (status->kind == TARGET_WAITKIND_STOPPED
491 && status->value.integer == GDB_SIGNAL_TRAP)
492 {
493 const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0);
494
495 lynx_debug ("(realsig = %d)", realsig);
496 switch (realsig)
497 {
498 case SIGNEWTHREAD:
499 /* We just added the new thread above. No need to do anything
500 further. Just resume the execution again. */
501 lynx_continue (ptid);
502 goto retry;
503
504 case SIGTHREADEXIT:
505 remove_thread (find_thread_ptid (new_ptid));
506 lynx_continue (ptid);
507 goto retry;
508 }
509 }
510
511 return new_ptid;
512 }
513
514 /* A wrapper around lynx_wait_1 that also prints debug traces when
515 such debug traces have been activated. */
516
517 static ptid_t
518 lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options)
519 {
520 ptid_t new_ptid;
521
522 lynx_debug ("lynx_wait (pid = %d, tid = %ld)",
523 lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
524 new_ptid = lynx_wait_1 (ptid, status, options);
525 lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)",
526 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid),
527 status->kind);
528 return new_ptid;
529 }
530
531 /* Implement the kill target_ops method. */
532
533 static int
534 lynx_kill (int pid)
535 {
536 ptid_t ptid = lynx_ptid_build (pid, 0);
537 struct target_waitstatus status;
538 struct process_info *process;
539
540 process = find_process_pid (pid);
541 if (process == NULL)
542 return -1;
543
544 lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0);
545 lynx_wait (ptid, &status, 0);
546 the_target->mourn (process);
547 return 0;
548 }
549
550 /* Implement the detach target_ops method. */
551
552 static int
553 lynx_detach (int pid)
554 {
555 ptid_t ptid = lynx_ptid_build (pid, 0);
556 struct process_info *process;
557
558 process = find_process_pid (pid);
559 if (process == NULL)
560 return -1;
561
562 lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0);
563 the_target->mourn (process);
564 return 0;
565 }
566
567 /* Implement the mourn target_ops method. */
568
569 static void
570 lynx_mourn (struct process_info *proc)
571 {
572 lynx_clear_inferiors ();
573 }
574
575 /* Implement the join target_ops method. */
576
577 static void
578 lynx_join (int pid)
579 {
580 /* The PTRACE_DETACH is sufficient to detach from the process.
581 So no need to do anything extra. */
582 }
583
584 /* Implement the thread_alive target_ops method. */
585
586 static int
587 lynx_thread_alive (ptid_t ptid)
588 {
589 /* The list of threads is updated at the end of each wait, so it
590 should be up to date. No need to re-fetch it. */
591 return (find_thread_ptid (ptid) != NULL);
592 }
593
594 /* Implement the fetch_registers target_ops method. */
595
596 static void
597 lynx_fetch_registers (struct regcache *regcache, int regno)
598 {
599 struct lynx_regset_info *regset = lynx_target_regsets;
600 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
601
602 lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
603
604 while (regset->size >= 0)
605 {
606 char *buf;
607 int res;
608
609 buf = xmalloc (regset->size);
610 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
611 if (res < 0)
612 perror ("ptrace");
613 regset->store_function (regcache, buf);
614 free (buf);
615 regset++;
616 }
617 }
618
619 /* Implement the store_registers target_ops method. */
620
621 static void
622 lynx_store_registers (struct regcache *regcache, int regno)
623 {
624 struct lynx_regset_info *regset = lynx_target_regsets;
625 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
626
627 lynx_debug ("lynx_store_registers (regno = %d)", regno);
628
629 while (regset->size >= 0)
630 {
631 char *buf;
632 int res;
633
634 buf = xmalloc (regset->size);
635 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
636 if (res == 0)
637 {
638 /* Then overlay our cached registers on that. */
639 regset->fill_function (regcache, buf);
640 /* Only now do we write the register set. */
641 res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf,
642 0, 0);
643 }
644 if (res < 0)
645 perror ("ptrace");
646 free (buf);
647 regset++;
648 }
649 }
650
651 /* Implement the read_memory target_ops method. */
652
653 static int
654 lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
655 {
656 /* On LynxOS, memory reads needs to be performed in chunks the size
657 of int types, and they should also be aligned accordingly. */
658 int buf;
659 const int xfer_size = sizeof (buf);
660 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
661 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
662
663 while (addr < memaddr + len)
664 {
665 int skip = 0;
666 int truncate = 0;
667
668 errno = 0;
669 if (addr < memaddr)
670 skip = memaddr - addr;
671 if (addr + xfer_size > memaddr + len)
672 truncate = addr + xfer_size - memaddr - len;
673 buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0);
674 if (errno)
675 return errno;
676 memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip,
677 xfer_size - skip - truncate);
678 addr += xfer_size;
679 }
680
681 return 0;
682 }
683
684 /* Implement the write_memory target_ops method. */
685
686 static int
687 lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
688 {
689 /* On LynxOS, memory writes 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 if (addr < memaddr)
702 skip = memaddr - addr;
703 if (addr + xfer_size > memaddr + len)
704 truncate = addr + xfer_size - memaddr - len;
705 if (skip > 0 || truncate > 0)
706 /* We need to read the memory at this address in order to preserve
707 the data that we are not overwriting. */
708 lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
709 if (errno)
710 return errno;
711 memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
712 xfer_size - skip - truncate);
713 errno = 0;
714 lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0);
715 if (errno)
716 return errno;
717 addr += xfer_size;
718 }
719
720 return 0;
721 }
722
723 /* Implement the kill_request target_ops method. */
724
725 static void
726 lynx_request_interrupt (void)
727 {
728 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
729
730 kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
731 }
732
733 /* The LynxOS target_ops vector. */
734
735 static struct target_ops lynx_target_ops = {
736 lynx_create_inferior,
737 lynx_attach,
738 lynx_kill,
739 lynx_detach,
740 lynx_mourn,
741 lynx_join,
742 lynx_thread_alive,
743 lynx_resume,
744 lynx_wait,
745 lynx_fetch_registers,
746 lynx_store_registers,
747 NULL, /* prepare_to_access_memory */
748 NULL, /* done_accessing_memory */
749 lynx_read_memory,
750 lynx_write_memory,
751 NULL, /* look_up_symbols */
752 lynx_request_interrupt,
753 NULL, /* read_auxv */
754 NULL, /* insert_point */
755 NULL, /* remove_point */
756 NULL, /* stopped_by_watchpoint */
757 NULL, /* stopped_data_address */
758 NULL, /* read_offsets */
759 NULL, /* get_tls_address */
760 NULL, /* qxfer_spu */
761 NULL, /* hostio_last_error */
762 NULL, /* qxfer_osdata */
763 NULL, /* qxfer_siginfo */
764 NULL, /* supports_non_stop */
765 NULL, /* async */
766 NULL, /* start_non_stop */
767 NULL, /* supports_multi_process */
768 NULL, /* handle_monitor_command */
769 };
770
771 void
772 initialize_low (void)
773 {
774 set_target_ops (&lynx_target_ops);
775 the_low_target.arch_setup ();
776 }
777
This page took 0.065621 seconds and 5 git commands to generate.