summaryrefslogtreecommitdiff
path: root/libunwindstack/Memory.cpp
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2017-12-15 20:00:59 -0800
committerChristopher Ferris <cferris@google.com>2017-12-20 12:57:01 -0800
commit01ec1b04d104029bb09fc633f557795f85c85003 (patch)
tree6a51ab108efc4553dd2128cfd28c6fc3ed38c9c6 /libunwindstack/Memory.cpp
parent10a1e25b5251f63ab67415245060804e54daea0d (diff)
downloadunwinding-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.cpp66
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) {