Add common write_memory and read_memory NetBSD routines

Instead of sharing the native-only code with all BSDs with slightly
different semantics of the kernels, share the NetBSD-only behavior beteen
the NetBSD native and gdbserver setup.

NetBSD does not differentiate the address space I and D in the
operations (contrary to OpenBSD). NetBSD handles EACCES that integrates
with NetBSD specific PaX MPROTECT error handling.

Add a verbose message in the native client that an operation could be
cancelled due to PaX MPROTECT setup.

gdb/ChangeLog:

       * nat/netbsd-nat.c (write_memory, read_memory): Add.
       * nat/netbsd-nat.h (write_memory, read_memory): Likewise.
       * nbsd-nat.c (nbsd_nat_target::xfer_partial): Update.

gdbserver/ChangeLog:

       * netbsd-low.cc (netbsd_process_target::read_memory)
       (netbsd_process_target::write_memory): Update.
This commit is contained in:
Kamil Rytarowski
2020-10-07 05:57:52 +02:00
parent 9529c85266
commit 91e5e8db33
6 changed files with 138 additions and 59 deletions

View File

@@ -1,3 +1,9 @@
2020-10-07 Kamil Rytarowski <n54@gmx.com>
* nat/netbsd-nat.c (write_memory, read_memory): Add.
* nat/netbsd-nat.h (write_memory, read_memory): Likewise.
* nbsd-nat.c (nbsd_nat_target::xfer_partial): Update.
2020-10-07 Simon Marchi <simon.marchi@polymtl.ca>
* break-catch-sig.c (signal_catch_counts): Make a static arrray.

View File

@@ -210,4 +210,84 @@ qxfer_siginfo (pid_t pid, const char *annex, unsigned char *readbuf,
return len;
}
/* See netbsd-nat.h. */
int
write_memory (pid_t pid, unsigned const char *writebuf, CORE_ADDR offset,
size_t len, size_t *xfered_len)
{
struct ptrace_io_desc io;
io.piod_op = PIOD_WRITE_D;
io.piod_len = len;
size_t bytes_written = 0;
/* Zero length write always succeeds. */
if (len > 0)
{
do
{
io.piod_addr = (void *)(writebuf + bytes_written);
io.piod_offs = (void *)(offset + bytes_written);
errno = 0;
int rv = ptrace (PT_IO, pid, &io, 0);
if (rv == -1)
{
gdb_assert (errno != 0);
return errno;
}
if (io.piod_len == 0)
return 0;
bytes_written += io.piod_len;
io.piod_len = len - bytes_written;
}
while (bytes_written < len);
}
if (xfered_len != nullptr)
*xfered_len = bytes_written;
return 0;
}
/* See netbsd-nat.h. */
int
read_memory (pid_t pid, unsigned char *readbuf, CORE_ADDR offset,
size_t len, size_t *xfered_len)
{
struct ptrace_io_desc io;
io.piod_op = PIOD_READ_D;
io.piod_len = len;
size_t bytes_read = 0;
/* Zero length read always succeeds. */
if (len > 0)
{
do
{
io.piod_offs = (void *)(offset + bytes_read);
io.piod_addr = readbuf + bytes_read;
int rv = ptrace (PT_IO, pid, &io, 0);
if (rv == -1)
return errno;
if (io.piod_len == 0)
return 0;
bytes_read += io.piod_len;
io.piod_len = len - bytes_read;
}
while (bytes_read < len);
}
if (xfered_len != nullptr)
*xfered_len = bytes_read;
return 0;
}
}

View File

