]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/linux-low.c
2002-02-14 Daniel Jacobowitz <drow@mvista.com>
[thirdparty/binutils-gdb.git] / gdb / gdbserver / linux-low.c
CommitLineData
da6d8c04
DJ
1/* Low level interface to ptrace, for the remote server for GDB.
2 Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22#include "server.h"
23#include <sys/wait.h>
da6d8c04
DJ
24
25#include <stdio.h>
26#include <sys/param.h>
27#include <sys/dir.h>
28#include <sys/ptrace.h>
29#include <sys/user.h>
30#include <signal.h>
31#include <sys/ioctl.h>
32#include <fcntl.h>
d07c63e7 33#include <string.h>
da6d8c04
DJ
34
35/***************Begin MY defs*********************/
36static char my_registers[REGISTER_BYTES];
37char *registers = my_registers;
38/***************End MY defs*********************/
39
40#ifdef HAVE_SYS_REG_H
41#include <sys/reg.h>
42#endif
43
d844cde6 44#define PTRACE_ARG3_TYPE long
da6d8c04 45#define PTRACE_XFER_TYPE int
da6d8c04
DJ
46
47extern int errno;
48
49static void initialize_arch (void);
50
51/* Start an inferior process and returns its pid.
52 ALLARGS is a vector of program-name and args. */
53
54int
55create_inferior (char *program, char **allargs)
56{
57 int pid;
58
59 pid = fork ();
60 if (pid < 0)
61 perror_with_name ("fork");
62
63 if (pid == 0)
64 {
65 ptrace (PTRACE_TRACEME, 0, 0, 0);
66
67 execv (program, allargs);
68
69 fprintf (stderr, "Cannot exec %s: %s.\n", program,
d07c63e7 70 strerror (errno));
da6d8c04
DJ
71 fflush (stderr);
72 _exit (0177);
73 }
74
75 return pid;
76}
77
78/* Attach to an inferior process. */
79
80int
81myattach (int pid)
82{
83 if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
84 {
85 fprintf (stderr, "Cannot attach to process %d: %s (%d)\n", pid,
86 errno < sys_nerr ? sys_errlist[errno] : "unknown error",
87 errno);
88 fflush (stderr);
89 _exit (0177);
90 }
91
92 return 0;
93}
94
95/* Kill the inferior process. Make us have no inferior. */
96
97void
98kill_inferior (void)
99{
100 if (inferior_pid == 0)
101 return;
102 ptrace (PTRACE_KILL, inferior_pid, 0, 0);
103 wait (0);
da6d8c04
DJ
104}
105
106/* Return nonzero if the given thread is still alive. */
107int
108mythread_alive (int pid)
109{
110 return 1;
111}
112
113/* Wait for process, returns status */
114
115unsigned char
116mywait (char *status)
117{
118 int pid;
119 union wait w;
120
121 enable_async_io ();
e18651ec 122 pid = waitpid (inferior_pid, (int *)&w, 0);
da6d8c04
DJ
123 disable_async_io ();
124 if (pid != inferior_pid)
125 perror_with_name ("wait");
126
127 if (WIFEXITED (w))
128 {
129 fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
130 *status = 'W';
131 return ((unsigned char) WEXITSTATUS (w));
132 }
133 else if (!WIFSTOPPED (w))
134 {
135 fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
136 *status = 'X';
137 return ((unsigned char) WTERMSIG (w));
138 }
139
140 fetch_inferior_registers (0);
141
142 *status = 'T';
143 return ((unsigned char) WSTOPSIG (w));
144}
145
146/* Resume execution of the inferior process.
147 If STEP is nonzero, single-step it.
148 If SIGNAL is nonzero, give it that signal. */
149
150void
151myresume (int step, int signal)
152{
153 errno = 0;
154 ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
155 if (errno)
156 perror_with_name ("ptrace");
157}
158
159
160#if !defined (offsetof)
161#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
162#endif
163
164/* U_REGS_OFFSET is the offset of the registers within the u area. */
165#if !defined (U_REGS_OFFSET)
166#define U_REGS_OFFSET \
167 ptrace (PT_READ_U, inferior_pid, \
168 (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
169 - KERNEL_U_ADDR
170#endif
171
172#ifdef I386_GNULINUX_TARGET
173/* This module only supports access to the general purpose registers.
174 Adjust the relevant constants accordingly.
175
176 FIXME: kettenis/2001-03-28: We should really use PTRACE_GETREGS to
177 get at the registers. Better yet, we should try to share code with
178 i386-linux-nat.c. */
179#undef NUM_FREGS
180#define NUM_FREGS 0
181#undef NUM_REGS
182#define NUM_REGS NUM_GREGS
183
184/* This stuff comes from i386-tdep.c. */
185
186/* i386_register_byte[i] is the offset into the register file of the
187 start of register number i. We initialize this from
188 i386_register_raw_size. */
189int i386_register_byte[MAX_NUM_REGS];
190
191/* i386_register_raw_size[i] is the number of bytes of storage in
192 GDB's register array occupied by register i. */
193int i386_register_raw_size[MAX_NUM_REGS] = {
194 4, 4, 4, 4,
195 4, 4, 4, 4,
196 4, 4, 4, 4,
197 4, 4, 4, 4,
198 10, 10, 10, 10,
199 10, 10, 10, 10,
200 4, 4, 4, 4,
201 4, 4, 4, 4,
202 16, 16, 16, 16,
203 16, 16, 16, 16,
204 4
205};
206
207static void
208initialize_arch (void)
209{
210 /* Initialize the table saying where each register starts in the
211 register file. */
212 {
213 int i, offset;
214
215 offset = 0;
216 for (i = 0; i < MAX_NUM_REGS; i++)
217 {
218 i386_register_byte[i] = offset;
219 offset += i386_register_raw_size[i];
220 }
221 }
222}
223
224/* This stuff comes from i386-linux-nat.c. */
225
226/* Mapping between the general-purpose registers in `struct user'
227 format and GDB's register array layout. */
228static int regmap[] =
229{
230 EAX, ECX, EDX, EBX,
231 UESP, EBP, ESI, EDI,
232 EIP, EFL, CS, SS,
233 DS, ES, FS, GS
234};
235
236/* Return the address of register REGNUM. BLOCKEND is the value of
237 u.u_ar0, which should point to the registers. */
238
239CORE_ADDR
240register_u_addr (CORE_ADDR blockend, int regnum)
241{
242 return (blockend + 4 * regmap[regnum]);
243}
244#elif defined(TARGET_M68K)
245static void
246initialize_arch (void)
247{
248 return;
249}
250
251/* This table must line up with REGISTER_NAMES in tm-m68k.h */
252static int regmap[] =
253{
254#ifdef PT_D0
255 PT_D0, PT_D1, PT_D2, PT_D3, PT_D4, PT_D5, PT_D6, PT_D7,
256 PT_A0, PT_A1, PT_A2, PT_A3, PT_A4, PT_A5, PT_A6, PT_USP,
257 PT_SR, PT_PC,
258#else
259 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15,
260 17, 18,
261#endif
262#ifdef PT_FP0
263 PT_FP0, PT_FP1, PT_FP2, PT_FP3, PT_FP4, PT_FP5, PT_FP6, PT_FP7,
264 PT_FPCR, PT_FPSR, PT_FPIAR
265#else
266 21, 24, 27, 30, 33, 36, 39, 42, 45, 46, 47
267#endif
268};
269
270/* BLOCKEND is the value of u.u_ar0, and points to the place where GS
271 is stored. */
272
273int
274m68k_linux_register_u_addr (int blockend, int regnum)
275{
276 return (blockend + 4 * regmap[regnum]);
277}
278#elif defined(IA64_GNULINUX_TARGET)
279#undef NUM_FREGS
280#define NUM_FREGS 0
281
282#include <asm/ptrace_offsets.h>
283
284static int u_offsets[] =
285 {
286 /* general registers */
287 -1, /* gr0 not available; i.e, it's always zero */
288 PT_R1,
289 PT_R2,
290 PT_R3,
291 PT_R4,
292 PT_R5,
293 PT_R6,
294 PT_R7,
295 PT_R8,
296 PT_R9,
297 PT_R10,
298 PT_R11,
299 PT_R12,
300 PT_R13,
301 PT_R14,
302 PT_R15,
303 PT_R16,
304 PT_R17,
305 PT_R18,
306 PT_R19,
307 PT_R20,
308 PT_R21,
309 PT_R22,
310 PT_R23,
311 PT_R24,
312 PT_R25,
313 PT_R26,
314 PT_R27,
315 PT_R28,
316 PT_R29,
317 PT_R30,
318 PT_R31,
319 /* gr32 through gr127 not directly available via the ptrace interface */
320 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
321 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
322 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
323 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
324 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
325 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
326 /* Floating point registers */
327 -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */
328 PT_F2,
329 PT_F3,
330 PT_F4,
331 PT_F5,
332 PT_F6,
333 PT_F7,
334 PT_F8,
335 PT_F9,
336 PT_F10,
337 PT_F11,
338 PT_F12,
339 PT_F13,
340 PT_F14,
341 PT_F15,
342 PT_F16,
343 PT_F17,
344 PT_F18,
345 PT_F19,
346 PT_F20,
347 PT_F21,
348 PT_F22,
349 PT_F23,
350 PT_F24,
351 PT_F25,
352 PT_F26,
353 PT_F27,
354 PT_F28,
355 PT_F29,
356 PT_F30,
357 PT_F31,
358 PT_F32,
359 PT_F33,
360 PT_F34,
361 PT_F35,
362 PT_F36,
363 PT_F37,
364 PT_F38,
365 PT_F39,
366 PT_F40,
367 PT_F41,
368 PT_F42,
369 PT_F43,
370 PT_F44,
371 PT_F45,
372 PT_F46,
373 PT_F47,
374 PT_F48,
375 PT_F49,
376 PT_F50,
377 PT_F51,
378 PT_F52,
379 PT_F53,
380 PT_F54,
381 PT_F55,
382 PT_F56,
383 PT_F57,
384 PT_F58,
385 PT_F59,
386 PT_F60,
387 PT_F61,
388 PT_F62,
389 PT_F63,
390 PT_F64,
391 PT_F65,
392 PT_F66,
393 PT_F67,
394 PT_F68,
395 PT_F69,
396 PT_F70,
397 PT_F71,
398 PT_F72,
399 PT_F73,
400 PT_F74,
401 PT_F75,
402 PT_F76,
403 PT_F77,
404 PT_F78,
405 PT_F79,
406 PT_F80,
407 PT_F81,
408 PT_F82,
409 PT_F83,
410 PT_F84,
411 PT_F85,
412 PT_F86,
413 PT_F87,
414 PT_F88,
415 PT_F89,
416 PT_F90,
417 PT_F91,
418 PT_F92,
419 PT_F93,
420 PT_F94,
421 PT_F95,
422 PT_F96,
423 PT_F97,
424 PT_F98,
425 PT_F99,
426 PT_F100,
427 PT_F101,
428 PT_F102,
429 PT_F103,
430 PT_F104,
431 PT_F105,
432 PT_F106,
433 PT_F107,
434 PT_F108,
435 PT_F109,
436 PT_F110,
437 PT_F111,
438 PT_F112,
439 PT_F113,
440 PT_F114,
441 PT_F115,
442 PT_F116,
443 PT_F117,
444 PT_F118,
445 PT_F119,
446 PT_F120,
447 PT_F121,
448 PT_F122,
449 PT_F123,
450 PT_F124,
451 PT_F125,
452 PT_F126,
453 PT_F127,
454 /* predicate registers - we don't fetch these individually */
455 -1, -1, -1, -1, -1, -1, -1, -1,
456 -1, -1, -1, -1, -1, -1, -1, -1,
457 -1, -1, -1, -1, -1, -1, -1, -1,
458 -1, -1, -1, -1, -1, -1, -1, -1,
459 -1, -1, -1, -1, -1, -1, -1, -1,
460 -1, -1, -1, -1, -1, -1, -1, -1,
461 -1, -1, -1, -1, -1, -1, -1, -1,
462 -1, -1, -1, -1, -1, -1, -1, -1,
463 /* branch registers */
464 PT_B0,
465 PT_B1,
466 PT_B2,
467 PT_B3,
468 PT_B4,
469 PT_B5,
470 PT_B6,
471 PT_B7,
472 /* virtual frame pointer and virtual return address pointer */
473 -1, -1,
474 /* other registers */
475 PT_PR,
476 PT_CR_IIP, /* ip */
477 PT_CR_IPSR, /* psr */
478 PT_CFM, /* cfm */
479 /* kernel registers not visible via ptrace interface (?) */
480 -1, -1, -1, -1, -1, -1, -1, -1,
481 /* hole */
482 -1, -1, -1, -1, -1, -1, -1, -1,
483 PT_AR_RSC,
484 PT_AR_BSP,
485 PT_AR_BSPSTORE,
486 PT_AR_RNAT,
487 -1,
488 -1, /* Not available: FCR, IA32 floating control register */
489 -1, -1,
490 -1, /* Not available: EFLAG */
491 -1, /* Not available: CSD */
492 -1, /* Not available: SSD */
493 -1, /* Not available: CFLG */
494 -1, /* Not available: FSR */
495 -1, /* Not available: FIR */
496 -1, /* Not available: FDR */
497 -1,
498 PT_AR_CCV,
499 -1, -1, -1,
500 PT_AR_UNAT,
501 -1, -1, -1,
502 PT_AR_FPSR,
503 -1, -1, -1,
504 -1, /* Not available: ITC */
505 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
506 -1, -1, -1, -1, -1, -1, -1, -1, -1,
507 PT_AR_PFS,
508 PT_AR_LC,
509 -1, /* Not available: EC, the Epilog Count register */
510 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
511 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
512 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
513 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
514 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
515 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
516 -1,
517 /* nat bits - not fetched directly; instead we obtain these bits from
518 either rnat or unat or from memory. */
519 -1, -1, -1, -1, -1, -1, -1, -1,
520 -1, -1, -1, -1, -1, -1, -1, -1,
521 -1, -1, -1, -1, -1, -1, -1, -1,
522 -1, -1, -1, -1, -1, -1, -1, -1,
523 -1, -1, -1, -1, -1, -1, -1, -1,
524 -1, -1, -1, -1, -1, -1, -1, -1,
525 -1, -1, -1, -1, -1, -1, -1, -1,
526 -1, -1, -1, -1, -1, -1, -1, -1,
527 -1, -1, -1, -1, -1, -1, -1, -1,
528 -1, -1, -1, -1, -1, -1, -1, -1,
529 -1, -1, -1, -1, -1, -1, -1, -1,
530 -1, -1, -1, -1, -1, -1, -1, -1,
531 -1, -1, -1, -1, -1, -1, -1, -1,
532 -1, -1, -1, -1, -1, -1, -1, -1,
533 -1, -1, -1, -1, -1, -1, -1, -1,
534 -1, -1, -1, -1, -1, -1, -1, -1,
535 };
536
537int
538ia64_register_u_addr (int blockend, int regnum)
539{
540 int addr;
541
542 if (regnum < 0 || regnum >= NUM_REGS)
543 error ("Invalid register number %d.", regnum);
544
545 addr = u_offsets[regnum];
546 if (addr == -1)
547 addr = 0;
548
549 return addr;
550}
551
552static void
553initialize_arch (void)
554{
555 return;
556}
557
558#elif defined(ARM_GNULINUX_TARGET)
559int arm_register_u_addr(blockend, regnum)
560 int blockend;
561 int regnum;
562{
563 return blockend + REGISTER_BYTE(regnum);
564}
565
566static void
567initialize_arch ()
568{
569}
570#endif
571
572CORE_ADDR
573register_addr (int regno, CORE_ADDR blockend)
574{
575 CORE_ADDR addr;
576
577 if (regno < 0 || regno >= NUM_REGS)
578 error ("Invalid register number %d.", regno);
579
580 REGISTER_U_ADDR (addr, blockend, regno);
581
582 return addr;
583}
584
585/* Fetch one register. */
586
587static void
588fetch_register (int regno)
589{
590 CORE_ADDR regaddr;
591 register int i;
592
593 /* Offset of registers within the u area. */
594 unsigned int offset;
595
596 offset = U_REGS_OFFSET;
597
598 regaddr = register_addr (regno, offset);
599 for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
600 {
601 errno = 0;
602 *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i] =
603 ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0);
604 regaddr += sizeof (PTRACE_XFER_TYPE);
605 if (errno != 0)
606 {
607 /* Warning, not error, in case we are attached; sometimes the
608 kernel doesn't let us at the registers. */
609 char *err = strerror (errno);
610 char *msg = alloca (strlen (err) + 128);
611 sprintf (msg, "reading register %d: %s", regno, err);
612 error (msg);
613 goto error_exit;
614 }
615 }
616error_exit:;
617}
618
619/* Fetch all registers, or just one, from the child process. */
620
621void
622fetch_inferior_registers (int regno)
623{
624 if (regno == -1 || regno == 0)
625 for (regno = 0; regno < NUM_REGS - NUM_FREGS; regno++)
626 fetch_register (regno);
627 else
628 fetch_register (regno);
629}
630
631/* Store our register values back into the inferior.
632 If REGNO is -1, do this for all registers.
633 Otherwise, REGNO specifies which register (so we can save time). */
634
635void
636store_inferior_registers (int regno)
637{
638 CORE_ADDR regaddr;
639 int i;
640 unsigned int offset = U_REGS_OFFSET;
641
642 if (regno >= 0)
643 {
644#if 0
645 if (CANNOT_STORE_REGISTER (regno))
646 return;
647#endif
648 regaddr = register_addr (regno, offset);
649 errno = 0;
650#if 0
651 if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
652 {
653 scratch = *(int *) &registers[REGISTER_BYTE (regno)] | 0x3;
654 ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
655 scratch, 0);
656 if (errno != 0)
657 {
658 /* Error, even if attached. Failing to write these two
659 registers is pretty serious. */
660 sprintf (buf, "writing register number %d", regno);
661 perror_with_name (buf);
662 }
663 }
664 else
665#endif
666 for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
667 {
668 errno = 0;
669 ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
670 *(int *) &registers[REGISTER_BYTE (regno) + i]);
671 if (errno != 0)
672 {
673 /* Warning, not error, in case we are attached; sometimes the
674 kernel doesn't let us at the registers. */
675 char *err = strerror (errno);
676 char *msg = alloca (strlen (err) + 128);
677 sprintf (msg, "writing register %d: %s",
678 regno, err);
679 error (msg);
680 return;
681 }
682 regaddr += sizeof (int);
683 }
684 }
685 else
686 for (regno = 0; regno < NUM_REGS - NUM_FREGS; regno++)
687 store_inferior_registers (regno);
688}
689
690/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
691 in the NEW_SUN_PTRACE case.
692 It ought to be straightforward. But it appears that writing did
693 not write the data that I specified. I cannot understand where
694 it got the data that it actually did write. */
695
696/* Copy LEN bytes from inferior's memory starting at MEMADDR
697 to debugger memory starting at MYADDR. */
698
699void
700read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
701{
702 register int i;
703 /* Round starting address down to longword boundary. */
704 register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
705 /* Round ending address up; get number of longwords that makes. */
706 register int count
707 = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
708 / sizeof (PTRACE_XFER_TYPE);
709 /* Allocate buffer of that many longwords. */
710 register PTRACE_XFER_TYPE *buffer
711 = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
712
713 /* Read all the longwords */
714 for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
715 {
d844cde6 716 buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
da6d8c04
DJ
717 }
718
719 /* Copy appropriate bytes out of the buffer. */
720 memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
721}
722
723/* Copy LEN bytes of data from debugger memory at MYADDR
724 to inferior's memory at MEMADDR.
725 On failure (cannot write the inferior)
726 returns the value of errno. */
727
728int
729write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
730{
731 register int i;
732 /* Round starting address down to longword boundary. */
733 register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
734 /* Round ending address up; get number of longwords that makes. */
735 register int count
736 = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
737 /* Allocate buffer of that many longwords. */
738 register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
739 extern int errno;
740
741 /* Fill start and end extra bytes of buffer with existing memory data. */
742
d844cde6
DJ
743 buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
744 (PTRACE_ARG3_TYPE) addr, 0);
da6d8c04
DJ
745
746 if (count > 1)
747 {
748 buffer[count - 1]
749 = ptrace (PTRACE_PEEKTEXT, inferior_pid,
d844cde6
DJ
750 (PTRACE_ARG3_TYPE) (addr + (count - 1)
751 * sizeof (PTRACE_XFER_TYPE)),
752 0);
da6d8c04
DJ
753 }
754
755 /* Copy data to be written over corresponding part of buffer */
756
757 memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len);
758
759 /* Write the entire buffer. */
760
761 for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
762 {
763 errno = 0;
d844cde6 764 ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
da6d8c04
DJ
765 if (errno)
766 return errno;
767 }
768
769 return 0;
770}
771\f
772void
773initialize_low (void)
774{
775 initialize_arch ();
776}