blob: a66cd5b54cf934bb08ae751e3037d948b8aa2843 [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>
Florian Mayer3f1f2e02018-10-23 15:56:28 +010019#include <string.h>
Christopher Ferris723cf9b2017-01-19 20:08:48 -080020#include <sys/mman.h>
21#include <sys/ptrace.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/uio.h>
25#include <unistd.h>
26
27#include <algorithm>
28#include <memory>
29
30#include <android-base/unique_fd.h>
31
Christopher Ferrisd226a512017-07-14 10:37:19 -070032#include <unwindstack/Memory.h>
33
34#include "Check.h"
Casey Dahlin6b95a0e2019-03-12 17:50:52 -070035#include "MemoryBuffer.h"
36#include "MemoryCache.h"
37#include "MemoryFileAtOffset.h"
38#include "MemoryLocal.h"
39#include "MemoryOffline.h"
40#include "MemoryOfflineBuffer.h"
41#include "MemoryRange.h"
42#include "MemoryRemote.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070043
Christopher Ferrise3286732017-12-07 17:41:18 -080044namespace unwindstack {
45
46static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
Josh Gao29c53782017-09-26 14:11:37 -070047
48 // Split up the remote read across page boundaries.
49 // From the manpage:
50 // A partial read/write may result if one of the remote_iov elements points to an invalid
51 // memory region in the remote process.
52 //
53 // Partial transfers apply at the granularity of iovec elements. These system calls won't
54 // perform a partial transfer that splits a single iovec element.
55 constexpr size_t kMaxIovecs = 64;
56 struct iovec src_iovs[kMaxIovecs];
Josh Gao29c53782017-09-26 14:11:37 -070057
58 uint64_t cur = remote_src;
Christopher Ferris3dfd2ae2017-12-15 20:00:59 -080059 size_t total_read = 0;
Josh Gao29c53782017-09-26 14:11:37 -070060 while (len > 0) {
Christopher Ferris3dfd2ae2017-12-15 20:00:59 -080061 struct iovec dst_iov = {
62 .iov_base = &reinterpret_cast<uint8_t*>(dst)[total_read], .iov_len = len,
63 };
64
65 size_t iovecs_used = 0;
66 while (len > 0) {
67 if (iovecs_used == kMaxIovecs) {
68 break;
69 }
70
71 // struct iovec uses void* for iov_base.
72 if (cur >= UINTPTR_MAX) {
73 errno = EFAULT;
74 return total_read;
75 }
76
77 src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
78
79 uintptr_t misalignment = cur & (getpagesize() - 1);
80 size_t iov_len = getpagesize() - misalignment;
81 iov_len = std::min(iov_len, len);
82
83 len -= iov_len;
84 if (__builtin_add_overflow(cur, iov_len, &cur)) {
85 errno = EFAULT;
86 return total_read;
87 }
88
89 src_iovs[iovecs_used].iov_len = iov_len;
90 ++iovecs_used;
Josh Gao29c53782017-09-26 14:11:37 -070091 }
92
Christopher Ferris3dfd2ae2017-12-15 20:00:59 -080093 ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
94 if (rc == -1) {
95 return total_read;
Josh Gao29c53782017-09-26 14:11:37 -070096 }
Christopher Ferris3dfd2ae2017-12-15 20:00:59 -080097 total_read += rc;
Josh Gao29c53782017-09-26 14:11:37 -070098 }
Christopher Ferris3dfd2ae2017-12-15 20:00:59 -080099 return total_read;
Josh Gao29c53782017-09-26 14:11:37 -0700100}
101
Christopher Ferrise3286732017-12-07 17:41:18 -0800102static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
103 // ptrace() returns -1 and sets errno when the operation fails.
104 // To disambiguate -1 from a valid result, we clear errno beforehand.
105 errno = 0;
106 *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
107 if (*value == -1 && errno) {
108 return false;
109 }
110 return true;
111}
112
113static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
114 // Make sure that there is no overflow.
115 uint64_t max_size;
116 if (__builtin_add_overflow(addr, bytes, &max_size)) {
117 return 0;
118 }
119
120 size_t bytes_read = 0;
121 long data;
122 size_t align_bytes = addr & (sizeof(long) - 1);
123 if (align_bytes != 0) {
124 if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
125 return 0;
126 }
127 size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
128 memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
129 addr += copy_bytes;
130 dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
131 bytes -= copy_bytes;
132 bytes_read += copy_bytes;
133 }
134
135 for (size_t i = 0; i < bytes / sizeof(long); i++) {
136 if (!PtraceReadLong(pid, addr, &data)) {
137 return bytes_read;
138 }
139 memcpy(dst, &data, sizeof(long));
140 dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
141 addr += sizeof(long);
142 bytes_read += sizeof(long);
143 }
144
145 size_t left_over = bytes & (sizeof(long) - 1);
146 if (left_over) {
147 if (!PtraceReadLong(pid, addr, &data)) {
148 return bytes_read;
149 }
150 memcpy(dst, &data, left_over);
151 bytes_read += left_over;
152 }
153 return bytes_read;
154}
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800155
Josh Gaoef35aa52017-10-18 11:44:51 -0700156bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
Josh Gaob8377632017-10-18 11:52:53 -0700157 size_t rc = Read(addr, dst, size);
Josh Gao29c53782017-09-26 14:11:37 -0700158 return rc == size;
159}
160
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800161bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
162 string->clear();
163 uint64_t bytes_read = 0;
164 while (bytes_read < max_read) {
165 uint8_t value;
Josh Gaoef35aa52017-10-18 11:44:51 -0700166 if (!ReadFully(addr, &value, sizeof(value))) {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800167 return false;
168 }
169 if (value == '\0') {
170 return true;
171 }
172 string->push_back(value);
173 addr++;
174 bytes_read++;
175 }
176 return false;
177}
178
Casey Dahlin6b95a0e2019-03-12 17:50:52 -0700179std::unique_ptr<Memory> Memory::CreateFileMemory(const std::string& path, uint64_t offset) {
180 auto memory = std::make_unique<MemoryFileAtOffset>();
181
182 if (memory->Init(path, offset)) {
183 return memory;
184 }
185
186 return nullptr;
187}
188
Christopher Ferris5f118512017-09-01 11:17:16 -0700189std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
190 if (pid == getpid()) {
191 return std::shared_ptr<Memory>(new MemoryLocal());
192 }
193 return std::shared_ptr<Memory>(new MemoryRemote(pid));
194}
195
Christopher Ferrisef640102018-11-14 15:36:45 -0800196std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
197 if (pid == getpid()) {
198 return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
199 }
200 return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
201}
202
Casey Dahlin6b95a0e2019-03-12 17:50:52 -0700203std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_t start,
204 uint64_t end) {
205 return std::shared_ptr<Memory>(new MemoryOfflineBuffer(data, start, end));
206}
207
Josh Gaob8377632017-10-18 11:52:53 -0700208size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700209 if (addr >= raw_.size()) {
210 return 0;
Christopher Ferris3958f802017-02-01 15:44:40 -0800211 }
Josh Gao29c53782017-09-26 14:11:37 -0700212
213 size_t bytes_left = raw_.size() - static_cast<size_t>(addr);
214 const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr;
215 size_t actual_len = std::min(bytes_left, size);
216
217 memcpy(dst, actual_base, actual_len);
218 return actual_len;
Christopher Ferris3958f802017-02-01 15:44:40 -0800219}
220
221uint8_t* MemoryBuffer::GetPtr(size_t offset) {
222 if (offset < raw_.size()) {
223 return &raw_[offset];
224 }
225 return nullptr;
226}
227
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800228MemoryFileAtOffset::~MemoryFileAtOffset() {
Christopher Ferris3958f802017-02-01 15:44:40 -0800229 Clear();
230}
231
232void MemoryFileAtOffset::Clear() {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800233 if (data_) {
234 munmap(&data_[-offset_], size_ + offset_);
235 data_ = nullptr;
236 }
237}
238
Christopher Ferris3958f802017-02-01 15:44:40 -0800239bool MemoryFileAtOffset::Init(const std::string& file, uint64_t offset, uint64_t size) {
240 // Clear out any previous data if it exists.
241 Clear();
242
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800243 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
244 if (fd == -1) {
245 return false;
246 }
247 struct stat buf;
248 if (fstat(fd, &buf) == -1) {
249 return false;
250 }
251 if (offset >= static_cast<uint64_t>(buf.st_size)) {
252 return false;
253 }
254
255 offset_ = offset & (getpagesize() - 1);
256 uint64_t aligned_offset = offset & ~(getpagesize() - 1);
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700257 if (aligned_offset > static_cast<uint64_t>(buf.st_size) ||
258 offset > static_cast<uint64_t>(buf.st_size)) {
259 return false;
260 }
261
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800262 size_ = buf.st_size - aligned_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700263 uint64_t max_size;
264 if (!__builtin_add_overflow(size, offset_, &max_size) && max_size < size_) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800265 // Truncate the mapped size.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700266 size_ = max_size;
Christopher Ferris3958f802017-02-01 15:44:40 -0800267 }
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800268 void* map = mmap(nullptr, size_, PROT_READ, MAP_PRIVATE, fd, aligned_offset);
269 if (map == MAP_FAILED) {
270 return false;
271 }
272
273 data_ = &reinterpret_cast<uint8_t*>(map)[offset_];
274 size_ -= offset_;
275
276 return true;
277}
278
Josh Gaob8377632017-10-18 11:52:53 -0700279size_t MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700280 if (addr >= size_) {
281 return 0;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800282 }
Josh Gao29c53782017-09-26 14:11:37 -0700283
284 size_t bytes_left = size_ - static_cast<size_t>(addr);
285 const unsigned char* actual_base = static_cast<const unsigned char*>(data_) + addr;
286 size_t actual_len = std::min(bytes_left, size);
287
288 memcpy(dst, actual_base, actual_len);
289 return actual_len;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800290}
291
Josh Gaob8377632017-10-18 11:52:53 -0700292size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
Christopher Ferrise714ed22017-12-04 14:23:58 -0800293#if !defined(__LP64__)
Christopher Ferrise3286732017-12-07 17:41:18 -0800294 // Cannot read an address greater than 32 bits in a 32 bit context.
Christopher Ferrise714ed22017-12-04 14:23:58 -0800295 if (addr > UINT32_MAX) {
296 return 0;
297 }
298#endif
Christopher Ferrise3286732017-12-07 17:41:18 -0800299
300 size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
301 reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
302 if (read_func != nullptr) {
303 return read_func(pid_, addr, dst, size);
304 } else {
305 // Prefer process_vm_read, try it first. If it doesn't work, use the
306 // ptrace function. If at least one of them returns at least some data,
307 // set that as the permanent function to use.
308 // This assumes that if process_vm_read works once, it will continue
309 // to work.
310 size_t bytes = ProcessVmRead(pid_, addr, dst, size);
311 if (bytes > 0) {
312 read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
313 return bytes;
314 }
315 bytes = PtraceRead(pid_, addr, dst, size);
316 if (bytes > 0) {
317 read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
318 }
319 return bytes;
320 }
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800321}
322
Josh Gaob8377632017-10-18 11:52:53 -0700323size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
Christopher Ferrise3286732017-12-07 17:41:18 -0800324 return ProcessVmRead(getpid(), addr, dst, size);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800325}
326
Josh Gao29c53782017-09-26 14:11:37 -0700327MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
328 uint64_t offset)
329 : memory_(memory), begin_(begin), length_(length), offset_(offset) {}
330
Josh Gaob8377632017-10-18 11:52:53 -0700331size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700332 if (addr < offset_) {
333 return 0;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700334 }
335
Josh Gao29c53782017-09-26 14:11:37 -0700336 uint64_t read_offset = addr - offset_;
337 if (read_offset >= length_) {
338 return 0;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800339 }
Josh Gao29c53782017-09-26 14:11:37 -0700340
341 uint64_t read_length = std::min(static_cast<uint64_t>(size), length_ - read_offset);
342 uint64_t read_addr;
343 if (__builtin_add_overflow(read_offset, begin_, &read_addr)) {
344 return 0;
345 }
346
Josh Gaob8377632017-10-18 11:52:53 -0700347 return memory_->Read(read_addr, dst, read_length);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800348}
349
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700350void MemoryRanges::Insert(MemoryRange* memory) {
351 maps_.emplace(memory->offset() + memory->length(), memory);
352}
353
354size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) {
355 auto entry = maps_.upper_bound(addr);
356 if (entry != maps_.end()) {
357 return entry->second->Read(addr, dst, size);
358 }
359 return 0;
360}
361
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800362bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
Josh Gao29c53782017-09-26 14:11:37 -0700363 auto memory_file = std::make_shared<MemoryFileAtOffset>();
364 if (!memory_file->Init(file, offset)) {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800365 return false;
366 }
Josh Gao29c53782017-09-26 14:11:37 -0700367
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800368 // The first uint64_t value is the start of memory.
Josh Gao29c53782017-09-26 14:11:37 -0700369 uint64_t start;
Josh Gaoef35aa52017-10-18 11:44:51 -0700370 if (!memory_file->ReadFully(0, &start, sizeof(start))) {
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800371 return false;
372 }
Josh Gao29c53782017-09-26 14:11:37 -0700373
374 uint64_t size = memory_file->Size();
375 if (__builtin_sub_overflow(size, sizeof(start), &size)) {
376 return false;
377 }
378
379 memory_ = std::make_unique<MemoryRange>(memory_file, sizeof(start), size, start);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800380 return true;
381}
382
Josh Gaob8377632017-10-18 11:52:53 -0700383size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
Josh Gao29c53782017-09-26 14:11:37 -0700384 if (!memory_) {
385 return 0;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700386 }
387
Josh Gaob8377632017-10-18 11:52:53 -0700388 return memory_->Read(addr, dst, size);
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700389}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700390
Christopher Ferris6633b0c2018-04-03 16:03:28 -0700391MemoryOfflineBuffer::MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end)
392 : data_(data), start_(start), end_(end) {}
393
394void MemoryOfflineBuffer::Reset(const uint8_t* data, uint64_t start, uint64_t end) {
395 data_ = data;
396 start_ = start;
397 end_ = end;
398}
399
400size_t MemoryOfflineBuffer::Read(uint64_t addr, void* dst, size_t size) {
401 if (addr < start_ || addr >= end_) {
402 return 0;
403 }
404
405 size_t read_length = std::min(size, static_cast<size_t>(end_ - addr));
406 memcpy(dst, &data_[addr - start_], read_length);
407 return read_length;
408}
409
Christopher Ferris150db122017-12-20 18:49:01 -0800410MemoryOfflineParts::~MemoryOfflineParts() {
411 for (auto memory : memories_) {
412 delete memory;
413 }
414}
415
416size_t MemoryOfflineParts::Read(uint64_t addr, void* dst, size_t size) {
417 if (memories_.empty()) {
418 return 0;
419 }
420
421 // Do a read on each memory object, no support for reading across the
422 // different memory objects.
423 for (MemoryOffline* memory : memories_) {
424 size_t bytes = memory->Read(addr, dst, size);
425 if (bytes != 0) {
426 return bytes;
427 }
428 }
429 return 0;
430}
431
Christopher Ferrisef640102018-11-14 15:36:45 -0800432size_t MemoryCache::Read(uint64_t addr, void* dst, size_t size) {
433 // Only bother caching and looking at the cache if this is a small read for now.
434 if (size > 64) {
435 return impl_->Read(addr, dst, size);
436 }
437
438 uint64_t addr_page = addr >> kCacheBits;
439 auto entry = cache_.find(addr_page);
440 uint8_t* cache_dst;
441 if (entry != cache_.end()) {
442 cache_dst = entry->second;
443 } else {
444 cache_dst = cache_[addr_page];
445 if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
446 // Erase the entry.
447 cache_.erase(addr_page);
448 return impl_->Read(addr, dst, size);
449 }
450 }
451 size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
452 if (size <= max_read) {
453 memcpy(dst, &cache_dst[addr & kCacheMask], size);
454 return size;
455 }
456
457 // The read crossed into another cached entry, since a read can only cross
458 // into one extra cached page, duplicate the code rather than looping.
459 memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
460 dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
461 addr_page++;
462
463 entry = cache_.find(addr_page);
464 if (entry != cache_.end()) {
465 cache_dst = entry->second;
466 } else {
467 cache_dst = cache_[addr_page];
468 if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
469 // Erase the entry.
470 cache_.erase(addr_page);
471 return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
472 }
473 }
474 memcpy(dst, cache_dst, size - max_read);
475 return size;
476}
477
Christopher Ferrisd226a512017-07-14 10:37:19 -0700478} // namespace unwindstack