From: Dmitry V. Levin Date: Tue, 31 Mar 2015 19:45:08 +0000 (+0000) Subject: umovestr: read chunks of memory up to pagesize at a time X-Git-Tag: v4.11~529 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ea1fea69828ded9dfb1980193da64aebf649f3b9;p=strace 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 e6aca371..34f1603b 100644 --- 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 41d90ec8..40826587 100644 --- a/mem.c +++ b/mem.c @@ -34,8 +34,8 @@ #include #include -static unsigned long -get_pagesize() +unsigned long +get_pagesize(void) { static unsigned long pagesize; diff --git a/util.c b/util.c index 534e7607..6afafbbf 100644 --- 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: