blob: 16fcdcafb96db6527b3f9a3c21eee344e6c0954b [file] [log] [blame]
Greg Claytond495c532011-05-17 03:37:42 +00001//===-- Memory.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/Target/Memory.h"
11// C Includes
12// C++ Includes
13// Other libraries and framework includes
14// Project includes
15#include "lldb/Core/DataBufferHeap.h"
16#include "lldb/Core/State.h"
17#include "lldb/Core/Log.h"
18#include "lldb/Target/Process.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
23//----------------------------------------------------------------------
24// MemoryCache constructor
25//----------------------------------------------------------------------
26MemoryCache::MemoryCache(Process &process) :
27 m_process (process),
28 m_cache_line_byte_size (512),
Greg Claytona9f40ad2012-02-22 04:37:26 +000029 m_mutex (Mutex::eMutexTypeRecursive),
30 m_cache (),
31 m_invalid_ranges ()
Greg Claytond495c532011-05-17 03:37:42 +000032{
33}
34
35//----------------------------------------------------------------------
36// Destructor
37//----------------------------------------------------------------------
38MemoryCache::~MemoryCache()
39{
40}
41
42void
43MemoryCache::Clear()
44{
Greg Claytona9f40ad2012-02-22 04:37:26 +000045 Mutex::Locker locker (m_mutex);
Greg Claytond495c532011-05-17 03:37:42 +000046 m_cache.clear();
47}
48
49void
50MemoryCache::Flush (addr_t addr, size_t size)
51{
52 if (size == 0)
53 return;
Greg Claytonde0e9d02012-04-13 20:37:20 +000054
Greg Claytona9f40ad2012-02-22 04:37:26 +000055 Mutex::Locker locker (m_mutex);
Greg Claytond495c532011-05-17 03:37:42 +000056 if (m_cache.empty())
57 return;
Greg Claytonde0e9d02012-04-13 20:37:20 +000058
59 const uint32_t cache_line_byte_size = m_cache_line_byte_size;
60 const addr_t end_addr = (addr + size - 1);
61 const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size);
62 const addr_t last_cache_line_addr = end_addr - (end_addr % cache_line_byte_size);
63 // Watch for overflow where size will cause us to go off the end of the
64 // 64 bit address space
65 uint32_t num_cache_lines;
66 if (last_cache_line_addr >= first_cache_line_addr)
67 num_cache_lines = ((last_cache_line_addr - first_cache_line_addr)/cache_line_byte_size) + 1;
68 else
69 num_cache_lines = (UINT64_MAX - first_cache_line_addr + 1)/cache_line_byte_size;
70
71 //printf ("MemoryCache::Flush (0x%16.16llx, %zu (0x%zx))\n", addr, size, size);
72
73 uint32_t cache_idx = 0;
74 for (addr_t curr_addr = first_cache_line_addr;
75 cache_idx < num_cache_lines;
76 curr_addr += cache_line_byte_size, ++cache_idx)
Greg Claytond495c532011-05-17 03:37:42 +000077 {
Greg Claytonde0e9d02012-04-13 20:37:20 +000078 //printf ("flushing: 0x%16.16llx\n", curr_addr); /// REMOVE THIS PRIOR TO CHECKIN!!!!
Greg Claytona9f40ad2012-02-22 04:37:26 +000079 BlockMap::iterator pos = m_cache.find (curr_addr);
Greg Claytond495c532011-05-17 03:37:42 +000080 if (pos != m_cache.end())
81 m_cache.erase(pos);
82 }
83}
84
Greg Claytona9f40ad2012-02-22 04:37:26 +000085void
86MemoryCache::AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size)
87{
88 if (byte_size > 0)
89 {
90 Mutex::Locker locker (m_mutex);
91 InvalidRanges::Entry range (base_addr, byte_size);
92 m_invalid_ranges.Append(range);
93 m_invalid_ranges.Sort();
94 }
95}
96
97bool
98MemoryCache::RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size)
99{
100 if (byte_size > 0)
101 {
102 Mutex::Locker locker (m_mutex);
103 const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr);
104 if (idx != UINT32_MAX)
105 {
106 const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex (idx);
107 if (entry->GetRangeBase() == base_addr && entry->GetByteSize() == byte_size)
108 return m_invalid_ranges.RemoveEntrtAtIndex (idx);
109 }
110 }
111 return false;
112}
113
114
115
Greg Claytond495c532011-05-17 03:37:42 +0000116size_t
117MemoryCache::Read (addr_t addr,
118 void *dst,
119 size_t dst_len,
120 Error &error)
121{
122 size_t bytes_left = dst_len;
123 if (dst && bytes_left > 0)
124 {
125 const uint32_t cache_line_byte_size = m_cache_line_byte_size;
126 uint8_t *dst_buf = (uint8_t *)dst;
127 addr_t curr_addr = addr - (addr % cache_line_byte_size);
128 addr_t cache_offset = addr - curr_addr;
Greg Claytona9f40ad2012-02-22 04:37:26 +0000129 Mutex::Locker locker (m_mutex);
Greg Claytond495c532011-05-17 03:37:42 +0000130
131 while (bytes_left > 0)
132 {
Greg Claytona9f40ad2012-02-22 04:37:26 +0000133 if (m_invalid_ranges.FindEntryThatContains(curr_addr))
134 return dst_len - bytes_left;
135
136 BlockMap::const_iterator pos = m_cache.find (curr_addr);
137 BlockMap::const_iterator end = m_cache.end ();
Greg Claytond495c532011-05-17 03:37:42 +0000138
139 if (pos != end)
140 {
141 size_t curr_read_size = cache_line_byte_size - cache_offset;
142 if (curr_read_size > bytes_left)
143 curr_read_size = bytes_left;
144
145 memcpy (dst_buf + dst_len - bytes_left, pos->second->GetBytes() + cache_offset, curr_read_size);
146
147 bytes_left -= curr_read_size;
148 curr_addr += curr_read_size + cache_offset;
149 cache_offset = 0;
150
151 if (bytes_left > 0)
152 {
153 // Get sequential cache page hits
154 for (++pos; (pos != end) && (bytes_left > 0); ++pos)
155 {
156 assert ((curr_addr % cache_line_byte_size) == 0);
157
158 if (pos->first != curr_addr)
159 break;
160
161 curr_read_size = pos->second->GetByteSize();
162 if (curr_read_size > bytes_left)
163 curr_read_size = bytes_left;
164
165 memcpy (dst_buf + dst_len - bytes_left, pos->second->GetBytes(), curr_read_size);
166
167 bytes_left -= curr_read_size;
168 curr_addr += curr_read_size;
169
170 // We have a cache page that succeeded to read some bytes
171 // but not an entire page. If this happens, we must cap
172 // off how much data we are able to read...
173 if (pos->second->GetByteSize() != cache_line_byte_size)
174 return dst_len - bytes_left;
175 }
176 }
177 }
178
179 // We need to read from the process
180
181 if (bytes_left > 0)
182 {
183 assert ((curr_addr % cache_line_byte_size) == 0);
184 std::auto_ptr<DataBufferHeap> data_buffer_heap_ap(new DataBufferHeap (cache_line_byte_size, 0));
185 size_t process_bytes_read = m_process.ReadMemoryFromInferior (curr_addr,
186 data_buffer_heap_ap->GetBytes(),
187 data_buffer_heap_ap->GetByteSize(),
188 error);
189 if (process_bytes_read == 0)
190 return dst_len - bytes_left;
191
192 if (process_bytes_read != cache_line_byte_size)
193 data_buffer_heap_ap->SetByteSize (process_bytes_read);
194 m_cache[curr_addr] = DataBufferSP (data_buffer_heap_ap.release());
195 // We have read data and put it into the cache, continue through the
196 // loop again to get the data out of the cache...
197 }
198 }
199 }
200
201 return dst_len - bytes_left;
202}
203
204
205
206AllocatedBlock::AllocatedBlock (lldb::addr_t addr,
207 uint32_t byte_size,
208 uint32_t permissions,
209 uint32_t chunk_size) :
210 m_addr (addr),
211 m_byte_size (byte_size),
212 m_permissions (permissions),
213 m_chunk_size (chunk_size),
214 m_offset_to_chunk_size ()
215// m_allocated (byte_size / chunk_size)
216{
217 assert (byte_size > chunk_size);
218}
219
220AllocatedBlock::~AllocatedBlock ()
221{
222}
223
224lldb::addr_t
225AllocatedBlock::ReserveBlock (uint32_t size)
226{
227 addr_t addr = LLDB_INVALID_ADDRESS;
228 if (size <= m_byte_size)
229 {
230 const uint32_t needed_chunks = CalculateChunksNeededForSize (size);
231 LogSP log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
232
233 if (m_offset_to_chunk_size.empty())
234 {
235 m_offset_to_chunk_size[0] = needed_chunks;
236 if (log)
237 log->Printf ("[1] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, 0, needed_chunks, m_chunk_size);
238 addr = m_addr;
239 }
240 else
241 {
242 uint32_t last_offset = 0;
243 OffsetToChunkSize::const_iterator pos = m_offset_to_chunk_size.begin();
244 OffsetToChunkSize::const_iterator end = m_offset_to_chunk_size.end();
245 while (pos != end)
246 {
247 if (pos->first > last_offset)
248 {
249 const uint32_t bytes_available = pos->first - last_offset;
250 const uint32_t num_chunks = CalculateChunksNeededForSize (bytes_available);
251 if (num_chunks >= needed_chunks)
252 {
253 m_offset_to_chunk_size[last_offset] = needed_chunks;
254 if (log)
255 log->Printf ("[2] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
256 addr = m_addr + last_offset;
257 break;
258 }
259 }
260
261 last_offset = pos->first + pos->second * m_chunk_size;
262
263 if (++pos == end)
264 {
265 // Last entry...
266 const uint32_t chunks_left = CalculateChunksNeededForSize (m_byte_size - last_offset);
267 if (chunks_left >= needed_chunks)
268 {
269 m_offset_to_chunk_size[last_offset] = needed_chunks;
270 if (log)
271 log->Printf ("[3] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
272 addr = m_addr + last_offset;
273 break;
274 }
275 }
276 }
277 }
278// const uint32_t total_chunks = m_allocated.size ();
279// uint32_t unallocated_idx = 0;
280// uint32_t allocated_idx = m_allocated.find_first();
281// uint32_t first_chunk_idx = UINT32_MAX;
282// uint32_t num_chunks;
283// while (1)
284// {
285// if (allocated_idx == UINT32_MAX)
286// {
287// // No more bits are set starting from unallocated_idx, so we
288// // either have enough chunks for the request, or we don't.
289// // Eiter way we break out of the while loop...
290// num_chunks = total_chunks - unallocated_idx;
291// if (needed_chunks <= num_chunks)
292// first_chunk_idx = unallocated_idx;
293// break;
294// }
295// else if (allocated_idx > unallocated_idx)
296// {
297// // We have some allocated chunks, check if there are enough
298// // free chunks to satisfy the request?
299// num_chunks = allocated_idx - unallocated_idx;
300// if (needed_chunks <= num_chunks)
301// {
302// // Yep, we have enough!
303// first_chunk_idx = unallocated_idx;
304// break;
305// }
306// }
307//
308// while (unallocated_idx < total_chunks)
309// {
310// if (m_allocated[unallocated_idx])
311// ++unallocated_idx;
312// else
313// break;
314// }
315//
316// if (unallocated_idx >= total_chunks)
317// break;
318//
319// allocated_idx = m_allocated.find_next(unallocated_idx);
320// }
321//
322// if (first_chunk_idx != UINT32_MAX)
323// {
324// const uint32_t end_bit_idx = unallocated_idx + needed_chunks;
325// for (uint32_t idx = first_chunk_idx; idx < end_bit_idx; ++idx)
326// m_allocated.set(idx);
327// return m_addr + m_chunk_size * first_chunk_idx;
328// }
329 }
330 LogSP log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
331 if (log)
332 log->Printf ("AllocatedBlock::ReserveBlock (size = %u (0x%x)) => 0x%16.16llx", size, size, (uint64_t)addr);
333 return addr;
334}
335
336bool
337AllocatedBlock::FreeBlock (addr_t addr)
338{
339 uint32_t offset = addr - m_addr;
340 OffsetToChunkSize::iterator pos = m_offset_to_chunk_size.find (offset);
341 bool success = false;
342 if (pos != m_offset_to_chunk_size.end())
343 {
344 m_offset_to_chunk_size.erase (pos);
345 success = true;
346 }
347 LogSP log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
348 if (log)
349 log->Printf ("AllocatedBlock::FreeBlock (addr = 0x%16.16llx) => %i", (uint64_t)addr, success);
350 return success;
351}
352
353
354AllocatedMemoryCache::AllocatedMemoryCache (Process &process) :
355 m_process (process),
356 m_mutex (Mutex::eMutexTypeRecursive),
357 m_memory_map()
358{
359}
360
361AllocatedMemoryCache::~AllocatedMemoryCache ()
362{
363}
364
365
366void
367AllocatedMemoryCache::Clear()
368{
369 Mutex::Locker locker (m_mutex);
370 if (m_process.IsAlive())
371 {
372 PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
373 for (pos = m_memory_map.begin(); pos != end; ++pos)
374 m_process.DoDeallocateMemory(pos->second->GetBaseAddress());
375 }
376 m_memory_map.clear();
377}
378
379
380AllocatedMemoryCache::AllocatedBlockSP
381AllocatedMemoryCache::AllocatePage (uint32_t byte_size,
382 uint32_t permissions,
383 uint32_t chunk_size,
384 Error &error)
385{
386 AllocatedBlockSP block_sp;
387 const size_t page_size = 4096;
388 const size_t num_pages = (byte_size + page_size - 1) / page_size;
389 const size_t page_byte_size = num_pages * page_size;
390
391 addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error);
392
393 LogSP log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
394 if (log)
395 {
396 log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16llx",
397 page_byte_size,
398 GetPermissionsAsCString(permissions),
399 (uint64_t)addr);
400 }
401
402 if (addr != LLDB_INVALID_ADDRESS)
403 {
404 block_sp.reset (new AllocatedBlock (addr, page_byte_size, permissions, chunk_size));
405 m_memory_map.insert (std::make_pair (permissions, block_sp));
406 }
407 return block_sp;
408}
409
410lldb::addr_t
411AllocatedMemoryCache::AllocateMemory (size_t byte_size,
412 uint32_t permissions,
413 Error &error)
414{
415 Mutex::Locker locker (m_mutex);
416
417 addr_t addr = LLDB_INVALID_ADDRESS;
418 std::pair<PermissionsToBlockMap::iterator, PermissionsToBlockMap::iterator> range = m_memory_map.equal_range (permissions);
419
420 for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second; ++pos)
421 {
422 addr = (*pos).second->ReserveBlock (byte_size);
423 }
424
425 if (addr == LLDB_INVALID_ADDRESS)
426 {
427 AllocatedBlockSP block_sp (AllocatePage (byte_size, permissions, 16, error));
428
429 if (block_sp)
430 addr = block_sp->ReserveBlock (byte_size);
431 }
432 LogSP log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
433 if (log)
434 log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16llx", byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr);
435 return addr;
436}
437
438bool
439AllocatedMemoryCache::DeallocateMemory (lldb::addr_t addr)
440{
441 Mutex::Locker locker (m_mutex);
442
443 PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
444 bool success = false;
445 for (pos = m_memory_map.begin(); pos != end; ++pos)
446 {
447 if (pos->second->Contains (addr))
448 {
449 success = pos->second->FreeBlock (addr);
450 break;
451 }
452 }
453 LogSP log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
454 if (log)
455 log->Printf("AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16llx) => %i", (uint64_t)addr, success);
456 return success;
457}
458
459