180814287SRaphael Isemann //===-- IRMemoryMap.cpp ---------------------------------------------------===//
25a1af4e6SSean Callanan //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a1af4e6SSean Callanan //
75a1af4e6SSean Callanan //===----------------------------------------------------------------------===//
85a1af4e6SSean Callanan 
9b9c1b51eSKate Stone #include "lldb/Expression/IRMemoryMap.h"
10f3df7e86SSean Callanan #include "lldb/Target/MemoryRegionInfo.h"
115a1af4e6SSean Callanan #include "lldb/Target/Process.h"
1235005f76SSean Callanan #include "lldb/Target/Target.h"
13666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
14666cc0b2SZachary Turner #include "lldb/Utility/DataExtractor.h"
15f3df7e86SSean Callanan #include "lldb/Utility/LLDBAssert.h"
16*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
176f9e6901SZachary Turner #include "lldb/Utility/Log.h"
18d821c997SPavel Labath #include "lldb/Utility/Scalar.h"
1997206d57SZachary Turner #include "lldb/Utility/Status.h"
205a1af4e6SSean Callanan 
215a1af4e6SSean Callanan using namespace lldb_private;
225a1af4e6SSean Callanan 
IRMemoryMap(lldb::TargetSP target_sp)23b9c1b51eSKate Stone IRMemoryMap::IRMemoryMap(lldb::TargetSP target_sp) : m_target_wp(target_sp) {
24b024d878SSean Callanan   if (target_sp)
25b024d878SSean Callanan     m_process_wp = target_sp->GetProcessSP();
265a1af4e6SSean Callanan }
275a1af4e6SSean Callanan 
~IRMemoryMap()28b9c1b51eSKate Stone IRMemoryMap::~IRMemoryMap() {
295a1af4e6SSean Callanan   lldb::ProcessSP process_sp = m_process_wp.lock();
305a1af4e6SSean Callanan 
31b9c1b51eSKate Stone   if (process_sp) {
32bb77704cSSean Callanan     AllocationMap::iterator iter;
335a1af4e6SSean Callanan 
3497206d57SZachary Turner     Status err;
35bb77704cSSean Callanan 
36b9c1b51eSKate Stone     while ((iter = m_allocations.begin()) != m_allocations.end()) {
37bb77704cSSean Callanan       err.Clear();
38fbf5c682SSean Callanan       if (iter->second.m_leak)
39fbf5c682SSean Callanan         m_allocations.erase(iter);
40fbf5c682SSean Callanan       else
41bb77704cSSean Callanan         Free(iter->first, err);
425a1af4e6SSean Callanan     }
435a1af4e6SSean Callanan   }
445a1af4e6SSean Callanan }
455a1af4e6SSean Callanan 
FindSpace(size_t size)46b9c1b51eSKate Stone lldb::addr_t IRMemoryMap::FindSpace(size_t size) {
47f3df7e86SSean Callanan   // The FindSpace algorithm's job is to find a region of memory that the
48f3df7e86SSean Callanan   // underlying process is unlikely to be using.
49f3df7e86SSean Callanan   //
50f3df7e86SSean Callanan   // The memory returned by this function will never be written to.  The only
51f3df7e86SSean Callanan   // point is that it should not shadow process memory if possible, so that
5205097246SAdrian Prantl   // expressions processing real values from the process do not use the wrong
5305097246SAdrian Prantl   // data.
54f3df7e86SSean Callanan   //
55f3df7e86SSean Callanan   // If the process can in fact allocate memory (CanJIT() lets us know this)
56f3df7e86SSean Callanan   // then this can be accomplished just be allocating memory in the inferior.
57f3df7e86SSean Callanan   // Then no guessing is required.
58f3df7e86SSean Callanan 
59bb9945f4SSean Callanan   lldb::TargetSP target_sp = m_target_wp.lock();
60bb9945f4SSean Callanan   lldb::ProcessSP process_sp = m_process_wp.lock();
615a1af4e6SSean Callanan 
62f3df7e86SSean Callanan   const bool process_is_alive = process_sp && process_sp->IsAlive();
63f3df7e86SSean Callanan 
64bb9945f4SSean Callanan   lldb::addr_t ret = LLDB_INVALID_ADDRESS;
653ddcd314SZachary Turner   if (size == 0)
663ddcd314SZachary Turner     return ret;
675a1af4e6SSean Callanan 
68b9c1b51eSKate Stone   if (process_is_alive && process_sp->CanJIT()) {
6997206d57SZachary Turner     Status alloc_error;
70df56540aSSean Callanan 
71b9c1b51eSKate Stone     ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable |
72b9c1b51eSKate Stone                                                lldb::ePermissionsWritable,
73b9c1b51eSKate Stone                                      alloc_error);
74df56540aSSean Callanan 
75df56540aSSean Callanan     if (!alloc_error.Success())
76df56540aSSean Callanan       return LLDB_INVALID_ADDRESS;
77df56540aSSean Callanan     else
78df56540aSSean Callanan       return ret;
79df56540aSSean Callanan   }
80df56540aSSean Callanan 
81f3df7e86SSean Callanan   // At this point we know that we need to hunt.
82f3df7e86SSean Callanan   //
83f3df7e86SSean Callanan   // First, go to the end of the existing allocations we've made if there are
84f3df7e86SSean Callanan   // any allocations.  Otherwise start at the beginning of memory.
85f3df7e86SSean Callanan 
86b9c1b51eSKate Stone   if (m_allocations.empty()) {
87f3df7e86SSean Callanan     ret = 0x0;
88b9c1b51eSKate Stone   } else {
89f3df7e86SSean Callanan     auto back = m_allocations.rbegin();
90f3df7e86SSean Callanan     lldb::addr_t addr = back->first;
91f3df7e86SSean Callanan     size_t alloc_size = back->second.m_size;
92f3df7e86SSean Callanan     ret = llvm::alignTo(addr + alloc_size, 4096);
93f3df7e86SSean Callanan   }
94f3df7e86SSean Callanan 
95f3df7e86SSean Callanan   // Now, if it's possible to use the GetMemoryRegionInfo API to detect mapped
9605097246SAdrian Prantl   // regions, walk forward through memory until a region is found that has
9705097246SAdrian Prantl   // adequate space for our allocation.
98b9c1b51eSKate Stone   if (process_is_alive) {
99b9c1b51eSKate Stone     const uint64_t end_of_memory = process_sp->GetAddressByteSize() == 8
100b9c1b51eSKate Stone                                        ? 0xffffffffffffffffull
101b9c1b51eSKate Stone                                        : 0xffffffffull;
102f3df7e86SSean Callanan 
103b9c1b51eSKate Stone     lldbassert(process_sp->GetAddressByteSize() == 4 ||
104b9c1b51eSKate Stone                end_of_memory != 0xffffffffull);
105f3df7e86SSean Callanan 
106f3df7e86SSean Callanan     MemoryRegionInfo region_info;
10797206d57SZachary Turner     Status err = process_sp->GetMemoryRegionInfo(ret, region_info);
108b9c1b51eSKate Stone     if (err.Success()) {
109b9c1b51eSKate Stone       while (true) {
110f3df7e86SSean Callanan         if (region_info.GetReadable() != MemoryRegionInfo::OptionalBool::eNo ||
111f3df7e86SSean Callanan             region_info.GetWritable() != MemoryRegionInfo::OptionalBool::eNo ||
112b9c1b51eSKate Stone             region_info.GetExecutable() !=
113b9c1b51eSKate Stone                 MemoryRegionInfo::OptionalBool::eNo) {
114b9c1b51eSKate Stone           if (region_info.GetRange().GetRangeEnd() - 1 >= end_of_memory) {
115f3df7e86SSean Callanan             ret = LLDB_INVALID_ADDRESS;
116f3df7e86SSean Callanan             break;
117b9c1b51eSKate Stone           } else {
118f3df7e86SSean Callanan             ret = region_info.GetRange().GetRangeEnd();
119f3df7e86SSean Callanan           }
120b9c1b51eSKate Stone         } else if (ret + size < region_info.GetRange().GetRangeEnd()) {
121f3df7e86SSean Callanan           return ret;
122b9c1b51eSKate Stone         } else {
123f3df7e86SSean Callanan           // ret stays the same.  We just need to walk a bit further.
124f3df7e86SSean Callanan         }
125f3df7e86SSean Callanan 
126b9c1b51eSKate Stone         err = process_sp->GetMemoryRegionInfo(
127b9c1b51eSKate Stone             region_info.GetRange().GetRangeEnd(), region_info);
128b9c1b51eSKate Stone         if (err.Fail()) {
129f31c9d27SPavel Labath           lldbassert(0 && "GetMemoryRegionInfo() succeeded, then failed");
130f3df7e86SSean Callanan           ret = LLDB_INVALID_ADDRESS;
131f3df7e86SSean Callanan           break;
132f3df7e86SSean Callanan         }
133f3df7e86SSean Callanan       }
134f3df7e86SSean Callanan     }
135f3df7e86SSean Callanan   }
136f3df7e86SSean Callanan 
137f3df7e86SSean Callanan   // We've tried our algorithm, and it didn't work.  Now we have to reset back
138f3df7e86SSean Callanan   // to the end of the allocations we've already reported, or use a 'sensible'
139f3df7e86SSean Callanan   // default if this is our first allocation.
140f3df7e86SSean Callanan 
141b9c1b51eSKate Stone   if (m_allocations.empty()) {
142f3df7e86SSean Callanan     uint32_t address_byte_size = GetAddressByteSize();
143b9c1b51eSKate Stone     if (address_byte_size != UINT32_MAX) {
144b9c1b51eSKate Stone       switch (address_byte_size) {
145f3df7e86SSean Callanan       case 8:
146f3df7e86SSean Callanan         ret = 0xffffffff00000000ull;
147f3df7e86SSean Callanan         break;
148f3df7e86SSean Callanan       case 4:
149f3df7e86SSean Callanan         ret = 0xee000000ull;
150f3df7e86SSean Callanan         break;
151f3df7e86SSean Callanan       default:
152f3df7e86SSean Callanan         break;
153f3df7e86SSean Callanan       }
154f3df7e86SSean Callanan     }
155b9c1b51eSKate Stone   } else {
1563ddcd314SZachary Turner     auto back = m_allocations.rbegin();
1573ddcd314SZachary Turner     lldb::addr_t addr = back->first;
1583ddcd314SZachary Turner     size_t alloc_size = back->second.m_size;
159a94ae1e0SRafael Espindola     ret = llvm::alignTo(addr + alloc_size, 4096);
1605a1af4e6SSean Callanan   }
1615a1af4e6SSean Callanan 
162bb9945f4SSean Callanan   return ret;
1635a1af4e6SSean Callanan }
1645a1af4e6SSean Callanan 
1655a1af4e6SSean Callanan IRMemoryMap::AllocationMap::iterator
FindAllocation(lldb::addr_t addr,size_t size)166b9c1b51eSKate Stone IRMemoryMap::FindAllocation(lldb::addr_t addr, size_t size) {
1671582ee68SSean Callanan   if (addr == LLDB_INVALID_ADDRESS)
1681582ee68SSean Callanan     return m_allocations.end();
1691582ee68SSean Callanan 
1705a1af4e6SSean Callanan   AllocationMap::iterator iter = m_allocations.lower_bound(addr);
1715a1af4e6SSean Callanan 
172b9c1b51eSKate Stone   if (iter == m_allocations.end() || iter->first > addr) {
1735a1af4e6SSean Callanan     if (iter == m_allocations.begin())
1745a1af4e6SSean Callanan       return m_allocations.end();
1755a1af4e6SSean Callanan     iter--;
1765a1af4e6SSean Callanan   }
1775a1af4e6SSean Callanan 
1785a1af4e6SSean Callanan   if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size)
1795a1af4e6SSean Callanan     return iter;
1805a1af4e6SSean Callanan 
1815a1af4e6SSean Callanan   return m_allocations.end();
1825a1af4e6SSean Callanan }
1835a1af4e6SSean Callanan 
IntersectsAllocation(lldb::addr_t addr,size_t size) const184b9c1b51eSKate Stone bool IRMemoryMap::IntersectsAllocation(lldb::addr_t addr, size_t size) const {
185bb9945f4SSean Callanan   if (addr == LLDB_INVALID_ADDRESS)
186bb9945f4SSean Callanan     return false;
187bb9945f4SSean Callanan 
18815362445SZachary Turner   AllocationMap::const_iterator iter = m_allocations.lower_bound(addr);
189bb9945f4SSean Callanan 
190b9c1b51eSKate Stone   // Since we only know that the returned interval begins at a location greater
19105097246SAdrian Prantl   // than or equal to where the given interval begins, it's possible that the
19205097246SAdrian Prantl   // given interval intersects either the returned interval or the previous
19305097246SAdrian Prantl   // interval.  Thus, we need to check both. Note that we only need to check
19405097246SAdrian Prantl   // these two intervals.  Since all intervals are disjoint it is not possible
19505097246SAdrian Prantl   // that an adjacent interval does not intersect, but a non-adjacent interval
19605097246SAdrian Prantl   // does intersect.
19715362445SZachary Turner   if (iter != m_allocations.end()) {
198b9c1b51eSKate Stone     if (AllocationsIntersect(addr, size, iter->second.m_process_start,
199b9c1b51eSKate Stone                              iter->second.m_size))
200bb9945f4SSean Callanan       return true;
20115362445SZachary Turner   }
202bb9945f4SSean Callanan 
20315362445SZachary Turner   if (iter != m_allocations.begin()) {
20415362445SZachary Turner     --iter;
205b9c1b51eSKate Stone     if (AllocationsIntersect(addr, size, iter->second.m_process_start,
206b9c1b51eSKate Stone                              iter->second.m_size))
20715362445SZachary Turner       return true;
208bb9945f4SSean Callanan   }
209bb9945f4SSean Callanan 
210bb9945f4SSean Callanan   return false;
211bb9945f4SSean Callanan }
212bb9945f4SSean Callanan 
AllocationsIntersect(lldb::addr_t addr1,size_t size1,lldb::addr_t addr2,size_t size2)213b9c1b51eSKate Stone bool IRMemoryMap::AllocationsIntersect(lldb::addr_t addr1, size_t size1,
214b9c1b51eSKate Stone                                        lldb::addr_t addr2, size_t size2) {
215b9c1b51eSKate Stone   // Given two half open intervals [A, B) and [X, Y), the only 6 permutations
21605097246SAdrian Prantl   // that satisfy A<B and X<Y are the following:
21715362445SZachary Turner   // A B X Y
21815362445SZachary Turner   // A X B Y  (intersects)
21915362445SZachary Turner   // A X Y B  (intersects)
22015362445SZachary Turner   // X A B Y  (intersects)
22115362445SZachary Turner   // X A Y B  (intersects)
22215362445SZachary Turner   // X Y A B
22305097246SAdrian Prantl   // The first is B <= X, and the last is Y <= A. So the condition is !(B <= X
22405097246SAdrian Prantl   // || Y <= A)), or (X < B && A < Y)
22515362445SZachary Turner   return (addr2 < (addr1 + size1)) && (addr1 < (addr2 + size2));
22615362445SZachary Turner }
22715362445SZachary Turner 
GetByteOrder()228b9c1b51eSKate Stone lldb::ByteOrder IRMemoryMap::GetByteOrder() {
22935005f76SSean Callanan   lldb::ProcessSP process_sp = m_process_wp.lock();
23035005f76SSean Callanan 
23135005f76SSean Callanan   if (process_sp)
23235005f76SSean Callanan     return process_sp->GetByteOrder();
23335005f76SSean Callanan 
23435005f76SSean Callanan   lldb::TargetSP target_sp = m_target_wp.lock();
23535005f76SSean Callanan 
23635005f76SSean Callanan   if (target_sp)
23708052afaSSean Callanan     return target_sp->GetArchitecture().GetByteOrder();
23835005f76SSean Callanan 
23935005f76SSean Callanan   return lldb::eByteOrderInvalid;
24035005f76SSean Callanan }
24135005f76SSean Callanan 
GetAddressByteSize()242b9c1b51eSKate Stone uint32_t IRMemoryMap::GetAddressByteSize() {
24335005f76SSean Callanan   lldb::ProcessSP process_sp = m_process_wp.lock();
24435005f76SSean Callanan 
24535005f76SSean Callanan   if (process_sp)
24635005f76SSean Callanan     return process_sp->GetAddressByteSize();
24735005f76SSean Callanan 
24835005f76SSean Callanan   lldb::TargetSP target_sp = m_target_wp.lock();
24935005f76SSean Callanan 
25035005f76SSean Callanan   if (target_sp)
25108052afaSSean Callanan     return target_sp->GetArchitecture().GetAddressByteSize();
25235005f76SSean Callanan 
25335005f76SSean Callanan   return UINT32_MAX;
25435005f76SSean Callanan }
25535005f76SSean Callanan 
GetBestExecutionContextScope() const256b9c1b51eSKate Stone ExecutionContextScope *IRMemoryMap::GetBestExecutionContextScope() const {
25735005f76SSean Callanan   lldb::ProcessSP process_sp = m_process_wp.lock();
25835005f76SSean Callanan 
25935005f76SSean Callanan   if (process_sp)
26035005f76SSean Callanan     return process_sp.get();
26135005f76SSean Callanan 
26235005f76SSean Callanan   lldb::TargetSP target_sp = m_target_wp.lock();
26335005f76SSean Callanan 
26435005f76SSean Callanan   if (target_sp)
26535005f76SSean Callanan     return target_sp.get();
26635005f76SSean Callanan 
267248a1305SKonrad Kleine   return nullptr;
26835005f76SSean Callanan }
26935005f76SSean Callanan 
Allocation(lldb::addr_t process_alloc,lldb::addr_t process_start,size_t size,uint32_t permissions,uint8_t alignment,AllocationPolicy policy)270d2562509SSean Callanan IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc,
271b9c1b51eSKate Stone                                     lldb::addr_t process_start, size_t size,
272b9c1b51eSKate Stone                                     uint32_t permissions, uint8_t alignment,
273b9c1b51eSKate Stone                                     AllocationPolicy policy)
274b9c1b51eSKate Stone     : m_process_alloc(process_alloc), m_process_start(process_start),
275f71dd344SVedant Kumar       m_size(size), m_policy(policy), m_leak(false), m_permissions(permissions),
276f71dd344SVedant Kumar       m_alignment(alignment) {
277b9c1b51eSKate Stone   switch (policy) {
278d2562509SSean Callanan   default:
27935861f21SFangrui Song     llvm_unreachable("Invalid AllocationPolicy");
280d2562509SSean Callanan   case eAllocationPolicyHostOnly:
281d2562509SSean Callanan   case eAllocationPolicyMirror:
282d2562509SSean Callanan     m_data.SetByteSize(size);
28394523598SVedant Kumar     break;
28494523598SVedant Kumar   case eAllocationPolicyProcessOnly:
285d2562509SSean Callanan     break;
286d2562509SSean Callanan   }
287d2562509SSean Callanan }
288d2562509SSean Callanan 
Malloc(size_t size,uint8_t alignment,uint32_t permissions,AllocationPolicy policy,bool zero_memory,Status & error)289b9c1b51eSKate Stone lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
290b9c1b51eSKate Stone                                  uint32_t permissions, AllocationPolicy policy,
29197206d57SZachary Turner                                  bool zero_memory, Status &error) {
292a007a6d8SPavel Labath   lldb_private::Log *log(GetLog(LLDBLog::Expressions));
29308052afaSSean Callanan   error.Clear();
29408052afaSSean Callanan 
2955a1af4e6SSean Callanan   lldb::ProcessSP process_sp;
2965a1af4e6SSean Callanan   lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
2975a1af4e6SSean Callanan   lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
2985a1af4e6SSean Callanan 
299750dcc33SMatt Kopec   size_t allocation_size;
300750dcc33SMatt Kopec 
3015b71e75eSVedant Kumar   if (size == 0) {
3025b71e75eSVedant Kumar     // FIXME: Malloc(0) should either return an invalid address or assert, in
3035b71e75eSVedant Kumar     // order to cut down on unnecessary allocations.
304750dcc33SMatt Kopec     allocation_size = alignment;
3055b71e75eSVedant Kumar   } else {
3065b71e75eSVedant Kumar     // Round up the requested size to an aligned value.
3075b71e75eSVedant Kumar     allocation_size = llvm::alignTo(size, alignment);
3085b71e75eSVedant Kumar 
3095b71e75eSVedant Kumar     // The process page cache does not see the requested alignment. We can't
3105b71e75eSVedant Kumar     // assume its result will be any more than 1-byte aligned. To work around
3115b71e75eSVedant Kumar     // this, request `alignment - 1` additional bytes.
3125b71e75eSVedant Kumar     allocation_size += alignment - 1;
3135b71e75eSVedant Kumar   }
3145a1af4e6SSean Callanan 
315b9c1b51eSKate Stone   switch (policy) {
3165a1af4e6SSean Callanan   default:
3175a1af4e6SSean Callanan     error.SetErrorToGenericError();
3185a1af4e6SSean Callanan     error.SetErrorString("Couldn't malloc: invalid allocation policy");
3195a1af4e6SSean Callanan     return LLDB_INVALID_ADDRESS;
3205a1af4e6SSean Callanan   case eAllocationPolicyHostOnly:
3215a1af4e6SSean Callanan     allocation_address = FindSpace(allocation_size);
322b9c1b51eSKate Stone     if (allocation_address == LLDB_INVALID_ADDRESS) {
3235a1af4e6SSean Callanan       error.SetErrorToGenericError();
3245a1af4e6SSean Callanan       error.SetErrorString("Couldn't malloc: address space is full");
3255a1af4e6SSean Callanan       return LLDB_INVALID_ADDRESS;
3265a1af4e6SSean Callanan     }
3275a1af4e6SSean Callanan     break;
3285a1af4e6SSean Callanan   case eAllocationPolicyMirror:
3295a1af4e6SSean Callanan     process_sp = m_process_wp.lock();
33063e5fb76SJonas Devlieghere     LLDB_LOGF(log,
331df6879ecSJan Kratochvil               "IRMemoryMap::%s process_sp=0x%" PRIxPTR
332b9c1b51eSKate Stone               ", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s",
333df6879ecSJan Kratochvil               __FUNCTION__, reinterpret_cast<uintptr_t>(process_sp.get()),
334b9c1b51eSKate Stone               process_sp && process_sp->CanJIT() ? "true" : "false",
335b9c1b51eSKate Stone               process_sp && process_sp->IsAlive() ? "true" : "false");
336b9c1b51eSKate Stone     if (process_sp && process_sp->CanJIT() && process_sp->IsAlive()) {
3372c381414SJim Ingham       if (!zero_memory)
338b9c1b51eSKate Stone         allocation_address =
339b9c1b51eSKate Stone             process_sp->AllocateMemory(allocation_size, permissions, error);
3402c381414SJim Ingham       else
341b9c1b51eSKate Stone         allocation_address =
342b9c1b51eSKate Stone             process_sp->CallocateMemory(allocation_size, permissions, error);
3432c381414SJim Ingham 
3445a1af4e6SSean Callanan       if (!error.Success())
3455a1af4e6SSean Callanan         return LLDB_INVALID_ADDRESS;
346b9c1b51eSKate Stone     } else {
34763e5fb76SJonas Devlieghere       LLDB_LOGF(log,
34863e5fb76SJonas Devlieghere                 "IRMemoryMap::%s switching to eAllocationPolicyHostOnly "
349b9c1b51eSKate Stone                 "due to failed condition (see previous expr log message)",
350b9c1b51eSKate Stone                 __FUNCTION__);
351bb9945f4SSean Callanan       policy = eAllocationPolicyHostOnly;
3525a1af4e6SSean Callanan       allocation_address = FindSpace(allocation_size);
353b9c1b51eSKate Stone       if (allocation_address == LLDB_INVALID_ADDRESS) {
3545a1af4e6SSean Callanan         error.SetErrorToGenericError();
3555a1af4e6SSean Callanan         error.SetErrorString("Couldn't malloc: address space is full");
3565a1af4e6SSean Callanan         return LLDB_INVALID_ADDRESS;
3575a1af4e6SSean Callanan       }
3585a1af4e6SSean Callanan     }
3595a1af4e6SSean Callanan     break;
3605a1af4e6SSean Callanan   case eAllocationPolicyProcessOnly:
3615a1af4e6SSean Callanan     process_sp = m_process_wp.lock();
362b9c1b51eSKate Stone     if (process_sp) {
363b9c1b51eSKate Stone       if (process_sp->CanJIT() && process_sp->IsAlive()) {
3642c381414SJim Ingham         if (!zero_memory)
365b9c1b51eSKate Stone           allocation_address =
366b9c1b51eSKate Stone               process_sp->AllocateMemory(allocation_size, permissions, error);
3672c381414SJim Ingham         else
368b9c1b51eSKate Stone           allocation_address =
369b9c1b51eSKate Stone               process_sp->CallocateMemory(allocation_size, permissions, error);
3702c381414SJim Ingham 
3715a1af4e6SSean Callanan         if (!error.Success())
3725a1af4e6SSean Callanan           return LLDB_INVALID_ADDRESS;
373b9c1b51eSKate Stone       } else {
3745a1af4e6SSean Callanan         error.SetErrorToGenericError();
375b9c1b51eSKate Stone         error.SetErrorString(
376b9c1b51eSKate Stone             "Couldn't malloc: process doesn't support allocating memory");
377bb9945f4SSean Callanan         return LLDB_INVALID_ADDRESS;
378bb9945f4SSean Callanan       }
379b9c1b51eSKate Stone     } else {
380bb9945f4SSean Callanan       error.SetErrorToGenericError();
381b9c1b51eSKate Stone       error.SetErrorString("Couldn't malloc: process doesn't exist, and this "
382b9c1b51eSKate Stone                            "memory must be in the process");
3835a1af4e6SSean Callanan       return LLDB_INVALID_ADDRESS;
3845a1af4e6SSean Callanan     }
3855a1af4e6SSean Callanan     break;
3865a1af4e6SSean Callanan   }
3875a1af4e6SSean Callanan 
3885a1af4e6SSean Callanan   lldb::addr_t mask = alignment - 1;
3895a1af4e6SSean Callanan   aligned_address = (allocation_address + mask) & (~mask);
3905a1af4e6SSean Callanan 
391f71dd344SVedant Kumar   m_allocations.emplace(
392f71dd344SVedant Kumar       std::piecewise_construct, std::forward_as_tuple(aligned_address),
393f71dd344SVedant Kumar       std::forward_as_tuple(allocation_address, aligned_address,
394f71dd344SVedant Kumar                             allocation_size, permissions, alignment, policy));
3955a1af4e6SSean Callanan 
396b9c1b51eSKate Stone   if (zero_memory) {
39797206d57SZachary Turner     Status write_error;
398b37674dcSSean Callanan     std::vector<uint8_t> zero_buf(size, 0);
399b37674dcSSean Callanan     WriteMemory(aligned_address, zero_buf.data(), size, write_error);
400b37674dcSSean Callanan   }
401b37674dcSSean Callanan 
402b9c1b51eSKate Stone   if (log) {
4035a1af4e6SSean Callanan     const char *policy_string;
4045a1af4e6SSean Callanan 
405b9c1b51eSKate Stone     switch (policy) {
4065a1af4e6SSean Callanan     default:
4075a1af4e6SSean Callanan       policy_string = "<invalid policy>";
4085a1af4e6SSean Callanan       break;
4095a1af4e6SSean Callanan     case eAllocationPolicyHostOnly:
4105a1af4e6SSean Callanan       policy_string = "eAllocationPolicyHostOnly";
4115a1af4e6SSean Callanan       break;
4125a1af4e6SSean Callanan     case eAllocationPolicyProcessOnly:
4135a1af4e6SSean Callanan       policy_string = "eAllocationPolicyProcessOnly";
4145a1af4e6SSean Callanan       break;
4155a1af4e6SSean Callanan     case eAllocationPolicyMirror:
4165a1af4e6SSean Callanan       policy_string = "eAllocationPolicyMirror";
4175a1af4e6SSean Callanan       break;
4185a1af4e6SSean Callanan     }
4195a1af4e6SSean Callanan 
42063e5fb76SJonas Devlieghere     LLDB_LOGF(log,
42163e5fb76SJonas Devlieghere               "IRMemoryMap::Malloc (%" PRIu64 ", 0x%" PRIx64 ", 0x%" PRIx64
422b9c1b51eSKate Stone               ", %s) -> 0x%" PRIx64,
423b9c1b51eSKate Stone               (uint64_t)allocation_size, (uint64_t)alignment,
424b9c1b51eSKate Stone               (uint64_t)permissions, policy_string, aligned_address);
4255a1af4e6SSean Callanan   }
4265a1af4e6SSean Callanan 
4275a1af4e6SSean Callanan   return aligned_address;
4285a1af4e6SSean Callanan }
4295a1af4e6SSean Callanan 
Leak(lldb::addr_t process_address,Status & error)43097206d57SZachary Turner void IRMemoryMap::Leak(lldb::addr_t process_address, Status &error) {
431fbf5c682SSean Callanan   error.Clear();
432fbf5c682SSean Callanan 
433fbf5c682SSean Callanan   AllocationMap::iterator iter = m_allocations.find(process_address);
434fbf5c682SSean Callanan 
435b9c1b51eSKate Stone   if (iter == m_allocations.end()) {
436fbf5c682SSean Callanan     error.SetErrorToGenericError();
437fbf5c682SSean Callanan     error.SetErrorString("Couldn't leak: allocation doesn't exist");
438fbf5c682SSean Callanan     return;
439fbf5c682SSean Callanan   }
440fbf5c682SSean Callanan 
441fbf5c682SSean Callanan   Allocation &allocation = iter->second;
442fbf5c682SSean Callanan 
443fbf5c682SSean Callanan   allocation.m_leak = true;
444fbf5c682SSean Callanan }
445fbf5c682SSean Callanan 
Free(lldb::addr_t process_address,Status & error)44697206d57SZachary Turner void IRMemoryMap::Free(lldb::addr_t process_address, Status &error) {
44708052afaSSean Callanan   error.Clear();
44808052afaSSean Callanan 
4495a1af4e6SSean Callanan   AllocationMap::iterator iter = m_allocations.find(process_address);
4505a1af4e6SSean Callanan 
451b9c1b51eSKate Stone   if (iter == m_allocations.end()) {
4525a1af4e6SSean Callanan     error.SetErrorToGenericError();
4535a1af4e6SSean Callanan     error.SetErrorString("Couldn't free: allocation doesn't exist");
4545a1af4e6SSean Callanan     return;
4555a1af4e6SSean Callanan   }
4565a1af4e6SSean Callanan 
4575a1af4e6SSean Callanan   Allocation &allocation = iter->second;
4585a1af4e6SSean Callanan 
459b9c1b51eSKate Stone   switch (allocation.m_policy) {
4605a1af4e6SSean Callanan   default:
461b9c1b51eSKate Stone   case eAllocationPolicyHostOnly: {
462df56540aSSean Callanan     lldb::ProcessSP process_sp = m_process_wp.lock();
463b9c1b51eSKate Stone     if (process_sp) {
464ad7cc466SSean Callanan       if (process_sp->CanJIT() && process_sp->IsAlive())
465b9c1b51eSKate Stone         process_sp->DeallocateMemory(
466b9c1b51eSKate Stone             allocation.m_process_alloc); // FindSpace allocated this for real
467bb77704cSSean Callanan     }
468df56540aSSean Callanan 
4695a1af4e6SSean Callanan     break;
470df56540aSSean Callanan   }
4715a1af4e6SSean Callanan   case eAllocationPolicyMirror:
472b9c1b51eSKate Stone   case eAllocationPolicyProcessOnly: {
4735a1af4e6SSean Callanan     lldb::ProcessSP process_sp = m_process_wp.lock();
4745a1af4e6SSean Callanan     if (process_sp)
4755a1af4e6SSean Callanan       process_sp->DeallocateMemory(allocation.m_process_alloc);
4765a1af4e6SSean Callanan   }
477df56540aSSean Callanan   }
4785a1af4e6SSean Callanan 
479a007a6d8SPavel Labath   if (lldb_private::Log *log = GetLog(LLDBLog::Expressions)) {
48063e5fb76SJonas Devlieghere     LLDB_LOGF(log,
48163e5fb76SJonas Devlieghere               "IRMemoryMap::Free (0x%" PRIx64 ") freed [0x%" PRIx64
482b9c1b51eSKate Stone               "..0x%" PRIx64 ")",
483b9c1b51eSKate Stone               (uint64_t)process_address, iter->second.m_process_start,
4845a1af4e6SSean Callanan               iter->second.m_process_start + iter->second.m_size);
4855a1af4e6SSean Callanan   }
4865a1af4e6SSean Callanan 
4875a1af4e6SSean Callanan   m_allocations.erase(iter);
4885a1af4e6SSean Callanan }
4895a1af4e6SSean Callanan 
GetAllocSize(lldb::addr_t address,size_t & size)490b9c1b51eSKate Stone bool IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size) {
49190ff7911SEwan Crawford   AllocationMap::iterator iter = FindAllocation(address, size);
49290ff7911SEwan Crawford   if (iter == m_allocations.end())
49390ff7911SEwan Crawford     return false;
49490ff7911SEwan Crawford 
49590ff7911SEwan Crawford   Allocation &al = iter->second;
49690ff7911SEwan Crawford 
497b9c1b51eSKate Stone   if (address > (al.m_process_start + al.m_size)) {
49890ff7911SEwan Crawford     size = 0;
49990ff7911SEwan Crawford     return false;
50090ff7911SEwan Crawford   }
50190ff7911SEwan Crawford 
502b9c1b51eSKate Stone   if (address > al.m_process_start) {
50390ff7911SEwan Crawford     int dif = address - al.m_process_start;
50490ff7911SEwan Crawford     size = al.m_size - dif;
50590ff7911SEwan Crawford     return true;
50690ff7911SEwan Crawford   }
50790ff7911SEwan Crawford 
50890ff7911SEwan Crawford   size = al.m_size;
50990ff7911SEwan Crawford   return true;
51090ff7911SEwan Crawford }
51190ff7911SEwan Crawford 
WriteMemory(lldb::addr_t process_address,const uint8_t * bytes,size_t size,Status & error)512b9c1b51eSKate Stone void IRMemoryMap::WriteMemory(lldb::addr_t process_address,
51397206d57SZachary Turner                               const uint8_t *bytes, size_t size,
51497206d57SZachary Turner                               Status &error) {
51508052afaSSean Callanan   error.Clear();
51608052afaSSean Callanan 
5175a1af4e6SSean Callanan   AllocationMap::iterator iter = FindAllocation(process_address, size);
5185a1af4e6SSean Callanan 
519b9c1b51eSKate Stone   if (iter == m_allocations.end()) {
520c8c5b8dcSSean Callanan     lldb::ProcessSP process_sp = m_process_wp.lock();
521c8c5b8dcSSean Callanan 
522b9c1b51eSKate Stone     if (process_sp) {
523c8c5b8dcSSean Callanan       process_sp->WriteMemory(process_address, bytes, size, error);
524c8c5b8dcSSean Callanan       return;
525c8c5b8dcSSean Callanan     }
526c8c5b8dcSSean Callanan 
5275a1af4e6SSean Callanan     error.SetErrorToGenericError();
528b9c1b51eSKate Stone     error.SetErrorString("Couldn't write: no allocation contains the target "
529b9c1b51eSKate Stone                          "range and the process doesn't exist");
5305a1af4e6SSean Callanan     return;
5315a1af4e6SSean Callanan   }
5325a1af4e6SSean Callanan 
5335a1af4e6SSean Callanan   Allocation &allocation = iter->second;
5345a1af4e6SSean Callanan 
5355a1af4e6SSean Callanan   uint64_t offset = process_address - allocation.m_process_start;
5365a1af4e6SSean Callanan 
5375a1af4e6SSean Callanan   lldb::ProcessSP process_sp;
5385a1af4e6SSean Callanan 
539b9c1b51eSKate Stone   switch (allocation.m_policy) {
5405a1af4e6SSean Callanan   default:
5415a1af4e6SSean Callanan     error.SetErrorToGenericError();
5425a1af4e6SSean Callanan     error.SetErrorString("Couldn't write: invalid allocation policy");
5435a1af4e6SSean Callanan     return;
5445a1af4e6SSean Callanan   case eAllocationPolicyHostOnly:
545b9c1b51eSKate Stone     if (!allocation.m_data.GetByteSize()) {
5465a1af4e6SSean Callanan       error.SetErrorToGenericError();
5475a1af4e6SSean Callanan       error.SetErrorString("Couldn't write: data buffer is empty");
5485a1af4e6SSean Callanan       return;
5495a1af4e6SSean Callanan     }
550d2562509SSean Callanan     ::memcpy(allocation.m_data.GetBytes() + offset, bytes, size);
5515a1af4e6SSean Callanan     break;
5525a1af4e6SSean Callanan   case eAllocationPolicyMirror:
553b9c1b51eSKate Stone     if (!allocation.m_data.GetByteSize()) {
5545a1af4e6SSean Callanan       error.SetErrorToGenericError();
5555a1af4e6SSean Callanan       error.SetErrorString("Couldn't write: data buffer is empty");
5565a1af4e6SSean Callanan       return;
5575a1af4e6SSean Callanan     }
558d2562509SSean Callanan     ::memcpy(allocation.m_data.GetBytes() + offset, bytes, size);
5595a1af4e6SSean Callanan     process_sp = m_process_wp.lock();
560b9c1b51eSKate Stone     if (process_sp) {
5615a1af4e6SSean Callanan       process_sp->WriteMemory(process_address, bytes, size, error);
5625a1af4e6SSean Callanan       if (!error.Success())
5635a1af4e6SSean Callanan         return;
5645a1af4e6SSean Callanan     }
5655a1af4e6SSean Callanan     break;
5665a1af4e6SSean Callanan   case eAllocationPolicyProcessOnly:
5675a1af4e6SSean Callanan     process_sp = m_process_wp.lock();
568b9c1b51eSKate Stone     if (process_sp) {
5695a1af4e6SSean Callanan       process_sp->WriteMemory(process_address, bytes, size, error);
5705a1af4e6SSean Callanan       if (!error.Success())
5715a1af4e6SSean Callanan         return;
5725a1af4e6SSean Callanan     }
5735a1af4e6SSean Callanan     break;
5745a1af4e6SSean Callanan   }
5755a1af4e6SSean Callanan 
576a007a6d8SPavel Labath   if (lldb_private::Log *log = GetLog(LLDBLog::Expressions)) {
57763e5fb76SJonas Devlieghere     LLDB_LOGF(log,
578df6879ecSJan Kratochvil               "IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIxPTR
579b9c1b51eSKate Stone               ", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")",
580df6879ecSJan Kratochvil               (uint64_t)process_address, reinterpret_cast<uintptr_t>(bytes), (uint64_t)size,
5815a1af4e6SSean Callanan               (uint64_t)allocation.m_process_start,
582b9c1b51eSKate Stone               (uint64_t)allocation.m_process_start +
583b9c1b51eSKate Stone                   (uint64_t)allocation.m_size);
5845a1af4e6SSean Callanan   }
5855a1af4e6SSean Callanan }
5865a1af4e6SSean Callanan 
WriteScalarToMemory(lldb::addr_t process_address,Scalar & scalar,size_t size,Status & error)587b9c1b51eSKate Stone void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
588b9c1b51eSKate Stone                                       Scalar &scalar, size_t size,
58997206d57SZachary Turner                                       Status &error) {
59008052afaSSean Callanan   error.Clear();
59108052afaSSean Callanan 
59235005f76SSean Callanan   if (size == UINT32_MAX)
59335005f76SSean Callanan     size = scalar.GetByteSize();
59435005f76SSean Callanan 
595b9c1b51eSKate Stone   if (size > 0) {
59635005f76SSean Callanan     uint8_t buf[32];
597b9c1b51eSKate Stone     const size_t mem_size =
598b9c1b51eSKate Stone         scalar.GetAsMemoryData(buf, size, GetByteOrder(), error);
599b9c1b51eSKate Stone     if (mem_size > 0) {
60035005f76SSean Callanan       return WriteMemory(process_address, buf, mem_size, error);
601b9c1b51eSKate Stone     } else {
60235005f76SSean Callanan       error.SetErrorToGenericError();
603b9c1b51eSKate Stone       error.SetErrorString(
604b9c1b51eSKate Stone           "Couldn't write scalar: failed to get scalar as memory data");
60535005f76SSean Callanan     }
606b9c1b51eSKate Stone   } else {
60735005f76SSean Callanan     error.SetErrorToGenericError();
60835005f76SSean Callanan     error.SetErrorString("Couldn't write scalar: its size was zero");
60935005f76SSean Callanan   }
61035005f76SSean Callanan }
61135005f76SSean Callanan 
WritePointerToMemory(lldb::addr_t process_address,lldb::addr_t address,Status & error)612b9c1b51eSKate Stone void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
61397206d57SZachary Turner                                        lldb::addr_t address, Status &error) {
61408052afaSSean Callanan   error.Clear();
61508052afaSSean Callanan 
616f8043fa5SSean Callanan   Scalar scalar(address);
617f8043fa5SSean Callanan 
618f8043fa5SSean Callanan   WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
619f8043fa5SSean Callanan }
620f8043fa5SSean Callanan 
ReadMemory(uint8_t * bytes,lldb::addr_t process_address,size_t size,Status & error)621b9c1b51eSKate Stone void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address,
62297206d57SZachary Turner                              size_t size, Status &error) {
62308052afaSSean Callanan   error.Clear();
62408052afaSSean Callanan 
6255a1af4e6SSean Callanan   AllocationMap::iterator iter = FindAllocation(process_address, size);
6265a1af4e6SSean Callanan 
627b9c1b51eSKate Stone   if (iter == m_allocations.end()) {
628c8c5b8dcSSean Callanan     lldb::ProcessSP process_sp = m_process_wp.lock();
629c8c5b8dcSSean Callanan 
630b9c1b51eSKate Stone     if (process_sp) {
631c8c5b8dcSSean Callanan       process_sp->ReadMemory(process_address, bytes, size, error);
632c8c5b8dcSSean Callanan       return;
633c8c5b8dcSSean Callanan     }
634c8c5b8dcSSean Callanan 
635c8c5b8dcSSean Callanan     lldb::TargetSP target_sp = m_target_wp.lock();
636c8c5b8dcSSean Callanan 
637b9c1b51eSKate Stone     if (target_sp) {
638c8c5b8dcSSean Callanan       Address absolute_address(process_address);
639e9fe788dSJason Molenda       target_sp->ReadMemory(absolute_address, bytes, size, error, true);
640c8c5b8dcSSean Callanan       return;
641c8c5b8dcSSean Callanan     }
642c8c5b8dcSSean Callanan 
6435a1af4e6SSean Callanan     error.SetErrorToGenericError();
644b9c1b51eSKate Stone     error.SetErrorString("Couldn't read: no allocation contains the target "
645b9c1b51eSKate Stone                          "range, and neither the process nor the target exist");
6465a1af4e6SSean Callanan     return;
6475a1af4e6SSean Callanan   }
6485a1af4e6SSean Callanan 
6495a1af4e6SSean Callanan   Allocation &allocation = iter->second;
6505a1af4e6SSean Callanan 
6515a1af4e6SSean Callanan   uint64_t offset = process_address - allocation.m_process_start;
6525a1af4e6SSean Callanan 
653b9c1b51eSKate Stone   if (offset > allocation.m_size) {
6549bbf3cd3SSean Callanan     error.SetErrorToGenericError();
6559bbf3cd3SSean Callanan     error.SetErrorString("Couldn't read: data is not in the allocation");
6569bbf3cd3SSean Callanan     return;
6579bbf3cd3SSean Callanan   }
6589bbf3cd3SSean Callanan 
6595a1af4e6SSean Callanan   lldb::ProcessSP process_sp;
6605a1af4e6SSean Callanan 
661b9c1b51eSKate Stone   switch (allocation.m_policy) {
6625a1af4e6SSean Callanan   default:
6635a1af4e6SSean Callanan     error.SetErrorToGenericError();
6645a1af4e6SSean Callanan     error.SetErrorString("Couldn't read: invalid allocation policy");
6655a1af4e6SSean Callanan     return;
6665a1af4e6SSean Callanan   case eAllocationPolicyHostOnly:
667b9c1b51eSKate Stone     if (!allocation.m_data.GetByteSize()) {
6685a1af4e6SSean Callanan       error.SetErrorToGenericError();
6695a1af4e6SSean Callanan       error.SetErrorString("Couldn't read: data buffer is empty");
6705a1af4e6SSean Callanan       return;
6715a1af4e6SSean Callanan     }
672b9c1b51eSKate Stone     if (allocation.m_data.GetByteSize() < offset + size) {
6739bbf3cd3SSean Callanan       error.SetErrorToGenericError();
6749bbf3cd3SSean Callanan       error.SetErrorString("Couldn't read: not enough underlying data");
6759bbf3cd3SSean Callanan       return;
6769bbf3cd3SSean Callanan     }
6779bbf3cd3SSean Callanan 
678d2562509SSean Callanan     ::memcpy(bytes, allocation.m_data.GetBytes() + offset, size);
6795a1af4e6SSean Callanan     break;
6805a1af4e6SSean Callanan   case eAllocationPolicyMirror:
6815a1af4e6SSean Callanan     process_sp = m_process_wp.lock();
682b9c1b51eSKate Stone     if (process_sp) {
6835a1af4e6SSean Callanan       process_sp->ReadMemory(process_address, bytes, size, error);
6845a1af4e6SSean Callanan       if (!error.Success())
6855a1af4e6SSean Callanan         return;
686b9c1b51eSKate Stone     } else {
687b9c1b51eSKate Stone       if (!allocation.m_data.GetByteSize()) {
6885a1af4e6SSean Callanan         error.SetErrorToGenericError();
6895a1af4e6SSean Callanan         error.SetErrorString("Couldn't read: data buffer is empty");
6905a1af4e6SSean Callanan         return;
6915a1af4e6SSean Callanan       }
692d2562509SSean Callanan       ::memcpy(bytes, allocation.m_data.GetBytes() + offset, size);
6935a1af4e6SSean Callanan     }
6945a1af4e6SSean Callanan     break;
6955a1af4e6SSean Callanan   case eAllocationPolicyProcessOnly:
6965a1af4e6SSean Callanan     process_sp = m_process_wp.lock();
697b9c1b51eSKate Stone     if (process_sp) {
6985a1af4e6SSean Callanan       process_sp->ReadMemory(process_address, bytes, size, error);
6995a1af4e6SSean Callanan       if (!error.Success())
7005a1af4e6SSean Callanan         return;
7015a1af4e6SSean Callanan     }
7025a1af4e6SSean Callanan     break;
7035a1af4e6SSean Callanan   }
7045a1af4e6SSean Callanan 
705a007a6d8SPavel Labath   if (lldb_private::Log *log = GetLog(LLDBLog::Expressions)) {
70663e5fb76SJonas Devlieghere     LLDB_LOGF(log,
707df6879ecSJan Kratochvil               "IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIxPTR
708b9c1b51eSKate Stone               ", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")",
709df6879ecSJan Kratochvil               (uint64_t)process_address, reinterpret_cast<uintptr_t>(bytes), (uint64_t)size,
7105a1af4e6SSean Callanan               (uint64_t)allocation.m_process_start,
711b9c1b51eSKate Stone               (uint64_t)allocation.m_process_start +
712b9c1b51eSKate Stone                   (uint64_t)allocation.m_size);
7135a1af4e6SSean Callanan   }
7145a1af4e6SSean Callanan }
71535005f76SSean Callanan 
ReadScalarFromMemory(Scalar & scalar,lldb::addr_t process_address,size_t size,Status & error)716b9c1b51eSKate Stone void IRMemoryMap::ReadScalarFromMemory(Scalar &scalar,
717b9c1b51eSKate Stone                                        lldb::addr_t process_address,
71897206d57SZachary Turner                                        size_t size, Status &error) {
71908052afaSSean Callanan   error.Clear();
72008052afaSSean Callanan 
721b9c1b51eSKate Stone   if (size > 0) {
72235005f76SSean Callanan     DataBufferHeap buf(size, 0);
72335005f76SSean Callanan     ReadMemory(buf.GetBytes(), process_address, size, error);
72435005f76SSean Callanan 
72535005f76SSean Callanan     if (!error.Success())
72635005f76SSean Callanan       return;
72735005f76SSean Callanan 
728b9c1b51eSKate Stone     DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(),
729b9c1b51eSKate Stone                             GetAddressByteSize());
73035005f76SSean Callanan 
73135005f76SSean Callanan     lldb::offset_t offset = 0;
73235005f76SSean Callanan 
733b9c1b51eSKate Stone     switch (size) {
73435005f76SSean Callanan     default:
73535005f76SSean Callanan       error.SetErrorToGenericError();
736b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
737b9c1b51eSKate Stone           "Couldn't read scalar: unsupported size %" PRIu64, (uint64_t)size);
73835005f76SSean Callanan       return;
739b9c1b51eSKate Stone     case 1:
740b9c1b51eSKate Stone       scalar = extractor.GetU8(&offset);
741b9c1b51eSKate Stone       break;
742b9c1b51eSKate Stone     case 2:
743b9c1b51eSKate Stone       scalar = extractor.GetU16(&offset);
744b9c1b51eSKate Stone       break;
745b9c1b51eSKate Stone     case 4:
746b9c1b51eSKate Stone       scalar = extractor.GetU32(&offset);
747b9c1b51eSKate Stone       break;
748b9c1b51eSKate Stone     case 8:
749b9c1b51eSKate Stone       scalar = extractor.GetU64(&offset);
750b9c1b51eSKate Stone       break;
75135005f76SSean Callanan     }
752b9c1b51eSKate Stone   } else {
75335005f76SSean Callanan     error.SetErrorToGenericError();
754458ae1c6SSean Callanan     error.SetErrorString("Couldn't read scalar: its size was zero");
75535005f76SSean Callanan   }
75635005f76SSean Callanan }
75735005f76SSean Callanan 
ReadPointerFromMemory(lldb::addr_t * address,lldb::addr_t process_address,Status & error)758b9c1b51eSKate Stone void IRMemoryMap::ReadPointerFromMemory(lldb::addr_t *address,
759b9c1b51eSKate Stone                                         lldb::addr_t process_address,
76097206d57SZachary Turner                                         Status &error) {
76108052afaSSean Callanan   error.Clear();
76208052afaSSean Callanan 
7632d37e5a5SSean Callanan   Scalar pointer_scalar;
764b9c1b51eSKate Stone   ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(),
765b9c1b51eSKate Stone                        error);
7662d37e5a5SSean Callanan 
7672d37e5a5SSean Callanan   if (!error.Success())
7682d37e5a5SSean Callanan     return;
7692d37e5a5SSean Callanan 
7702d37e5a5SSean Callanan   *address = pointer_scalar.ULongLong();
7712d37e5a5SSean Callanan }
7722d37e5a5SSean Callanan 
GetMemoryData(DataExtractor & extractor,lldb::addr_t process_address,size_t size,Status & error)773b9c1b51eSKate Stone void IRMemoryMap::GetMemoryData(DataExtractor &extractor,
774b9c1b51eSKate Stone                                 lldb::addr_t process_address, size_t size,
77597206d57SZachary Turner                                 Status &error) {
77608052afaSSean Callanan   error.Clear();
77708052afaSSean Callanan 
778b9c1b51eSKate Stone   if (size > 0) {
779458ae1c6SSean Callanan     AllocationMap::iterator iter = FindAllocation(process_address, size);
780458ae1c6SSean Callanan 
781b9c1b51eSKate Stone     if (iter == m_allocations.end()) {
782458ae1c6SSean Callanan       error.SetErrorToGenericError();
783b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
784b9c1b51eSKate Stone           "Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64
785b9c1b51eSKate Stone           ")",
786b9c1b51eSKate Stone           process_address, process_address + size);
787458ae1c6SSean Callanan       return;
788458ae1c6SSean Callanan     }
789458ae1c6SSean Callanan 
790458ae1c6SSean Callanan     Allocation &allocation = iter->second;
791458ae1c6SSean Callanan 
792b9c1b51eSKate Stone     switch (allocation.m_policy) {
793458ae1c6SSean Callanan     default:
794458ae1c6SSean Callanan       error.SetErrorToGenericError();
795b9c1b51eSKate Stone       error.SetErrorString(
796b9c1b51eSKate Stone           "Couldn't get memory data: invalid allocation policy");
797458ae1c6SSean Callanan       return;
798458ae1c6SSean Callanan     case eAllocationPolicyProcessOnly:
799458ae1c6SSean Callanan       error.SetErrorToGenericError();
800b9c1b51eSKate Stone       error.SetErrorString(
801b9c1b51eSKate Stone           "Couldn't get memory data: memory is only in the target");
802458ae1c6SSean Callanan       return;
803b9c1b51eSKate Stone     case eAllocationPolicyMirror: {
804c8c5b8dcSSean Callanan       lldb::ProcessSP process_sp = m_process_wp.lock();
805c8c5b8dcSSean Callanan 
806b9c1b51eSKate Stone       if (!allocation.m_data.GetByteSize()) {
807c8c5b8dcSSean Callanan         error.SetErrorToGenericError();
808c8c5b8dcSSean Callanan         error.SetErrorString("Couldn't get memory data: data buffer is empty");
809c8c5b8dcSSean Callanan         return;
810c8c5b8dcSSean Callanan       }
811b9c1b51eSKate Stone       if (process_sp) {
812b9c1b51eSKate Stone         process_sp->ReadMemory(allocation.m_process_start,
813b9c1b51eSKate Stone                                allocation.m_data.GetBytes(),
814b9c1b51eSKate Stone                                allocation.m_data.GetByteSize(), error);
815c8c5b8dcSSean Callanan         if (!error.Success())
816c8c5b8dcSSean Callanan           return;
817c8c5b8dcSSean Callanan         uint64_t offset = process_address - allocation.m_process_start;
818b9c1b51eSKate Stone         extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size,
819b9c1b51eSKate Stone                                   GetByteOrder(), GetAddressByteSize());
820c8c5b8dcSSean Callanan         return;
821c8c5b8dcSSean Callanan       }
822b9c1b51eSKate Stone     } break;
823c8c5b8dcSSean Callanan     case eAllocationPolicyHostOnly:
824b9c1b51eSKate Stone       if (!allocation.m_data.GetByteSize()) {
825458ae1c6SSean Callanan         error.SetErrorToGenericError();
826458ae1c6SSean Callanan         error.SetErrorString("Couldn't get memory data: data buffer is empty");
827458ae1c6SSean Callanan         return;
828458ae1c6SSean Callanan       }
829458ae1c6SSean Callanan       uint64_t offset = process_address - allocation.m_process_start;
830b9c1b51eSKate Stone       extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size,
831b9c1b51eSKate Stone                                 GetByteOrder(), GetAddressByteSize());
832458ae1c6SSean Callanan       return;
833458ae1c6SSean Callanan     }
834b9c1b51eSKate Stone   } else {
835458ae1c6SSean Callanan     error.SetErrorToGenericError();
836458ae1c6SSean Callanan     error.SetErrorString("Couldn't get memory data: its size was zero");
837458ae1c6SSean Callanan     return;
838458ae1c6SSean Callanan   }
839458ae1c6SSean Callanan }
840