- {
- union
- {
- PTRACE_TYPE_RET word;
- gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
- } buffer;
- ULONGEST rounded_offset;
- LONGEST partial_len;
-
- /* Round the start offset down to the next long word
- boundary. */
- rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
-
- /* Since ptrace will transfer a single word starting at that
- rounded_offset the partial_len needs to be adjusted down to
- that (remember this function only does a single transfer).
- Should the required length be even less, adjust it down
- again. */
- partial_len = (rounded_offset + sizeof (PTRACE_TYPE_RET)) - offset;
- if (partial_len > len)
- partial_len = len;
-
- if (writebuf)
- {
- /* If OFFSET:PARTIAL_LEN is smaller than
- ROUNDED_OFFSET:WORDSIZE then a read/modify write will
- be needed. Read in the entire word. */
- if (rounded_offset < offset
- || (offset + partial_len
- < rounded_offset + sizeof (PTRACE_TYPE_RET)))
- /* Need part of initial word -- fetch it. */
- buffer.word = ptrace (PT_READ_I, pid,
- (PTRACE_TYPE_ARG3)(uintptr_t)
- rounded_offset, 0);
-
- /* Copy data to be written over corresponding part of
- buffer. */
- memcpy (buffer.byte + (offset - rounded_offset),
- writebuf, partial_len);
-
- errno = 0;
- ptrace (PT_WRITE_D, pid,
- (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
- buffer.word);
- if (errno)
- {
- /* Using the appropriate one (I or D) is necessary for
- Gould NP1, at least. */
- errno = 0;
- ptrace (PT_WRITE_I, pid,
- (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
- buffer.word);
- if (errno)
- return 0;
- }
- }
-
- if (readbuf)
- {
- errno = 0;
- buffer.word = ptrace (PT_READ_I, pid,
- (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
- 0);
- if (errno)
- return 0;
- /* Copy appropriate bytes out of the buffer. */
- memcpy (readbuf, buffer.byte + (offset - rounded_offset),
- partial_len);
- }
-
- return partial_len;
- }