diff options
Diffstat (limited to 'libunwindstack/Memory.cpp')
-rw-r--r-- | libunwindstack/Memory.cpp | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp index 1f3c6c393..285f8790a 100644 --- a/libunwindstack/Memory.cpp +++ b/libunwindstack/Memory.cpp @@ -35,10 +35,6 @@ namespace unwindstack { static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) { - struct iovec dst_iov = { - .iov_base = dst, - .iov_len = len, - }; // Split up the remote read across page boundaries. // From the manpage: @@ -49,39 +45,49 @@ static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t le // perform a partial transfer that splits a single iovec element. constexpr size_t kMaxIovecs = 64; struct iovec src_iovs[kMaxIovecs]; - size_t iovecs_used = 0; uint64_t cur = remote_src; + size_t total_read = 0; while (len > 0) { - if (iovecs_used == kMaxIovecs) { - errno = EINVAL; - return 0; + struct iovec dst_iov = { + .iov_base = &reinterpret_cast<uint8_t*>(dst)[total_read], .iov_len = len, + }; + + size_t iovecs_used = 0; + while (len > 0) { + if (iovecs_used == kMaxIovecs) { + break; + } + + // struct iovec uses void* for iov_base. + if (cur >= UINTPTR_MAX) { + errno = EFAULT; + return total_read; + } + + src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur); + + uintptr_t misalignment = cur & (getpagesize() - 1); + size_t iov_len = getpagesize() - misalignment; + iov_len = std::min(iov_len, len); + + len -= iov_len; + if (__builtin_add_overflow(cur, iov_len, &cur)) { + errno = EFAULT; + return total_read; + } + + src_iovs[iovecs_used].iov_len = iov_len; + ++iovecs_used; } - // struct iovec uses void* for iov_base. - if (cur >= UINTPTR_MAX) { - errno = EFAULT; - return 0; + ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0); + if (rc == -1) { + return total_read; } - - src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur); - - uintptr_t misalignment = cur & (getpagesize() - 1); - size_t iov_len = getpagesize() - misalignment; - iov_len = std::min(iov_len, len); - - len -= iov_len; - if (__builtin_add_overflow(cur, iov_len, &cur)) { - errno = EFAULT; - return 0; - } - - src_iovs[iovecs_used].iov_len = iov_len; - ++iovecs_used; + total_read += rc; } - - ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0); - return rc == -1 ? 0 : rc; + return total_read; } static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) { |