[lynxos] gdbserver hangs when killing inferior from GDB
[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 = XCNEW (struct process_info_private);
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_pid (ptid_get_pid (ptid));
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 /* A callback for find_inferior which removes from the thread list
550    all threads belonging to process PROC.  */
551
552 static int
553 lynx_delete_thread_callback (struct inferior_list_entry *entry, void *proc)
554 {
555   struct process_info *process = (struct process_info *) proc;
556
557   if (ptid_get_pid (entry->id) == pid_of (process))
558     {
559       struct thread_info *thr = find_thread_ptid (entry->id);
560
561       remove_thread (thr);
562     }
563
564   return 0;
565 }
566
567 /* Implement the mourn target_ops method.  */
568
569 static void
570 lynx_mourn (struct process_info *proc)
571 {
572   find_inferior (&all_threads, lynx_delete_thread_callback, proc);
573
574   /* Free our private data.  */
575   free (proc->priv);
576   proc->priv = NULL;
577
578   remove_process (proc);
579 }
580
581 /* Implement the join target_ops method.  */
582
583 static void
584 lynx_join (int pid)
585 {
586   /* The PTRACE_DETACH is sufficient to detach from the process.
587      So no need to do anything extra.  */
588 }
589
590 /* Implement the thread_alive target_ops method.  */
591
592 static int
593 lynx_thread_alive (ptid_t ptid)
594 {
595   /* The list of threads is updated at the end of each wait, so it
596      should be up to date.  No need to re-fetch it.  */
597   return (find_thread_ptid (ptid) != NULL);
598 }
599
600 /* Implement the fetch_registers target_ops method.  */
601
602 static void
603 lynx_fetch_registers (struct regcache *regcache, int regno)
604 {
605   struct lynx_regset_info *regset = lynx_target_regsets;
606   ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
607
608   lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
609
610   while (regset->size >= 0)
611     {
612       char *buf;
613       int res;
614
615       buf = xmalloc (regset->size);
616       res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
617       if (res < 0)
618         perror ("ptrace");
619       regset->store_function (regcache, buf);
620       free (buf);
621       regset++;
622     }
623 }
624
625 /* Implement the store_registers target_ops method.  */
626
627 static void
628 lynx_store_registers (struct regcache *regcache, int regno)
629 {
630   struct lynx_regset_info *regset = lynx_target_regsets;
631   ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
632
633   lynx_debug ("lynx_store_registers (regno = %d)", regno);
634
635   while (regset->size >= 0)
636     {
637       char *buf;
638       int res;
639
640       buf = xmalloc (regset->size);
641       res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0);
642       if (res == 0)
643         {
644           /* Then overlay our cached registers on that.  */
645           regset->fill_function (regcache, buf);
646           /* Only now do we write the register set.  */
647           res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf,
648                              0, 0);
649         }
650       if (res < 0)
651         perror ("ptrace");
652       free (buf);
653       regset++;
654     }
655 }
656
657 /* Implement the read_memory target_ops method.  */
658
659 static int
660 lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
661 {
662   /* On LynxOS, memory reads needs to be performed in chunks the size
663      of int types, and they should also be aligned accordingly.  */
664   int buf;
665   const int xfer_size = sizeof (buf);
666   CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
667   ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
668
669   while (addr < memaddr + len)
670     {
671       int skip = 0;
672       int truncate = 0;
673
674       errno = 0;
675       if (addr < memaddr)
676         skip = memaddr - addr;
677       if (addr + xfer_size > memaddr + len)
678         truncate = addr + xfer_size - memaddr - len;
679       buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0);
680       if (errno)
681         return errno;
682       memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip,
683               xfer_size - skip - truncate);
684       addr += xfer_size;
685     }
686
687   return 0;
688 }
689
690 /* Implement the write_memory target_ops method.  */
691
692 static int
693 lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
694 {
695   /* On LynxOS, memory writes needs to be performed in chunks the size
696      of int types, and they should also be aligned accordingly.  */
697   int buf;
698   const int xfer_size = sizeof (buf);
699   CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
700   ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
701
702   while (addr < memaddr + len)
703     {
704       int skip = 0;
705       int truncate = 0;
706
707       if (addr < memaddr)
708         skip = memaddr - addr;
709       if (addr + xfer_size > memaddr + len)
710         truncate = addr + xfer_size - memaddr - len;
711       if (skip > 0 || truncate > 0)
712         {
713           /* We need to read the memory at this address in order to preserve
714              the data that we are not overwriting.  */
715           lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
716           if (errno)
717             return errno;
718         }
719       memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
720               xfer_size - skip - truncate);
721       errno = 0;
722       lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0);
723       if (errno)
724         return errno;
725       addr += xfer_size;
726     }
727
728   return 0;
729 }
730
731 /* Implement the kill_request target_ops method.  */
732
733 static void
734 lynx_request_interrupt (void)
735 {
736   ptid_t inferior_ptid = thread_to_gdb_id (get_first_thread ());
737
738   kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
739 }
740
741 /* The LynxOS target_ops vector.  */
742
743 static struct target_ops lynx_target_ops = {
744   lynx_create_inferior,
745   NULL,  /* post_create_inferior */
746   lynx_attach,
747   lynx_kill,
748   lynx_detach,
749   lynx_mourn,
750   lynx_join,
751   lynx_thread_alive,
752   lynx_resume,
753   lynx_wait,
754   lynx_fetch_registers,
755   lynx_store_registers,
756   NULL,  /* prepare_to_access_memory */
757   NULL,  /* done_accessing_memory */
758   lynx_read_memory,
759   lynx_write_memory,
760   NULL,  /* look_up_symbols */
761   lynx_request_interrupt,
762   NULL,  /* read_auxv */
763   NULL,  /* supports_z_point_type */
764   NULL,  /* insert_point */
765   NULL,  /* remove_point */
766   NULL,  /* stopped_by_sw_breakpoint */
767   NULL,  /* supports_stopped_by_sw_breakpoint */
768   NULL,  /* stopped_by_hw_breakpoint */
769   NULL,  /* supports_stopped_by_hw_breakpoint */
770   target_can_do_hardware_single_step,
771   NULL,  /* stopped_by_watchpoint */
772   NULL,  /* stopped_data_address */
773   NULL,  /* read_offsets */
774   NULL,  /* get_tls_address */
775   NULL,  /* qxfer_spu */
776   NULL,  /* hostio_last_error */
777   NULL,  /* qxfer_osdata */
778   NULL,  /* qxfer_siginfo */
779   NULL,  /* supports_non_stop */
780   NULL,  /* async */
781   NULL,  /* start_non_stop */
782   NULL,  /* supports_multi_process */
783   NULL,  /* supports_fork_events */
784   NULL,  /* supports_vfork_events */
785   NULL,  /* supports_exec_events */
786   NULL,  /* handle_new_gdb_connection */
787   NULL,  /* handle_monitor_command */
788 };
789
790 void
791 initialize_low (void)
792 {
793   set_target_ops (&lynx_target_ops);
794   the_low_target.arch_setup ();
795 }
796