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