@@ -67,6 +67,28 @@ extern void enable_proc_events (pid_t pid);
extern int qxfer_siginfo (pid_t pid, const char *annex, unsigned char *readbuf,
unsigned const char *writebuf, CORE_ADDR offset,
int len);
/* Write gdb's LEN bytes from WRITEBUF and copy it to OFFSET in inferior
process' address space. The inferior is specified by PID.
Returns 0 on success or errno on failure and the number of bytes
on a successful transfer in XFERED_LEN.
This function assumes internally that the queried process is stopped and
traced. */
extern int write_memory (pid_t pid, unsigned const char *writebuf,
CORE_ADDR offset, size_t len, size_t *xfered_len);
/* Read inferior process's LEN bytes from OFFSET and copy it to WRITEBUF in
gdb's address space.
Returns 0 on success or errno on failure and the number of bytes
on a successful transfer in XFERED_LEN.
This function assumes internally that the queried process is stopped and
traced. */
extern int read_memory (pid_t pid, unsigned char *readbuf, CORE_ADDR offset,
size_t len, size_t *xfered_len);
}
#endif

View File

@@ -764,6 +764,29 @@ nbsd_nat_target::xfer_partial (enum target_object object,
*xfered_len = len;
return TARGET_XFER_OK;
}
case TARGET_OBJECT_MEMORY:
{
size_t xfered;
int res;
if (writebuf != nullptr)
res = netbsd_nat::write_memory (pid, writebuf, offset, len, &xfered);
else
res = netbsd_nat::read_memory (pid, readbuf, offset, len, &xfered);
if (res != 0)
{
if (res == EACCES)
fprintf_unfiltered (gdb_stderr, "Cannot %s process at %s (%s). "
"Is PaX MPROTECT active? See security(7), "
"sysctl(7), paxctl(8)\n",
(writebuf ? "write to" : "read from"),
pulongest (offset), safe_strerror (errno));
return TARGET_XFER_E_IO;
}
if (xfered == 0)
return TARGET_XFER_EOF;
*xfered_len = (ULONGEST) xfered;
return TARGET_XFER_OK;
}
default:
return inf_ptrace_target::xfer_partial (object, annex,
readbuf, writebuf, offset,

View File

@@ -1,3 +1,8 @@
2020-10-07 Kamil Rytarowski <n54@gmx.com>
* netbsd-low.cc (netbsd_process_target::read_memory)
(netbsd_process_target::write_memory): Update.
2020-10-07 Kamil Rytarowski <n54@gmx.com>
* netbsd-aarch64-low.cc: Add.

View File

@@ -556,36 +556,8 @@ int
netbsd_process_target::read_memory (CORE_ADDR memaddr, unsigned char *myaddr,
int size)
{
struct ptrace_io_desc io;
io.piod_op = PIOD_READ_D;
io.piod_len = size;
pid_t pid = current_process ()->pid;
int bytes_read = 0;
if (size == 0)
{
/* Zero length write always succeeds. */
return 0;
}
do
{
io.piod_offs = (void *)(memaddr + bytes_read);
io.piod_addr = myaddr + bytes_read;
int rv = ptrace (PT_IO, pid, &io, 0);
if (rv == -1)
return errno;
if (io.piod_len == 0)
return 0;
bytes_read += io.piod_len;
io.piod_len = size - bytes_read;
}
while (bytes_read < size);
return 0;
return netbsd_nat::read_memory (pid, myaddr, memaddr, size, nullptr);
}
/* Implement the write_memory target_ops method. */
@@ -594,37 +566,8 @@ int
netbsd_process_target::write_memory (CORE_ADDR memaddr,
const unsigned char *myaddr, int size)
{
struct ptrace_io_desc io;
io.piod_op = PIOD_WRITE_D;
io.piod_len = size;
pid_t pid = current_process ()->pid;
int bytes_written = 0;
if (size == 0)
{
/* Zero length write always succeeds. */
return 0;
}
do
{
io.piod_addr = (void *)(myaddr + bytes_written);
io.piod_offs = (void *)(memaddr + bytes_written);
int rv = ptrace (PT_IO, pid, &io, 0);
if (rv == -1)
return errno;
if (io.piod_len == 0)
return 0;
bytes_written += io.piod_len;
io.piod_len = size - bytes_written;
}
while (bytes_written < size);
return 0;
return netbsd_nat::write_memory (pid, myaddr, memaddr, size, nullptr);
}
/* Implement the request_interrupt target_ops method. */