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: