blob: 1f3c6c393686edb0c52808bcac7b8e96cbfeafda [file] [log] [blame]
Christopher Ferris723cf9b2017-01-19 20:08:48 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <sys/mman.h>
20#include <sys/ptrace.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <sys/uio.h>
24#include <unistd.h>
25
26#include <algorithm>
27#include <memory>
28
29#include <android-base/unique_fd.h>
30
Christopher Ferrisd226a512017-07-14 10:37:19 -070031#include <unwindstack/Memory.h>
32
33#include "Check.h"
34
Christopher Ferrise3286732017-12-07 17:41:18 -080035namespace unwindstack {
36
37static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
Josh Gao29c53782017-09-26 14:11:37 -070038 struct iovec dst_iov = {
39 .iov_base = dst,
40 .iov_len = len,
41 };
42
43 // Split up the remote read across page boundaries.
44 // From the manpage:
45 // A partial read/write may result if one of the remote_iov elements points to an invalid
46 // memory region in the remote process.
47 //
48 // Partial transfers apply at the granularity of iovec elements. These system calls won't
49 // perform a partial transfer that splits a single iovec element.
50 constexpr size_t kMaxIovecs = 64;
51 struct iovec src_iovs[kMaxIovecs];
52 size_t iovecs_used = 0;
53
54 uint64_t cur = remote_src;
55 while (len > 0) {
56 if (iovecs_used == kMaxIovecs) {
57 errno = EINVAL;
58 return 0;
59 }
60
61 // struct iovec uses void* for iov_base.
62 if (cur >= UINTPTR_MAX) {
63 errno = EFAULT;
64 return 0;
65 }
66
67 src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
68
69 uintptr_t misalignment = cur & (getpagesize() - 1);
70 size_t iov_len = getpagesize() - misalignment;
71 iov_len = std::min(iov_len, len);
72
73 len -= iov_len;
74 if (__builtin_add_overflow(cur, iov_len, &cur)) {
75 errno = EFAULT;
76 return 0;
77 }
78
79 src_iovs[iovecs_used].iov_len = iov_len;
80 ++iovecs_used;
81 }
82
83 ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
84 return rc == -1 ? 0 : rc;
85}
86
Christopher Ferrise3286732017-12-07 17:41:18 -080087static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
88 // ptrace() returns -1 and sets errno when the operation fails.
89 // To disambiguate -1 from a valid result, we clear errno beforehand.
90 errno = 0;
91 *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
92 if (*value == -1 && errno) {
93 return false;
94 }
95 return true;
96}
97
98static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
99 // Make sure that there is no overflow.
100 uint64_t max_size;
101 if (__builtin_add_overflow(addr, bytes, &max_size)) {
102 return 0;
103 }
104
105 size_t bytes_read = 0;
106 long data;
107 size_t align_bytes = addr & (sizeof(long) - 1);
108 if (align_bytes != 0) {
109 if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
110 return 0;
111 }
112 size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
113 memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
114 addr += copy_bytes;
115 dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
116 bytes -= copy_bytes;
117 bytes_read += copy_bytes;
118 }
119
120 for (size_t i = 0; i < bytes / sizeof(long); i++) {
121 if (!PtraceReadLong(pid, addr, &data)) {
122 return bytes_read;
123 }
124 memcpy(dst, &data, sizeof(long));
125 dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
126 addr += sizeof(long);
127 bytes_read += sizeof(long);
128 }
129
130 size_t left_over = bytes & (sizeof(long) - 1);
131 if (left_over) {
132 if (!PtraceReadLong(pid, addr, &data)) {
133 return bytes_read;
134 }
135 memcpy(dst, &data, left_over);
136 bytes_read += left_over;
137 }
138 return bytes_read;
139}
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800140
Josh Gaoef35aa52017-10-18 11:44:51 -0700141bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
Josh Gaob8377632017-10-18 11:52:53 -0700142 size_t rc = Read(addr, dst, size);
Josh Gao29c53782017-09-26 14:11:37 -0700143 return rc == size;
144}
145
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800146bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
147 string->clear();
148 uint64_t bytes_read = 0;
149 while (bytes_read < max_read) {
150 uint8_t value;
Josh Gaoef35aa52017-10-18 11:44:51 -0700151 if (!ReadFully(addr, &value, sizeof(value))) {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800152 return false;
153 }
154 if (value == '\0') {
155 return true;
156 }
157 string->push_back(value);
158 addr++;
159 bytes_read++;
160 }
161 return false;
162}
163
Christopher Ferris5f118512017-09-01 11:17:16 -0700164std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
165 if (pid == getpid()) {
166 return std::shared_ptr<Memory>(new MemoryLocal());
167 }
168 return std::shared_ptr<Memory>(new MemoryRemote(pid));
169}
170
Josh Gaob8377632017-10-18 11:52:53 -0700171size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700172 if (addr >= raw_.size()) {
173 return 0;
Christopher Ferris3958f802017-02-01 15:44:40 -0800174 }
Josh Gao29c53782017-09-26 14:11:37 -0700175
176 size_t bytes_left = raw_.size() - static_cast<size_t>(addr);
177 const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr;
178 size_t actual_len = std::min(bytes_left, size);
179
180 memcpy(dst, actual_base, actual_len);
181 return actual_len;
Christopher Ferris3958f802017-02-01 15:44:40 -0800182}
183
184uint8_t* MemoryBuffer::GetPtr(size_t offset) {
185 if (offset < raw_.size()) {
186 return &raw_[offset];
187 }
188 return nullptr;
189}
190
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800191MemoryFileAtOffset::~MemoryFileAtOffset() {
Christopher Ferris3958f802017-02-01 15:44:40 -0800192 Clear();
193}
194
195void MemoryFileAtOffset::Clear() {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800196 if (data_) {
197 munmap(&data_[-offset_], size_ + offset_);
198 data_ = nullptr;
199 }
200}
201
Christopher Ferris3958f802017-02-01 15:44:40 -0800202bool MemoryFileAtOffset::Init(const std::string& file, uint64_t offset, uint64_t size) {
203 // Clear out any previous data if it exists.
204 Clear();
205
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800206 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
207 if (fd == -1) {
208 return false;
209 }
210 struct stat buf;
211 if (fstat(fd, &buf) == -1) {
212 return false;
213 }
214 if (offset >= static_cast<uint64_t>(buf.st_size)) {
215 return false;
216 }
217
218 offset_ = offset & (getpagesize() - 1);
219 uint64_t aligned_offset = offset & ~(getpagesize() - 1);
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700220 if (aligned_offset > static_cast<uint64_t>(buf.st_size) ||
221 offset > static_cast<uint64_t>(buf.st_size)) {
222 return false;
223 }
224
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800225 size_ = buf.st_size - aligned_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700226 uint64_t max_size;
227 if (!__builtin_add_overflow(size, offset_, &max_size) && max_size < size_) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800228 // Truncate the mapped size.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700229 size_ = max_size;
Christopher Ferris3958f802017-02-01 15:44:40 -0800230 }
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800231 void* map = mmap(nullptr, size_, PROT_READ, MAP_PRIVATE, fd, aligned_offset);
232 if (map == MAP_FAILED) {
233 return false;
234 }
235
236 data_ = &reinterpret_cast<uint8_t*>(map)[offset_];
237 size_ -= offset_;
238
239 return true;
240}
241
Josh Gaob8377632017-10-18 11:52:53 -0700242size_t MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700243 if (addr >= size_) {
244 return 0;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800245 }
Josh Gao29c53782017-09-26 14:11:37 -0700246
247 size_t bytes_left = size_ - static_cast<size_t>(addr);
248 const unsigned char* actual_base = static_cast<const unsigned char*>(data_) + addr;
249 size_t actual_len = std::min(bytes_left, size);
250
251 memcpy(dst, actual_base, actual_len);
252 return actual_len;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800253}
254
Josh Gaob8377632017-10-18 11:52:53 -0700255size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
Christopher Ferrise714ed22017-12-04 14:23:58 -0800256#if !defined(__LP64__)
Christopher Ferrise3286732017-12-07 17:41:18 -0800257 // Cannot read an address greater than 32 bits in a 32 bit context.
Christopher Ferrise714ed22017-12-04 14:23:58 -0800258 if (addr > UINT32_MAX) {
259 return 0;
260 }
261#endif
Christopher Ferrise3286732017-12-07 17:41:18 -0800262
263 size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
264 reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
265 if (read_func != nullptr) {
266 return read_func(pid_, addr, dst, size);
267 } else {
268 // Prefer process_vm_read, try it first. If it doesn't work, use the
269 // ptrace function. If at least one of them returns at least some data,
270 // set that as the permanent function to use.
271 // This assumes that if process_vm_read works once, it will continue
272 // to work.
273 size_t bytes = ProcessVmRead(pid_, addr, dst, size);
274 if (bytes > 0) {
275 read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
276 return bytes;
277 }
278 bytes = PtraceRead(pid_, addr, dst, size);
279 if (bytes > 0) {
280 read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
281 }
282 return bytes;
283 }
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800284}
285
Josh Gaob8377632017-10-18 11:52:53 -0700286size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
Christopher Ferrise3286732017-12-07 17:41:18 -0800287 return ProcessVmRead(getpid(), addr, dst, size);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800288}
289
Josh Gao29c53782017-09-26 14:11:37 -0700290MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
291 uint64_t offset)
292 : memory_(memory), begin_(begin), length_(length), offset_(offset) {}
293
Josh Gaob8377632017-10-18 11:52:53 -0700294size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700295 if (addr < offset_) {
296 return 0;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700297 }
298
Josh Gao29c53782017-09-26 14:11:37 -0700299 uint64_t read_offset = addr - offset_;
300 if (read_offset >= length_) {
301 return 0;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800302 }
Josh Gao29c53782017-09-26 14:11:37 -0700303
304 uint64_t read_length = std::min(static_cast<uint64_t>(size), length_ - read_offset);
305 uint64_t read_addr;
306 if (__builtin_add_overflow(read_offset, begin_, &read_addr)) {
307 return 0;
308 }
309
Josh Gaob8377632017-10-18 11:52:53 -0700310 return memory_->Read(read_addr, dst, read_length);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800311}
312
313bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
Josh Gao29c53782017-09-26 14:11:37 -0700314 auto memory_file = std::make_shared<MemoryFileAtOffset>();
315 if (!memory_file->Init(file, offset)) {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800316 return false;
317 }
Josh Gao29c53782017-09-26 14:11:37 -0700318
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800319 // The first uint64_t value is the start of memory.
Josh Gao29c53782017-09-26 14:11:37 -0700320 uint64_t start;
Josh Gaoef35aa52017-10-18 11:44:51 -0700321 if (!memory_file->ReadFully(0, &start, sizeof(start))) {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800322 return false;
323 }
Josh Gao29c53782017-09-26 14:11:37 -0700324
325 uint64_t size = memory_file->Size();
326 if (__builtin_sub_overflow(size, sizeof(start), &size)) {
327 return false;
328 }
329
330 memory_ = std::make_unique<MemoryRange>(memory_file, sizeof(start), size, start);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800331 return true;
332}
333
Josh Gaob8377632017-10-18 11:52:53 -0700334size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700335 if (!memory_) {
336 return 0;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700337 }
338
Josh Gaob8377632017-10-18 11:52:53 -0700339 return memory_->Read(addr, dst, size);
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700340}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700341
342} // namespace unwindstack