]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/lynx-low.c
Fix PR remote/19840: gdb crashes on reverse-stepi
[thirdparty/binutils-gdb.git] / gdb / gdbserver / lynx-low.c
CommitLineData
618f726f 1/* Copyright (C) 2009-2016 Free Software Foundation, Inc.
8ed54b31
JB
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>
1adfc54d 23#include <sys/ptrace.h>
8ed54b31
JB
24#include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc. */
25#include <unistd.h>
26#include <sys/ioctl.h>
27#include <sys/types.h>
8bdce1ff 28#include "gdb_wait.h"
8ed54b31 29#include <signal.h>
602e3198 30#include "filestuff.h"
8ed54b31
JB
31
32int using_threads = 1;
33
3aee8918
PA
34const struct target_desc *lynx_tdesc;
35
d631c5a7
JB
36/* Per-process private data. */
37
38struct 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
8ed54b31
JB
45/* Print a debug trace on standard output if debug_threads is set. */
46
47static void
48lynx_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
64static ptid_t
65lynx_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
81static int
82lynx_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
89static long
90lynx_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
100static int
101lynx_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
108static char *
109ptrace_request_to_str (int request)
110{
4039cf45 111#define CASE(X) case X: return #X
8ed54b31
JB
112 switch (request)
113 {
4039cf45
JB
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);
8ed54b31 144#ifdef PT_READ_GPR
4039cf45 145 CASE(PT_READ_GPR);
8ed54b31
JB
146#endif
147#ifdef PT_WRITE_GPR
4039cf45 148 CASE(PT_WRITE_GPR);
8ed54b31
JB
149#endif
150#ifdef PT_READ_FPR
4039cf45 151 CASE(PT_READ_FPR);
8ed54b31
JB
152#endif
153#ifdef PT_WRITE_FPR
4039cf45 154 CASE(PT_WRITE_FPR);
8ed54b31 155#endif
8ed54b31 156#ifdef PT_READ_VPR
4039cf45 157 CASE(PT_READ_VPR);
8ed54b31
JB
158#endif
159#ifdef PT_WRITE_VPR
4039cf45 160 CASE(PT_WRITE_VPR);
8ed54b31
JB
161#endif
162#ifdef PTRACE_PEEKUSP
4039cf45 163 CASE(PTRACE_PEEKUSP);
8ed54b31
JB
164#endif
165#ifdef PTRACE_POKEUSP
4039cf45 166 CASE(PTRACE_POKEUSP);
8ed54b31 167#endif
4039cf45
JB
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);
78cbc024 178#ifdef PTRACE_GETTHREADLIST
4039cf45 179 CASE(PTRACE_GETTHREADLIST);
78cbc024 180#endif
8ed54b31 181 }
4039cf45
JB
182#undef CASE
183
8ed54b31
JB
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
190static int
191lynx_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
d631c5a7
JB
211/* Call add_process with the given parameters, and initializes
212 the process' private data. */
213
214static struct process_info *
215lynx_add_process (int pid, int attached)
216{
217 struct process_info *proc;
218
219 proc = add_process (pid, attached);
3aee8918 220 proc->tdesc = lynx_tdesc;
8d749320 221 proc->priv = XCNEW (struct process_info_private);
fe978cb0 222 proc->priv->last_wait_event_ptid = null_ptid;
d631c5a7
JB
223
224 return proc;
225}
226
8ed54b31
JB
227/* Implement the create_inferior method of the target_ops vector. */
228
229static int
230lynx_create_inferior (char *program, char **allargs)
231{
8ed54b31
JB
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
602e3198
JK
244 close_most_fds ();
245
8ed54b31
JB
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
d631c5a7 258 lynx_add_process (pid, 0);
8ed54b31
JB
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
97ad4581
JB
265/* Assuming we've just attached to a running inferior whose pid is PID,
266 add all threads running in that process. */
267
268static void
269lynx_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
8ed54b31
JB
301/* Implement the attach target_ops method. */
302
303static int
304lynx_attach (unsigned long pid)
305{
8ed54b31
JB
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
d631c5a7 312 lynx_add_process (pid, 1);
97ad4581 313 lynx_add_threads_after_attach (pid);
8ed54b31
JB
314
315 return 0;
316}
317
318/* Implement the resume target_ops method. */
319
320static void
321lynx_resume (struct thread_resume *resume_info, size_t n)
322{
3f6e77ef 323 ptid_t ptid = resume_info[0].thread;
5227d625
JB
324 const int request
325 = (resume_info[0].kind == resume_step
326 ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP)
327 : PTRACE_CONT);
8ed54b31 328 const int signal = resume_info[0].sig;
8ed54b31 329
58794e1a 330 /* If given a minus_one_ptid, then try using the current_process'
d631c5a7
JB
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))
fe978cb0 337 ptid = current_process()->priv->last_wait_event_ptid;
d631c5a7 338
58794e1a
JB
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
0bfdf32f 342 fine to use the current_thread's ptid in those cases. */
3f6e77ef 343 if (ptid_equal (ptid, minus_one_ptid))
0bfdf32f 344 ptid = thread_to_gdb_id (current_thread);
3f6e77ef 345
80d82c19 346 regcache_invalidate_pid (ptid_get_pid (ptid));
9044dee2
JB
347
348 errno = 0;
3f6e77ef 349 lynx_ptrace (request, ptid, 1, signal, 0);
9044dee2
JB
350 if (errno)
351 perror_with_name ("ptrace");
8ed54b31
JB
352}
353
354/* Resume the execution of the given PTID. */
355
356static void
357lynx_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
8ed54b31
JB
368/* A wrapper around waitpid that handles the various idiosyncrasies
369 of LynxOS' waitpid. */
370
371static int
372lynx_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
408static ptid_t
409lynx_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))
0bfdf32f 417 pid = lynx_ptid_get_pid (thread_to_gdb_id (current_thread));
8ed54b31
JB
418 else
419 pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
420
421retry:
422
423 ret = lynx_waitpid (pid, &wstat);
424 new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
fe978cb0 425 find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid;
8ed54b31
JB
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))
8b93d60f
JB
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 }
8ed54b31
JB
438
439 if (WIFSTOPPED (wstat))
440 {
441 status->kind = TARGET_WAITKIND_STOPPED;
2ea28649 442 status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat));
8ed54b31
JB
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;
2ea28649 455 status->value.integer = gdb_signal_from_host (WTERMSIG (wstat));
8ed54b31
JB
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;
2ea28649 465 status->value.integer = gdb_signal_from_host (0);
8ed54b31
JB
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
a493e3e2 473 && status->value.integer == GDB_SIGNAL_TRAP)
8ed54b31
JB
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. */
3f6e77ef 483 lynx_continue (new_ptid);
8ed54b31
JB
484 goto retry;
485
486 case SIGTHREADEXIT:
487 remove_thread (find_thread_ptid (new_ptid));
3f6e77ef 488 lynx_continue (new_ptid);
8ed54b31
JB
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
499static ptid_t
500lynx_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
515static int
516lynx_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
534static int
535lynx_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
4abd5ed2
JB
549/* A callback for find_inferior which removes from the thread list
550 all threads belonging to process PROC. */
551
552static int
553lynx_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
8ed54b31
JB
567/* Implement the mourn target_ops method. */
568
569static void
570lynx_mourn (struct process_info *proc)
571{
4abd5ed2
JB
572 find_inferior (&all_threads, lynx_delete_thread_callback, proc);
573
d631c5a7 574 /* Free our private data. */
fe978cb0
PA
575 free (proc->priv);
576 proc->priv = NULL;
d631c5a7 577
4abd5ed2 578 remove_process (proc);
8ed54b31
JB
579}
580
581/* Implement the join target_ops method. */
582
583static void
584lynx_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
592static int
593lynx_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
602static void
603lynx_fetch_registers (struct regcache *regcache, int regno)
604{
605 struct lynx_regset_info *regset = lynx_target_regsets;
0bfdf32f 606 ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
8ed54b31
JB
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
627static void
628lynx_store_registers (struct regcache *regcache, int regno)
629{
630 struct lynx_regset_info *regset = lynx_target_regsets;
0bfdf32f 631 ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
8ed54b31
JB
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
659static int
660lynx_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;
0bfdf32f 667 ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
8ed54b31
JB
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
692static int
693lynx_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;
0bfdf32f 700 ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
8ed54b31
JB
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)
43968415
JB
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 }
8ed54b31
JB
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
733static void
734lynx_request_interrupt (void)
735{
f0db101d 736 ptid_t inferior_ptid = thread_to_gdb_id (get_first_thread ());
8ed54b31
JB
737
738 kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
739}
740
741/* The LynxOS target_ops vector. */
742
743static struct target_ops lynx_target_ops = {
744 lynx_create_inferior,
ece66d65 745 NULL, /* post_create_inferior */
8ed54b31
JB
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 */
802e8e6d 763 NULL, /* supports_z_point_type */
8ed54b31
JB
764 NULL, /* insert_point */
765 NULL, /* remove_point */
f5771b1d
PA
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 */
70b90b91 770 target_can_do_hardware_single_step,
8ed54b31
JB
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 */
89245bc0
DB
783 NULL, /* supports_fork_events */
784 NULL, /* supports_vfork_events */
94585166 785 NULL, /* supports_exec_events */
de0d863e 786 NULL, /* handle_new_gdb_connection */
8ed54b31
JB
787 NULL, /* handle_monitor_command */
788};
789
790void
791initialize_low (void)
792{
793 set_target_ops (&lynx_target_ops);
794 the_low_target.arch_setup ();
795}
796