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