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