blob: 5756e7071d7dbf4fedd900d5fa6f665484554e80 [file] [log] [blame]
Jason Molendaa7b5afa2013-11-15 00:17:32 +00001//===-- 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"
Jason Molenda5e8dce42013-12-13 00:29:16 +000025#include "lldb/Target/Queue.h"
26#include "lldb/Target/QueueList.h"
Jason Molendaa7b5afa2013-11-15 00:17:32 +000027#include "lldb/Target/Target.h"
28#include "lldb/Target/Thread.h"
29
Jason Molendaa7b5afa2013-11-15 00:17:32 +000030#include "SystemRuntimeMacOSX.h"
31
32using namespace lldb;
33using 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//----------------------------------------------------------------------
40SystemRuntime *
41SystemRuntimeMacOSX::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//----------------------------------------------------------------------
82SystemRuntimeMacOSX::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//----------------------------------------------------------------------
93SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
94{
95 Clear (true);
96}
97
98//----------------------------------------------------------------------
99// Clear out the state of this class.
100//----------------------------------------------------------------------
101void
102SystemRuntimeMacOSX::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
116void
117SystemRuntimeMacOSX::DidAttach ()
118{
119}
120
121void
122SystemRuntimeMacOSX::DidLaunch ()
123{
124}
125
126void
127SystemRuntimeMacOSX::ModulesDidLoad (ModuleList &module_list)
128{
129}
130
131bool
132SystemRuntimeMacOSX::LdiHeadersInitialized ()
133{
134 ParseLdiHeaders();
135 return m_ldi_header.initialized;
136}
137
138void
139SystemRuntimeMacOSX::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);
Jason Molendaa6e91302013-11-19 05:44:41 +0000202
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 }
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000211 }
212 }
213 }
214 }
215}
216
217lldb::addr_t
218SystemRuntimeMacOSX::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
231lldb::addr_t
232SystemRuntimeMacOSX::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
245addr_t
246SystemRuntimeMacOSX::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
287SystemRuntimeMacOSX::ArchivedBacktrace
288SystemRuntimeMacOSX::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
321const std::vector<ConstString> &
322SystemRuntimeMacOSX::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
332void
333SystemRuntimeMacOSX::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 {
Jason Molenda8ee9cb52013-11-16 01:24:22 +0000343 char namebuf[512];
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000344 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
352void
Jason Molenda8ee9cb52013-11-16 01:24:22 +0000353SystemRuntimeMacOSX::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
373void
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000374SystemRuntimeMacOSX::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
Jason Molendaa6e91302013-11-19 05:44:41 +0000388void
389SystemRuntimeMacOSX::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
Jason Molenda8ee9cb52013-11-16 01:24:22 +0000408lldb::tid_t
Jason Molendaa6e91302013-11-19 05:44:41 +0000409SystemRuntimeMacOSX::GetNewThreadUniqueThreadID (ThreadSP original_thread_sp)
Jason Molenda8ee9cb52013-11-16 01:24:22 +0000410{
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
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000423ThreadSP
424SystemRuntimeMacOSX::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
Jason Molendaa6e91302013-11-19 05:44:41 +0000436 tid_t unique_thread_id = GetNewThreadUniqueThreadID (original_thread_sp);
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000437
Jason Molenda8ee9cb52013-11-16 01:24:22 +0000438 new_extended_thread_sp.reset (new HistoryThread (*m_process, unique_thread_id, bt.pcs, bt.stop_id, bt.stop_id_is_valid));
439
Jason Molendaa6e91302013-11-19 05:44:41 +0000440 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);
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000444 return new_extended_thread_sp;
445}
446
Jason Molenda5e8dce42013-12-13 00:29:16 +0000447void
448SystemRuntimeMacOSX::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
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000467
468void
469SystemRuntimeMacOSX::Initialize()
470{
471 PluginManager::RegisterPlugin (GetPluginNameStatic(),
472 GetPluginDescriptionStatic(),
473 CreateInstance);
474}
475
476void
477SystemRuntimeMacOSX::Terminate()
478{
479 PluginManager::UnregisterPlugin (CreateInstance);
480}
481
482
483lldb_private::ConstString
484SystemRuntimeMacOSX::GetPluginNameStatic()
485{
486 static ConstString g_name("systemruntime-macosx");
487 return g_name;
488}
489
490const char *
491SystemRuntimeMacOSX::GetPluginDescriptionStatic()
492{
493 return "System runtime plugin for Mac OS X native libraries.";
494}
495
496
497//------------------------------------------------------------------
498// PluginInterface protocol
499//------------------------------------------------------------------
500lldb_private::ConstString
501SystemRuntimeMacOSX::GetPluginName()
502{
503 return GetPluginNameStatic();
504}
505
506uint32_t
507SystemRuntimeMacOSX::GetPluginVersion()
508{
509 return 1;
510}