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