xref: /aosp_15_r20/system/unwinding/libunwindstack/Memory.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker  *
4*eb293b8fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker  *
8*eb293b8fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker  *
10*eb293b8fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker  * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker  */
16*eb293b8fSAndroid Build Coastguard Worker 
17*eb293b8fSAndroid Build Coastguard Worker #include <errno.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <fcntl.h>
19*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
20*eb293b8fSAndroid Build Coastguard Worker #include <string.h>
21*eb293b8fSAndroid Build Coastguard Worker #include <sys/mman.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <sys/ptrace.h>
23*eb293b8fSAndroid Build Coastguard Worker #include <sys/stat.h>
24*eb293b8fSAndroid Build Coastguard Worker #include <sys/types.h>
25*eb293b8fSAndroid Build Coastguard Worker #include <sys/uio.h>
26*eb293b8fSAndroid Build Coastguard Worker #include <unistd.h>
27*eb293b8fSAndroid Build Coastguard Worker 
28*eb293b8fSAndroid Build Coastguard Worker #include <algorithm>
29*eb293b8fSAndroid Build Coastguard Worker #include <memory>
30*eb293b8fSAndroid Build Coastguard Worker #include <mutex>
31*eb293b8fSAndroid Build Coastguard Worker #include <optional>
32*eb293b8fSAndroid Build Coastguard Worker #include <string>
33*eb293b8fSAndroid Build Coastguard Worker 
34*eb293b8fSAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
35*eb293b8fSAndroid Build Coastguard Worker 
36*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Log.h>
37*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
38*eb293b8fSAndroid Build Coastguard Worker 
39*eb293b8fSAndroid Build Coastguard Worker #include "MemoryBuffer.h"
40*eb293b8fSAndroid Build Coastguard Worker #include "MemoryCache.h"
41*eb293b8fSAndroid Build Coastguard Worker #include "MemoryFileAtOffset.h"
42*eb293b8fSAndroid Build Coastguard Worker #include "MemoryLocal.h"
43*eb293b8fSAndroid Build Coastguard Worker #include "MemoryLocalUnsafe.h"
44*eb293b8fSAndroid Build Coastguard Worker #include "MemoryOffline.h"
45*eb293b8fSAndroid Build Coastguard Worker #include "MemoryOfflineBuffer.h"
46*eb293b8fSAndroid Build Coastguard Worker #include "MemoryRange.h"
47*eb293b8fSAndroid Build Coastguard Worker #include "MemoryRemote.h"
48*eb293b8fSAndroid Build Coastguard Worker 
49*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
50*eb293b8fSAndroid Build Coastguard Worker 
ProcessVmRead(pid_t pid,uint64_t remote_src,void * dst,size_t len)51*eb293b8fSAndroid Build Coastguard Worker static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
52*eb293b8fSAndroid Build Coastguard Worker 
53*eb293b8fSAndroid Build Coastguard Worker   // Split up the remote read across page boundaries.
54*eb293b8fSAndroid Build Coastguard Worker   // From the manpage:
55*eb293b8fSAndroid Build Coastguard Worker   //   A partial read/write may result if one of the remote_iov elements points to an invalid
56*eb293b8fSAndroid Build Coastguard Worker   //   memory region in the remote process.
57*eb293b8fSAndroid Build Coastguard Worker   //
58*eb293b8fSAndroid Build Coastguard Worker   //   Partial transfers apply at the granularity of iovec elements.  These system calls won't
59*eb293b8fSAndroid Build Coastguard Worker   //   perform a partial transfer that splits a single iovec element.
60*eb293b8fSAndroid Build Coastguard Worker   constexpr size_t kMaxIovecs = 64;
61*eb293b8fSAndroid Build Coastguard Worker   struct iovec src_iovs[kMaxIovecs];
62*eb293b8fSAndroid Build Coastguard Worker 
63*eb293b8fSAndroid Build Coastguard Worker   uint64_t cur = remote_src;
64*eb293b8fSAndroid Build Coastguard Worker   size_t total_read = 0;
65*eb293b8fSAndroid Build Coastguard Worker   while (len > 0) {
66*eb293b8fSAndroid Build Coastguard Worker     struct iovec dst_iov = {
67*eb293b8fSAndroid Build Coastguard Worker         .iov_base = &reinterpret_cast<uint8_t*>(dst)[total_read], .iov_len = len,
68*eb293b8fSAndroid Build Coastguard Worker     };
69*eb293b8fSAndroid Build Coastguard Worker 
70*eb293b8fSAndroid Build Coastguard Worker     size_t iovecs_used = 0;
71*eb293b8fSAndroid Build Coastguard Worker     while (len > 0) {
72*eb293b8fSAndroid Build Coastguard Worker       if (iovecs_used == kMaxIovecs) {
73*eb293b8fSAndroid Build Coastguard Worker         break;
74*eb293b8fSAndroid Build Coastguard Worker       }
75*eb293b8fSAndroid Build Coastguard Worker 
76*eb293b8fSAndroid Build Coastguard Worker       // struct iovec uses void* for iov_base.
77*eb293b8fSAndroid Build Coastguard Worker       if (cur >= UINTPTR_MAX) {
78*eb293b8fSAndroid Build Coastguard Worker         errno = EFAULT;
79*eb293b8fSAndroid Build Coastguard Worker         return total_read;
80*eb293b8fSAndroid Build Coastguard Worker       }
81*eb293b8fSAndroid Build Coastguard Worker 
82*eb293b8fSAndroid Build Coastguard Worker       src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
83*eb293b8fSAndroid Build Coastguard Worker 
84*eb293b8fSAndroid Build Coastguard Worker       uintptr_t misalignment = cur & (getpagesize() - 1);
85*eb293b8fSAndroid Build Coastguard Worker       size_t iov_len = getpagesize() - misalignment;
86*eb293b8fSAndroid Build Coastguard Worker       iov_len = std::min(iov_len, len);
87*eb293b8fSAndroid Build Coastguard Worker 
88*eb293b8fSAndroid Build Coastguard Worker       len -= iov_len;
89*eb293b8fSAndroid Build Coastguard Worker       if (__builtin_add_overflow(cur, iov_len, &cur)) {
90*eb293b8fSAndroid Build Coastguard Worker         errno = EFAULT;
91*eb293b8fSAndroid Build Coastguard Worker         return total_read;
92*eb293b8fSAndroid Build Coastguard Worker       }
93*eb293b8fSAndroid Build Coastguard Worker 
94*eb293b8fSAndroid Build Coastguard Worker       src_iovs[iovecs_used].iov_len = iov_len;
95*eb293b8fSAndroid Build Coastguard Worker       ++iovecs_used;
96*eb293b8fSAndroid Build Coastguard Worker     }
97*eb293b8fSAndroid Build Coastguard Worker 
98*eb293b8fSAndroid Build Coastguard Worker     ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
99*eb293b8fSAndroid Build Coastguard Worker     if (rc == -1) {
100*eb293b8fSAndroid Build Coastguard Worker       return total_read;
101*eb293b8fSAndroid Build Coastguard Worker     }
102*eb293b8fSAndroid Build Coastguard Worker     total_read += rc;
103*eb293b8fSAndroid Build Coastguard Worker   }
104*eb293b8fSAndroid Build Coastguard Worker   return total_read;
105*eb293b8fSAndroid Build Coastguard Worker }
106*eb293b8fSAndroid Build Coastguard Worker 
PtraceReadLong(pid_t pid,uint64_t addr,long * value)107*eb293b8fSAndroid Build Coastguard Worker static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
108*eb293b8fSAndroid Build Coastguard Worker   // ptrace() returns -1 and sets errno when the operation fails.
109*eb293b8fSAndroid Build Coastguard Worker   // To disambiguate -1 from a valid result, we clear errno beforehand.
110*eb293b8fSAndroid Build Coastguard Worker   errno = 0;
111*eb293b8fSAndroid Build Coastguard Worker   *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
112*eb293b8fSAndroid Build Coastguard Worker   if (*value == -1 && errno) {
113*eb293b8fSAndroid Build Coastguard Worker     return false;
114*eb293b8fSAndroid Build Coastguard Worker   }
115*eb293b8fSAndroid Build Coastguard Worker   return true;
116*eb293b8fSAndroid Build Coastguard Worker }
117*eb293b8fSAndroid Build Coastguard Worker 
PtraceRead(pid_t pid,uint64_t addr,void * dst,size_t bytes)118*eb293b8fSAndroid Build Coastguard Worker static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
119*eb293b8fSAndroid Build Coastguard Worker   // Make sure that there is no overflow.
120*eb293b8fSAndroid Build Coastguard Worker   uint64_t max_size;
121*eb293b8fSAndroid Build Coastguard Worker   if (__builtin_add_overflow(addr, bytes, &max_size)) {
122*eb293b8fSAndroid Build Coastguard Worker     return 0;
123*eb293b8fSAndroid Build Coastguard Worker   }
124*eb293b8fSAndroid Build Coastguard Worker 
125*eb293b8fSAndroid Build Coastguard Worker   size_t bytes_read = 0;
126*eb293b8fSAndroid Build Coastguard Worker   long data;
127*eb293b8fSAndroid Build Coastguard Worker   size_t align_bytes = addr & (sizeof(long) - 1);
128*eb293b8fSAndroid Build Coastguard Worker   if (align_bytes != 0) {
129*eb293b8fSAndroid Build Coastguard Worker     if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
130*eb293b8fSAndroid Build Coastguard Worker       return 0;
131*eb293b8fSAndroid Build Coastguard Worker     }
132*eb293b8fSAndroid Build Coastguard Worker     size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
133*eb293b8fSAndroid Build Coastguard Worker     memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
134*eb293b8fSAndroid Build Coastguard Worker     addr += copy_bytes;
135*eb293b8fSAndroid Build Coastguard Worker     dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
136*eb293b8fSAndroid Build Coastguard Worker     bytes -= copy_bytes;
137*eb293b8fSAndroid Build Coastguard Worker     bytes_read += copy_bytes;
138*eb293b8fSAndroid Build Coastguard Worker   }
139*eb293b8fSAndroid Build Coastguard Worker 
140*eb293b8fSAndroid Build Coastguard Worker   for (size_t i = 0; i < bytes / sizeof(long); i++) {
141*eb293b8fSAndroid Build Coastguard Worker     if (!PtraceReadLong(pid, addr, &data)) {
142*eb293b8fSAndroid Build Coastguard Worker       return bytes_read;
143*eb293b8fSAndroid Build Coastguard Worker     }
144*eb293b8fSAndroid Build Coastguard Worker     memcpy(dst, &data, sizeof(long));
145*eb293b8fSAndroid Build Coastguard Worker     dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
146*eb293b8fSAndroid Build Coastguard Worker     addr += sizeof(long);
147*eb293b8fSAndroid Build Coastguard Worker     bytes_read += sizeof(long);
148*eb293b8fSAndroid Build Coastguard Worker   }
149*eb293b8fSAndroid Build Coastguard Worker 
150*eb293b8fSAndroid Build Coastguard Worker   size_t left_over = bytes & (sizeof(long) - 1);
151*eb293b8fSAndroid Build Coastguard Worker   if (left_over) {
152*eb293b8fSAndroid Build Coastguard Worker     if (!PtraceReadLong(pid, addr, &data)) {
153*eb293b8fSAndroid Build Coastguard Worker       return bytes_read;
154*eb293b8fSAndroid Build Coastguard Worker     }
155*eb293b8fSAndroid Build Coastguard Worker     memcpy(dst, &data, left_over);
156*eb293b8fSAndroid Build Coastguard Worker     bytes_read += left_over;
157*eb293b8fSAndroid Build Coastguard Worker   }
158*eb293b8fSAndroid Build Coastguard Worker   return bytes_read;
159*eb293b8fSAndroid Build Coastguard Worker }
160*eb293b8fSAndroid Build Coastguard Worker 
ReadFully(uint64_t addr,void * dst,size_t size)161*eb293b8fSAndroid Build Coastguard Worker bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
162*eb293b8fSAndroid Build Coastguard Worker   size_t rc = Read(addr, dst, size);
163*eb293b8fSAndroid Build Coastguard Worker   return rc == size;
164*eb293b8fSAndroid Build Coastguard Worker }
165*eb293b8fSAndroid Build Coastguard Worker 
ReadString(uint64_t addr,std::string * dst,size_t max_read)166*eb293b8fSAndroid Build Coastguard Worker bool Memory::ReadString(uint64_t addr, std::string* dst, size_t max_read) {
167*eb293b8fSAndroid Build Coastguard Worker   char buffer[256];  // Large enough for 99% of symbol names.
168*eb293b8fSAndroid Build Coastguard Worker   size_t size = 0;   // Number of bytes which were read into the buffer.
169*eb293b8fSAndroid Build Coastguard Worker   for (size_t offset = 0; offset < max_read; offset += size) {
170*eb293b8fSAndroid Build Coastguard Worker     // Look for null-terminator first, so we can allocate string of exact size.
171*eb293b8fSAndroid Build Coastguard Worker     // If we know the end of valid memory range, do the reads in larger blocks.
172*eb293b8fSAndroid Build Coastguard Worker     size_t read = std::min(sizeof(buffer), max_read - offset);
173*eb293b8fSAndroid Build Coastguard Worker     size = Read(addr + offset, buffer, read);
174*eb293b8fSAndroid Build Coastguard Worker     if (size == 0) {
175*eb293b8fSAndroid Build Coastguard Worker       return false;  // We have not found end of string yet and we can not read more data.
176*eb293b8fSAndroid Build Coastguard Worker     }
177*eb293b8fSAndroid Build Coastguard Worker     size_t length = strnlen(buffer, size);  // Index of the null-terminator.
178*eb293b8fSAndroid Build Coastguard Worker     if (length < size) {
179*eb293b8fSAndroid Build Coastguard Worker       // We found the null-terminator. Allocate the string and set its content.
180*eb293b8fSAndroid Build Coastguard Worker       if (offset == 0) {
181*eb293b8fSAndroid Build Coastguard Worker         // We did just single read, so the buffer already contains the whole string.
182*eb293b8fSAndroid Build Coastguard Worker         dst->assign(buffer, length);
183*eb293b8fSAndroid Build Coastguard Worker         return true;
184*eb293b8fSAndroid Build Coastguard Worker       } else {
185*eb293b8fSAndroid Build Coastguard Worker         // The buffer contains only the last block. Read the whole string again.
186*eb293b8fSAndroid Build Coastguard Worker         dst->assign(offset + length, '\0');
187*eb293b8fSAndroid Build Coastguard Worker         return ReadFully(addr, dst->data(), dst->size());
188*eb293b8fSAndroid Build Coastguard Worker       }
189*eb293b8fSAndroid Build Coastguard Worker     }
190*eb293b8fSAndroid Build Coastguard Worker   }
191*eb293b8fSAndroid Build Coastguard Worker   return false;
192*eb293b8fSAndroid Build Coastguard Worker }
193*eb293b8fSAndroid Build Coastguard Worker 
CreateFileMemory(const std::string & path,uint64_t offset,uint64_t size)194*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> Memory::CreateFileMemory(const std::string& path, uint64_t offset,
195*eb293b8fSAndroid Build Coastguard Worker                                                  uint64_t size) {
196*eb293b8fSAndroid Build Coastguard Worker   auto memory = std::make_shared<MemoryFileAtOffset>();
197*eb293b8fSAndroid Build Coastguard Worker 
198*eb293b8fSAndroid Build Coastguard Worker   if (memory->Init(path, offset, size)) {
199*eb293b8fSAndroid Build Coastguard Worker     return memory;
200*eb293b8fSAndroid Build Coastguard Worker   }
201*eb293b8fSAndroid Build Coastguard Worker 
202*eb293b8fSAndroid Build Coastguard Worker   return nullptr;
203*eb293b8fSAndroid Build Coastguard Worker }
204*eb293b8fSAndroid Build Coastguard Worker 
CreateProcessMemoryLocalUnsafe()205*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> Memory::CreateProcessMemoryLocalUnsafe() {
206*eb293b8fSAndroid Build Coastguard Worker   return std::shared_ptr<Memory>(new MemoryLocalUnsafe());
207*eb293b8fSAndroid Build Coastguard Worker }
208*eb293b8fSAndroid Build Coastguard Worker 
CreateProcessMemory(pid_t pid)209*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
210*eb293b8fSAndroid Build Coastguard Worker   if (pid == getpid()) {
211*eb293b8fSAndroid Build Coastguard Worker     return std::shared_ptr<Memory>(new MemoryLocal());
212*eb293b8fSAndroid Build Coastguard Worker   }
213*eb293b8fSAndroid Build Coastguard Worker   return std::shared_ptr<Memory>(new MemoryRemote(pid));
214*eb293b8fSAndroid Build Coastguard Worker }
215*eb293b8fSAndroid Build Coastguard Worker 
CreateProcessMemoryCached(pid_t pid)216*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
217*eb293b8fSAndroid Build Coastguard Worker   if (pid == getpid()) {
218*eb293b8fSAndroid Build Coastguard Worker     return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
219*eb293b8fSAndroid Build Coastguard Worker   }
220*eb293b8fSAndroid Build Coastguard Worker   return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
221*eb293b8fSAndroid Build Coastguard Worker }
222*eb293b8fSAndroid Build Coastguard Worker 
CreateProcessMemoryThreadCached(pid_t pid)223*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> Memory::CreateProcessMemoryThreadCached(pid_t pid) {
224*eb293b8fSAndroid Build Coastguard Worker   if (pid == getpid()) {
225*eb293b8fSAndroid Build Coastguard Worker     return std::shared_ptr<Memory>(new MemoryThreadCache(new MemoryLocal()));
226*eb293b8fSAndroid Build Coastguard Worker   }
227*eb293b8fSAndroid Build Coastguard Worker   return std::shared_ptr<Memory>(new MemoryThreadCache(new MemoryRemote(pid)));
228*eb293b8fSAndroid Build Coastguard Worker }
229*eb293b8fSAndroid Build Coastguard Worker 
CreateOfflineMemory(const uint8_t * data,uint64_t start,uint64_t end)230*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_t start,
231*eb293b8fSAndroid Build Coastguard Worker                                                     uint64_t end) {
232*eb293b8fSAndroid Build Coastguard Worker   return std::shared_ptr<Memory>(new MemoryOfflineBuffer(data, start, end));
233*eb293b8fSAndroid Build Coastguard Worker }
234*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)235*eb293b8fSAndroid Build Coastguard Worker size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
236*eb293b8fSAndroid Build Coastguard Worker   if (addr < offset_) {
237*eb293b8fSAndroid Build Coastguard Worker     return 0;
238*eb293b8fSAndroid Build Coastguard Worker   }
239*eb293b8fSAndroid Build Coastguard Worker   addr -= offset_;
240*eb293b8fSAndroid Build Coastguard Worker   size_t raw_size = raw_.size();
241*eb293b8fSAndroid Build Coastguard Worker   if (addr >= raw_size) {
242*eb293b8fSAndroid Build Coastguard Worker     return 0;
243*eb293b8fSAndroid Build Coastguard Worker   }
244*eb293b8fSAndroid Build Coastguard Worker 
245*eb293b8fSAndroid Build Coastguard Worker   size_t bytes_left = raw_size - static_cast<size_t>(addr);
246*eb293b8fSAndroid Build Coastguard Worker   size_t actual_len = std::min(bytes_left, size);
247*eb293b8fSAndroid Build Coastguard Worker   memcpy(dst, &raw_[addr], actual_len);
248*eb293b8fSAndroid Build Coastguard Worker   return actual_len;
249*eb293b8fSAndroid Build Coastguard Worker }
250*eb293b8fSAndroid Build Coastguard Worker 
GetPtr(size_t addr)251*eb293b8fSAndroid Build Coastguard Worker uint8_t* MemoryBuffer::GetPtr(size_t addr) {
252*eb293b8fSAndroid Build Coastguard Worker   if (addr < offset_) {
253*eb293b8fSAndroid Build Coastguard Worker     return nullptr;
254*eb293b8fSAndroid Build Coastguard Worker   }
255*eb293b8fSAndroid Build Coastguard Worker   addr -= offset_;
256*eb293b8fSAndroid Build Coastguard Worker   if (addr < raw_.size()) {
257*eb293b8fSAndroid Build Coastguard Worker     return &raw_[addr];
258*eb293b8fSAndroid Build Coastguard Worker   }
259*eb293b8fSAndroid Build Coastguard Worker   return nullptr;
260*eb293b8fSAndroid Build Coastguard Worker }
261*eb293b8fSAndroid Build Coastguard Worker 
~MemoryFileAtOffset()262*eb293b8fSAndroid Build Coastguard Worker MemoryFileAtOffset::~MemoryFileAtOffset() {
263*eb293b8fSAndroid Build Coastguard Worker   Clear();
264*eb293b8fSAndroid Build Coastguard Worker }
265*eb293b8fSAndroid Build Coastguard Worker 
Clear()266*eb293b8fSAndroid Build Coastguard Worker void MemoryFileAtOffset::Clear() {
267*eb293b8fSAndroid Build Coastguard Worker   if (data_) {
268*eb293b8fSAndroid Build Coastguard Worker     munmap(&data_[-offset_], size_ + offset_);
269*eb293b8fSAndroid Build Coastguard Worker     data_ = nullptr;
270*eb293b8fSAndroid Build Coastguard Worker     size_ = 0;
271*eb293b8fSAndroid Build Coastguard Worker   }
272*eb293b8fSAndroid Build Coastguard Worker }
273*eb293b8fSAndroid Build Coastguard Worker 
Init(const std::string & file,uint64_t offset,uint64_t size)274*eb293b8fSAndroid Build Coastguard Worker bool MemoryFileAtOffset::Init(const std::string& file, uint64_t offset, uint64_t size) {
275*eb293b8fSAndroid Build Coastguard Worker   // Clear out any previous data if it exists.
276*eb293b8fSAndroid Build Coastguard Worker   Clear();
277*eb293b8fSAndroid Build Coastguard Worker 
278*eb293b8fSAndroid Build Coastguard Worker   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
279*eb293b8fSAndroid Build Coastguard Worker   if (fd == -1) {
280*eb293b8fSAndroid Build Coastguard Worker     return false;
281*eb293b8fSAndroid Build Coastguard Worker   }
282*eb293b8fSAndroid Build Coastguard Worker   struct stat buf;
283*eb293b8fSAndroid Build Coastguard Worker   if (fstat(fd, &buf) == -1) {
284*eb293b8fSAndroid Build Coastguard Worker     return false;
285*eb293b8fSAndroid Build Coastguard Worker   }
286*eb293b8fSAndroid Build Coastguard Worker   if (offset >= static_cast<uint64_t>(buf.st_size)) {
287*eb293b8fSAndroid Build Coastguard Worker     return false;
288*eb293b8fSAndroid Build Coastguard Worker   }
289*eb293b8fSAndroid Build Coastguard Worker 
290*eb293b8fSAndroid Build Coastguard Worker   offset_ = offset & (getpagesize() - 1);
291*eb293b8fSAndroid Build Coastguard Worker   uint64_t aligned_offset = offset & ~(getpagesize() - 1);
292*eb293b8fSAndroid Build Coastguard Worker   if (aligned_offset > static_cast<uint64_t>(buf.st_size) ||
293*eb293b8fSAndroid Build Coastguard Worker       offset > static_cast<uint64_t>(buf.st_size)) {
294*eb293b8fSAndroid Build Coastguard Worker     return false;
295*eb293b8fSAndroid Build Coastguard Worker   }
296*eb293b8fSAndroid Build Coastguard Worker 
297*eb293b8fSAndroid Build Coastguard Worker   size_ = buf.st_size - aligned_offset;
298*eb293b8fSAndroid Build Coastguard Worker   uint64_t max_size;
299*eb293b8fSAndroid Build Coastguard Worker   if (!__builtin_add_overflow(size, offset_, &max_size) && max_size < size_) {
300*eb293b8fSAndroid Build Coastguard Worker     // Truncate the mapped size.
301*eb293b8fSAndroid Build Coastguard Worker     size_ = max_size;
302*eb293b8fSAndroid Build Coastguard Worker   }
303*eb293b8fSAndroid Build Coastguard Worker   void* map = mmap(nullptr, size_, PROT_READ, MAP_PRIVATE, fd, aligned_offset);
304*eb293b8fSAndroid Build Coastguard Worker   if (map == MAP_FAILED) {
305*eb293b8fSAndroid Build Coastguard Worker     return false;
306*eb293b8fSAndroid Build Coastguard Worker   }
307*eb293b8fSAndroid Build Coastguard Worker 
308*eb293b8fSAndroid Build Coastguard Worker   data_ = &reinterpret_cast<uint8_t*>(map)[offset_];
309*eb293b8fSAndroid Build Coastguard Worker   size_ -= offset_;
310*eb293b8fSAndroid Build Coastguard Worker 
311*eb293b8fSAndroid Build Coastguard Worker   return true;
312*eb293b8fSAndroid Build Coastguard Worker }
313*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)314*eb293b8fSAndroid Build Coastguard Worker size_t MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
315*eb293b8fSAndroid Build Coastguard Worker   if (addr >= size_) {
316*eb293b8fSAndroid Build Coastguard Worker     return 0;
317*eb293b8fSAndroid Build Coastguard Worker   }
318*eb293b8fSAndroid Build Coastguard Worker 
319*eb293b8fSAndroid Build Coastguard Worker   size_t bytes_left = size_ - static_cast<size_t>(addr);
320*eb293b8fSAndroid Build Coastguard Worker   const unsigned char* actual_base = static_cast<const unsigned char*>(data_) + addr;
321*eb293b8fSAndroid Build Coastguard Worker   size_t actual_len = std::min(bytes_left, size);
322*eb293b8fSAndroid Build Coastguard Worker 
323*eb293b8fSAndroid Build Coastguard Worker   memcpy(dst, actual_base, actual_len);
324*eb293b8fSAndroid Build Coastguard Worker   return actual_len;
325*eb293b8fSAndroid Build Coastguard Worker }
326*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)327*eb293b8fSAndroid Build Coastguard Worker size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
328*eb293b8fSAndroid Build Coastguard Worker #if !defined(__LP64__)
329*eb293b8fSAndroid Build Coastguard Worker   // Cannot read an address greater than 32 bits in a 32 bit context.
330*eb293b8fSAndroid Build Coastguard Worker   if (addr > UINT32_MAX) {
331*eb293b8fSAndroid Build Coastguard Worker     return 0;
332*eb293b8fSAndroid Build Coastguard Worker   }
333*eb293b8fSAndroid Build Coastguard Worker #endif
334*eb293b8fSAndroid Build Coastguard Worker 
335*eb293b8fSAndroid Build Coastguard Worker   size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
336*eb293b8fSAndroid Build Coastguard Worker       reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
337*eb293b8fSAndroid Build Coastguard Worker   if (read_func != nullptr) {
338*eb293b8fSAndroid Build Coastguard Worker     return read_func(pid_, addr, dst, size);
339*eb293b8fSAndroid Build Coastguard Worker   } else {
340*eb293b8fSAndroid Build Coastguard Worker     // Prefer process_vm_read, try it first. If it doesn't work, use the
341*eb293b8fSAndroid Build Coastguard Worker     // ptrace function. If at least one of them returns at least some data,
342*eb293b8fSAndroid Build Coastguard Worker     // set that as the permanent function to use.
343*eb293b8fSAndroid Build Coastguard Worker     // This assumes that if process_vm_read works once, it will continue
344*eb293b8fSAndroid Build Coastguard Worker     // to work.
345*eb293b8fSAndroid Build Coastguard Worker     size_t bytes = ProcessVmRead(pid_, addr, dst, size);
346*eb293b8fSAndroid Build Coastguard Worker     if (bytes > 0) {
347*eb293b8fSAndroid Build Coastguard Worker       read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
348*eb293b8fSAndroid Build Coastguard Worker       return bytes;
349*eb293b8fSAndroid Build Coastguard Worker     }
350*eb293b8fSAndroid Build Coastguard Worker     bytes = PtraceRead(pid_, addr, dst, size);
351*eb293b8fSAndroid Build Coastguard Worker     if (bytes > 0) {
352*eb293b8fSAndroid Build Coastguard Worker       read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
353*eb293b8fSAndroid Build Coastguard Worker     }
354*eb293b8fSAndroid Build Coastguard Worker     return bytes;
355*eb293b8fSAndroid Build Coastguard Worker   }
356*eb293b8fSAndroid Build Coastguard Worker }
357*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)358*eb293b8fSAndroid Build Coastguard Worker size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
359*eb293b8fSAndroid Build Coastguard Worker   return ProcessVmRead(getpid(), addr, dst, size);
360*eb293b8fSAndroid Build Coastguard Worker }
361*eb293b8fSAndroid Build Coastguard Worker 
MemoryRange(const std::shared_ptr<Memory> & memory,uint64_t begin,uint64_t length,uint64_t offset)362*eb293b8fSAndroid Build Coastguard Worker MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
363*eb293b8fSAndroid Build Coastguard Worker                          uint64_t offset)
364*eb293b8fSAndroid Build Coastguard Worker     : memory_(memory), begin_(begin), length_(length), offset_(offset) {}
365*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)366*eb293b8fSAndroid Build Coastguard Worker size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
367*eb293b8fSAndroid Build Coastguard Worker   if (addr < offset_) {
368*eb293b8fSAndroid Build Coastguard Worker     return 0;
369*eb293b8fSAndroid Build Coastguard Worker   }
370*eb293b8fSAndroid Build Coastguard Worker 
371*eb293b8fSAndroid Build Coastguard Worker   uint64_t read_offset = addr - offset_;
372*eb293b8fSAndroid Build Coastguard Worker   if (read_offset >= length_) {
373*eb293b8fSAndroid Build Coastguard Worker     return 0;
374*eb293b8fSAndroid Build Coastguard Worker   }
375*eb293b8fSAndroid Build Coastguard Worker 
376*eb293b8fSAndroid Build Coastguard Worker   uint64_t read_length = std::min(static_cast<uint64_t>(size), length_ - read_offset);
377*eb293b8fSAndroid Build Coastguard Worker   uint64_t read_addr;
378*eb293b8fSAndroid Build Coastguard Worker   if (__builtin_add_overflow(read_offset, begin_, &read_addr)) {
379*eb293b8fSAndroid Build Coastguard Worker     return 0;
380*eb293b8fSAndroid Build Coastguard Worker   }
381*eb293b8fSAndroid Build Coastguard Worker 
382*eb293b8fSAndroid Build Coastguard Worker   return memory_->Read(read_addr, dst, read_length);
383*eb293b8fSAndroid Build Coastguard Worker }
384*eb293b8fSAndroid Build Coastguard Worker 
Insert(MemoryRange * memory)385*eb293b8fSAndroid Build Coastguard Worker bool MemoryRanges::Insert(MemoryRange* memory) {
386*eb293b8fSAndroid Build Coastguard Worker   uint64_t last_addr;
387*eb293b8fSAndroid Build Coastguard Worker   if (__builtin_add_overflow(memory->offset(), memory->length(), &last_addr)) {
388*eb293b8fSAndroid Build Coastguard Worker     // This should never happen in the real world. However, it is possible
389*eb293b8fSAndroid Build Coastguard Worker     // that an offset in a mapped in segment could be crafted such that
390*eb293b8fSAndroid Build Coastguard Worker     // this value overflows. In that case, clamp the value to the max uint64
391*eb293b8fSAndroid Build Coastguard Worker     // value.
392*eb293b8fSAndroid Build Coastguard Worker     last_addr = UINT64_MAX;
393*eb293b8fSAndroid Build Coastguard Worker   }
394*eb293b8fSAndroid Build Coastguard Worker   auto entry = maps_.try_emplace(last_addr, memory);
395*eb293b8fSAndroid Build Coastguard Worker   if (entry.second) {
396*eb293b8fSAndroid Build Coastguard Worker     return true;
397*eb293b8fSAndroid Build Coastguard Worker   }
398*eb293b8fSAndroid Build Coastguard Worker   delete memory;
399*eb293b8fSAndroid Build Coastguard Worker   return false;
400*eb293b8fSAndroid Build Coastguard Worker }
401*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)402*eb293b8fSAndroid Build Coastguard Worker size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) {
403*eb293b8fSAndroid Build Coastguard Worker   auto entry = maps_.upper_bound(addr);
404*eb293b8fSAndroid Build Coastguard Worker   if (entry != maps_.end()) {
405*eb293b8fSAndroid Build Coastguard Worker     return entry->second->Read(addr, dst, size);
406*eb293b8fSAndroid Build Coastguard Worker   }
407*eb293b8fSAndroid Build Coastguard Worker   return 0;
408*eb293b8fSAndroid Build Coastguard Worker }
409*eb293b8fSAndroid Build Coastguard Worker 
Init(const std::string & file,uint64_t offset)410*eb293b8fSAndroid Build Coastguard Worker bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
411*eb293b8fSAndroid Build Coastguard Worker   auto memory_file = std::make_shared<MemoryFileAtOffset>();
412*eb293b8fSAndroid Build Coastguard Worker   if (!memory_file->Init(file, offset)) {
413*eb293b8fSAndroid Build Coastguard Worker     return false;
414*eb293b8fSAndroid Build Coastguard Worker   }
415*eb293b8fSAndroid Build Coastguard Worker 
416*eb293b8fSAndroid Build Coastguard Worker   // The first uint64_t value is the start of memory.
417*eb293b8fSAndroid Build Coastguard Worker   uint64_t start;
418*eb293b8fSAndroid Build Coastguard Worker   if (!memory_file->ReadFully(0, &start, sizeof(start))) {
419*eb293b8fSAndroid Build Coastguard Worker     return false;
420*eb293b8fSAndroid Build Coastguard Worker   }
421*eb293b8fSAndroid Build Coastguard Worker 
422*eb293b8fSAndroid Build Coastguard Worker   uint64_t size = memory_file->Size();
423*eb293b8fSAndroid Build Coastguard Worker   if (__builtin_sub_overflow(size, sizeof(start), &size)) {
424*eb293b8fSAndroid Build Coastguard Worker     return false;
425*eb293b8fSAndroid Build Coastguard Worker   }
426*eb293b8fSAndroid Build Coastguard Worker 
427*eb293b8fSAndroid Build Coastguard Worker   memory_ = std::make_unique<MemoryRange>(memory_file, sizeof(start), size, start);
428*eb293b8fSAndroid Build Coastguard Worker   return true;
429*eb293b8fSAndroid Build Coastguard Worker }
430*eb293b8fSAndroid Build Coastguard Worker 
Init(const std::string & file,uint64_t offset,uint64_t start,uint64_t size)431*eb293b8fSAndroid Build Coastguard Worker bool MemoryOffline::Init(const std::string& file, uint64_t offset, uint64_t start, uint64_t size) {
432*eb293b8fSAndroid Build Coastguard Worker   auto memory_file = std::make_shared<MemoryFileAtOffset>();
433*eb293b8fSAndroid Build Coastguard Worker   if (!memory_file->Init(file, offset)) {
434*eb293b8fSAndroid Build Coastguard Worker     return false;
435*eb293b8fSAndroid Build Coastguard Worker   }
436*eb293b8fSAndroid Build Coastguard Worker 
437*eb293b8fSAndroid Build Coastguard Worker   memory_ = std::make_unique<MemoryRange>(memory_file, 0, size, start);
438*eb293b8fSAndroid Build Coastguard Worker   return true;
439*eb293b8fSAndroid Build Coastguard Worker }
440*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)441*eb293b8fSAndroid Build Coastguard Worker size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
442*eb293b8fSAndroid Build Coastguard Worker   if (!memory_) {
443*eb293b8fSAndroid Build Coastguard Worker     return 0;
444*eb293b8fSAndroid Build Coastguard Worker   }
445*eb293b8fSAndroid Build Coastguard Worker 
446*eb293b8fSAndroid Build Coastguard Worker   return memory_->Read(addr, dst, size);
447*eb293b8fSAndroid Build Coastguard Worker }
448*eb293b8fSAndroid Build Coastguard Worker 
MemoryOfflineBuffer(const uint8_t * data,uint64_t start,uint64_t end)449*eb293b8fSAndroid Build Coastguard Worker MemoryOfflineBuffer::MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end)
450*eb293b8fSAndroid Build Coastguard Worker     : data_(data), start_(start), end_(end) {}
451*eb293b8fSAndroid Build Coastguard Worker 
Reset(const uint8_t * data,uint64_t start,uint64_t end)452*eb293b8fSAndroid Build Coastguard Worker void MemoryOfflineBuffer::Reset(const uint8_t* data, uint64_t start, uint64_t end) {
453*eb293b8fSAndroid Build Coastguard Worker   data_ = data;
454*eb293b8fSAndroid Build Coastguard Worker   start_ = start;
455*eb293b8fSAndroid Build Coastguard Worker   end_ = end;
456*eb293b8fSAndroid Build Coastguard Worker }
457*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)458*eb293b8fSAndroid Build Coastguard Worker size_t MemoryOfflineBuffer::Read(uint64_t addr, void* dst, size_t size) {
459*eb293b8fSAndroid Build Coastguard Worker   if (addr < start_ || addr >= end_) {
460*eb293b8fSAndroid Build Coastguard Worker     return 0;
461*eb293b8fSAndroid Build Coastguard Worker   }
462*eb293b8fSAndroid Build Coastguard Worker 
463*eb293b8fSAndroid Build Coastguard Worker   size_t read_length = std::min(size, static_cast<size_t>(end_ - addr));
464*eb293b8fSAndroid Build Coastguard Worker   memcpy(dst, &data_[addr - start_], read_length);
465*eb293b8fSAndroid Build Coastguard Worker   return read_length;
466*eb293b8fSAndroid Build Coastguard Worker }
467*eb293b8fSAndroid Build Coastguard Worker 
~MemoryOfflineParts()468*eb293b8fSAndroid Build Coastguard Worker MemoryOfflineParts::~MemoryOfflineParts() {
469*eb293b8fSAndroid Build Coastguard Worker   for (auto memory : memories_) {
470*eb293b8fSAndroid Build Coastguard Worker     delete memory;
471*eb293b8fSAndroid Build Coastguard Worker   }
472*eb293b8fSAndroid Build Coastguard Worker }
473*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)474*eb293b8fSAndroid Build Coastguard Worker size_t MemoryOfflineParts::Read(uint64_t addr, void* dst, size_t size) {
475*eb293b8fSAndroid Build Coastguard Worker   if (memories_.empty()) {
476*eb293b8fSAndroid Build Coastguard Worker     return 0;
477*eb293b8fSAndroid Build Coastguard Worker   }
478*eb293b8fSAndroid Build Coastguard Worker 
479*eb293b8fSAndroid Build Coastguard Worker   // Do a read on each memory object, no support for reading across the
480*eb293b8fSAndroid Build Coastguard Worker   // different memory objects.
481*eb293b8fSAndroid Build Coastguard Worker   for (MemoryOffline* memory : memories_) {
482*eb293b8fSAndroid Build Coastguard Worker     size_t bytes = memory->Read(addr, dst, size);
483*eb293b8fSAndroid Build Coastguard Worker     if (bytes != 0) {
484*eb293b8fSAndroid Build Coastguard Worker       return bytes;
485*eb293b8fSAndroid Build Coastguard Worker     }
486*eb293b8fSAndroid Build Coastguard Worker   }
487*eb293b8fSAndroid Build Coastguard Worker   return 0;
488*eb293b8fSAndroid Build Coastguard Worker }
489*eb293b8fSAndroid Build Coastguard Worker 
InternalCachedRead(uint64_t addr,void * dst,size_t size,CacheDataType * cache)490*eb293b8fSAndroid Build Coastguard Worker size_t MemoryCacheBase::InternalCachedRead(uint64_t addr, void* dst, size_t size,
491*eb293b8fSAndroid Build Coastguard Worker                                            CacheDataType* cache) {
492*eb293b8fSAndroid Build Coastguard Worker   uint64_t addr_page = addr >> kCacheBits;
493*eb293b8fSAndroid Build Coastguard Worker   auto entry = cache->find(addr_page);
494*eb293b8fSAndroid Build Coastguard Worker   uint8_t* cache_dst;
495*eb293b8fSAndroid Build Coastguard Worker   if (entry != cache->end()) {
496*eb293b8fSAndroid Build Coastguard Worker     cache_dst = entry->second;
497*eb293b8fSAndroid Build Coastguard Worker   } else {
498*eb293b8fSAndroid Build Coastguard Worker     cache_dst = (*cache)[addr_page];
499*eb293b8fSAndroid Build Coastguard Worker     if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
500*eb293b8fSAndroid Build Coastguard Worker       // Erase the entry.
501*eb293b8fSAndroid Build Coastguard Worker       cache->erase(addr_page);
502*eb293b8fSAndroid Build Coastguard Worker       return impl_->Read(addr, dst, size);
503*eb293b8fSAndroid Build Coastguard Worker     }
504*eb293b8fSAndroid Build Coastguard Worker   }
505*eb293b8fSAndroid Build Coastguard Worker   size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
506*eb293b8fSAndroid Build Coastguard Worker   if (size <= max_read) {
507*eb293b8fSAndroid Build Coastguard Worker     memcpy(dst, &cache_dst[addr & kCacheMask], size);
508*eb293b8fSAndroid Build Coastguard Worker     return size;
509*eb293b8fSAndroid Build Coastguard Worker   }
510*eb293b8fSAndroid Build Coastguard Worker 
511*eb293b8fSAndroid Build Coastguard Worker   // The read crossed into another cached entry, since a read can only cross
512*eb293b8fSAndroid Build Coastguard Worker   // into one extra cached page, duplicate the code rather than looping.
513*eb293b8fSAndroid Build Coastguard Worker   memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
514*eb293b8fSAndroid Build Coastguard Worker   dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
515*eb293b8fSAndroid Build Coastguard Worker   addr_page++;
516*eb293b8fSAndroid Build Coastguard Worker 
517*eb293b8fSAndroid Build Coastguard Worker   entry = cache->find(addr_page);
518*eb293b8fSAndroid Build Coastguard Worker   if (entry != cache->end()) {
519*eb293b8fSAndroid Build Coastguard Worker     cache_dst = entry->second;
520*eb293b8fSAndroid Build Coastguard Worker   } else {
521*eb293b8fSAndroid Build Coastguard Worker     cache_dst = (*cache)[addr_page];
522*eb293b8fSAndroid Build Coastguard Worker     if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
523*eb293b8fSAndroid Build Coastguard Worker       // Erase the entry.
524*eb293b8fSAndroid Build Coastguard Worker       cache->erase(addr_page);
525*eb293b8fSAndroid Build Coastguard Worker       return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
526*eb293b8fSAndroid Build Coastguard Worker     }
527*eb293b8fSAndroid Build Coastguard Worker   }
528*eb293b8fSAndroid Build Coastguard Worker   memcpy(dst, cache_dst, size - max_read);
529*eb293b8fSAndroid Build Coastguard Worker   return size;
530*eb293b8fSAndroid Build Coastguard Worker }
531*eb293b8fSAndroid Build Coastguard Worker 
Clear()532*eb293b8fSAndroid Build Coastguard Worker void MemoryCache::Clear() {
533*eb293b8fSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(cache_lock_);
534*eb293b8fSAndroid Build Coastguard Worker   cache_.clear();
535*eb293b8fSAndroid Build Coastguard Worker }
536*eb293b8fSAndroid Build Coastguard Worker 
CachedRead(uint64_t addr,void * dst,size_t size)537*eb293b8fSAndroid Build Coastguard Worker size_t MemoryCache::CachedRead(uint64_t addr, void* dst, size_t size) {
538*eb293b8fSAndroid Build Coastguard Worker   // Use a single lock since this object is not designed to be performant
539*eb293b8fSAndroid Build Coastguard Worker   // for multiple object reading from multiple threads.
540*eb293b8fSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(cache_lock_);
541*eb293b8fSAndroid Build Coastguard Worker 
542*eb293b8fSAndroid Build Coastguard Worker   return InternalCachedRead(addr, dst, size, &cache_);
543*eb293b8fSAndroid Build Coastguard Worker }
544*eb293b8fSAndroid Build Coastguard Worker 
MemoryThreadCache(Memory * memory)545*eb293b8fSAndroid Build Coastguard Worker MemoryThreadCache::MemoryThreadCache(Memory* memory) : MemoryCacheBase(memory) {
546*eb293b8fSAndroid Build Coastguard Worker   thread_cache_ = std::make_optional<pthread_t>();
547*eb293b8fSAndroid Build Coastguard Worker   if (pthread_key_create(&*thread_cache_, [](void* memory) {
548*eb293b8fSAndroid Build Coastguard Worker         CacheDataType* cache = reinterpret_cast<CacheDataType*>(memory);
549*eb293b8fSAndroid Build Coastguard Worker         delete cache;
550*eb293b8fSAndroid Build Coastguard Worker       }) != 0) {
551*eb293b8fSAndroid Build Coastguard Worker     Log::AsyncSafe("Failed to create pthread key.");
552*eb293b8fSAndroid Build Coastguard Worker     thread_cache_.reset();
553*eb293b8fSAndroid Build Coastguard Worker   }
554*eb293b8fSAndroid Build Coastguard Worker }
555*eb293b8fSAndroid Build Coastguard Worker 
~MemoryThreadCache()556*eb293b8fSAndroid Build Coastguard Worker MemoryThreadCache::~MemoryThreadCache() {
557*eb293b8fSAndroid Build Coastguard Worker   if (thread_cache_) {
558*eb293b8fSAndroid Build Coastguard Worker     CacheDataType* cache = reinterpret_cast<CacheDataType*>(pthread_getspecific(*thread_cache_));
559*eb293b8fSAndroid Build Coastguard Worker     delete cache;
560*eb293b8fSAndroid Build Coastguard Worker     pthread_key_delete(*thread_cache_);
561*eb293b8fSAndroid Build Coastguard Worker   }
562*eb293b8fSAndroid Build Coastguard Worker }
563*eb293b8fSAndroid Build Coastguard Worker 
CachedRead(uint64_t addr,void * dst,size_t size)564*eb293b8fSAndroid Build Coastguard Worker size_t MemoryThreadCache::CachedRead(uint64_t addr, void* dst, size_t size) {
565*eb293b8fSAndroid Build Coastguard Worker   if (!thread_cache_) {
566*eb293b8fSAndroid Build Coastguard Worker     return impl_->Read(addr, dst, size);
567*eb293b8fSAndroid Build Coastguard Worker   }
568*eb293b8fSAndroid Build Coastguard Worker 
569*eb293b8fSAndroid Build Coastguard Worker   CacheDataType* cache = reinterpret_cast<CacheDataType*>(pthread_getspecific(*thread_cache_));
570*eb293b8fSAndroid Build Coastguard Worker   if (cache == nullptr) {
571*eb293b8fSAndroid Build Coastguard Worker     cache = new CacheDataType;
572*eb293b8fSAndroid Build Coastguard Worker     pthread_setspecific(*thread_cache_, cache);
573*eb293b8fSAndroid Build Coastguard Worker   }
574*eb293b8fSAndroid Build Coastguard Worker 
575*eb293b8fSAndroid Build Coastguard Worker   return InternalCachedRead(addr, dst, size, cache);
576*eb293b8fSAndroid Build Coastguard Worker }
577*eb293b8fSAndroid Build Coastguard Worker 
Clear()578*eb293b8fSAndroid Build Coastguard Worker void MemoryThreadCache::Clear() {
579*eb293b8fSAndroid Build Coastguard Worker   if (!thread_cache_) {
580*eb293b8fSAndroid Build Coastguard Worker     return;
581*eb293b8fSAndroid Build Coastguard Worker   }
582*eb293b8fSAndroid Build Coastguard Worker 
583*eb293b8fSAndroid Build Coastguard Worker   CacheDataType* cache = reinterpret_cast<CacheDataType*>(pthread_getspecific(*thread_cache_));
584*eb293b8fSAndroid Build Coastguard Worker   if (cache != nullptr) {
585*eb293b8fSAndroid Build Coastguard Worker     delete cache;
586*eb293b8fSAndroid Build Coastguard Worker     pthread_setspecific(*thread_cache_, nullptr);
587*eb293b8fSAndroid Build Coastguard Worker   }
588*eb293b8fSAndroid Build Coastguard Worker }
589*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * dst,size_t size)590*eb293b8fSAndroid Build Coastguard Worker size_t MemoryLocalUnsafe::Read(uint64_t addr, void* dst, size_t size) {
591*eb293b8fSAndroid Build Coastguard Worker   void* raw_ptr = reinterpret_cast<void*>(addr);
592*eb293b8fSAndroid Build Coastguard Worker   memcpy(dst, raw_ptr, size);
593*eb293b8fSAndroid Build Coastguard Worker   return size;
594*eb293b8fSAndroid Build Coastguard Worker }
595*eb293b8fSAndroid Build Coastguard Worker 
596*eb293b8fSAndroid Build Coastguard Worker }  // namespace unwindstack
597