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