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