umovestr: read chunks of memory up to pagesize at a time
* defs.h (get_pagesize): New prototype.
* mem.c (get_pagesize) Make global.
* util.c (PAGMASK): Remove.
(vm_read_mem): New process_vm_readv proxy function.
(umoven, umovestr): Use it.
(umovestr): Read chunks up to pagesize at a time.
diff --git a/defs.h b/defs.h
index e6aca37..34f1603 100644
--- a/defs.h
+++ b/defs.h
@@ -478,6 +478,7 @@
extern const char *xlookup(const struct xlat *, const unsigned int);
extern const char *xlat_search(const struct xlat *, const size_t, const unsigned int);
+extern unsigned long get_pagesize(void);
extern int string_to_uint(const char *str);
extern int next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits);
diff --git a/mem.c b/mem.c
index 41d90ec..4082658 100644
--- a/mem.c
+++ b/mem.c
@@ -34,8 +34,8 @@
#include <asm/mman.h>
#include <sys/mman.h>
-static unsigned long
-get_pagesize()
+unsigned long
+get_pagesize(void)
{
static unsigned long pagesize;
diff --git a/util.c b/util.c
index 534e760..6afafbb 100644
--- a/util.c
+++ b/util.c
@@ -963,7 +963,21 @@
#endif /* end of hack */
-#define PAGMASK (~(PAGSIZ - 1))
+static ssize_t
+vm_read_mem(pid_t pid, void *laddr, long raddr, size_t len)
+{
+ const struct iovec local = {
+ .iov_base = laddr,
+ .iov_len = len
+ };
+ const struct iovec remote = {
+ .iov_base = (void *) raddr,
+ .iov_len = len
+ };
+
+ return process_vm_readv(pid, &local, 1, &remote, 1, 0);
+}
+
/*
* move `len' bytes of data from process `pid'
* at address `addr' to our space at `our_addr'
@@ -985,13 +999,7 @@
#endif
if (!process_vm_readv_not_supported) {
- struct iovec local[1], remote[1];
- int r;
-
- local[0].iov_base = laddr;
- remote[0].iov_base = (void*)addr;
- local[0].iov_len = remote[0].iov_len = len;
- r = process_vm_readv(pid, local, 1, remote, 1, 0);
+ int r = vm_read_mem(pid, laddr, addr, len);
if ((unsigned int) r == len)
return 0;
if (r >= 0) {
@@ -1120,38 +1128,31 @@
nread = 0;
if (!process_vm_readv_not_supported) {
- struct iovec local[1], remote[1];
-
- local[0].iov_base = laddr;
- remote[0].iov_base = (void*)addr;
+ const size_t page_size = get_pagesize();
+ const size_t page_mask = page_size - 1;
while (len > 0) {
unsigned int chunk_len;
unsigned int end_in_page;
- int r;
- /* Don't read kilobytes: most strings are short */
- chunk_len = len;
- if (chunk_len > 256)
- chunk_len = 256;
- /* Don't cross pages. I guess otherwise we can get EFAULT
+ /*
+ * Don't cross pages, otherwise we can get EFAULT
* and fail to notice that terminating NUL lies
* in the existing (first) page.
- * (I hope there aren't arches with pages < 4K)
*/
- end_in_page = ((long) remote[0].iov_base + chunk_len) & 4095;
+ chunk_len = len > page_size ? page_size : len;
+ end_in_page = (addr + chunk_len) & page_mask;
if (chunk_len > end_in_page) /* crosses to the next page */
chunk_len -= end_in_page;
- local[0].iov_len = remote[0].iov_len = chunk_len;
- r = process_vm_readv(pid, local, 1, remote, 1, 0);
+ int r = vm_read_mem(pid, laddr, addr, chunk_len);
if (r > 0) {
- if (memchr(local[0].iov_base, '\0', r))
+ if (memchr(laddr, '\0', r))
return 1;
- local[0].iov_base += r;
- remote[0].iov_base += r;
- len -= r;
+ addr += r;
+ laddr += r;
nread += r;
+ len -= r;
continue;
}
switch (errno) {
@@ -1170,7 +1171,7 @@
/* address space is inaccessible */
if (nread) {
perror_msg("umovestr: short read (%d < %d) @0x%lx",
- nread, nread + len, addr);
+ nread, nread + len, addr - nread);
}
return -1;
default: