1 //===-- SystemRuntimeMacOSX.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 11 #include "lldb/Breakpoint/StoppointCallbackContext.h" 12 #include "lldb/Core/Log.h" 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/ModuleSpec.h" 15 #include "lldb/Core/PluginManager.h" 16 #include "lldb/Core/DataExtractor.h" 17 #include "lldb/Core/DataBufferHeap.h" 18 #include "lldb/Core/Section.h" 19 #include "lldb/Expression/ClangFunction.h" 20 #include "lldb/Expression/ClangUtilityFunction.h" 21 #include "lldb/Host/FileSpec.h" 22 #include "lldb/Symbol/ObjectFile.h" 23 #include "lldb/Symbol/SymbolContext.h" 24 #include "Plugins/Process/Utility/HistoryThread.h" 25 #include "lldb/Target/Queue.h" 26 #include "lldb/Target/QueueList.h" 27 #include "lldb/Target/Target.h" 28 #include "lldb/Target/Thread.h" 29 30 #include "SystemRuntimeMacOSX.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 35 //---------------------------------------------------------------------- 36 // Create an instance of this class. This function is filled into 37 // the plugin info class that gets handed out by the plugin factory and 38 // allows the lldb to instantiate an instance of this class. 39 //---------------------------------------------------------------------- 40 SystemRuntime * 41 SystemRuntimeMacOSX::CreateInstance (Process* process) 42 { 43 bool create = false; 44 if (!create) 45 { 46 create = true; 47 Module* exe_module = process->GetTarget().GetExecutableModulePointer(); 48 if (exe_module) 49 { 50 ObjectFile *object_file = exe_module->GetObjectFile(); 51 if (object_file) 52 { 53 create = (object_file->GetStrata() == ObjectFile::eStrataUser); 54 } 55 } 56 57 if (create) 58 { 59 const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); 60 switch (triple_ref.getOS()) 61 { 62 case llvm::Triple::Darwin: 63 case llvm::Triple::MacOSX: 64 case llvm::Triple::IOS: 65 create = triple_ref.getVendor() == llvm::Triple::Apple; 66 break; 67 default: 68 create = false; 69 break; 70 } 71 } 72 } 73 74 if (create) 75 return new SystemRuntimeMacOSX (process); 76 return NULL; 77 } 78 79 //---------------------------------------------------------------------- 80 // Constructor 81 //---------------------------------------------------------------------- 82 SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) : 83 SystemRuntime(process), 84 m_break_id(LLDB_INVALID_BREAK_ID), 85 m_mutex(Mutex::eMutexTypeRecursive) 86 { 87 m_ldi_header.initialized = 0; 88 } 89 90 //---------------------------------------------------------------------- 91 // Destructor 92 //---------------------------------------------------------------------- 93 SystemRuntimeMacOSX::~SystemRuntimeMacOSX() 94 { 95 Clear (true); 96 } 97 98 //---------------------------------------------------------------------- 99 // Clear out the state of this class. 100 //---------------------------------------------------------------------- 101 void 102 SystemRuntimeMacOSX::Clear (bool clear_process) 103 { 104 Mutex::Locker locker(m_mutex); 105 106 if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id)) 107 m_process->ClearBreakpointSiteByID(m_break_id); 108 109 if (clear_process) 110 m_process = NULL; 111 m_break_id = LLDB_INVALID_BREAK_ID; 112 m_ldi_header.initialized = 0; 113 } 114 115 116 void 117 SystemRuntimeMacOSX::DidAttach () 118 { 119 } 120 121 void 122 SystemRuntimeMacOSX::DidLaunch () 123 { 124 } 125 126 void 127 SystemRuntimeMacOSX::ModulesDidLoad (ModuleList &module_list) 128 { 129 } 130 131 bool 132 SystemRuntimeMacOSX::LdiHeadersInitialized () 133 { 134 ParseLdiHeaders(); 135 return m_ldi_header.initialized; 136 } 137 138 void 139 SystemRuntimeMacOSX::ParseLdiHeaders () 140 { 141 if (m_ldi_header.initialized) 142 return; 143 static ConstString ldi_header_symbol ("ldi_infos"); 144 SymbolContextList sc_list; 145 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (ldi_header_symbol, eSymbolTypeData, sc_list) > 0) 146 { 147 SymbolContext sc; 148 sc_list.GetContextAtIndex (0, sc); 149 AddressRange addr_range; 150 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range); 151 152 Error error; 153 Address ldi_header_addr = addr_range.GetBaseAddress(); 154 uint8_t version_buf[6]; // version, ldi_header_size, initialized fields 155 DataExtractor data (version_buf, sizeof(version_buf), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 156 const size_t count = sizeof (version_buf); 157 const bool prefer_file_cache = false; 158 if (m_process->GetTarget().ReadMemory (ldi_header_addr, prefer_file_cache, version_buf, count, error) == sizeof (version_buf)) 159 { 160 int version, initialized, ldi_header_size; 161 offset_t offset = 0; 162 version = data.GetU16(&offset); 163 ldi_header_size = data.GetU16(&offset); 164 initialized = data.GetU16(&offset); 165 if (initialized) 166 { 167 DataBufferHeap ldi_header (ldi_header_size, 0); 168 DataExtractor ldi_extractor (ldi_header.GetBytes(), ldi_header.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 169 if (m_process->GetTarget().ReadMemory (ldi_header_addr, prefer_file_cache, ldi_header.GetBytes(), ldi_header.GetByteSize(), error) == ldi_header.GetByteSize()) 170 { 171 offset = 0; 172 m_ldi_header.version = ldi_extractor.GetU16(&offset); 173 m_ldi_header.ldi_header_size = ldi_extractor.GetU16(&offset); 174 m_ldi_header.initialized = ldi_extractor.GetU16(&offset); 175 m_ldi_header.queue_size = ldi_extractor.GetU16(&offset); 176 m_ldi_header.item_size = ldi_extractor.GetU16(&offset); 177 178 // 6 bytes of padding here 179 offset += 6; 180 181 m_ldi_header.queues_head_ptr_address = ldi_extractor.GetU64(&offset); 182 m_ldi_header.items_head_ptr_address = ldi_extractor.GetU64(&offset); 183 184 m_ldi_header.queue_offsets.next = ldi_extractor.GetU16(&offset); 185 m_ldi_header.queue_offsets.prev = ldi_extractor.GetU16(&offset); 186 m_ldi_header.queue_offsets.queue_id = ldi_extractor.GetU16(&offset); 187 m_ldi_header.queue_offsets.current_item_ptr = ldi_extractor.GetU16(&offset); 188 189 m_ldi_header.item_offsets.next = ldi_extractor.GetU16(&offset); 190 m_ldi_header.item_offsets.prev = ldi_extractor.GetU16(&offset); 191 m_ldi_header.item_offsets.type = ldi_extractor.GetU16(&offset); 192 m_ldi_header.item_offsets.identifier = ldi_extractor.GetU16(&offset); 193 m_ldi_header.item_offsets.stop_id = ldi_extractor.GetU16(&offset); 194 m_ldi_header.item_offsets.backtrace_length = ldi_extractor.GetU16(&offset); 195 m_ldi_header.item_offsets.backtrace_ptr = ldi_extractor.GetU16(&offset); 196 m_ldi_header.item_offsets.thread_name_ptr = ldi_extractor.GetU16(&offset); 197 m_ldi_header.item_offsets.queue_name_ptr = ldi_extractor.GetU16(&offset); 198 m_ldi_header.item_offsets.unique_thread_id = ldi_extractor.GetU16(&offset); 199 m_ldi_header.item_offsets.pthread_id = ldi_extractor.GetU16(&offset); 200 m_ldi_header.item_offsets.enqueueing_thread_dispatch_queue_t = ldi_extractor.GetU16(&offset); 201 m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr = ldi_extractor.GetU16(&offset); 202 203 if (ldi_header.GetByteSize () > offset) 204 { 205 m_ldi_header.item_offsets.queue_id_from_thread_info = ldi_extractor.GetU16(&offset); 206 } 207 else 208 { 209 m_ldi_header.item_offsets.queue_id_from_thread_info = 0xffff; 210 } 211 } 212 } 213 } 214 } 215 } 216 217 lldb::addr_t 218 SystemRuntimeMacOSX::GetQueuesHead () 219 { 220 if (!LdiHeadersInitialized()) 221 return LLDB_INVALID_ADDRESS; 222 223 Error error; 224 addr_t queues_head = m_process->ReadPointerFromMemory (m_ldi_header.queues_head_ptr_address, error); 225 if (error.Success() == false || queues_head == LLDB_INVALID_ADDRESS || queues_head == 0) 226 return LLDB_INVALID_ADDRESS; 227 228 return queues_head; 229 } 230 231 lldb::addr_t 232 SystemRuntimeMacOSX::GetItemsHead () 233 { 234 if (!LdiHeadersInitialized()) 235 return LLDB_INVALID_ADDRESS; 236 237 Error error; 238 addr_t items_head = m_process->ReadPointerFromMemory (m_ldi_header.items_head_ptr_address, error); 239 if (error.Success() == false || items_head == LLDB_INVALID_ADDRESS || items_head == 0) 240 return LLDB_INVALID_ADDRESS; 241 242 return items_head; 243 } 244 245 addr_t 246 SystemRuntimeMacOSX::GetThreadCreatorItem (ThreadSP thread_sp) 247 { 248 addr_t enqueued_item_ptr = thread_sp->GetExtendedBacktraceToken(); 249 if (enqueued_item_ptr == LLDB_INVALID_ADDRESS) 250 { 251 if (thread_sp->GetQueueID() == LLDB_INVALID_QUEUE_ID || thread_sp->GetQueueID() == 0) 252 return LLDB_INVALID_ADDRESS; 253 254 Error error; 255 uint64_t this_thread_queue_id = thread_sp->GetQueueID(); 256 257 addr_t queues_head = GetQueuesHead(); 258 if (queues_head == LLDB_INVALID_ADDRESS) 259 return LLDB_INVALID_ADDRESS; 260 261 // Step through the queues_head linked list looking for a queue matching this thread, if any 262 uint64_t queue_obj_ptr = queues_head; 263 enqueued_item_ptr = LLDB_INVALID_ADDRESS; 264 265 while (queue_obj_ptr != 0) 266 { 267 uint64_t queue_id = m_process->ReadUnsignedIntegerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.queue_id, 8, LLDB_INVALID_ADDRESS, error); 268 if (error.Success() && queue_id != LLDB_INVALID_ADDRESS) 269 { 270 if (queue_id == this_thread_queue_id) 271 { 272 enqueued_item_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.current_item_ptr, error); 273 break; 274 } 275 } 276 queue_obj_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.next, error); 277 if (error.Success() == false || queue_obj_ptr == LLDB_INVALID_ADDRESS) 278 { 279 break; 280 } 281 } 282 } 283 284 return enqueued_item_ptr; 285 } 286 287 SystemRuntimeMacOSX::ArchivedBacktrace 288 SystemRuntimeMacOSX::GetLibdispatchExtendedBacktrace (ThreadSP thread_sp) 289 { 290 ArchivedBacktrace bt; 291 bt.stop_id = 0; 292 bt.stop_id_is_valid = false; 293 bt.libdispatch_queue_id = LLDB_INVALID_QUEUE_ID; 294 295 addr_t enqueued_item_ptr = GetThreadCreatorItem (thread_sp); 296 297 if (enqueued_item_ptr == LLDB_INVALID_ADDRESS) 298 return bt; 299 300 Error error; 301 uint32_t ptr_size = m_process->GetTarget().GetArchitecture().GetAddressByteSize(); 302 303 uint32_t backtrace_length = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_length, 4, 0, error); 304 addr_t pc_array_address = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_ptr, error); 305 306 if (backtrace_length == 0 || pc_array_address == LLDB_INVALID_ADDRESS) 307 return bt; 308 309 for (uint32_t idx = 0; idx < backtrace_length; idx++) 310 { 311 addr_t pc_val = m_process->ReadPointerFromMemory (pc_array_address + (ptr_size * idx), error); 312 if (error.Success() && pc_val != LLDB_INVALID_ADDRESS) 313 { 314 bt.pcs.push_back (pc_val); 315 } 316 } 317 318 return bt; 319 } 320 321 const std::vector<ConstString> & 322 SystemRuntimeMacOSX::GetExtendedBacktraceTypes () 323 { 324 if (m_types.size () == 0) 325 { 326 m_types.push_back(ConstString("libdispatch")); 327 m_types.push_back(ConstString("pthread")); 328 } 329 return m_types; 330 } 331 332 void 333 SystemRuntimeMacOSX::SetNewThreadQueueName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) 334 { 335 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); 336 337 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS) 338 { 339 Error error; 340 addr_t queue_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_name_ptr, error); 341 if (queue_name_ptr != LLDB_INVALID_ADDRESS && error.Success()) 342 { 343 char namebuf[512]; 344 if (m_process->ReadCStringFromMemory (queue_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success()) 345 { 346 new_extended_thread_sp->SetQueueName (namebuf); 347 } 348 } 349 } 350 } 351 352 void 353 SystemRuntimeMacOSX::SetNewThreadThreadName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) 354 { 355 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); 356 357 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS) 358 { 359 Error error; 360 addr_t thread_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.thread_name_ptr, error); 361 if (thread_name_ptr != LLDB_INVALID_ADDRESS && error.Success()) 362 { 363 char namebuf[512]; 364 if (m_process->ReadCStringFromMemory (thread_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success()) 365 { 366 new_extended_thread_sp->SetName (namebuf); 367 } 368 } 369 } 370 } 371 372 373 void 374 SystemRuntimeMacOSX::SetNewThreadExtendedBacktraceToken (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) 375 { 376 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); 377 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS) 378 { 379 Error error; 380 uint64_t further_extended_backtrace = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr, error); 381 if (error.Success() && further_extended_backtrace != 0 && further_extended_backtrace != LLDB_INVALID_ADDRESS) 382 { 383 new_extended_thread_sp->SetExtendedBacktraceToken (further_extended_backtrace); 384 } 385 } 386 } 387 388 void 389 SystemRuntimeMacOSX::SetNewThreadQueueID (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) 390 { 391 queue_id_t queue_id = LLDB_INVALID_QUEUE_ID; 392 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); 393 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS && m_ldi_header.item_offsets.queue_id_from_thread_info != 0xffff) 394 { 395 Error error; 396 queue_id = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_id_from_thread_info, 8, LLDB_INVALID_QUEUE_ID, error); 397 if (!error.Success()) 398 queue_id = LLDB_INVALID_QUEUE_ID; 399 } 400 401 if (queue_id != LLDB_INVALID_QUEUE_ID) 402 { 403 new_extended_thread_sp->SetQueueID (queue_id); 404 } 405 } 406 407 408 lldb::tid_t 409 SystemRuntimeMacOSX::GetNewThreadUniqueThreadID (ThreadSP original_thread_sp) 410 { 411 tid_t ret = LLDB_INVALID_THREAD_ID; 412 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); 413 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS) 414 { 415 Error error; 416 ret = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.unique_thread_id, 8, LLDB_INVALID_THREAD_ID, error); 417 if (!error.Success()) 418 ret = LLDB_INVALID_THREAD_ID; 419 } 420 return ret; 421 } 422 423 ThreadSP 424 SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP original_thread_sp, ConstString type) 425 { 426 ThreadSP new_extended_thread_sp; 427 428 if (type != ConstString("libdispatch")) 429 return new_extended_thread_sp; 430 431 ArchivedBacktrace bt = GetLibdispatchExtendedBacktrace (original_thread_sp); 432 433 if (bt.pcs.size() == 0) 434 return new_extended_thread_sp; 435 436 tid_t unique_thread_id = GetNewThreadUniqueThreadID (original_thread_sp); 437 438 new_extended_thread_sp.reset (new HistoryThread (*m_process, unique_thread_id, bt.pcs, bt.stop_id, bt.stop_id_is_valid)); 439 440 SetNewThreadThreadName (original_thread_sp, new_extended_thread_sp); 441 SetNewThreadQueueName (original_thread_sp, new_extended_thread_sp); 442 SetNewThreadQueueID (original_thread_sp, new_extended_thread_sp); 443 SetNewThreadExtendedBacktraceToken (original_thread_sp, new_extended_thread_sp); 444 return new_extended_thread_sp; 445 } 446 447 void 448 SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list) 449 { 450 // For now, iterate over the threads and see what queue each thread is associated with. 451 // If we haven't already added this queue, add it to the QueueList. 452 // (a single libdispatch queue may be using multiple threads simultaneously.) 453 454 for (ThreadSP thread_sp : m_process->Threads()) 455 { 456 if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) 457 { 458 if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL) 459 { 460 QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName())); 461 queue_list.AddQueue (queue_sp); 462 } 463 } 464 } 465 } 466 467 468 void 469 SystemRuntimeMacOSX::Initialize() 470 { 471 PluginManager::RegisterPlugin (GetPluginNameStatic(), 472 GetPluginDescriptionStatic(), 473 CreateInstance); 474 } 475 476 void 477 SystemRuntimeMacOSX::Terminate() 478 { 479 PluginManager::UnregisterPlugin (CreateInstance); 480 } 481 482 483 lldb_private::ConstString 484 SystemRuntimeMacOSX::GetPluginNameStatic() 485 { 486 static ConstString g_name("systemruntime-macosx"); 487 return g_name; 488 } 489 490 const char * 491 SystemRuntimeMacOSX::GetPluginDescriptionStatic() 492 { 493 return "System runtime plugin for Mac OS X native libraries."; 494 } 495 496 497 //------------------------------------------------------------------ 498 // PluginInterface protocol 499 //------------------------------------------------------------------ 500 lldb_private::ConstString 501 SystemRuntimeMacOSX::GetPluginName() 502 { 503 return GetPluginNameStatic(); 504 } 505 506 uint32_t 507 SystemRuntimeMacOSX::GetPluginVersion() 508 { 509 return 1; 510 } 511