diff options
author | Christopher Ferris <cferris@google.com> | 2017-12-15 20:00:59 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2017-12-20 12:57:01 -0800 |
commit | 01ec1b04d104029bb09fc633f557795f85c85003 (patch) | |
tree | 6a51ab108efc4553dd2128cfd28c6fc3ed38c9c6 /libunwindstack/Memory.cpp | |
parent | 10a1e25b5251f63ab67415245060804e54daea0d (diff) | |
download | unwinding-01ec1b04d104029bb09fc633f557795f85c85003.tar.gz |
Add tool to save information from a process.
Also, modify the ProcessVmRead function to allow arbitrarily large
reads and add a test for it.
Test: Run tool and verify the output can be used to do an offline
Test: unwind.
Test: Ran unit tests.
Change-Id: I0974ddca4f5cf72b4c9fa29b597a0a669e223828
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 1f3c6c3..285f879 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) { |