xref: /openbsd-src/gnu/llvm/lldb/source/Expression/IRMemoryMap.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- IRMemoryMap.cpp ---------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Expression/IRMemoryMap.h"
10061da546Spatrick #include "lldb/Target/MemoryRegionInfo.h"
11061da546Spatrick #include "lldb/Target/Process.h"
12061da546Spatrick #include "lldb/Target/Target.h"
13061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
14061da546Spatrick #include "lldb/Utility/DataExtractor.h"
15061da546Spatrick #include "lldb/Utility/LLDBAssert.h"
16*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
17061da546Spatrick #include "lldb/Utility/Log.h"
18061da546Spatrick #include "lldb/Utility/Scalar.h"
19061da546Spatrick #include "lldb/Utility/Status.h"
20061da546Spatrick 
21061da546Spatrick using namespace lldb_private;
22061da546Spatrick 
IRMemoryMap(lldb::TargetSP target_sp)23061da546Spatrick IRMemoryMap::IRMemoryMap(lldb::TargetSP target_sp) : m_target_wp(target_sp) {
24061da546Spatrick   if (target_sp)
25061da546Spatrick     m_process_wp = target_sp->GetProcessSP();
26061da546Spatrick }
27061da546Spatrick 
~IRMemoryMap()28061da546Spatrick IRMemoryMap::~IRMemoryMap() {
29061da546Spatrick   lldb::ProcessSP process_sp = m_process_wp.lock();
30061da546Spatrick 
31061da546Spatrick   if (process_sp) {
32061da546Spatrick     AllocationMap::iterator iter;
33061da546Spatrick 
34061da546Spatrick     Status err;
35061da546Spatrick 
36061da546Spatrick     while ((iter = m_allocations.begin()) != m_allocations.end()) {
37061da546Spatrick       err.Clear();
38061da546Spatrick       if (iter->second.m_leak)
39061da546Spatrick         m_allocations.erase(iter);
40061da546Spatrick       else
41061da546Spatrick         Free(iter->first, err);
42061da546Spatrick     }
43061da546Spatrick   }
44061da546Spatrick }
45061da546Spatrick 
FindSpace(size_t size)46061da546Spatrick lldb::addr_t IRMemoryMap::FindSpace(size_t size) {
47061da546Spatrick   // The FindSpace algorithm's job is to find a region of memory that the
48061da546Spatrick   // underlying process is unlikely to be using.
49061da546Spatrick   //
50061da546Spatrick   // The memory returned by this function will never be written to.  The only
51061da546Spatrick   // point is that it should not shadow process memory if possible, so that
52061da546Spatrick   // expressions processing real values from the process do not use the wrong
53061da546Spatrick   // data.
54061da546Spatrick   //
55061da546Spatrick   // If the process can in fact allocate memory (CanJIT() lets us know this)
56061da546Spatrick   // then this can be accomplished just be allocating memory in the inferior.
57061da546Spatrick   // Then no guessing is required.
58061da546Spatrick 
59061da546Spatrick   lldb::TargetSP target_sp = m_target_wp.lock();
60061da546Spatrick   lldb::ProcessSP process_sp = m_process_wp.lock();
61061da546Spatrick 
62061da546Spatrick   const bool process_is_alive = process_sp && process_sp->IsAlive();
63061da546Spatrick 
64061da546Spatrick   lldb::addr_t ret = LLDB_INVALID_ADDRESS;
65061da546Spatrick   if (size == 0)
66061da546Spatrick     return ret;
67061da546Spatrick 
68061da546Spatrick   if (process_is_alive && process_sp->CanJIT()) {
69061da546Spatrick     Status alloc_error;
70061da546Spatrick 
71061da546Spatrick     ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable |
72061da546Spatrick                                                lldb::ePermissionsWritable,
73061da546Spatrick                                      alloc_error);
74061da546Spatrick 
75061da546Spatrick     if (!alloc_error.Success())
76061da546Spatrick       return LLDB_INVALID_ADDRESS;
77061da546Spatrick     else
78061da546Spatrick       return ret;
79061da546Spatrick   }
80061da546Spatrick 
81061da546Spatrick   // At this point we know that we need to hunt.
82061da546Spatrick   //
83061da546Spatrick   // First, go to the end of the existing allocations we've made if there are
84061da546Spatrick   // any allocations.  Otherwise start at the beginning of memory.
85061da546Spatrick 
86061da546Spatrick   if (m_allocations.empty()) {
87061da546Spatrick     ret = 0x0;
88061da546Spatrick   } else {
89061da546Spatrick     auto back = m_allocations.rbegin();
90061da546Spatrick     lldb::addr_t addr = back->first;
91061da546Spatrick     size_t alloc_size = back->second.m_size;
92061da546Spatrick     ret = llvm::alignTo(addr + alloc_size, 4096);
93061da546Spatrick   }
94061da546Spatrick 
95061da546Spatrick   // Now, if it's possible to use the GetMemoryRegionInfo API to detect mapped
96061da546Spatrick   // regions, walk forward through memory until a region is found that has
97061da546Spatrick   // adequate space for our allocation.
98061da546Spatrick   if (process_is_alive) {
99061da546Spatrick     const uint64_t end_of_memory = process_sp->GetAddressByteSize() == 8
100061da546Spatrick                                        ? 0xffffffffffffffffull
101061da546Spatrick                                        : 0xffffffffull;
102061da546Spatrick 
103061da546Spatrick     lldbassert(process_sp->GetAddressByteSize() == 4 ||
104061da546Spatrick                end_of_memory != 0xffffffffull);
105061da546Spatrick 
106061da546Spatrick     MemoryRegionInfo region_info;
107061da546Spatrick     Status err = process_sp->GetMemoryRegionInfo(ret, region_info);
108061da546Spatrick     if (err.Success()) {
109061da546Spatrick       while (true) {
110061da546Spatrick         if (region_info.GetReadable() != MemoryRegionInfo::OptionalBool::eNo ||
111061da546Spatrick             region_info.GetWritable() != MemoryRegionInfo::OptionalBool::eNo ||
112061da546Spatrick             region_info.GetExecutable() !=
113061da546Spatrick                 MemoryRegionInfo::OptionalBool::eNo) {
114061da546Spatrick           if (region_info.GetRange().GetRangeEnd() - 1 >= end_of_memory) {
115061da546Spatrick             ret = LLDB_INVALID_ADDRESS;
116061da546Spatrick             break;
117061da546Spatrick           } else {
118061da546Spatrick             ret = region_info.GetRange().GetRangeEnd();
119061da546Spatrick           }
120061da546Spatrick         } else if (ret + size < region_info.GetRange().GetRangeEnd()) {
121061da546Spatrick           return ret;
122061da546Spatrick         } else {
123061da546Spatrick           // ret stays the same.  We just need to walk a bit further.
124061da546Spatrick         }
125061da546Spatrick 
126061da546Spatrick         err = process_sp->GetMemoryRegionInfo(
127061da546Spatrick             region_info.GetRange().GetRangeEnd(), region_info);
128061da546Spatrick         if (err.Fail()) {
129061da546Spatrick           lldbassert(0 && "GetMemoryRegionInfo() succeeded, then failed");
130061da546Spatrick           ret = LLDB_INVALID_ADDRESS;
131061da546Spatrick           break;
132061da546Spatrick         }
133061da546Spatrick       }
134061da546Spatrick     }
135061da546Spatrick   }
136061da546Spatrick 
137061da546Spatrick   // We've tried our algorithm, and it didn't work.  Now we have to reset back
138061da546Spatrick   // to the end of the allocations we've already reported, or use a 'sensible'
139061da546Spatrick   // default if this is our first allocation.
140061da546Spatrick 
141061da546Spatrick   if (m_allocations.empty()) {
142061da546Spatrick     uint32_t address_byte_size = GetAddressByteSize();
143061da546Spatrick     if (address_byte_size != UINT32_MAX) {
144061da546Spatrick       switch (address_byte_size) {
145061da546Spatrick       case 8:
146*f6aab3d8Srobert         ret = 0xdead0fff00000000ull;
147061da546Spatrick         break;
148061da546Spatrick       case 4:
149061da546Spatrick         ret = 0xee000000ull;
150061da546Spatrick         break;
151061da546Spatrick       default:
152061da546Spatrick         break;
153061da546Spatrick       }
154061da546Spatrick     }
155061da546Spatrick   } else {
156061da546Spatrick     auto back = m_allocations.rbegin();
157061da546Spatrick     lldb::addr_t addr = back->first;
158061da546Spatrick     size_t alloc_size = back->second.m_size;
159061da546Spatrick     ret = llvm::alignTo(addr + alloc_size, 4096);
160061da546Spatrick   }
161061da546Spatrick 
162061da546Spatrick   return ret;
163061da546Spatrick }
164061da546Spatrick 
165061da546Spatrick IRMemoryMap::AllocationMap::iterator
FindAllocation(lldb::addr_t addr,size_t size)166061da546Spatrick IRMemoryMap::FindAllocation(lldb::addr_t addr, size_t size) {
167061da546Spatrick   if (addr == LLDB_INVALID_ADDRESS)
168061da546Spatrick     return m_allocations.end();
169061da546Spatrick 
170061da546Spatrick   AllocationMap::iterator iter = m_allocations.lower_bound(addr);
171061da546Spatrick 
172061da546Spatrick   if (iter == m_allocations.end() || iter->first > addr) {
173061da546Spatrick     if (iter == m_allocations.begin())
174061da546Spatrick       return m_allocations.end();
175061da546Spatrick     iter--;
176061da546Spatrick   }
177061da546Spatrick 
178061da546Spatrick   if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size)
179061da546Spatrick     return iter;
180061da546Spatrick 
181061da546Spatrick   return m_allocations.end();
182061da546Spatrick }
183061da546Spatrick 
IntersectsAllocation(lldb::addr_t addr,size_t size) const184061da546Spatrick bool IRMemoryMap::IntersectsAllocation(lldb::addr_t addr, size_t size) const {
185061da546Spatrick   if (addr == LLDB_INVALID_ADDRESS)
186061da546Spatrick     return false;
187061da546Spatrick 
188061da546Spatrick   AllocationMap::const_iterator iter = m_allocations.lower_bound(addr);
189061da546Spatrick 
190061da546Spatrick   // Since we only know that the returned interval begins at a location greater
191061da546Spatrick   // than or equal to where the given interval begins, it's possible that the
192061da546Spatrick   // given interval intersects either the returned interval or the previous
193061da546Spatrick   // interval.  Thus, we need to check both. Note that we only need to check
194061da546Spatrick   // these two intervals.  Since all intervals are disjoint it is not possible
195061da546Spatrick   // that an adjacent interval does not intersect, but a non-adjacent interval
196061da546Spatrick   // does intersect.
197061da546Spatrick   if (iter != m_allocations.end()) {
198061da546Spatrick     if (AllocationsIntersect(addr, size, iter->second.m_process_start,
199061da546Spatrick                              iter->second.m_size))
200061da546Spatrick       return true;
201061da546Spatrick   }
202061da546Spatrick 
203061da546Spatrick   if (iter != m_allocations.begin()) {
204061da546Spatrick     --iter;
205061da546Spatrick     if (AllocationsIntersect(addr, size, iter->second.m_process_start,
206061da546Spatrick                              iter->second.m_size))
207061da546Spatrick       return true;
208061da546Spatrick   }
209061da546Spatrick 
210061da546Spatrick   return false;
211061da546Spatrick }
212061da546Spatrick 
AllocationsIntersect(lldb::addr_t addr1,size_t size1,lldb::addr_t addr2,size_t size2)213061da546Spatrick bool IRMemoryMap::AllocationsIntersect(lldb::addr_t addr1, size_t size1,
214061da546Spatrick                                        lldb::addr_t addr2, size_t size2) {
215061da546Spatrick   // Given two half open intervals [A, B) and [X, Y), the only 6 permutations
216061da546Spatrick   // that satisfy A<B and X<Y are the following:
217061da546Spatrick   // A B X Y
218061da546Spatrick   // A X B Y  (intersects)
219061da546Spatrick   // A X Y B  (intersects)
220061da546Spatrick   // X A B Y  (intersects)
221061da546Spatrick   // X A Y B  (intersects)
222061da546Spatrick   // X Y A B
223061da546Spatrick   // The first is B <= X, and the last is Y <= A. So the condition is !(B <= X
224061da546Spatrick   // || Y <= A)), or (X < B && A < Y)
225061da546Spatrick   return (addr2 < (addr1 + size1)) && (addr1 < (addr2 + size2));
226061da546Spatrick }
227061da546Spatrick 
GetByteOrder()228061da546Spatrick lldb::ByteOrder IRMemoryMap::GetByteOrder() {
229061da546Spatrick   lldb::ProcessSP process_sp = m_process_wp.lock();
230061da546Spatrick 
231061da546Spatrick   if (process_sp)
232061da546Spatrick     return process_sp->GetByteOrder();
233061da546Spatrick 
234061da546Spatrick   lldb::TargetSP target_sp = m_target_wp.lock();
235061da546Spatrick 
236061da546Spatrick   if (target_sp)
237061da546Spatrick     return target_sp->GetArchitecture().GetByteOrder();
238061da546Spatrick 
239061da546Spatrick   return lldb::eByteOrderInvalid;
240061da546Spatrick }
241061da546Spatrick 
GetAddressByteSize()242061da546Spatrick uint32_t IRMemoryMap::GetAddressByteSize() {
243061da546Spatrick   lldb::ProcessSP process_sp = m_process_wp.lock();
244061da546Spatrick 
245061da546Spatrick   if (process_sp)
246061da546Spatrick     return process_sp->GetAddressByteSize();
247061da546Spatrick 
248061da546Spatrick   lldb::TargetSP target_sp = m_target_wp.lock();
249061da546Spatrick 
250061da546Spatrick   if (target_sp)
251061da546Spatrick     return target_sp->GetArchitecture().GetAddressByteSize();
252061da546Spatrick 
253061da546Spatrick   return UINT32_MAX;
254061da546Spatrick }
255061da546Spatrick 
GetBestExecutionContextScope() const256061da546Spatrick ExecutionContextScope *IRMemoryMap::GetBestExecutionContextScope() const {
257061da546Spatrick   lldb::ProcessSP process_sp = m_process_wp.lock();
258061da546Spatrick 
259061da546Spatrick   if (process_sp)
260061da546Spatrick     return process_sp.get();
261061da546Spatrick 
262061da546Spatrick   lldb::TargetSP target_sp = m_target_wp.lock();
263061da546Spatrick 
264061da546Spatrick   if (target_sp)
265061da546Spatrick     return target_sp.get();
266061da546Spatrick 
267061da546Spatrick   return nullptr;
268061da546Spatrick }
269061da546Spatrick 
Allocation(lldb::addr_t process_alloc,lldb::addr_t process_start,size_t size,uint32_t permissions,uint8_t alignment,AllocationPolicy policy)270061da546Spatrick IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc,
271061da546Spatrick                                     lldb::addr_t process_start, size_t size,
272061da546Spatrick                                     uint32_t permissions, uint8_t alignment,
273061da546Spatrick                                     AllocationPolicy policy)
274061da546Spatrick     : m_process_alloc(process_alloc), m_process_start(process_start),
275061da546Spatrick       m_size(size), m_policy(policy), m_leak(false), m_permissions(permissions),
276061da546Spatrick       m_alignment(alignment) {
277061da546Spatrick   switch (policy) {
278061da546Spatrick   default:
279061da546Spatrick     llvm_unreachable("Invalid AllocationPolicy");
280061da546Spatrick   case eAllocationPolicyHostOnly:
281061da546Spatrick   case eAllocationPolicyMirror:
282061da546Spatrick     m_data.SetByteSize(size);
283061da546Spatrick     break;
284061da546Spatrick   case eAllocationPolicyProcessOnly:
285061da546Spatrick     break;
286061da546Spatrick   }
287061da546Spatrick }
288061da546Spatrick 
Malloc(size_t size,uint8_t alignment,uint32_t permissions,AllocationPolicy policy,bool zero_memory,Status & error)289061da546Spatrick lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
290061da546Spatrick                                  uint32_t permissions, AllocationPolicy policy,
291061da546Spatrick                                  bool zero_memory, Status &error) {
292*f6aab3d8Srobert   lldb_private::Log *log(GetLog(LLDBLog::Expressions));
293061da546Spatrick   error.Clear();
294061da546Spatrick 
295061da546Spatrick   lldb::ProcessSP process_sp;
296061da546Spatrick   lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
297061da546Spatrick   lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
298061da546Spatrick 
299061da546Spatrick   size_t allocation_size;
300061da546Spatrick 
301061da546Spatrick   if (size == 0) {
302061da546Spatrick     // FIXME: Malloc(0) should either return an invalid address or assert, in
303061da546Spatrick     // order to cut down on unnecessary allocations.
304061da546Spatrick     allocation_size = alignment;
305061da546Spatrick   } else {
306061da546Spatrick     // Round up the requested size to an aligned value.
307061da546Spatrick     allocation_size = llvm::alignTo(size, alignment);
308061da546Spatrick 
309061da546Spatrick     // The process page cache does not see the requested alignment. We can't
310061da546Spatrick     // assume its result will be any more than 1-byte aligned. To work around
311061da546Spatrick     // this, request `alignment - 1` additional bytes.
312061da546Spatrick     allocation_size += alignment - 1;
313061da546Spatrick   }
314061da546Spatrick 
315061da546Spatrick   switch (policy) {
316061da546Spatrick   default:
317061da546Spatrick     error.SetErrorToGenericError();
318061da546Spatrick     error.SetErrorString("Couldn't malloc: invalid allocation policy");
319061da546Spatrick     return LLDB_INVALID_ADDRESS;
320061da546Spatrick   case eAllocationPolicyHostOnly:
321061da546Spatrick     allocation_address = FindSpace(allocation_size);
322061da546Spatrick     if (allocation_address == LLDB_INVALID_ADDRESS) {
323061da546Spatrick       error.SetErrorToGenericError();
324061da546Spatrick       error.SetErrorString("Couldn't malloc: address space is full");
325061da546Spatrick       return LLDB_INVALID_ADDRESS;
326061da546Spatrick     }
327061da546Spatrick     break;
328061da546Spatrick   case eAllocationPolicyMirror:
329061da546Spatrick     process_sp = m_process_wp.lock();
330061da546Spatrick     LLDB_LOGF(log,
331061da546Spatrick               "IRMemoryMap::%s process_sp=0x%" PRIxPTR
332061da546Spatrick               ", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s",
333061da546Spatrick               __FUNCTION__, reinterpret_cast<uintptr_t>(process_sp.get()),
334061da546Spatrick               process_sp && process_sp->CanJIT() ? "true" : "false",
335061da546Spatrick               process_sp && process_sp->IsAlive() ? "true" : "false");
336061da546Spatrick     if (process_sp && process_sp->CanJIT() && process_sp->IsAlive()) {
337061da546Spatrick       if (!zero_memory)
338061da546Spatrick         allocation_address =
339061da546Spatrick             process_sp->AllocateMemory(allocation_size, permissions, error);
340061da546Spatrick       else
341061da546Spatrick         allocation_address =
342061da546Spatrick             process_sp->CallocateMemory(allocation_size, permissions, error);
343061da546Spatrick 
344061da546Spatrick       if (!error.Success())
345061da546Spatrick         return LLDB_INVALID_ADDRESS;
346061da546Spatrick     } else {
347061da546Spatrick       LLDB_LOGF(log,
348061da546Spatrick                 "IRMemoryMap::%s switching to eAllocationPolicyHostOnly "
349061da546Spatrick                 "due to failed condition (see previous expr log message)",
350061da546Spatrick                 __FUNCTION__);
351061da546Spatrick       policy = eAllocationPolicyHostOnly;
352061da546Spatrick       allocation_address = FindSpace(allocation_size);
353061da546Spatrick       if (allocation_address == LLDB_INVALID_ADDRESS) {
354061da546Spatrick         error.SetErrorToGenericError();
355061da546Spatrick         error.SetErrorString("Couldn't malloc: address space is full");
356061da546Spatrick         return LLDB_INVALID_ADDRESS;
357061da546Spatrick       }
358061da546Spatrick     }
359061da546Spatrick     break;
360061da546Spatrick   case eAllocationPolicyProcessOnly:
361061da546Spatrick     process_sp = m_process_wp.lock();
362061da546Spatrick     if (process_sp) {
363061da546Spatrick       if (process_sp->CanJIT() && process_sp->IsAlive()) {
364061da546Spatrick         if (!zero_memory)
365061da546Spatrick           allocation_address =
366061da546Spatrick               process_sp->AllocateMemory(allocation_size, permissions, error);
367061da546Spatrick         else
368061da546Spatrick           allocation_address =
369061da546Spatrick               process_sp->CallocateMemory(allocation_size, permissions, error);
370061da546Spatrick 
371061da546Spatrick         if (!error.Success())
372061da546Spatrick           return LLDB_INVALID_ADDRESS;
373061da546Spatrick       } else {
374061da546Spatrick         error.SetErrorToGenericError();
375061da546Spatrick         error.SetErrorString(
376061da546Spatrick             "Couldn't malloc: process doesn't support allocating memory");
377061da546Spatrick         return LLDB_INVALID_ADDRESS;
378061da546Spatrick       }
379061da546Spatrick     } else {
380061da546Spatrick       error.SetErrorToGenericError();
381061da546Spatrick       error.SetErrorString("Couldn't malloc: process doesn't exist, and this "
382061da546Spatrick                            "memory must be in the process");
383061da546Spatrick       return LLDB_INVALID_ADDRESS;
384061da546Spatrick     }
385061da546Spatrick     break;
386061da546Spatrick   }
387061da546Spatrick 
388061da546Spatrick   lldb::addr_t mask = alignment - 1;
389061da546Spatrick   aligned_address = (allocation_address + mask) & (~mask);
390061da546Spatrick 
391061da546Spatrick   m_allocations.emplace(
392061da546Spatrick       std::piecewise_construct, std::forward_as_tuple(aligned_address),
393061da546Spatrick       std::forward_as_tuple(allocation_address, aligned_address,
394061da546Spatrick                             allocation_size, permissions, alignment, policy));
395061da546Spatrick 
396061da546Spatrick   if (zero_memory) {
397061da546Spatrick     Status write_error;
398061da546Spatrick     std::vector<uint8_t> zero_buf(size, 0);
399061da546Spatrick     WriteMemory(aligned_address, zero_buf.data(), size, write_error);
400061da546Spatrick   }
401061da546Spatrick 
402061da546Spatrick   if (log) {
403061da546Spatrick     const char *policy_string;
404061da546Spatrick 
405061da546Spatrick     switch (policy) {
406061da546Spatrick     default:
407061da546Spatrick       policy_string = "<invalid policy>";
408061da546Spatrick       break;
409061da546Spatrick     case eAllocationPolicyHostOnly:
410061da546Spatrick       policy_string = "eAllocationPolicyHostOnly";
411061da546Spatrick       break;
412061da546Spatrick     case eAllocationPolicyProcessOnly:
413061da546Spatrick       policy_string = "eAllocationPolicyProcessOnly";
414061da546Spatrick       break;
415061da546Spatrick     case eAllocationPolicyMirror:
416061da546Spatrick       policy_string = "eAllocationPolicyMirror";
417061da546Spatrick       break;
418061da546Spatrick     }
419061da546Spatrick 
420061da546Spatrick     LLDB_LOGF(log,
421061da546Spatrick               "IRMemoryMap::Malloc (%" PRIu64 ", 0x%" PRIx64 ", 0x%" PRIx64
422061da546Spatrick               ", %s) -> 0x%" PRIx64,
423061da546Spatrick               (uint64_t)allocation_size, (uint64_t)alignment,
424061da546Spatrick               (uint64_t)permissions, policy_string, aligned_address);
425061da546Spatrick   }
426061da546Spatrick 
427061da546Spatrick   return aligned_address;
428061da546Spatrick }
429061da546Spatrick 
Leak(lldb::addr_t process_address,Status & error)430061da546Spatrick void IRMemoryMap::Leak(lldb::addr_t process_address, Status &error) {
431061da546Spatrick   error.Clear();
432061da546Spatrick 
433061da546Spatrick   AllocationMap::iterator iter = m_allocations.find(process_address);
434061da546Spatrick 
435061da546Spatrick   if (iter == m_allocations.end()) {
436061da546Spatrick     error.SetErrorToGenericError();
437061da546Spatrick     error.SetErrorString("Couldn't leak: allocation doesn't exist");
438061da546Spatrick     return;
439061da546Spatrick   }
440061da546Spatrick 
441061da546Spatrick   Allocation &allocation = iter->second;
442061da546Spatrick 
443061da546Spatrick   allocation.m_leak = true;
444061da546Spatrick }
445061da546Spatrick 
Free(lldb::addr_t process_address,Status & error)446061da546Spatrick void IRMemoryMap::Free(lldb::addr_t process_address, Status &error) {
447061da546Spatrick   error.Clear();
448061da546Spatrick 
449061da546Spatrick   AllocationMap::iterator iter = m_allocations.find(process_address);
450061da546Spatrick 
451061da546Spatrick   if (iter == m_allocations.end()) {
452061da546Spatrick     error.SetErrorToGenericError();
453061da546Spatrick     error.SetErrorString("Couldn't free: allocation doesn't exist");
454061da546Spatrick     return;
455061da546Spatrick   }
456061da546Spatrick 
457061da546Spatrick   Allocation &allocation = iter->second;
458061da546Spatrick 
459061da546Spatrick   switch (allocation.m_policy) {
460061da546Spatrick   default:
461061da546Spatrick   case eAllocationPolicyHostOnly: {
462061da546Spatrick     lldb::ProcessSP process_sp = m_process_wp.lock();
463061da546Spatrick     if (process_sp) {
464061da546Spatrick       if (process_sp->CanJIT() && process_sp->IsAlive())
465061da546Spatrick         process_sp->DeallocateMemory(
466061da546Spatrick             allocation.m_process_alloc); // FindSpace allocated this for real
467061da546Spatrick     }
468061da546Spatrick 
469061da546Spatrick     break;
470061da546Spatrick   }
471061da546Spatrick   case eAllocationPolicyMirror:
472061da546Spatrick   case eAllocationPolicyProcessOnly: {
473061da546Spatrick     lldb::ProcessSP process_sp = m_process_wp.lock();
474061da546Spatrick     if (process_sp)
475061da546Spatrick       process_sp->DeallocateMemory(allocation.m_process_alloc);
476061da546Spatrick   }
477061da546Spatrick   }
478061da546Spatrick 
479*f6aab3d8Srobert   if (lldb_private::Log *log = GetLog(LLDBLog::Expressions)) {
480061da546Spatrick     LLDB_LOGF(log,
481061da546Spatrick               "IRMemoryMap::Free (0x%" PRIx64 ") freed [0x%" PRIx64
482061da546Spatrick               "..0x%" PRIx64 ")",
483061da546Spatrick               (uint64_t)process_address, iter->second.m_process_start,
484061da546Spatrick               iter->second.m_process_start + iter->second.m_size);
485061da546Spatrick   }
486061da546Spatrick 
487061da546Spatrick   m_allocations.erase(iter);
488061da546Spatrick }
489061da546Spatrick 
GetAllocSize(lldb::addr_t address,size_t & size)490061da546Spatrick bool IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size) {
491061da546Spatrick   AllocationMap::iterator iter = FindAllocation(address, size);
492061da546Spatrick   if (iter == m_allocations.end())
493061da546Spatrick     return false;
494061da546Spatrick 
495061da546Spatrick   Allocation &al = iter->second;
496061da546Spatrick 
497061da546Spatrick   if (address > (al.m_process_start + al.m_size)) {
498061da546Spatrick     size = 0;
499061da546Spatrick     return false;
500061da546Spatrick   }
501061da546Spatrick 
502061da546Spatrick   if (address > al.m_process_start) {
503061da546Spatrick     int dif = address - al.m_process_start;
504061da546Spatrick     size = al.m_size - dif;
505061da546Spatrick     return true;
506061da546Spatrick   }
507061da546Spatrick 
508061da546Spatrick   size = al.m_size;
509061da546Spatrick   return true;
510061da546Spatrick }
511061da546Spatrick 
WriteMemory(lldb::addr_t process_address,const uint8_t * bytes,size_t size,Status & error)512061da546Spatrick void IRMemoryMap::WriteMemory(lldb::addr_t process_address,
513061da546Spatrick                               const uint8_t *bytes, size_t size,
514061da546Spatrick                               Status &error) {
515061da546Spatrick   error.Clear();
516061da546Spatrick 
517061da546Spatrick   AllocationMap::iterator iter = FindAllocation(process_address, size);
518061da546Spatrick 
519061da546Spatrick   if (iter == m_allocations.end()) {
520061da546Spatrick     lldb::ProcessSP process_sp = m_process_wp.lock();
521061da546Spatrick 
522061da546Spatrick     if (process_sp) {
523061da546Spatrick       process_sp->WriteMemory(process_address, bytes, size, error);
524061da546Spatrick       return;
525061da546Spatrick     }
526061da546Spatrick 
527061da546Spatrick     error.SetErrorToGenericError();
528061da546Spatrick     error.SetErrorString("Couldn't write: no allocation contains the target "
529061da546Spatrick                          "range and the process doesn't exist");
530061da546Spatrick     return;
531061da546Spatrick   }
532061da546Spatrick 
533061da546Spatrick   Allocation &allocation = iter->second;
534061da546Spatrick 
535061da546Spatrick   uint64_t offset = process_address - allocation.m_process_start;
536061da546Spatrick 
537061da546Spatrick   lldb::ProcessSP process_sp;
538061da546Spatrick 
539061da546Spatrick   switch (allocation.m_policy) {
540061da546Spatrick   default:
541061da546Spatrick     error.SetErrorToGenericError();
542061da546Spatrick     error.SetErrorString("Couldn't write: invalid allocation policy");
543061da546Spatrick     return;
544061da546Spatrick   case eAllocationPolicyHostOnly:
545061da546Spatrick     if (!allocation.m_data.GetByteSize()) {
546061da546Spatrick       error.SetErrorToGenericError();
547061da546Spatrick       error.SetErrorString("Couldn't write: data buffer is empty");
548061da546Spatrick       return;
549061da546Spatrick     }
550061da546Spatrick     ::memcpy(allocation.m_data.GetBytes() + offset, bytes, size);
551061da546Spatrick     break;
552061da546Spatrick   case eAllocationPolicyMirror:
553061da546Spatrick     if (!allocation.m_data.GetByteSize()) {
554061da546Spatrick       error.SetErrorToGenericError();
555061da546Spatrick       error.SetErrorString("Couldn't write: data buffer is empty");
556061da546Spatrick       return;
557061da546Spatrick     }
558061da546Spatrick     ::memcpy(allocation.m_data.GetBytes() + offset, bytes, size);
559061da546Spatrick     process_sp = m_process_wp.lock();
560061da546Spatrick     if (process_sp) {
561061da546Spatrick       process_sp->WriteMemory(process_address, bytes, size, error);
562061da546Spatrick       if (!error.Success())
563061da546Spatrick         return;
564061da546Spatrick     }
565061da546Spatrick     break;
566061da546Spatrick   case eAllocationPolicyProcessOnly:
567061da546Spatrick     process_sp = m_process_wp.lock();
568061da546Spatrick     if (process_sp) {
569061da546Spatrick       process_sp->WriteMemory(process_address, bytes, size, error);
570061da546Spatrick       if (!error.Success())
571061da546Spatrick         return;
572061da546Spatrick     }
573061da546Spatrick     break;
574061da546Spatrick   }
575061da546Spatrick 
576*f6aab3d8Srobert   if (lldb_private::Log *log = GetLog(LLDBLog::Expressions)) {
577061da546Spatrick     LLDB_LOGF(log,
578061da546Spatrick               "IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIxPTR
579061da546Spatrick               ", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")",
580061da546Spatrick               (uint64_t)process_address, reinterpret_cast<uintptr_t>(bytes), (uint64_t)size,
581061da546Spatrick               (uint64_t)allocation.m_process_start,
582061da546Spatrick               (uint64_t)allocation.m_process_start +
583061da546Spatrick                   (uint64_t)allocation.m_size);
584061da546Spatrick   }
585061da546Spatrick }
586061da546Spatrick 
WriteScalarToMemory(lldb::addr_t process_address,Scalar & scalar,size_t size,Status & error)587061da546Spatrick void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
588061da546Spatrick                                       Scalar &scalar, size_t size,
589061da546Spatrick                                       Status &error) {
590061da546Spatrick   error.Clear();
591061da546Spatrick 
592061da546Spatrick   if (size == UINT32_MAX)
593061da546Spatrick     size = scalar.GetByteSize();
594061da546Spatrick 
595061da546Spatrick   if (size > 0) {
596061da546Spatrick     uint8_t buf[32];
597061da546Spatrick     const size_t mem_size =
598061da546Spatrick         scalar.GetAsMemoryData(buf, size, GetByteOrder(), error);
599061da546Spatrick     if (mem_size > 0) {
600061da546Spatrick       return WriteMemory(process_address, buf, mem_size, error);
601061da546Spatrick     } else {
602061da546Spatrick       error.SetErrorToGenericError();
603061da546Spatrick       error.SetErrorString(
604061da546Spatrick           "Couldn't write scalar: failed to get scalar as memory data");
605061da546Spatrick     }
606061da546Spatrick   } else {
607061da546Spatrick     error.SetErrorToGenericError();
608061da546Spatrick     error.SetErrorString("Couldn't write scalar: its size was zero");
609061da546Spatrick   }
610061da546Spatrick }
611061da546Spatrick 
WritePointerToMemory(lldb::addr_t process_address,lldb::addr_t address,Status & error)612061da546Spatrick void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
613061da546Spatrick                                        lldb::addr_t address, Status &error) {
614061da546Spatrick   error.Clear();
615061da546Spatrick 
616061da546Spatrick   Scalar scalar(address);
617061da546Spatrick 
618061da546Spatrick   WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
619061da546Spatrick }
620061da546Spatrick 
ReadMemory(uint8_t * bytes,lldb::addr_t process_address,size_t size,Status & error)621061da546Spatrick void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address,
622061da546Spatrick                              size_t size, Status &error) {
623061da546Spatrick   error.Clear();
624061da546Spatrick 
625061da546Spatrick   AllocationMap::iterator iter = FindAllocation(process_address, size);
626061da546Spatrick 
627061da546Spatrick   if (iter == m_allocations.end()) {
628061da546Spatrick     lldb::ProcessSP process_sp = m_process_wp.lock();
629061da546Spatrick 
630061da546Spatrick     if (process_sp) {
631061da546Spatrick       process_sp->ReadMemory(process_address, bytes, size, error);
632061da546Spatrick       return;
633061da546Spatrick     }
634061da546Spatrick 
635061da546Spatrick     lldb::TargetSP target_sp = m_target_wp.lock();
636061da546Spatrick 
637061da546Spatrick     if (target_sp) {
638061da546Spatrick       Address absolute_address(process_address);
639be691f3bSpatrick       target_sp->ReadMemory(absolute_address, bytes, size, error, true);
640061da546Spatrick       return;
641061da546Spatrick     }
642061da546Spatrick 
643061da546Spatrick     error.SetErrorToGenericError();
644061da546Spatrick     error.SetErrorString("Couldn't read: no allocation contains the target "
645061da546Spatrick                          "range, and neither the process nor the target exist");
646061da546Spatrick     return;
647061da546Spatrick   }
648061da546Spatrick 
649061da546Spatrick   Allocation &allocation = iter->second;
650061da546Spatrick 
651061da546Spatrick   uint64_t offset = process_address - allocation.m_process_start;
652061da546Spatrick 
653061da546Spatrick   if (offset > allocation.m_size) {
654061da546Spatrick     error.SetErrorToGenericError();
655061da546Spatrick     error.SetErrorString("Couldn't read: data is not in the allocation");
656061da546Spatrick     return;
657061da546Spatrick   }
658061da546Spatrick 
659061da546Spatrick   lldb::ProcessSP process_sp;
660061da546Spatrick 
661061da546Spatrick   switch (allocation.m_policy) {
662061da546Spatrick   default:
663061da546Spatrick     error.SetErrorToGenericError();
664061da546Spatrick     error.SetErrorString("Couldn't read: invalid allocation policy");
665061da546Spatrick     return;
666061da546Spatrick   case eAllocationPolicyHostOnly:
667061da546Spatrick     if (!allocation.m_data.GetByteSize()) {
668061da546Spatrick       error.SetErrorToGenericError();
669061da546Spatrick       error.SetErrorString("Couldn't read: data buffer is empty");
670061da546Spatrick       return;
671061da546Spatrick     }
672061da546Spatrick     if (allocation.m_data.GetByteSize() < offset + size) {
673061da546Spatrick       error.SetErrorToGenericError();
674061da546Spatrick       error.SetErrorString("Couldn't read: not enough underlying data");
675061da546Spatrick       return;
676061da546Spatrick     }
677061da546Spatrick 
678061da546Spatrick     ::memcpy(bytes, allocation.m_data.GetBytes() + offset, size);
679061da546Spatrick     break;
680061da546Spatrick   case eAllocationPolicyMirror:
681061da546Spatrick     process_sp = m_process_wp.lock();
682061da546Spatrick     if (process_sp) {
683061da546Spatrick       process_sp->ReadMemory(process_address, bytes, size, error);
684061da546Spatrick       if (!error.Success())
685061da546Spatrick         return;
686061da546Spatrick     } else {
687061da546Spatrick       if (!allocation.m_data.GetByteSize()) {
688061da546Spatrick         error.SetErrorToGenericError();
689061da546Spatrick         error.SetErrorString("Couldn't read: data buffer is empty");
690061da546Spatrick         return;
691061da546Spatrick       }
692061da546Spatrick       ::memcpy(bytes, allocation.m_data.GetBytes() + offset, size);
693061da546Spatrick     }
694061da546Spatrick     break;
695061da546Spatrick   case eAllocationPolicyProcessOnly:
696061da546Spatrick     process_sp = m_process_wp.lock();
697061da546Spatrick     if (process_sp) {
698061da546Spatrick       process_sp->ReadMemory(process_address, bytes, size, error);
699061da546Spatrick       if (!error.Success())
700061da546Spatrick         return;
701061da546Spatrick     }
702061da546Spatrick     break;
703061da546Spatrick   }
704061da546Spatrick 
705*f6aab3d8Srobert   if (lldb_private::Log *log = GetLog(LLDBLog::Expressions)) {
706061da546Spatrick     LLDB_LOGF(log,
707061da546Spatrick               "IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIxPTR
708061da546Spatrick               ", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")",
709061da546Spatrick               (uint64_t)process_address, reinterpret_cast<uintptr_t>(bytes), (uint64_t)size,
710061da546Spatrick               (uint64_t)allocation.m_process_start,
711061da546Spatrick               (uint64_t)allocation.m_process_start +
712061da546Spatrick                   (uint64_t)allocation.m_size);
713061da546Spatrick   }
714061da546Spatrick }
715061da546Spatrick 
ReadScalarFromMemory(Scalar & scalar,lldb::addr_t process_address,size_t size,Status & error)716061da546Spatrick void IRMemoryMap::ReadScalarFromMemory(Scalar &scalar,
717061da546Spatrick                                        lldb::addr_t process_address,
718061da546Spatrick                                        size_t size, Status &error) {
719061da546Spatrick   error.Clear();
720061da546Spatrick 
721061da546Spatrick   if (size > 0) {
722061da546Spatrick     DataBufferHeap buf(size, 0);
723061da546Spatrick     ReadMemory(buf.GetBytes(), process_address, size, error);
724061da546Spatrick 
725061da546Spatrick     if (!error.Success())
726061da546Spatrick       return;
727061da546Spatrick 
728061da546Spatrick     DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(),
729061da546Spatrick                             GetAddressByteSize());
730061da546Spatrick 
731061da546Spatrick     lldb::offset_t offset = 0;
732061da546Spatrick 
733061da546Spatrick     switch (size) {
734061da546Spatrick     default:
735061da546Spatrick       error.SetErrorToGenericError();
736061da546Spatrick       error.SetErrorStringWithFormat(
737061da546Spatrick           "Couldn't read scalar: unsupported size %" PRIu64, (uint64_t)size);
738061da546Spatrick       return;
739061da546Spatrick     case 1:
740061da546Spatrick       scalar = extractor.GetU8(&offset);
741061da546Spatrick       break;
742061da546Spatrick     case 2:
743061da546Spatrick       scalar = extractor.GetU16(&offset);
744061da546Spatrick       break;
745061da546Spatrick     case 4:
746061da546Spatrick       scalar = extractor.GetU32(&offset);
747061da546Spatrick       break;
748061da546Spatrick     case 8:
749061da546Spatrick       scalar = extractor.GetU64(&offset);
750061da546Spatrick       break;
751061da546Spatrick     }
752061da546Spatrick   } else {
753061da546Spatrick     error.SetErrorToGenericError();
754061da546Spatrick     error.SetErrorString("Couldn't read scalar: its size was zero");
755061da546Spatrick   }
756061da546Spatrick }
757061da546Spatrick 
ReadPointerFromMemory(lldb::addr_t * address,lldb::addr_t process_address,Status & error)758061da546Spatrick void IRMemoryMap::ReadPointerFromMemory(lldb::addr_t *address,
759061da546Spatrick                                         lldb::addr_t process_address,
760061da546Spatrick                                         Status &error) {
761061da546Spatrick   error.Clear();
762061da546Spatrick 
763061da546Spatrick   Scalar pointer_scalar;
764061da546Spatrick   ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(),
765061da546Spatrick                        error);
766061da546Spatrick 
767061da546Spatrick   if (!error.Success())
768061da546Spatrick     return;
769061da546Spatrick 
770061da546Spatrick   *address = pointer_scalar.ULongLong();
771061da546Spatrick }
772061da546Spatrick 
GetMemoryData(DataExtractor & extractor,lldb::addr_t process_address,size_t size,Status & error)773061da546Spatrick void IRMemoryMap::GetMemoryData(DataExtractor &extractor,
774061da546Spatrick                                 lldb::addr_t process_address, size_t size,
775061da546Spatrick                                 Status &error) {
776061da546Spatrick   error.Clear();
777061da546Spatrick 
778061da546Spatrick   if (size > 0) {
779061da546Spatrick     AllocationMap::iterator iter = FindAllocation(process_address, size);
780061da546Spatrick 
781061da546Spatrick     if (iter == m_allocations.end()) {
782061da546Spatrick       error.SetErrorToGenericError();
783061da546Spatrick       error.SetErrorStringWithFormat(
784061da546Spatrick           "Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64
785061da546Spatrick           ")",
786061da546Spatrick           process_address, process_address + size);
787061da546Spatrick       return;
788061da546Spatrick     }
789061da546Spatrick 
790061da546Spatrick     Allocation &allocation = iter->second;
791061da546Spatrick 
792061da546Spatrick     switch (allocation.m_policy) {
793061da546Spatrick     default:
794061da546Spatrick       error.SetErrorToGenericError();
795061da546Spatrick       error.SetErrorString(
796061da546Spatrick           "Couldn't get memory data: invalid allocation policy");
797061da546Spatrick       return;
798061da546Spatrick     case eAllocationPolicyProcessOnly:
799061da546Spatrick       error.SetErrorToGenericError();
800061da546Spatrick       error.SetErrorString(
801061da546Spatrick           "Couldn't get memory data: memory is only in the target");
802061da546Spatrick       return;
803061da546Spatrick     case eAllocationPolicyMirror: {
804061da546Spatrick       lldb::ProcessSP process_sp = m_process_wp.lock();
805061da546Spatrick 
806061da546Spatrick       if (!allocation.m_data.GetByteSize()) {
807061da546Spatrick         error.SetErrorToGenericError();
808061da546Spatrick         error.SetErrorString("Couldn't get memory data: data buffer is empty");
809061da546Spatrick         return;
810061da546Spatrick       }
811061da546Spatrick       if (process_sp) {
812061da546Spatrick         process_sp->ReadMemory(allocation.m_process_start,
813061da546Spatrick                                allocation.m_data.GetBytes(),
814061da546Spatrick                                allocation.m_data.GetByteSize(), error);
815061da546Spatrick         if (!error.Success())
816061da546Spatrick           return;
817061da546Spatrick         uint64_t offset = process_address - allocation.m_process_start;
818061da546Spatrick         extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size,
819061da546Spatrick                                   GetByteOrder(), GetAddressByteSize());
820061da546Spatrick         return;
821061da546Spatrick       }
822061da546Spatrick     } break;
823061da546Spatrick     case eAllocationPolicyHostOnly:
824061da546Spatrick       if (!allocation.m_data.GetByteSize()) {
825061da546Spatrick         error.SetErrorToGenericError();
826061da546Spatrick         error.SetErrorString("Couldn't get memory data: data buffer is empty");
827061da546Spatrick         return;
828061da546Spatrick       }
829061da546Spatrick       uint64_t offset = process_address - allocation.m_process_start;
830061da546Spatrick       extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size,
831061da546Spatrick                                 GetByteOrder(), GetAddressByteSize());
832061da546Spatrick       return;
833061da546Spatrick     }
834061da546Spatrick   } else {
835061da546Spatrick     error.SetErrorToGenericError();
836061da546Spatrick     error.SetErrorString("Couldn't get memory data: its size was zero");
837061da546Spatrick     return;
838061da546Spatrick   }
839061da546Spatrick }
840