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