]> granicus.if.org Git - strace/commitdiff
umovestr: read chunks of memory up to pagesize at a time
authorDmitry V. Levin <ldv@altlinux.org>
Tue, 31 Mar 2015 19:45:08 +0000 (19:45 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Tue, 31 Mar 2015 20:56:38 +0000 (20:56 +0000)
* 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.

defs.h
mem.c
util.c

diff --git a/defs.h b/defs.h
index e6aca3714fac68fc024de5d942128ce93d1f3a49..34f1603b816271342b159c9cba5292a2227bf7c2 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -478,6 +478,7 @@ extern int getfdpath(struct tcb *, int, char *, unsigned);
 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 41d90ec82d8d415f6664a84a4af9f86793c0b077..408265877b42ffd619a9c1de681bce85c140e5f3 100644 (file)
--- 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 534e76079e961528f56d5a444042661a8fa7d09a..6afafbbf6d74aac60c713e5f910db0797a2c81a8 100644 (file)
--- a/util.c
+++ b/util.c
@@ -963,7 +963,21 @@ static bool process_vm_readv_not_supported = 1;
 
 #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 @@ umoven(struct tcb *tcp, long addr, unsigned int len, void *our_addr)
 #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 @@ umovestr(struct tcb *tcp, long addr, unsigned int len, char *laddr)
 
        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 @@ umovestr(struct tcb *tcp, long addr, unsigned int len, char *laddr)
                                        /* 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: