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