blob: aea57b25ae1a139c373e5cca3dd7358e88d714ed [file] [log] [blame]
Sean Callanan5a1af4e2013-04-05 02:22:57 +00001//===-- IRMemoryMap.cpp -----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Core/Error.h"
11#include "lldb/Core/Log.h"
12#include "lldb/Expression/IRMemoryMap.h"
13#include "lldb/Target/Process.h"
14
15using namespace lldb_private;
16
17IRMemoryMap::IRMemoryMap (lldb::ProcessSP process_sp) :
18 m_process_wp(process_sp)
19{
20}
21
22IRMemoryMap::~IRMemoryMap ()
23{
24 lldb::ProcessSP process_sp = m_process_wp.lock();
25
26 if (process_sp)
27 {
28 for (AllocationMap::value_type &allocation : m_allocations)
29 {
30 if (allocation.second.m_policy == eAllocationPolicyMirror ||
31 allocation.second.m_policy == eAllocationPolicyHostOnly)
32 process_sp->DeallocateMemory(allocation.second.m_process_alloc);
33
34 if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
35 {
36 log->Printf("IRMemoryMap::~IRMemoryMap deallocated [0x%llx..0x%llx)",
37 (uint64_t)allocation.second.m_process_start,
38 (uint64_t)allocation.second.m_process_start + (uint64_t)allocation.second.m_size);
39 }
40 }
41 }
42}
43
44lldb::addr_t
45IRMemoryMap::FindSpace (size_t size)
46{
47 // Yup, this is just plain O(n) insertion. We'll use a range tree if we
48 // start caring.
49
50 lldb::addr_t remote_address = 0x1000; // skip first page of memory
51
52 for (AllocationMap::value_type &allocation : m_allocations)
53 {
54 if (remote_address < allocation.second.m_process_start &&
55 remote_address + size <= allocation.second.m_process_start)
56 return remote_address;
57
58 remote_address = allocation.second.m_process_start = allocation.second.m_size;
59 }
60
61 if (remote_address + size < remote_address)
62 return LLDB_INVALID_ADDRESS; // massively unlikely
63
64 return remote_address;
65}
66
67bool
68IRMemoryMap::ContainsHostOnlyAllocations ()
69{
70 for (AllocationMap::value_type &allocation : m_allocations)
71 {
72 if (allocation.second.m_policy == eAllocationPolicyHostOnly)
73 return true;
74 }
75
76 return false;
77}
78
79IRMemoryMap::AllocationMap::iterator
80IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size)
81{
82 AllocationMap::iterator iter = m_allocations.lower_bound (addr);
83
84 if (iter == m_allocations.end())
85 return iter;
86
87 if (iter->first > addr)
88 {
89 if (iter == m_allocations.begin())
90 return m_allocations.end();
91 iter--;
92 }
93
94 if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size)
95 return iter;
96
97 return m_allocations.end();
98}
99
100lldb::addr_t
101IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
102{
103 lldb::ProcessSP process_sp;
104 lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
105 lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
106
107 size_t allocation_size = (size ? size : 1) + alignment - 1;
108
109 switch (policy)
110 {
111 default:
112 error.SetErrorToGenericError();
113 error.SetErrorString("Couldn't malloc: invalid allocation policy");
114 return LLDB_INVALID_ADDRESS;
115 case eAllocationPolicyHostOnly:
116 allocation_address = FindSpace(allocation_size);
117 if (allocation_address == LLDB_INVALID_ADDRESS)
118 {
119 error.SetErrorToGenericError();
120 error.SetErrorString("Couldn't malloc: address space is full");
121 return LLDB_INVALID_ADDRESS;
122 }
123 break;
124 case eAllocationPolicyMirror:
125 if (ContainsHostOnlyAllocations())
126 {
127 error.SetErrorToGenericError();
128 error.SetErrorString("Couldn't malloc: host-only allocations are polluting the address space");
129 return LLDB_INVALID_ADDRESS;
130 }
131 process_sp = m_process_wp.lock();
132 if (process_sp)
133 {
134 allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
135 if (!error.Success())
136 return LLDB_INVALID_ADDRESS;
137 }
138 else
139 {
140 allocation_address = FindSpace(allocation_size);
141 if (allocation_address == LLDB_INVALID_ADDRESS)
142 {
143 error.SetErrorToGenericError();
144 error.SetErrorString("Couldn't malloc: address space is full");
145 return LLDB_INVALID_ADDRESS;
146 }
147 }
148 break;
149 case eAllocationPolicyProcessOnly:
150 if (ContainsHostOnlyAllocations())
151 {
152 error.SetErrorToGenericError();
153 error.SetErrorString("Couldn't malloc: host-only allocations are polluting the address space");
154 return LLDB_INVALID_ADDRESS;
155 }
156 process_sp = m_process_wp.lock();
157 if (process_sp)
158 {
159 allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
160 if (!error.Success())
161 return LLDB_INVALID_ADDRESS;
162 }
163 else
164 {
165 error.SetErrorToGenericError();
166 error.SetErrorString("Couldn't malloc: process doesn't exist, and this memory must be in the process");
167 return LLDB_INVALID_ADDRESS;
168 }
169 break;
170 }
171
172
173 lldb::addr_t mask = alignment - 1;
174 aligned_address = (allocation_address + mask) & (~mask);
175
176 Allocation &allocation(m_allocations[aligned_address]);
177
178 allocation.m_process_alloc = allocation_address;
179 allocation.m_process_start = aligned_address;
180 allocation.m_size = size;
181 allocation.m_permissions = permissions;
182 allocation.m_alignment = alignment;
183 allocation.m_policy = policy;
184
185 switch (policy)
186 {
187 default:
188 assert (0 && "We cannot reach this!");
189 case eAllocationPolicyHostOnly:
190 allocation.m_data.reset(new DataBufferHeap(size, 0));
191 break;
192 case eAllocationPolicyProcessOnly:
193 break;
194 case eAllocationPolicyMirror:
195 allocation.m_data.reset(new DataBufferHeap(size, 0));
196 break;
197 }
198
199 if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
200 {
201 const char * policy_string;
202
203 switch (policy)
204 {
205 default:
206 policy_string = "<invalid policy>";
207 break;
208 case eAllocationPolicyHostOnly:
209 policy_string = "eAllocationPolicyHostOnly";
210 break;
211 case eAllocationPolicyProcessOnly:
212 policy_string = "eAllocationPolicyProcessOnly";
213 break;
214 case eAllocationPolicyMirror:
215 policy_string = "eAllocationPolicyMirror";
216 break;
217 }
218
219 log->Printf("IRMemoryMap::Malloc (%llu, 0x%llx, 0x%llx, %s) -> 0x%llx",
220 (uint64_t)size,
221 (uint64_t)alignment,
222 (uint64_t)permissions,
223 policy_string,
224 aligned_address);
225 }
226
227 return aligned_address;
228}
229
230void
231IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
232{
233 AllocationMap::iterator iter = m_allocations.find(process_address);
234
235 if (iter == m_allocations.end())
236 {
237 error.SetErrorToGenericError();
238 error.SetErrorString("Couldn't free: allocation doesn't exist");
239 return;
240 }
241
242 Allocation &allocation = iter->second;
243
244 switch (allocation.m_policy)
245 {
246 default:
247 case eAllocationPolicyHostOnly:
248 break;
249 case eAllocationPolicyMirror:
250 case eAllocationPolicyProcessOnly:
251 lldb::ProcessSP process_sp = m_process_wp.lock();
252 if (process_sp)
253 process_sp->DeallocateMemory(allocation.m_process_alloc);
254 }
255
256 if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
257 {
258 log->Printf("IRMemoryMap::Free (0x%llx) freed [0x%llx..0x%llx)",
259 (uint64_t)process_address,
260 iter->second.m_process_start,
261 iter->second.m_process_start + iter->second.m_size);
262 }
263
264 m_allocations.erase(iter);
265}
266
267void
268IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error)
269{
270 AllocationMap::iterator iter = FindAllocation(process_address, size);
271
272 if (iter == m_allocations.end())
273 {
274 error.SetErrorToGenericError();
275 error.SetErrorString("Couldn't write: no allocation contains the target range");
276 return;
277 }
278
279 Allocation &allocation = iter->second;
280
281 uint64_t offset = process_address - allocation.m_process_start;
282
283 lldb::ProcessSP process_sp;
284
285 switch (allocation.m_policy)
286 {
287 default:
288 error.SetErrorToGenericError();
289 error.SetErrorString("Couldn't write: invalid allocation policy");
290 return;
291 case eAllocationPolicyHostOnly:
292 if (!allocation.m_data)
293 {
294 error.SetErrorToGenericError();
295 error.SetErrorString("Couldn't write: data buffer is empty");
296 return;
297 }
298 ::memcpy (allocation.m_data->GetBytes() + offset, bytes, size);
299 break;
300 case eAllocationPolicyMirror:
301 if (!allocation.m_data)
302 {
303 error.SetErrorToGenericError();
304 error.SetErrorString("Couldn't write: data buffer is empty");
305 return;
306 }
307 ::memcpy (allocation.m_data->GetBytes() + offset, bytes, size);
308 process_sp = m_process_wp.lock();
309 if (process_sp)
310 {
311 process_sp->WriteMemory(process_address, bytes, size, error);
312 if (!error.Success())
313 return;
314 }
315 break;
316 case eAllocationPolicyProcessOnly:
317 process_sp = m_process_wp.lock();
318 if (process_sp)
319 {
320 process_sp->WriteMemory(process_address, bytes, size, error);
321 if (!error.Success())
322 return;
323 }
324 break;
325 }
326
327 if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
328 {
329 log->Printf("IRMemoryMap::WriteMemory (0x%llx, 0x%llx, 0x%lld) went to [0x%llx..0x%llx)",
330 (uint64_t)process_address,
331 (uint64_t)bytes,
332 (uint64_t)size,
333 (uint64_t)allocation.m_process_start,
334 (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size);
335 }
336}
337
338void
339IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error)
340{
341 AllocationMap::iterator iter = FindAllocation(process_address, size);
342
343 if (iter == m_allocations.end())
344 {
345 error.SetErrorToGenericError();
346 error.SetErrorString("Couldn't read: no allocation contains the target range");
347 return;
348 }
349
350 Allocation &allocation = iter->second;
351
352 uint64_t offset = process_address - allocation.m_process_start;
353
354 lldb::ProcessSP process_sp;
355
356 switch (allocation.m_policy)
357 {
358 default:
359 error.SetErrorToGenericError();
360 error.SetErrorString("Couldn't read: invalid allocation policy");
361 return;
362 case eAllocationPolicyHostOnly:
363 if (!allocation.m_data)
364 {
365 error.SetErrorToGenericError();
366 error.SetErrorString("Couldn't read: data buffer is empty");
367 return;
368 }
369 ::memcpy (bytes, allocation.m_data->GetBytes() + offset, size);
370 break;
371 case eAllocationPolicyMirror:
372 process_sp = m_process_wp.lock();
373 if (process_sp)
374 {
375 process_sp->ReadMemory(process_address, bytes, size, error);
376 if (!error.Success())
377 return;
378 }
379 else
380 {
381 if (!allocation.m_data)
382 {
383 error.SetErrorToGenericError();
384 error.SetErrorString("Couldn't read: data buffer is empty");
385 return;
386 }
387 ::memcpy (bytes, allocation.m_data->GetBytes() + offset, size);
388 }
389 break;
390 case eAllocationPolicyProcessOnly:
391 process_sp = m_process_wp.lock();
392 if (process_sp)
393 {
394 process_sp->ReadMemory(process_address, bytes, size, error);
395 if (!error.Success())
396 return;
397 }
398 break;
399 }
400
401 if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
402 {
403 log->Printf("IRMemoryMap::ReadMemory (0x%llx, 0x%llx, 0x%lld) came from [0x%llx..0x%llx)",
404 (uint64_t)process_address,
405 (uint64_t)bytes,
406 (uint64_t)size,
407 (uint64_t)allocation.m_process_start,
408 (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size);
409 }
410}