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