blob: ba52ce55f1f4a419e2e4965694fb60363c41e2bf [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"
25#include "lldb/Target/Target.h"
26#include "lldb/Target/Thread.h"
27
28
29#include "SystemRuntimeMacOSX.h"
30
31using namespace lldb;
32using 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//----------------------------------------------------------------------
39SystemRuntime *
40SystemRuntimeMacOSX::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//----------------------------------------------------------------------
81SystemRuntimeMacOSX::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//----------------------------------------------------------------------
92SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
93{
94 Clear (true);
95}
96
97//----------------------------------------------------------------------
98// Clear out the state of this class.
99//----------------------------------------------------------------------
100void
101SystemRuntimeMacOSX::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
115void
116SystemRuntimeMacOSX::DidAttach ()
117{
118}
119
120void
121SystemRuntimeMacOSX::DidLaunch ()
122{
123}
124
125void
126SystemRuntimeMacOSX::ModulesDidLoad (ModuleList &module_list)
127{
128}
129
130bool
131SystemRuntimeMacOSX::LdiHeadersInitialized ()
132{
133 ParseLdiHeaders();
134 return m_ldi_header.initialized;
135}
136
137void
138SystemRuntimeMacOSX::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 }
203 }
204 }
205 }
206}
207
208lldb::addr_t
209SystemRuntimeMacOSX::GetQueuesHead ()
210{
211 if (!LdiHeadersInitialized())
212 return LLDB_INVALID_ADDRESS;
213
214 Error error;
215 addr_t queues_head = m_process->ReadPointerFromMemory (m_ldi_header.queues_head_ptr_address, error);
216 if (error.Success() == false || queues_head == LLDB_INVALID_ADDRESS || queues_head == 0)
217 return LLDB_INVALID_ADDRESS;
218
219 return queues_head;
220}
221
222lldb::addr_t
223SystemRuntimeMacOSX::GetItemsHead ()
224{
225 if (!LdiHeadersInitialized())
226 return LLDB_INVALID_ADDRESS;
227
228 Error error;
229 addr_t items_head = m_process->ReadPointerFromMemory (m_ldi_header.items_head_ptr_address, error);
230 if (error.Success() == false || items_head == LLDB_INVALID_ADDRESS || items_head == 0)
231 return LLDB_INVALID_ADDRESS;
232
233 return items_head;
234}
235
236addr_t
237SystemRuntimeMacOSX::GetThreadCreatorItem (ThreadSP thread_sp)
238{
239 addr_t enqueued_item_ptr = thread_sp->GetExtendedBacktraceToken();
240 if (enqueued_item_ptr == LLDB_INVALID_ADDRESS)
241 {
242 if (thread_sp->GetQueueID() == LLDB_INVALID_QUEUE_ID || thread_sp->GetQueueID() == 0)
243 return LLDB_INVALID_ADDRESS;
244
245 Error error;
246 uint64_t this_thread_queue_id = thread_sp->GetQueueID();
247
248 addr_t queues_head = GetQueuesHead();
249 if (queues_head == LLDB_INVALID_ADDRESS)
250 return LLDB_INVALID_ADDRESS;
251
252 // Step through the queues_head linked list looking for a queue matching this thread, if any
253 uint64_t queue_obj_ptr = queues_head;
254 enqueued_item_ptr = LLDB_INVALID_ADDRESS;
255
256 while (queue_obj_ptr != 0)
257 {
258 uint64_t queue_id = m_process->ReadUnsignedIntegerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.queue_id, 8, LLDB_INVALID_ADDRESS, error);
259 if (error.Success() && queue_id != LLDB_INVALID_ADDRESS)
260 {
261 if (queue_id == this_thread_queue_id)
262 {
263 enqueued_item_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.current_item_ptr, error);
264 break;
265 }
266 }
267 queue_obj_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.next, error);
268 if (error.Success() == false || queue_obj_ptr == LLDB_INVALID_ADDRESS)
269 {
270 break;
271 }
272 }
273 }
274
275 return enqueued_item_ptr;
276}
277
278SystemRuntimeMacOSX::ArchivedBacktrace
279SystemRuntimeMacOSX::GetLibdispatchExtendedBacktrace (ThreadSP thread_sp)
280{
281 ArchivedBacktrace bt;
282 bt.stop_id = 0;
283 bt.stop_id_is_valid = false;
284 bt.libdispatch_queue_id = LLDB_INVALID_QUEUE_ID;
285
286 addr_t enqueued_item_ptr = GetThreadCreatorItem (thread_sp);
287
288 if (enqueued_item_ptr == LLDB_INVALID_ADDRESS)
289 return bt;
290
291 Error error;
292 uint32_t ptr_size = m_process->GetTarget().GetArchitecture().GetAddressByteSize();
293
294 uint32_t backtrace_length = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_length, 4, 0, error);
295 addr_t pc_array_address = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_ptr, error);
296
297 if (backtrace_length == 0 || pc_array_address == LLDB_INVALID_ADDRESS)
298 return bt;
299
300 for (uint32_t idx = 0; idx < backtrace_length; idx++)
301 {
302 addr_t pc_val = m_process->ReadPointerFromMemory (pc_array_address + (ptr_size * idx), error);
303 if (error.Success() && pc_val != LLDB_INVALID_ADDRESS)
304 {
305 bt.pcs.push_back (pc_val);
306 }
307 }
308
309 return bt;
310}
311
312const std::vector<ConstString> &
313SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
314{
315 if (m_types.size () == 0)
316 {
317 m_types.push_back(ConstString("libdispatch"));
318 m_types.push_back(ConstString("pthread"));
319 }
320 return m_types;
321}
322
323void
324SystemRuntimeMacOSX::SetNewThreadQueueName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
325{
326 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
327
328 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
329 {
330 Error error;
331 addr_t queue_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_name_ptr, error);
332 if (queue_name_ptr != LLDB_INVALID_ADDRESS && error.Success())
333 {
334 char namebuf[256];
335 if (m_process->ReadCStringFromMemory (queue_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success())
336 {
337 new_extended_thread_sp->SetQueueName (namebuf);
338 }
339 }
340 }
341}
342
343void
344SystemRuntimeMacOSX::SetNewThreadExtendedBacktraceToken (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
345{
346 addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
347 if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
348 {
349 Error error;
350 uint64_t further_extended_backtrace = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr, error);
351 if (error.Success() && further_extended_backtrace != 0 && further_extended_backtrace != LLDB_INVALID_ADDRESS)
352 {
353 new_extended_thread_sp->SetExtendedBacktraceToken (further_extended_backtrace);
354 }
355 }
356}
357
358ThreadSP
359SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP original_thread_sp, ConstString type)
360{
361 ThreadSP new_extended_thread_sp;
362
363 if (type != ConstString("libdispatch"))
364 return new_extended_thread_sp;
365
366 ArchivedBacktrace bt = GetLibdispatchExtendedBacktrace (original_thread_sp);
367
368 if (bt.pcs.size() == 0)
369 return new_extended_thread_sp;
370
371 new_extended_thread_sp.reset (new HistoryThread (*m_process, bt.pcs, bt.stop_id, bt.stop_id_is_valid));
372
373 SetNewThreadQueueName(original_thread_sp, new_extended_thread_sp);
374 SetNewThreadExtendedBacktraceToken(original_thread_sp, new_extended_thread_sp);
375
376 return new_extended_thread_sp;
377}
378
379
380void
381SystemRuntimeMacOSX::Initialize()
382{
383 PluginManager::RegisterPlugin (GetPluginNameStatic(),
384 GetPluginDescriptionStatic(),
385 CreateInstance);
386}
387
388void
389SystemRuntimeMacOSX::Terminate()
390{
391 PluginManager::UnregisterPlugin (CreateInstance);
392}
393
394
395lldb_private::ConstString
396SystemRuntimeMacOSX::GetPluginNameStatic()
397{
398 static ConstString g_name("systemruntime-macosx");
399 return g_name;
400}
401
402const char *
403SystemRuntimeMacOSX::GetPluginDescriptionStatic()
404{
405 return "System runtime plugin for Mac OS X native libraries.";
406}
407
408
409//------------------------------------------------------------------
410// PluginInterface protocol
411//------------------------------------------------------------------
412lldb_private::ConstString
413SystemRuntimeMacOSX::GetPluginName()
414{
415 return GetPluginNameStatic();
416}
417
418uint32_t
419SystemRuntimeMacOSX::GetPluginVersion()
420{
421 return 1;
422}