blob: 7ff14fc5e092b94f2e37bba0ddc573c3d49d7eed [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"
Jason Molenda2fd83352014-02-05 05:44:54 +000029#include "lldb/Target/Process.h"
30
Jason Molendaa7b5afa2013-11-15 00:17:32 +000031
Jason Molendaa7b5afa2013-11-15 00:17:32 +000032#include "SystemRuntimeMacOSX.h"
33
34using namespace lldb;
35using namespace lldb_private;
36
37//----------------------------------------------------------------------
38// Create an instance of this class. This function is filled into
39// the plugin info class that gets handed out by the plugin factory and
40// allows the lldb to instantiate an instance of this class.
41//----------------------------------------------------------------------
42SystemRuntime *
43SystemRuntimeMacOSX::CreateInstance (Process* process)
44{
45 bool create = false;
46 if (!create)
47 {
48 create = true;
49 Module* exe_module = process->GetTarget().GetExecutableModulePointer();
50 if (exe_module)
51 {
52 ObjectFile *object_file = exe_module->GetObjectFile();
53 if (object_file)
54 {
55 create = (object_file->GetStrata() == ObjectFile::eStrataUser);
56 }
57 }
58
59 if (create)
60 {
61 const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
62 switch (triple_ref.getOS())
63 {
64 case llvm::Triple::Darwin:
65 case llvm::Triple::MacOSX:
66 case llvm::Triple::IOS:
67 create = triple_ref.getVendor() == llvm::Triple::Apple;
68 break;
69 default:
70 create = false;
71 break;
72 }
73 }
74 }
75
76 if (create)
77 return new SystemRuntimeMacOSX (process);
78 return NULL;
79}
80
81//----------------------------------------------------------------------
82// Constructor
83//----------------------------------------------------------------------
84SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) :
85 SystemRuntime(process),
86 m_break_id(LLDB_INVALID_BREAK_ID),
Jason Molenda2fd83352014-02-05 05:44:54 +000087 m_mutex(Mutex::eMutexTypeRecursive),
88 m_get_queues_handler(process),
89 m_get_pending_items_handler(process),
90 m_get_item_info_handler(process),
91 m_get_thread_item_info_handler(process),
92 m_page_to_free(LLDB_INVALID_ADDRESS),
93 m_page_to_free_size(0),
94 m_lib_backtrace_recording_info(),
95 m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
96 m_libdispatch_offsets()
Jason Molendaa7b5afa2013-11-15 00:17:32 +000097{
Jason Molendaa7b5afa2013-11-15 00:17:32 +000098}
99
100//----------------------------------------------------------------------
101// Destructor
102//----------------------------------------------------------------------
103SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
104{
105 Clear (true);
106}
107
Jason Molenda2fd83352014-02-05 05:44:54 +0000108void
109SystemRuntimeMacOSX::Detach ()
110{
111 m_get_queues_handler.Detach();
112 m_get_pending_items_handler.Detach();
113 m_get_item_info_handler.Detach();
114 m_get_thread_item_info_handler.Detach();
115}
116
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000117//----------------------------------------------------------------------
118// Clear out the state of this class.
119//----------------------------------------------------------------------
120void
121SystemRuntimeMacOSX::Clear (bool clear_process)
122{
123 Mutex::Locker locker(m_mutex);
124
125 if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
126 m_process->ClearBreakpointSiteByID(m_break_id);
127
128 if (clear_process)
129 m_process = NULL;
130 m_break_id = LLDB_INVALID_BREAK_ID;
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000131}
132
133
Jason Molenda2fd83352014-02-05 05:44:54 +0000134std::string
135SystemRuntimeMacOSX::GetQueueNameFromThreadQAddress (addr_t dispatch_qaddr)
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000136{
Jason Molenda2fd83352014-02-05 05:44:54 +0000137 std::string dispatch_queue_name;
138 if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
139 return "";
140
141 ReadLibdispatchOffsets ();
142 if (m_libdispatch_offsets.IsValid ())
143 {
144 // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
145 // deref it to get the address of the dispatch_queue_t structure for this thread's
146 // queue.
147 Error error;
148 addr_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
149 if (error.Success())
150 {
151 if (m_libdispatch_offsets.dqo_version >= 4)
152 {
153 // libdispatch versions 4+, pointer to dispatch name is in the
154 // queue structure.
155 addr_t pointer_to_label_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
156 addr_t label_addr = m_process->ReadPointerFromMemory (pointer_to_label_address, error);
157 if (error.Success())
158 {
159 m_process->ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
160 }
161 }
162 else
163 {
164 // libdispatch versions 1-3, dispatch name is a fixed width char array
165 // in the queue structure.
166 addr_t label_addr = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
167 dispatch_queue_name.resize (m_libdispatch_offsets.dqo_label_size, '\0');
168 size_t bytes_read = m_process->ReadMemory (label_addr, &dispatch_queue_name[0], m_libdispatch_offsets.dqo_label_size, error);
169 if (bytes_read < m_libdispatch_offsets.dqo_label_size)
170 dispatch_queue_name.erase (bytes_read);
171 }
172 }
173 }
174 return dispatch_queue_name;
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000175}
176
Jason Molendaaac16e02014-03-13 02:54:54 +0000177lldb::addr_t
178SystemRuntimeMacOSX::GetLibdispatchQueueAddressFromThreadQAddress (addr_t dispatch_qaddr)
179{
180 addr_t libdispatch_queue_t_address = LLDB_INVALID_ADDRESS;
181 Error error;
182 libdispatch_queue_t_address = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
183 if (!error.Success())
184 {
185 libdispatch_queue_t_address = LLDB_INVALID_ADDRESS;
186 }
187 return libdispatch_queue_t_address;
188}
189
190lldb::QueueKind
191SystemRuntimeMacOSX::GetQueueKind (addr_t dispatch_queue_addr)
192{
193 if (dispatch_queue_addr == LLDB_INVALID_ADDRESS || dispatch_queue_addr == 0)
194 return eQueueKindUnknown;
195
196 QueueKind kind = eQueueKindUnknown;
197 ReadLibdispatchOffsets ();
198 if (m_libdispatch_offsets.IsValid () && m_libdispatch_offsets.dqo_version >= 4)
199 {
200 Error error;
201 uint64_t width = m_process->ReadUnsignedIntegerFromMemory (dispatch_queue_addr + m_libdispatch_offsets.dqo_width, m_libdispatch_offsets.dqo_width_size, 0, error);
202 if (error.Success())
203 {
204 if (width == 1)
205 {
206 kind = eQueueKindSerial;
207 }
208 if (width > 1)
209 {
210 kind = eQueueKindConcurrent;
211 }
212 }
213 }
214 return kind;
215}
216
Jason Molenda2fd83352014-02-05 05:44:54 +0000217lldb::queue_id_t
218SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr)
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000219{
Jason Molenda2fd83352014-02-05 05:44:54 +0000220 queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
221
222 if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
223 return queue_id;
224
225 ReadLibdispatchOffsets ();
226 if (m_libdispatch_offsets.IsValid ())
227 {
228 // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
229 // deref it to get the address of the dispatch_queue_t structure for this thread's
230 // queue.
231 Error error;
232 uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
233 if (error.Success())
234 {
235 addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum;
236 queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory (serialnum_address, m_libdispatch_offsets.dqo_serialnum_size, LLDB_INVALID_QUEUE_ID, error);
237 if (error.Success())
238 {
239 queue_id = serialnum;
240 }
241 }
242 }
243
244 return queue_id;
245}
246
247
248void
249SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress ()
250{
251 if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS)
252 return;
253
254 static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
255 const Symbol *dispatch_queue_offsets_symbol = NULL;
256
257 // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
258 ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
259 ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
260 if (module_sp)
261 dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
262
263 // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
264 if (dispatch_queue_offsets_symbol == NULL)
265 {
266 ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
267 module_sp = m_process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
268 if (module_sp)
269 dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
270 }
271 if (dispatch_queue_offsets_symbol)
272 m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget());
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000273}
274
275void
Jason Molenda2fd83352014-02-05 05:44:54 +0000276SystemRuntimeMacOSX::ReadLibdispatchOffsets ()
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000277{
Jason Molenda2fd83352014-02-05 05:44:54 +0000278 if (m_libdispatch_offsets.IsValid())
279 return;
280
281 ReadLibdispatchOffsetsAddress ();
282
283 uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)];
284 DataExtractor data (memory_buffer,
285 sizeof(memory_buffer),
286 m_process->GetByteOrder(),
287 m_process->GetAddressByteSize());
288
289 Error error;
290 if (m_process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
291 {
292 lldb::offset_t data_offset = 0;
293
294 // The struct LibdispatchOffsets is a series of uint16_t's - extract them all
295 // in one big go.
296 data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t));
297 }
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000298}
299
Jason Molenda2fd83352014-02-05 05:44:54 +0000300
301ThreadSP
302SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type)
303{
304 ThreadSP originating_thread_sp;
305 if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch"))
306 {
307 Error error;
308
309 // real_thread is either an actual, live thread (in which case we need to call into
310 // libBacktraceRecording to find its originator) or it is an extended backtrace itself,
311 // in which case we get the token from it and call into libBacktraceRecording to find
312 // the originator of that token.
313
314 if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS)
315 {
316 originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken());
317 }
318 else
319 {
Jason Molendada276f92014-02-11 00:36:18 +0000320 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
321 AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = m_get_thread_item_info_handler.GetThreadItemInfo (*cur_thread_sp.get(), real_thread->GetID(), m_page_to_free, m_page_to_free_size, error);
Jason Molenda2a6c2522014-02-15 00:20:40 +0000322 m_page_to_free = LLDB_INVALID_ADDRESS;
323 m_page_to_free_size = 0;
Jason Molenda2fd83352014-02-05 05:44:54 +0000324 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
325 {
326 DataBufferHeap data (ret.item_buffer_size, 0);
327 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
328 {
329 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
330 ItemInfo item = ExtractItemInfoFromBuffer (extractor);
331 bool stop_id_is_valid = true;
332 if (item.stop_id == 0)
333 stop_id_is_valid = false;
334 originating_thread_sp.reset (new HistoryThread (*m_process,
335 item.enqueuing_thread_id,
336 item.enqueuing_callstack,
337 item.stop_id,
338 stop_id_is_valid));
339 originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
340 originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
341 originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
342// originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
343 }
Jason Molendada276f92014-02-11 00:36:18 +0000344 m_page_to_free = ret.item_buffer_ptr;
345 m_page_to_free_size = ret.item_buffer_size;
Jason Molenda2fd83352014-02-05 05:44:54 +0000346 }
347 }
348 }
349 return originating_thread_sp;
350}
351
352ThreadSP
353SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref)
354{
355 ThreadSP return_thread_sp;
356
357 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
358 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
359 Error error;
360 ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
Jason Molenda2a6c2522014-02-15 00:20:40 +0000361 m_page_to_free = LLDB_INVALID_ADDRESS;
362 m_page_to_free_size = 0;
Jason Molenda2fd83352014-02-05 05:44:54 +0000363 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
364 {
365 DataBufferHeap data (ret.item_buffer_size, 0);
366 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
367 {
368 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
369 ItemInfo item = ExtractItemInfoFromBuffer (extractor);
370 bool stop_id_is_valid = true;
371 if (item.stop_id == 0)
372 stop_id_is_valid = false;
373 return_thread_sp.reset (new HistoryThread (*m_process,
374 item.enqueuing_thread_id,
375 item.enqueuing_callstack,
376 item.stop_id,
377 stop_id_is_valid));
378 return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
379 return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
380 return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
381// return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
382
Jason Molendada276f92014-02-11 00:36:18 +0000383 m_page_to_free = ret.item_buffer_ptr;
384 m_page_to_free_size = ret.item_buffer_size;
Jason Molenda2fd83352014-02-05 05:44:54 +0000385 }
386 }
387 return return_thread_sp;
388}
389
390ThreadSP
391SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem (QueueItemSP queue_item_sp, ConstString type)
392{
393 ThreadSP extended_thread_sp;
394 if (type != ConstString("libdispatch"))
395 return extended_thread_sp;
396
397 bool stop_id_is_valid = true;
398 if (queue_item_sp->GetStopID() == 0)
399 stop_id_is_valid = false;
400
401 extended_thread_sp.reset (new HistoryThread (*m_process,
402 queue_item_sp->GetEnqueueingThreadID(),
403 queue_item_sp->GetEnqueueingBacktrace(),
404 queue_item_sp->GetStopID(),
405 stop_id_is_valid));
406 extended_thread_sp->SetExtendedBacktraceToken (queue_item_sp->GetItemThatEnqueuedThis());
407 extended_thread_sp->SetQueueName (queue_item_sp->GetQueueLabel().c_str());
408 extended_thread_sp->SetQueueID (queue_item_sp->GetEnqueueingQueueID());
409// extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str());
410
411 return extended_thread_sp;
412}
413
414/* Returns true if we were able to get the version / offset information
415 * out of libBacktraceRecording. false means we were unable to retrieve
416 * this; the queue_info_version field will be 0.
417 */
418
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000419bool
Jason Molenda2fd83352014-02-05 05:44:54 +0000420SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized ()
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000421{
Jason Molenda2fd83352014-02-05 05:44:54 +0000422 if (m_lib_backtrace_recording_info.queue_info_version != 0)
423 return true;
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000424
Jason Molenda2fd83352014-02-05 05:44:54 +0000425 addr_t queue_info_version_address = LLDB_INVALID_ADDRESS;
426 addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS;
427 addr_t item_info_version_address = LLDB_INVALID_ADDRESS;
428 addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS;
429 Target &target = m_process->GetTarget();
430
431
432 static ConstString introspection_dispatch_queue_info_version ("__introspection_dispatch_queue_info_version");
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000433 SymbolContextList sc_list;
Jason Molenda2fd83352014-02-05 05:44:54 +0000434 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list) > 0)
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000435 {
436 SymbolContext sc;
437 sc_list.GetContextAtIndex (0, sc);
438 AddressRange addr_range;
439 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
Jason Molenda2fd83352014-02-05 05:44:54 +0000440 queue_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
441 }
442 sc_list.Clear();
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000443
Jason Molenda2fd83352014-02-05 05:44:54 +0000444 static ConstString introspection_dispatch_queue_info_data_offset ("__introspection_dispatch_queue_info_data_offset");
445 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list) > 0)
446 {
447 SymbolContext sc;
448 sc_list.GetContextAtIndex (0, sc);
449 AddressRange addr_range;
450 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
451 queue_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
452 }
453 sc_list.Clear();
454
455 static ConstString introspection_dispatch_item_info_version ("__introspection_dispatch_item_info_version");
456 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_version, eSymbolTypeData, sc_list) > 0)
457 {
458 SymbolContext sc;
459 sc_list.GetContextAtIndex (0, sc);
460 AddressRange addr_range;
461 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
462 item_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
463 }
464 sc_list.Clear();
465
466 static ConstString introspection_dispatch_item_info_data_offset ("__introspection_dispatch_item_info_data_offset");
467 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list) > 0)
468 {
469 SymbolContext sc;
470 sc_list.GetContextAtIndex (0, sc);
471 AddressRange addr_range;
472 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
473 item_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
474 }
475
476 if (queue_info_version_address != LLDB_INVALID_ADDRESS
477 && queue_info_data_offset_address != LLDB_INVALID_ADDRESS
478 && item_info_version_address != LLDB_INVALID_ADDRESS
479 && item_info_data_offset_address != LLDB_INVALID_ADDRESS)
480 {
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000481 Error error;
Jason Molenda2fd83352014-02-05 05:44:54 +0000482 m_lib_backtrace_recording_info.queue_info_version = m_process->ReadUnsignedIntegerFromMemory (queue_info_version_address, 2, 0, error);
483 if (error.Success())
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000484 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000485 m_lib_backtrace_recording_info.queue_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (queue_info_data_offset_address, 2, 0, error);
486 if (error.Success())
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000487 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000488 m_lib_backtrace_recording_info.item_info_version = m_process->ReadUnsignedIntegerFromMemory (item_info_version_address, 2, 0, error);
489 if (error.Success())
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000490 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000491 m_lib_backtrace_recording_info.item_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (item_info_data_offset_address, 2, 0, error);
492 if (!error.Success())
Jason Molendaa6e91302013-11-19 05:44:41 +0000493 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000494 m_lib_backtrace_recording_info.queue_info_version = 0;
Jason Molendaa6e91302013-11-19 05:44:41 +0000495 }
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000496 }
Jason Molenda2fd83352014-02-05 05:44:54 +0000497 else
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000498 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000499 m_lib_backtrace_recording_info.queue_info_version = 0;
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000500 }
501 }
Jason Molenda2fd83352014-02-05 05:44:54 +0000502 else
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000503 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000504 m_lib_backtrace_recording_info.queue_info_version = 0;
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000505 }
506 }
507 }
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000508
Jason Molenda2fd83352014-02-05 05:44:54 +0000509 return m_lib_backtrace_recording_info.queue_info_version != 0;
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000510}
511
512const std::vector<ConstString> &
513SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
514{
515 if (m_types.size () == 0)
516 {
517 m_types.push_back(ConstString("libdispatch"));
Jason Molenda2fd83352014-02-05 05:44:54 +0000518 // We could have pthread as another type in the future if we have a way of
519 // gathering that information & it's useful to distinguish between them.
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000520 }
521 return m_types;
522}
523
524void
Jason Molenda5e8dce42013-12-13 00:29:16 +0000525SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
526{
Jason Molendab9ffa982014-04-25 00:01:15 +0000527 if (BacktraceRecordingHeadersInitialized())
Jason Molenda2fd83352014-02-05 05:44:54 +0000528 {
529 AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer;
530 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
531 if (cur_thread_sp)
532 {
533 Error error;
534 queue_info_pointer = m_get_queues_handler.GetCurrentQueues (*cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error);
Jason Molenda2a6c2522014-02-15 00:20:40 +0000535 m_page_to_free = LLDB_INVALID_ADDRESS;
536 m_page_to_free_size = 0;
Jason Molenda2fd83352014-02-05 05:44:54 +0000537 if (error.Success())
538 {
Jason Molenda2fd83352014-02-05 05:44:54 +0000539
540 if (queue_info_pointer.count > 0
541 && queue_info_pointer.queues_buffer_size > 0
542 && queue_info_pointer.queues_buffer_ptr != 0
543 && queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS)
544 {
545 PopulateQueuesUsingLibBTR (queue_info_pointer.queues_buffer_ptr, queue_info_pointer.queues_buffer_size, queue_info_pointer.count, queue_list);
546 }
Jason Molenda5e8dce42013-12-13 00:29:16 +0000547 }
548 }
549 }
Jason Molendab9ffa982014-04-25 00:01:15 +0000550
551 // We either didn't have libBacktraceRecording (and need to create the queues list based on threads)
552 // or we did get the queues list from libBacktraceRecording but some special queues may not be
553 // included in its information. This is needed because libBacktraceRecording
554 // will only list queues with pending or running items by default - but the magic com.apple.main-thread
555 // queue on thread 1 is always around.
556
557 for (ThreadSP thread_sp : m_process->Threads())
558 {
559 if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
560 {
561 if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
562 {
563 QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
564 queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress()));
565 queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress());
566 queue_list.AddQueue (queue_sp);
567 }
568 }
569 }
Jason Molenda5e8dce42013-12-13 00:29:16 +0000570}
571
Jason Molenda37e9b5a2014-03-09 21:17:08 +0000572// Returns either an array of introspection_dispatch_item_info_ref's for the pending items on
573// a queue or an array introspection_dispatch_item_info_ref's and code addresses for the
574// pending items on a queue. The information about each of these pending items then needs to
575// be fetched individually by passing the ref to libBacktraceRecording.
576
577SystemRuntimeMacOSX::PendingItemsForQueue
578SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue)
579{
580 PendingItemsForQueue pending_item_refs;
581 AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer;
582 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
583 if (cur_thread_sp)
584 {
585 Error error;
586 pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error);
587 m_page_to_free = LLDB_INVALID_ADDRESS;
588 m_page_to_free_size = 0;
589 if (error.Success())
590 {
591 if (pending_items_pointer.count > 0
592 && pending_items_pointer.items_buffer_size > 0
593 && pending_items_pointer.items_buffer_ptr != 0
594 && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS)
595 {
596 DataBufferHeap data (pending_items_pointer.items_buffer_size, 0);
597 if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error))
598 {
599 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
600
601 // We either have an array of
602 // void* item_ref
603 // (old style) or we have a structure returned which looks like
604 //
605 // struct introspection_dispatch_pending_item_info_s {
606 // void *item_ref;
607 // void *function_or_block;
608 // };
609 //
610 // struct introspection_dispatch_pending_items_array_s {
611 // uint32_t version;
612 // uint32_t size_of_item_info;
613 // introspection_dispatch_pending_item_info_s items[];
614 // }
615
616 offset_t offset = 0;
617 int i = 0;
618 uint32_t version = extractor.GetU32(&offset);
619 if (version == 1)
620 {
621 pending_item_refs.new_style = true;
622 uint32_t item_size = extractor.GetU32(&offset);
623 uint32_t start_of_array_offset = offset;
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000624 while (offset < pending_items_pointer.items_buffer_size &&
625 static_cast<size_t>(i) < pending_items_pointer.count)
Jason Molenda37e9b5a2014-03-09 21:17:08 +0000626 {
627 offset = start_of_array_offset + (i * item_size);
628 ItemRefAndCodeAddress item;
629 item.item_ref = extractor.GetPointer (&offset);
630 item.code_address = extractor.GetPointer (&offset);
631 pending_item_refs.item_refs_and_code_addresses.push_back (item);
632 i++;
633 }
634 }
635 else
636 {
637 offset = 0;
638 pending_item_refs.new_style = false;
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000639 while (offset < pending_items_pointer.items_buffer_size &&
640 static_cast<size_t>(i) < pending_items_pointer.count)
Jason Molenda37e9b5a2014-03-09 21:17:08 +0000641 {
642 ItemRefAndCodeAddress item;
643 item.item_ref = extractor.GetPointer (&offset);
644 item.code_address = LLDB_INVALID_ADDRESS;
645 pending_item_refs.item_refs_and_code_addresses.push_back (item);
646 i++;
647 }
648 }
649 }
650 m_page_to_free = pending_items_pointer.items_buffer_ptr;
651 m_page_to_free_size = pending_items_pointer.items_buffer_size;
652 }
653 }
654 }
655 return pending_item_refs;
656}
657
658
659
Jason Molenda2fd83352014-02-05 05:44:54 +0000660void
661SystemRuntimeMacOSX::PopulatePendingItemsForQueue (Queue *queue)
662{
663 if (BacktraceRecordingHeadersInitialized())
664 {
Jason Molenda37e9b5a2014-03-09 21:17:08 +0000665 PendingItemsForQueue pending_item_refs = GetPendingItemRefsForQueue (queue->GetLibdispatchQueueAddress());
666 for (ItemRefAndCodeAddress pending_item : pending_item_refs.item_refs_and_code_addresses)
Jason Molenda2fd83352014-02-05 05:44:54 +0000667 {
Jason Molendae32cd192014-03-10 08:42:03 +0000668 Address addr;
669 m_process->GetTarget().ResolveLoadAddress (pending_item.code_address, addr);
670 QueueItemSP queue_item_sp (new QueueItem (queue->shared_from_this(), m_process->shared_from_this(), pending_item.item_ref, addr));
671 queue->PushPendingQueueItem (queue_item_sp);
Jason Molenda2fd83352014-02-05 05:44:54 +0000672 }
673 }
674}
675
Jason Molendae32cd192014-03-10 08:42:03 +0000676void
677SystemRuntimeMacOSX::CompleteQueueItem (QueueItem *queue_item, addr_t item_ref)
678{
679 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
680
681 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
682 Error error;
683 ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
684 m_page_to_free = LLDB_INVALID_ADDRESS;
685 m_page_to_free_size = 0;
686 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
687 {
688 DataBufferHeap data (ret.item_buffer_size, 0);
689 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
690 {
691 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
692 ItemInfo item = ExtractItemInfoFromBuffer (extractor);
693 queue_item->SetItemThatEnqueuedThis (item.item_that_enqueued_this);
694 queue_item->SetEnqueueingThreadID (item.enqueuing_thread_id);
695 queue_item->SetEnqueueingQueueID (item.enqueuing_queue_serialnum);
696 queue_item->SetStopID (item.stop_id);
697 queue_item->SetEnqueueingBacktrace (item.enqueuing_callstack);
698 queue_item->SetThreadLabel (item.enqueuing_thread_label);
699 queue_item->SetQueueLabel (item.enqueuing_queue_label);
700 queue_item->SetTargetQueueLabel (item.target_queue_label);
701 }
702 m_page_to_free = ret.item_buffer_ptr;
703 m_page_to_free_size = ret.item_buffer_size;
704 }
705}
706
Jason Molenda2fd83352014-02-05 05:44:54 +0000707void
708SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size,
709 uint64_t count, lldb_private::QueueList &queue_list)
710{
711 Error error;
712 DataBufferHeap data (queues_buffer_size, 0);
Jason Molendad84f6062014-02-26 22:27:09 +0000713 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
Jason Molenda2fd83352014-02-05 05:44:54 +0000714 if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success())
715 {
716 // We've read the information out of inferior memory; free it on the next call we make
717 m_page_to_free = queues_buffer;
718 m_page_to_free_size = queues_buffer_size;
719
720 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
721 offset_t offset = 0;
722 uint64_t queues_read = 0;
723
724 // The information about the queues is stored in this format (v1):
725 // typedef struct introspection_dispatch_queue_info_s {
726 // uint32_t offset_to_next;
727 // dispatch_queue_t queue;
728 // uint64_t serialnum; // queue's serialnum in the process, as provided by libdispatch
729 // uint32_t running_work_items_count;
730 // uint32_t pending_work_items_count;
731 //
732 // char data[]; // Starting here, we have variable-length data:
733 // // char queue_label[];
734 // } introspection_dispatch_queue_info_s;
735
736 while (queues_read < count && offset < queues_buffer_size)
737 {
738 offset_t start_of_this_item = offset;
739
740 uint32_t offset_to_next = extractor.GetU32 (&offset);
Jason Molendad84f6062014-02-26 22:27:09 +0000741
742 offset += 4; // Skip over the 4 bytes of reserved space
Jason Molenda2fd83352014-02-05 05:44:54 +0000743 addr_t queue = extractor.GetPointer (&offset);
744 uint64_t serialnum = extractor.GetU64 (&offset);
745 uint32_t running_work_items_count = extractor.GetU32 (&offset);
746 uint32_t pending_work_items_count = extractor.GetU32 (&offset);
747
748 // Read the first field of the variable length data
749 offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset;
750 const char *queue_label = extractor.GetCStr (&offset);
751 if (queue_label == NULL)
752 queue_label = "";
753
754 offset_t start_of_next_item = start_of_this_item + offset_to_next;
755 offset = start_of_next_item;
756
Jason Molendad84f6062014-02-26 22:27:09 +0000757 if (log)
758 log->Printf ("SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added queue with dispatch_queue_t 0x%" PRIx64 ", serial number 0x%" PRIx64 ", running items %d, pending items %d, name '%s'", queue, serialnum, running_work_items_count, pending_work_items_count, queue_label);
759
Jason Molenda2fd83352014-02-05 05:44:54 +0000760 QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label));
761 queue_sp->SetNumRunningWorkItems (running_work_items_count);
762 queue_sp->SetNumPendingWorkItems (pending_work_items_count);
763 queue_sp->SetLibdispatchQueueAddress (queue);
Jason Molendaaac16e02014-03-13 02:54:54 +0000764 queue_sp->SetKind (GetQueueKind (queue));
Jason Molenda2fd83352014-02-05 05:44:54 +0000765 queue_list.AddQueue (queue_sp);
766 queues_read++;
767 }
768 }
769}
770
771SystemRuntimeMacOSX::ItemInfo
772SystemRuntimeMacOSX::ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor)
773{
774 ItemInfo item;
775
776 offset_t offset = 0;
777
778 item.item_that_enqueued_this = extractor.GetPointer (&offset);
779 item.function_or_block = extractor.GetPointer (&offset);
780 item.enqueuing_thread_id = extractor.GetU64 (&offset);
781 item.enqueuing_queue_serialnum = extractor.GetU64 (&offset);
782 item.target_queue_serialnum = extractor.GetU64 (&offset);
783 item.enqueuing_callstack_frame_count = extractor.GetU32 (&offset);
784 item.stop_id = extractor.GetU32 (&offset);
785
786 offset = m_lib_backtrace_recording_info.item_info_data_offset;
787
788 for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++)
789 {
790 item.enqueuing_callstack.push_back (extractor.GetPointer (&offset));
791 }
792 item.enqueuing_thread_label = extractor.GetCStr (&offset);
793 item.enqueuing_queue_label = extractor.GetCStr (&offset);
794 item.target_queue_label = extractor.GetCStr (&offset);
795
796 return item;
797}
Jason Molendaa7b5afa2013-11-15 00:17:32 +0000798
799void
800SystemRuntimeMacOSX::Initialize()
801{
802 PluginManager::RegisterPlugin (GetPluginNameStatic(),
803 GetPluginDescriptionStatic(),
804 CreateInstance);
805}
806
807void
808SystemRuntimeMacOSX::Terminate()
809{
810 PluginManager::UnregisterPlugin (CreateInstance);
811}
812
813
814lldb_private::ConstString
815SystemRuntimeMacOSX::GetPluginNameStatic()
816{
817 static ConstString g_name("systemruntime-macosx");
818 return g_name;
819}
820
821const char *
822SystemRuntimeMacOSX::GetPluginDescriptionStatic()
823{
824 return "System runtime plugin for Mac OS X native libraries.";
825}
826
827
828//------------------------------------------------------------------
829// PluginInterface protocol
830//------------------------------------------------------------------
831lldb_private::ConstString
832SystemRuntimeMacOSX::GetPluginName()
833{
834 return GetPluginNameStatic();
835}
836
837uint32_t
838SystemRuntimeMacOSX::GetPluginVersion()
839{
840 return 1;
841}