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