1 | //===-- SystemRuntimeMacOSX.cpp -------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Plugins/Process/Utility/HistoryThread.h" |
10 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
11 | #include "lldb/Breakpoint/StoppointCallbackContext.h" |
12 | #include "lldb/Core/Module.h" |
13 | #include "lldb/Core/ModuleSpec.h" |
14 | #include "lldb/Core/PluginManager.h" |
15 | #include "lldb/Core/Section.h" |
16 | #include "lldb/Symbol/ObjectFile.h" |
17 | #include "lldb/Symbol/SymbolContext.h" |
18 | #include "lldb/Target/Process.h" |
19 | #include "lldb/Target/ProcessStructReader.h" |
20 | #include "lldb/Target/Queue.h" |
21 | #include "lldb/Target/QueueList.h" |
22 | #include "lldb/Target/Target.h" |
23 | #include "lldb/Target/Thread.h" |
24 | #include "lldb/Utility/DataBufferHeap.h" |
25 | #include "lldb/Utility/DataExtractor.h" |
26 | #include "lldb/Utility/FileSpec.h" |
27 | #include "lldb/Utility/LLDBLog.h" |
28 | #include "lldb/Utility/Log.h" |
29 | #include "lldb/Utility/StreamString.h" |
30 | |
31 | #include "SystemRuntimeMacOSX.h" |
32 | |
33 | #include <memory> |
34 | |
35 | using namespace lldb; |
36 | using namespace lldb_private; |
37 | |
38 | LLDB_PLUGIN_DEFINE(SystemRuntimeMacOSX) |
39 | |
40 | // Create an instance of this class. This function is filled into the plugin |
41 | // info class that gets handed out by the plugin factory and allows the lldb to |
42 | // instantiate an instance of this class. |
43 | SystemRuntime *SystemRuntimeMacOSX::CreateInstance(Process *process) { |
44 | bool create = false; |
45 | if (!create) { |
46 | create = true; |
47 | Module *exe_module = process->GetTarget().GetExecutableModulePointer(); |
48 | if (exe_module) { |
49 | ObjectFile *object_file = exe_module->GetObjectFile(); |
50 | if (object_file) { |
51 | create = (object_file->GetStrata() == ObjectFile::eStrataUser); |
52 | } |
53 | } |
54 | |
55 | if (create) { |
56 | const llvm::Triple &triple_ref = |
57 | process->GetTarget().GetArchitecture().GetTriple(); |
58 | switch (triple_ref.getOS()) { |
59 | case llvm::Triple::Darwin: |
60 | case llvm::Triple::MacOSX: |
61 | case llvm::Triple::IOS: |
62 | case llvm::Triple::TvOS: |
63 | case llvm::Triple::WatchOS: |
64 | case llvm::Triple::XROS: |
65 | case llvm::Triple::BridgeOS: |
66 | create = triple_ref.getVendor() == llvm::Triple::Apple; |
67 | break; |
68 | default: |
69 | create = false; |
70 | break; |
71 | } |
72 | } |
73 | } |
74 | |
75 | if (create) |
76 | return new SystemRuntimeMacOSX(process); |
77 | return nullptr; |
78 | } |
79 | |
80 | // Constructor |
81 | SystemRuntimeMacOSX::SystemRuntimeMacOSX(Process *process) |
82 | : SystemRuntime(process), m_break_id(LLDB_INVALID_BREAK_ID), m_mutex(), |
83 | m_get_queues_handler(process), m_get_pending_items_handler(process), |
84 | m_get_item_info_handler(process), m_get_thread_item_info_handler(process), |
85 | m_page_to_free(LLDB_INVALID_ADDRESS), m_page_to_free_size(0), |
86 | m_lib_backtrace_recording_info(), |
87 | m_dispatch_queue_offsets_addr(LLDB_INVALID_ADDRESS), |
88 | m_libdispatch_offsets(), |
89 | m_libpthread_layout_offsets_addr(LLDB_INVALID_ADDRESS), |
90 | m_libpthread_offsets(), m_dispatch_tsd_indexes_addr(LLDB_INVALID_ADDRESS), |
91 | m_libdispatch_tsd_indexes(), |
92 | m_dispatch_voucher_offsets_addr(LLDB_INVALID_ADDRESS), |
93 | m_libdispatch_voucher_offsets() {} |
94 | |
95 | // Destructor |
96 | SystemRuntimeMacOSX::~SystemRuntimeMacOSX() { Clear(clear_process: true); } |
97 | |
98 | void SystemRuntimeMacOSX::Detach() { |
99 | m_get_queues_handler.Detach(); |
100 | m_get_pending_items_handler.Detach(); |
101 | m_get_item_info_handler.Detach(); |
102 | m_get_thread_item_info_handler.Detach(); |
103 | } |
104 | |
105 | // Clear out the state of this class. |
106 | void SystemRuntimeMacOSX::Clear(bool clear_process) { |
107 | std::lock_guard<std::recursive_mutex> guard(m_mutex); |
108 | |
109 | if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id)) |
110 | m_process->ClearBreakpointSiteByID(break_id: m_break_id); |
111 | |
112 | if (clear_process) |
113 | m_process = nullptr; |
114 | m_break_id = LLDB_INVALID_BREAK_ID; |
115 | } |
116 | |
117 | std::string |
118 | SystemRuntimeMacOSX::GetQueueNameFromThreadQAddress(addr_t dispatch_qaddr) { |
119 | std::string dispatch_queue_name; |
120 | if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0) |
121 | return "" ; |
122 | |
123 | ReadLibdispatchOffsets(); |
124 | if (m_libdispatch_offsets.IsValid()) { |
125 | // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a |
126 | // thread - deref it to get the address of the dispatch_queue_t structure |
127 | // for this thread's queue. |
128 | Status error; |
129 | addr_t dispatch_queue_addr = |
130 | m_process->ReadPointerFromMemory(vm_addr: dispatch_qaddr, error); |
131 | if (error.Success()) { |
132 | if (m_libdispatch_offsets.dqo_version >= 4) { |
133 | // libdispatch versions 4+, pointer to dispatch name is in the queue |
134 | // structure. |
135 | addr_t pointer_to_label_address = |
136 | dispatch_queue_addr + m_libdispatch_offsets.dqo_label; |
137 | addr_t label_addr = |
138 | m_process->ReadPointerFromMemory(vm_addr: pointer_to_label_address, error); |
139 | if (error.Success()) { |
140 | m_process->ReadCStringFromMemory(vm_addr: label_addr, out_str&: dispatch_queue_name, |
141 | error); |
142 | } |
143 | } else { |
144 | // libdispatch versions 1-3, dispatch name is a fixed width char array |
145 | // in the queue structure. |
146 | addr_t label_addr = |
147 | dispatch_queue_addr + m_libdispatch_offsets.dqo_label; |
148 | dispatch_queue_name.resize(n: m_libdispatch_offsets.dqo_label_size, c: '\0'); |
149 | size_t bytes_read = |
150 | m_process->ReadMemory(vm_addr: label_addr, buf: &dispatch_queue_name[0], |
151 | size: m_libdispatch_offsets.dqo_label_size, error); |
152 | if (bytes_read < m_libdispatch_offsets.dqo_label_size) |
153 | dispatch_queue_name.erase(pos: bytes_read); |
154 | } |
155 | } |
156 | } |
157 | return dispatch_queue_name; |
158 | } |
159 | |
160 | lldb::addr_t SystemRuntimeMacOSX::GetLibdispatchQueueAddressFromThreadQAddress( |
161 | addr_t dispatch_qaddr) { |
162 | addr_t libdispatch_queue_t_address = LLDB_INVALID_ADDRESS; |
163 | Status error; |
164 | libdispatch_queue_t_address = |
165 | m_process->ReadPointerFromMemory(vm_addr: dispatch_qaddr, error); |
166 | if (!error.Success()) { |
167 | libdispatch_queue_t_address = LLDB_INVALID_ADDRESS; |
168 | } |
169 | return libdispatch_queue_t_address; |
170 | } |
171 | |
172 | lldb::QueueKind SystemRuntimeMacOSX::GetQueueKind(addr_t dispatch_queue_addr) { |
173 | if (dispatch_queue_addr == LLDB_INVALID_ADDRESS || dispatch_queue_addr == 0) |
174 | return eQueueKindUnknown; |
175 | |
176 | QueueKind kind = eQueueKindUnknown; |
177 | ReadLibdispatchOffsets(); |
178 | if (m_libdispatch_offsets.IsValid() && |
179 | m_libdispatch_offsets.dqo_version >= 4) { |
180 | Status error; |
181 | uint64_t width = m_process->ReadUnsignedIntegerFromMemory( |
182 | load_addr: dispatch_queue_addr + m_libdispatch_offsets.dqo_width, |
183 | byte_size: m_libdispatch_offsets.dqo_width_size, fail_value: 0, error); |
184 | if (error.Success()) { |
185 | if (width == 1) { |
186 | kind = eQueueKindSerial; |
187 | } |
188 | if (width > 1) { |
189 | kind = eQueueKindConcurrent; |
190 | } |
191 | } |
192 | } |
193 | return kind; |
194 | } |
195 | |
196 | void SystemRuntimeMacOSX::AddThreadExtendedInfoPacketHints( |
197 | lldb_private::StructuredData::ObjectSP dict_sp) { |
198 | StructuredData::Dictionary *dict = dict_sp->GetAsDictionary(); |
199 | if (dict) { |
200 | ReadLibpthreadOffsets(); |
201 | if (m_libpthread_offsets.IsValid()) { |
202 | dict->AddIntegerItem(key: "plo_pthread_tsd_base_offset" , |
203 | value: m_libpthread_offsets.plo_pthread_tsd_base_offset); |
204 | dict->AddIntegerItem( |
205 | key: "plo_pthread_tsd_base_address_offset" , |
206 | value: m_libpthread_offsets.plo_pthread_tsd_base_address_offset); |
207 | dict->AddIntegerItem(key: "plo_pthread_tsd_entry_size" , |
208 | value: m_libpthread_offsets.plo_pthread_tsd_entry_size); |
209 | } |
210 | |
211 | ReadLibdispatchTSDIndexes(); |
212 | if (m_libdispatch_tsd_indexes.IsValid()) { |
213 | dict->AddIntegerItem(key: "dti_queue_index" , |
214 | value: m_libdispatch_tsd_indexes.dti_queue_index); |
215 | dict->AddIntegerItem(key: "dti_voucher_index" , |
216 | value: m_libdispatch_tsd_indexes.dti_voucher_index); |
217 | dict->AddIntegerItem(key: "dti_qos_class_index" , |
218 | value: m_libdispatch_tsd_indexes.dti_qos_class_index); |
219 | } |
220 | } |
221 | } |
222 | |
223 | bool SystemRuntimeMacOSX::SafeToCallFunctionsOnThisThread(ThreadSP thread_sp) { |
224 | if (thread_sp && thread_sp->GetFrameWithConcreteFrameIndex(unwind_idx: 0)) { |
225 | const SymbolContext sym_ctx( |
226 | thread_sp->GetFrameWithConcreteFrameIndex(unwind_idx: 0)->GetSymbolContext( |
227 | resolve_scope: eSymbolContextSymbol)); |
228 | static ConstString g_select_symbol("__select" ); |
229 | if (sym_ctx.GetFunctionName() == g_select_symbol) { |
230 | return false; |
231 | } |
232 | } |
233 | return true; |
234 | } |
235 | |
236 | lldb::queue_id_t |
237 | SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress(lldb::addr_t dispatch_qaddr) { |
238 | queue_id_t queue_id = LLDB_INVALID_QUEUE_ID; |
239 | |
240 | if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0) |
241 | return queue_id; |
242 | |
243 | ReadLibdispatchOffsets(); |
244 | if (m_libdispatch_offsets.IsValid()) { |
245 | // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a |
246 | // thread - deref it to get the address of the dispatch_queue_t structure |
247 | // for this thread's queue. |
248 | Status error; |
249 | uint64_t dispatch_queue_addr = |
250 | m_process->ReadPointerFromMemory(vm_addr: dispatch_qaddr, error); |
251 | if (error.Success()) { |
252 | addr_t serialnum_address = |
253 | dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum; |
254 | queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory( |
255 | load_addr: serialnum_address, byte_size: m_libdispatch_offsets.dqo_serialnum_size, |
256 | LLDB_INVALID_QUEUE_ID, error); |
257 | if (error.Success()) { |
258 | queue_id = serialnum; |
259 | } |
260 | } |
261 | } |
262 | |
263 | return queue_id; |
264 | } |
265 | |
266 | void SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress() { |
267 | if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS) |
268 | return; |
269 | |
270 | static ConstString g_dispatch_queue_offsets_symbol_name( |
271 | "dispatch_queue_offsets" ); |
272 | const Symbol *dispatch_queue_offsets_symbol = nullptr; |
273 | |
274 | // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 |
275 | // ("Snow Leopard") |
276 | ModuleSpec libSystem_module_spec(FileSpec("libSystem.B.dylib" )); |
277 | ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule( |
278 | module_spec: libSystem_module_spec)); |
279 | if (module_sp) |
280 | dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType( |
281 | name: g_dispatch_queue_offsets_symbol_name, symbol_type: eSymbolTypeData); |
282 | |
283 | // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") |
284 | // and later |
285 | if (dispatch_queue_offsets_symbol == nullptr) { |
286 | ModuleSpec libdispatch_module_spec(FileSpec("libdispatch.dylib" )); |
287 | module_sp = m_process->GetTarget().GetImages().FindFirstModule( |
288 | module_spec: libdispatch_module_spec); |
289 | if (module_sp) |
290 | dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType( |
291 | name: g_dispatch_queue_offsets_symbol_name, symbol_type: eSymbolTypeData); |
292 | } |
293 | if (dispatch_queue_offsets_symbol) |
294 | m_dispatch_queue_offsets_addr = |
295 | dispatch_queue_offsets_symbol->GetLoadAddress(target: &m_process->GetTarget()); |
296 | } |
297 | |
298 | void SystemRuntimeMacOSX::ReadLibdispatchOffsets() { |
299 | if (m_libdispatch_offsets.IsValid()) |
300 | return; |
301 | |
302 | ReadLibdispatchOffsetsAddress(); |
303 | |
304 | uint8_t memory_buffer[sizeof(struct LibdispatchOffsets)]; |
305 | DataExtractor data(memory_buffer, sizeof(memory_buffer), |
306 | m_process->GetByteOrder(), |
307 | m_process->GetAddressByteSize()); |
308 | |
309 | Status error; |
310 | if (m_process->ReadMemory(vm_addr: m_dispatch_queue_offsets_addr, buf: memory_buffer, |
311 | size: sizeof(memory_buffer), |
312 | error) == sizeof(memory_buffer)) { |
313 | lldb::offset_t data_offset = 0; |
314 | |
315 | // The struct LibdispatchOffsets is a series of uint16_t's - extract them |
316 | // all in one big go. |
317 | data.GetU16(offset_ptr: &data_offset, dst: &m_libdispatch_offsets.dqo_version, |
318 | count: sizeof(struct LibdispatchOffsets) / sizeof(uint16_t)); |
319 | } |
320 | } |
321 | |
322 | void SystemRuntimeMacOSX::ReadLibpthreadOffsetsAddress() { |
323 | if (m_libpthread_layout_offsets_addr != LLDB_INVALID_ADDRESS) |
324 | return; |
325 | |
326 | static ConstString g_libpthread_layout_offsets_symbol_name( |
327 | "pthread_layout_offsets" ); |
328 | const Symbol *libpthread_layout_offsets_symbol = nullptr; |
329 | |
330 | ModuleSpec libpthread_module_spec(FileSpec("libsystem_pthread.dylib" )); |
331 | ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule( |
332 | module_spec: libpthread_module_spec)); |
333 | if (module_sp) { |
334 | libpthread_layout_offsets_symbol = |
335 | module_sp->FindFirstSymbolWithNameAndType( |
336 | name: g_libpthread_layout_offsets_symbol_name, symbol_type: eSymbolTypeData); |
337 | if (libpthread_layout_offsets_symbol) { |
338 | m_libpthread_layout_offsets_addr = |
339 | libpthread_layout_offsets_symbol->GetLoadAddress( |
340 | target: &m_process->GetTarget()); |
341 | } |
342 | } |
343 | } |
344 | |
345 | void SystemRuntimeMacOSX::ReadLibpthreadOffsets() { |
346 | if (m_libpthread_offsets.IsValid()) |
347 | return; |
348 | |
349 | ReadLibpthreadOffsetsAddress(); |
350 | |
351 | if (m_libpthread_layout_offsets_addr != LLDB_INVALID_ADDRESS) { |
352 | uint8_t memory_buffer[sizeof(struct LibpthreadOffsets)]; |
353 | DataExtractor data(memory_buffer, sizeof(memory_buffer), |
354 | m_process->GetByteOrder(), |
355 | m_process->GetAddressByteSize()); |
356 | Status error; |
357 | if (m_process->ReadMemory(vm_addr: m_libpthread_layout_offsets_addr, buf: memory_buffer, |
358 | size: sizeof(memory_buffer), |
359 | error) == sizeof(memory_buffer)) { |
360 | lldb::offset_t data_offset = 0; |
361 | |
362 | // The struct LibpthreadOffsets is a series of uint16_t's - extract them |
363 | // all in one big go. |
364 | data.GetU16(offset_ptr: &data_offset, dst: &m_libpthread_offsets.plo_version, |
365 | count: sizeof(struct LibpthreadOffsets) / sizeof(uint16_t)); |
366 | } |
367 | } |
368 | } |
369 | |
370 | void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexesAddress() { |
371 | if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS) |
372 | return; |
373 | |
374 | static ConstString g_libdispatch_tsd_indexes_symbol_name( |
375 | "dispatch_tsd_indexes" ); |
376 | const Symbol *libdispatch_tsd_indexes_symbol = nullptr; |
377 | |
378 | ModuleSpec libpthread_module_spec(FileSpec("libdispatch.dylib" )); |
379 | ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule( |
380 | module_spec: libpthread_module_spec)); |
381 | if (module_sp) { |
382 | libdispatch_tsd_indexes_symbol = module_sp->FindFirstSymbolWithNameAndType( |
383 | name: g_libdispatch_tsd_indexes_symbol_name, symbol_type: eSymbolTypeData); |
384 | if (libdispatch_tsd_indexes_symbol) { |
385 | m_dispatch_tsd_indexes_addr = |
386 | libdispatch_tsd_indexes_symbol->GetLoadAddress( |
387 | target: &m_process->GetTarget()); |
388 | } |
389 | } |
390 | } |
391 | |
392 | void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes() { |
393 | if (m_libdispatch_tsd_indexes.IsValid()) |
394 | return; |
395 | |
396 | ReadLibdispatchTSDIndexesAddress(); |
397 | |
398 | if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS) { |
399 | |
400 | // We don't need to check the version number right now, it will be at least 2, |
401 | // but keep this code around to fetch just the version # for the future where |
402 | // we need to fetch alternate versions of the struct. |
403 | #if 0 |
404 | uint16_t dti_version = 2; |
405 | Address dti_struct_addr; |
406 | if (m_process->GetTarget().ResolveLoadAddress (m_dispatch_tsd_indexes_addr, dti_struct_addr)) |
407 | { |
408 | Status error; |
409 | uint16_t version = m_process->GetTarget().ReadUnsignedIntegerFromMemory (dti_struct_addr, false, 2, UINT16_MAX, error); |
410 | if (error.Success() && dti_version != UINT16_MAX) |
411 | { |
412 | dti_version = version; |
413 | } |
414 | } |
415 | #endif |
416 | |
417 | TypeSystemClangSP scratch_ts_sp = |
418 | ScratchTypeSystemClang::GetForTarget(target&: m_process->GetTarget()); |
419 | if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS) { |
420 | CompilerType uint16 = |
421 | scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(encoding: eEncodingUint, bit_size: 16); |
422 | CompilerType dispatch_tsd_indexes_s = scratch_ts_sp->CreateRecordType( |
423 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, |
424 | name: "__lldb_dispatch_tsd_indexes_s" , |
425 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
426 | language: lldb::eLanguageTypeC); |
427 | |
428 | TypeSystemClang::StartTagDeclarationDefinition(type: dispatch_tsd_indexes_s); |
429 | TypeSystemClang::AddFieldToRecordType(type: dispatch_tsd_indexes_s, |
430 | name: "dti_version" , field_type: uint16, |
431 | access: lldb::eAccessPublic, bitfield_bit_size: 0); |
432 | TypeSystemClang::AddFieldToRecordType(type: dispatch_tsd_indexes_s, |
433 | name: "dti_queue_index" , field_type: uint16, |
434 | access: lldb::eAccessPublic, bitfield_bit_size: 0); |
435 | TypeSystemClang::AddFieldToRecordType(type: dispatch_tsd_indexes_s, |
436 | name: "dti_voucher_index" , field_type: uint16, |
437 | access: lldb::eAccessPublic, bitfield_bit_size: 0); |
438 | TypeSystemClang::AddFieldToRecordType(type: dispatch_tsd_indexes_s, |
439 | name: "dti_qos_class_index" , field_type: uint16, |
440 | access: lldb::eAccessPublic, bitfield_bit_size: 0); |
441 | TypeSystemClang::CompleteTagDeclarationDefinition(type: dispatch_tsd_indexes_s); |
442 | |
443 | ProcessStructReader struct_reader(m_process, m_dispatch_tsd_indexes_addr, |
444 | dispatch_tsd_indexes_s); |
445 | |
446 | m_libdispatch_tsd_indexes.dti_version = |
447 | struct_reader.GetField<uint16_t>(name: "dti_version" ); |
448 | m_libdispatch_tsd_indexes.dti_queue_index = |
449 | struct_reader.GetField<uint16_t>(name: "dti_queue_index" ); |
450 | m_libdispatch_tsd_indexes.dti_voucher_index = |
451 | struct_reader.GetField<uint16_t>(name: "dti_voucher_index" ); |
452 | m_libdispatch_tsd_indexes.dti_qos_class_index = |
453 | struct_reader.GetField<uint16_t>(name: "dti_qos_class_index" ); |
454 | } |
455 | } |
456 | } |
457 | |
458 | ThreadSP SystemRuntimeMacOSX::GetExtendedBacktraceThread(ThreadSP real_thread, |
459 | ConstString type) { |
460 | ThreadSP originating_thread_sp; |
461 | if (BacktraceRecordingHeadersInitialized() && type == "libdispatch" ) { |
462 | Status error; |
463 | |
464 | // real_thread is either an actual, live thread (in which case we need to |
465 | // call into libBacktraceRecording to find its originator) or it is an |
466 | // extended backtrace itself, in which case we get the token from it and |
467 | // call into libBacktraceRecording to find the originator of that token. |
468 | |
469 | if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS) { |
470 | originating_thread_sp = GetExtendedBacktraceFromItemRef( |
471 | item_ref: real_thread->GetExtendedBacktraceToken()); |
472 | } else { |
473 | ThreadSP cur_thread_sp( |
474 | m_process->GetThreadList().GetExpressionExecutionThread()); |
475 | AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = |
476 | m_get_thread_item_info_handler.GetThreadItemInfo( |
477 | thread&: *cur_thread_sp.get(), thread_id: real_thread->GetID(), page_to_free: m_page_to_free, |
478 | page_to_free_size: m_page_to_free_size, error); |
479 | m_page_to_free = LLDB_INVALID_ADDRESS; |
480 | m_page_to_free_size = 0; |
481 | if (ret.item_buffer_ptr != 0 && |
482 | ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && |
483 | ret.item_buffer_size > 0) { |
484 | DataBufferHeap data(ret.item_buffer_size, 0); |
485 | if (m_process->ReadMemory(vm_addr: ret.item_buffer_ptr, buf: data.GetBytes(), |
486 | size: ret.item_buffer_size, error) && |
487 | error.Success()) { |
488 | DataExtractor (data.GetBytes(), data.GetByteSize(), |
489 | m_process->GetByteOrder(), |
490 | m_process->GetAddressByteSize()); |
491 | ItemInfo item = ExtractItemInfoFromBuffer(extractor); |
492 | originating_thread_sp = std::make_shared<HistoryThread>( |
493 | args&: *m_process, args&: item.enqueuing_thread_id, args&: item.enqueuing_callstack); |
494 | originating_thread_sp->SetExtendedBacktraceToken( |
495 | item.item_that_enqueued_this); |
496 | originating_thread_sp->SetQueueName( |
497 | item.enqueuing_queue_label.c_str()); |
498 | originating_thread_sp->SetQueueID(item.enqueuing_queue_serialnum); |
499 | // originating_thread_sp->SetThreadName |
500 | // (item.enqueuing_thread_label.c_str()); |
501 | } |
502 | m_page_to_free = ret.item_buffer_ptr; |
503 | m_page_to_free_size = ret.item_buffer_size; |
504 | } |
505 | } |
506 | } else if (type == "Application Specific Backtrace" ) { |
507 | StructuredData::ObjectSP thread_extended_sp = |
508 | real_thread->GetExtendedInfo(); |
509 | |
510 | if (!thread_extended_sp) |
511 | return {}; |
512 | |
513 | StructuredData::Array *thread_extended_info = |
514 | thread_extended_sp->GetAsArray(); |
515 | |
516 | if (!thread_extended_info || !thread_extended_info->GetSize()) |
517 | return {}; |
518 | |
519 | std::vector<addr_t> app_specific_backtrace_pcs; |
520 | |
521 | auto = |
522 | [&app_specific_backtrace_pcs](StructuredData::Object *obj) -> bool { |
523 | if (!obj) |
524 | return false; |
525 | |
526 | StructuredData::Dictionary *dict = obj->GetAsDictionary(); |
527 | if (!dict) |
528 | return false; |
529 | |
530 | lldb::addr_t pc = LLDB_INVALID_ADDRESS; |
531 | if (!dict->GetValueForKeyAsInteger(key: "pc" , result&: pc)) |
532 | return false; |
533 | |
534 | app_specific_backtrace_pcs.push_back(x: pc); |
535 | |
536 | return pc != LLDB_INVALID_ADDRESS; |
537 | }; |
538 | |
539 | if (!thread_extended_info->ForEach(foreach_callback: extract_frame_pc)) |
540 | return {}; |
541 | |
542 | originating_thread_sp = |
543 | std::make_shared<HistoryThread>(args&: *m_process, args: real_thread->GetIndexID(), |
544 | args&: app_specific_backtrace_pcs, args: true); |
545 | originating_thread_sp->SetQueueName(type.AsCString()); |
546 | } |
547 | return originating_thread_sp; |
548 | } |
549 | |
550 | ThreadSP |
551 | SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef(lldb::addr_t item_ref) { |
552 | ThreadSP return_thread_sp; |
553 | |
554 | AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; |
555 | ThreadSP cur_thread_sp( |
556 | m_process->GetThreadList().GetExpressionExecutionThread()); |
557 | Status error; |
558 | ret = m_get_item_info_handler.GetItemInfo(thread&: *cur_thread_sp.get(), item: item_ref, |
559 | page_to_free: m_page_to_free, page_to_free_size: m_page_to_free_size, |
560 | error); |
561 | m_page_to_free = LLDB_INVALID_ADDRESS; |
562 | m_page_to_free_size = 0; |
563 | if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && |
564 | ret.item_buffer_size > 0) { |
565 | DataBufferHeap data(ret.item_buffer_size, 0); |
566 | if (m_process->ReadMemory(vm_addr: ret.item_buffer_ptr, buf: data.GetBytes(), |
567 | size: ret.item_buffer_size, error) && |
568 | error.Success()) { |
569 | DataExtractor (data.GetBytes(), data.GetByteSize(), |
570 | m_process->GetByteOrder(), |
571 | m_process->GetAddressByteSize()); |
572 | ItemInfo item = ExtractItemInfoFromBuffer(extractor); |
573 | return_thread_sp = std::make_shared<HistoryThread>( |
574 | args&: *m_process, args&: item.enqueuing_thread_id, args&: item.enqueuing_callstack); |
575 | return_thread_sp->SetExtendedBacktraceToken(item.item_that_enqueued_this); |
576 | return_thread_sp->SetQueueName(item.enqueuing_queue_label.c_str()); |
577 | return_thread_sp->SetQueueID(item.enqueuing_queue_serialnum); |
578 | // return_thread_sp->SetThreadName |
579 | // (item.enqueuing_thread_label.c_str()); |
580 | |
581 | m_page_to_free = ret.item_buffer_ptr; |
582 | m_page_to_free_size = ret.item_buffer_size; |
583 | } |
584 | } |
585 | return return_thread_sp; |
586 | } |
587 | |
588 | ThreadSP |
589 | SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem(QueueItemSP queue_item_sp, |
590 | ConstString type) { |
591 | ThreadSP extended_thread_sp; |
592 | if (type != "libdispatch" ) |
593 | return extended_thread_sp; |
594 | |
595 | extended_thread_sp = std::make_shared<HistoryThread>( |
596 | args&: *m_process, args: queue_item_sp->GetEnqueueingThreadID(), |
597 | args&: queue_item_sp->GetEnqueueingBacktrace()); |
598 | extended_thread_sp->SetExtendedBacktraceToken( |
599 | queue_item_sp->GetItemThatEnqueuedThis()); |
600 | extended_thread_sp->SetQueueName(queue_item_sp->GetQueueLabel().c_str()); |
601 | extended_thread_sp->SetQueueID(queue_item_sp->GetEnqueueingQueueID()); |
602 | // extended_thread_sp->SetThreadName |
603 | // (queue_item_sp->GetThreadLabel().c_str()); |
604 | |
605 | return extended_thread_sp; |
606 | } |
607 | |
608 | /* Returns true if we were able to get the version / offset information |
609 | * out of libBacktraceRecording. false means we were unable to retrieve |
610 | * this; the queue_info_version field will be 0. |
611 | */ |
612 | |
613 | bool SystemRuntimeMacOSX::() { |
614 | if (m_lib_backtrace_recording_info.queue_info_version != 0) |
615 | return true; |
616 | |
617 | addr_t queue_info_version_address = LLDB_INVALID_ADDRESS; |
618 | addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS; |
619 | addr_t item_info_version_address = LLDB_INVALID_ADDRESS; |
620 | addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS; |
621 | Target &target = m_process->GetTarget(); |
622 | |
623 | static ConstString introspection_dispatch_queue_info_version( |
624 | "__introspection_dispatch_queue_info_version" ); |
625 | SymbolContextList sc_list; |
626 | m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( |
627 | name: introspection_dispatch_queue_info_version, symbol_type: eSymbolTypeData, sc_list); |
628 | if (!sc_list.IsEmpty()) { |
629 | SymbolContext sc; |
630 | sc_list.GetContextAtIndex(idx: 0, sc); |
631 | AddressRange addr_range; |
632 | sc.GetAddressRange(scope: eSymbolContextSymbol, range_idx: 0, use_inline_block_range: false, range&: addr_range); |
633 | queue_info_version_address = |
634 | addr_range.GetBaseAddress().GetLoadAddress(target: &target); |
635 | } |
636 | sc_list.Clear(); |
637 | |
638 | static ConstString introspection_dispatch_queue_info_data_offset( |
639 | "__introspection_dispatch_queue_info_data_offset" ); |
640 | m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( |
641 | name: introspection_dispatch_queue_info_data_offset, symbol_type: eSymbolTypeData, sc_list); |
642 | if (!sc_list.IsEmpty()) { |
643 | SymbolContext sc; |
644 | sc_list.GetContextAtIndex(idx: 0, sc); |
645 | AddressRange addr_range; |
646 | sc.GetAddressRange(scope: eSymbolContextSymbol, range_idx: 0, use_inline_block_range: false, range&: addr_range); |
647 | queue_info_data_offset_address = |
648 | addr_range.GetBaseAddress().GetLoadAddress(target: &target); |
649 | } |
650 | sc_list.Clear(); |
651 | |
652 | static ConstString introspection_dispatch_item_info_version( |
653 | "__introspection_dispatch_item_info_version" ); |
654 | m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( |
655 | name: introspection_dispatch_item_info_version, symbol_type: eSymbolTypeData, sc_list); |
656 | if (!sc_list.IsEmpty()) { |
657 | SymbolContext sc; |
658 | sc_list.GetContextAtIndex(idx: 0, sc); |
659 | AddressRange addr_range; |
660 | sc.GetAddressRange(scope: eSymbolContextSymbol, range_idx: 0, use_inline_block_range: false, range&: addr_range); |
661 | item_info_version_address = |
662 | addr_range.GetBaseAddress().GetLoadAddress(target: &target); |
663 | } |
664 | sc_list.Clear(); |
665 | |
666 | static ConstString introspection_dispatch_item_info_data_offset( |
667 | "__introspection_dispatch_item_info_data_offset" ); |
668 | m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( |
669 | name: introspection_dispatch_item_info_data_offset, symbol_type: eSymbolTypeData, sc_list); |
670 | if (!sc_list.IsEmpty()) { |
671 | SymbolContext sc; |
672 | sc_list.GetContextAtIndex(idx: 0, sc); |
673 | AddressRange addr_range; |
674 | sc.GetAddressRange(scope: eSymbolContextSymbol, range_idx: 0, use_inline_block_range: false, range&: addr_range); |
675 | item_info_data_offset_address = |
676 | addr_range.GetBaseAddress().GetLoadAddress(target: &target); |
677 | } |
678 | |
679 | if (queue_info_version_address != LLDB_INVALID_ADDRESS && |
680 | queue_info_data_offset_address != LLDB_INVALID_ADDRESS && |
681 | item_info_version_address != LLDB_INVALID_ADDRESS && |
682 | item_info_data_offset_address != LLDB_INVALID_ADDRESS) { |
683 | Status error; |
684 | m_lib_backtrace_recording_info.queue_info_version = |
685 | m_process->ReadUnsignedIntegerFromMemory(load_addr: queue_info_version_address, byte_size: 2, |
686 | fail_value: 0, error); |
687 | if (error.Success()) { |
688 | m_lib_backtrace_recording_info.queue_info_data_offset = |
689 | m_process->ReadUnsignedIntegerFromMemory( |
690 | load_addr: queue_info_data_offset_address, byte_size: 2, fail_value: 0, error); |
691 | if (error.Success()) { |
692 | m_lib_backtrace_recording_info.item_info_version = |
693 | m_process->ReadUnsignedIntegerFromMemory(load_addr: item_info_version_address, |
694 | byte_size: 2, fail_value: 0, error); |
695 | if (error.Success()) { |
696 | m_lib_backtrace_recording_info.item_info_data_offset = |
697 | m_process->ReadUnsignedIntegerFromMemory( |
698 | load_addr: item_info_data_offset_address, byte_size: 2, fail_value: 0, error); |
699 | if (!error.Success()) { |
700 | m_lib_backtrace_recording_info.queue_info_version = 0; |
701 | } |
702 | } else { |
703 | m_lib_backtrace_recording_info.queue_info_version = 0; |
704 | } |
705 | } else { |
706 | m_lib_backtrace_recording_info.queue_info_version = 0; |
707 | } |
708 | } |
709 | } |
710 | |
711 | return m_lib_backtrace_recording_info.queue_info_version != 0; |
712 | } |
713 | |
714 | const std::vector<ConstString> & |
715 | SystemRuntimeMacOSX::GetExtendedBacktraceTypes() { |
716 | if (m_types.size() == 0) { |
717 | m_types.push_back(x: ConstString("libdispatch" )); |
718 | m_types.push_back(x: ConstString("Application Specific Backtrace" )); |
719 | // We could have pthread as another type in the future if we have a way of |
720 | // gathering that information & it's useful to distinguish between them. |
721 | } |
722 | return m_types; |
723 | } |
724 | |
725 | void SystemRuntimeMacOSX::PopulateQueueList( |
726 | lldb_private::QueueList &queue_list) { |
727 | if (BacktraceRecordingHeadersInitialized()) { |
728 | AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer; |
729 | ThreadSP cur_thread_sp( |
730 | m_process->GetThreadList().GetExpressionExecutionThread()); |
731 | if (cur_thread_sp) { |
732 | Status error; |
733 | queue_info_pointer = m_get_queues_handler.GetCurrentQueues( |
734 | thread&: *cur_thread_sp.get(), page_to_free: m_page_to_free, page_to_free_size: m_page_to_free_size, error); |
735 | m_page_to_free = LLDB_INVALID_ADDRESS; |
736 | m_page_to_free_size = 0; |
737 | if (error.Success()) { |
738 | |
739 | if (queue_info_pointer.count > 0 && |
740 | queue_info_pointer.queues_buffer_size > 0 && |
741 | queue_info_pointer.queues_buffer_ptr != 0 && |
742 | queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS) { |
743 | PopulateQueuesUsingLibBTR(queues_buffer: queue_info_pointer.queues_buffer_ptr, |
744 | queues_buffer_size: queue_info_pointer.queues_buffer_size, |
745 | count: queue_info_pointer.count, queue_list); |
746 | } |
747 | } |
748 | } |
749 | } |
750 | |
751 | // We either didn't have libBacktraceRecording (and need to create the queues |
752 | // list based on threads) or we did get the queues list from |
753 | // libBacktraceRecording but some special queues may not be included in its |
754 | // information. This is needed because libBacktraceRecording will only list |
755 | // queues with pending or running items by default - but the magic com.apple |
756 | // .main-thread queue on thread 1 is always around. |
757 | |
758 | for (ThreadSP thread_sp : m_process->Threads()) { |
759 | if (thread_sp->GetAssociatedWithLibdispatchQueue() != eLazyBoolNo) { |
760 | if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) { |
761 | if (queue_list.FindQueueByID(qid: thread_sp->GetQueueID()).get() == |
762 | nullptr) { |
763 | QueueSP queue_sp(new Queue(m_process->shared_from_this(), |
764 | thread_sp->GetQueueID(), |
765 | thread_sp->GetQueueName())); |
766 | if (thread_sp->ThreadHasQueueInformation()) { |
767 | queue_sp->SetKind(thread_sp->GetQueueKind()); |
768 | queue_sp->SetLibdispatchQueueAddress( |
769 | thread_sp->GetQueueLibdispatchQueueAddress()); |
770 | queue_list.AddQueue(queue: queue_sp); |
771 | } else { |
772 | queue_sp->SetKind( |
773 | GetQueueKind(dispatch_queue_addr: thread_sp->GetQueueLibdispatchQueueAddress())); |
774 | queue_sp->SetLibdispatchQueueAddress( |
775 | thread_sp->GetQueueLibdispatchQueueAddress()); |
776 | queue_list.AddQueue(queue: queue_sp); |
777 | } |
778 | } |
779 | } |
780 | } |
781 | } |
782 | } |
783 | |
784 | // Returns either an array of introspection_dispatch_item_info_ref's for the |
785 | // pending items on a queue or an array introspection_dispatch_item_info_ref's |
786 | // and code addresses for the pending items on a queue. The information about |
787 | // each of these pending items then needs to be fetched individually by passing |
788 | // the ref to libBacktraceRecording. |
789 | |
790 | SystemRuntimeMacOSX::PendingItemsForQueue |
791 | SystemRuntimeMacOSX::GetPendingItemRefsForQueue(lldb::addr_t queue) { |
792 | PendingItemsForQueue pending_item_refs = {}; |
793 | AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer; |
794 | ThreadSP cur_thread_sp( |
795 | m_process->GetThreadList().GetExpressionExecutionThread()); |
796 | if (cur_thread_sp) { |
797 | Status error; |
798 | pending_items_pointer = m_get_pending_items_handler.GetPendingItems( |
799 | thread&: *cur_thread_sp.get(), queue, page_to_free: m_page_to_free, page_to_free_size: m_page_to_free_size, |
800 | error); |
801 | m_page_to_free = LLDB_INVALID_ADDRESS; |
802 | m_page_to_free_size = 0; |
803 | if (error.Success()) { |
804 | if (pending_items_pointer.count > 0 && |
805 | pending_items_pointer.items_buffer_size > 0 && |
806 | pending_items_pointer.items_buffer_ptr != 0 && |
807 | pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS) { |
808 | DataBufferHeap data(pending_items_pointer.items_buffer_size, 0); |
809 | if (m_process->ReadMemory( |
810 | vm_addr: pending_items_pointer.items_buffer_ptr, buf: data.GetBytes(), |
811 | size: pending_items_pointer.items_buffer_size, error)) { |
812 | DataExtractor (data.GetBytes(), data.GetByteSize(), |
813 | m_process->GetByteOrder(), |
814 | m_process->GetAddressByteSize()); |
815 | |
816 | // We either have an array of |
817 | // void* item_ref |
818 | // (old style) or we have a structure returned which looks like |
819 | // |
820 | // struct introspection_dispatch_pending_item_info_s { |
821 | // void *item_ref; |
822 | // void *function_or_block; |
823 | // }; |
824 | // |
825 | // struct introspection_dispatch_pending_items_array_s { |
826 | // uint32_t version; |
827 | // uint32_t size_of_item_info; |
828 | // introspection_dispatch_pending_item_info_s items[]; |
829 | // } |
830 | |
831 | offset_t offset = 0; |
832 | uint64_t i = 0; |
833 | uint32_t version = extractor.GetU32(offset_ptr: &offset); |
834 | if (version == 1) { |
835 | pending_item_refs.new_style = true; |
836 | uint32_t item_size = extractor.GetU32(offset_ptr: &offset); |
837 | uint32_t start_of_array_offset = offset; |
838 | while (offset < pending_items_pointer.items_buffer_size && |
839 | i < pending_items_pointer.count) { |
840 | offset = start_of_array_offset + (i * item_size); |
841 | ItemRefAndCodeAddress item; |
842 | item.item_ref = extractor.GetAddress(offset_ptr: &offset); |
843 | item.code_address = extractor.GetAddress(offset_ptr: &offset); |
844 | pending_item_refs.item_refs_and_code_addresses.push_back(x: item); |
845 | i++; |
846 | } |
847 | } else { |
848 | offset = 0; |
849 | pending_item_refs.new_style = false; |
850 | while (offset < pending_items_pointer.items_buffer_size && |
851 | i < pending_items_pointer.count) { |
852 | ItemRefAndCodeAddress item; |
853 | item.item_ref = extractor.GetAddress(offset_ptr: &offset); |
854 | item.code_address = LLDB_INVALID_ADDRESS; |
855 | pending_item_refs.item_refs_and_code_addresses.push_back(x: item); |
856 | i++; |
857 | } |
858 | } |
859 | } |
860 | m_page_to_free = pending_items_pointer.items_buffer_ptr; |
861 | m_page_to_free_size = pending_items_pointer.items_buffer_size; |
862 | } |
863 | } |
864 | } |
865 | return pending_item_refs; |
866 | } |
867 | |
868 | void SystemRuntimeMacOSX::PopulatePendingItemsForQueue(Queue *queue) { |
869 | if (BacktraceRecordingHeadersInitialized()) { |
870 | PendingItemsForQueue pending_item_refs = |
871 | GetPendingItemRefsForQueue(queue: queue->GetLibdispatchQueueAddress()); |
872 | for (ItemRefAndCodeAddress pending_item : |
873 | pending_item_refs.item_refs_and_code_addresses) { |
874 | Address addr; |
875 | m_process->GetTarget().ResolveLoadAddress(load_addr: pending_item.code_address, |
876 | so_addr&: addr); |
877 | QueueItemSP queue_item_sp(new QueueItem(queue->shared_from_this(), |
878 | m_process->shared_from_this(), |
879 | pending_item.item_ref, addr)); |
880 | queue->PushPendingQueueItem(item: queue_item_sp); |
881 | } |
882 | } |
883 | } |
884 | |
885 | void SystemRuntimeMacOSX::CompleteQueueItem(QueueItem *queue_item, |
886 | addr_t item_ref) { |
887 | AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; |
888 | |
889 | ThreadSP cur_thread_sp( |
890 | m_process->GetThreadList().GetExpressionExecutionThread()); |
891 | Status error; |
892 | ret = m_get_item_info_handler.GetItemInfo(thread&: *cur_thread_sp.get(), item: item_ref, |
893 | page_to_free: m_page_to_free, page_to_free_size: m_page_to_free_size, |
894 | error); |
895 | m_page_to_free = LLDB_INVALID_ADDRESS; |
896 | m_page_to_free_size = 0; |
897 | if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && |
898 | ret.item_buffer_size > 0) { |
899 | DataBufferHeap data(ret.item_buffer_size, 0); |
900 | if (m_process->ReadMemory(vm_addr: ret.item_buffer_ptr, buf: data.GetBytes(), |
901 | size: ret.item_buffer_size, error) && |
902 | error.Success()) { |
903 | DataExtractor (data.GetBytes(), data.GetByteSize(), |
904 | m_process->GetByteOrder(), |
905 | m_process->GetAddressByteSize()); |
906 | ItemInfo item = ExtractItemInfoFromBuffer(extractor); |
907 | queue_item->SetItemThatEnqueuedThis(item.item_that_enqueued_this); |
908 | queue_item->SetEnqueueingThreadID(item.enqueuing_thread_id); |
909 | queue_item->SetEnqueueingQueueID(item.enqueuing_queue_serialnum); |
910 | queue_item->SetStopID(item.stop_id); |
911 | queue_item->SetEnqueueingBacktrace(item.enqueuing_callstack); |
912 | queue_item->SetThreadLabel(item.enqueuing_thread_label); |
913 | queue_item->SetQueueLabel(item.enqueuing_queue_label); |
914 | queue_item->SetTargetQueueLabel(item.target_queue_label); |
915 | } |
916 | m_page_to_free = ret.item_buffer_ptr; |
917 | m_page_to_free_size = ret.item_buffer_size; |
918 | } |
919 | } |
920 | |
921 | void SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR( |
922 | lldb::addr_t queues_buffer, uint64_t queues_buffer_size, uint64_t count, |
923 | lldb_private::QueueList &queue_list) { |
924 | Status error; |
925 | DataBufferHeap data(queues_buffer_size, 0); |
926 | Log *log = GetLog(mask: LLDBLog::SystemRuntime); |
927 | if (m_process->ReadMemory(vm_addr: queues_buffer, buf: data.GetBytes(), size: queues_buffer_size, |
928 | error) == queues_buffer_size && |
929 | error.Success()) { |
930 | // We've read the information out of inferior memory; free it on the next |
931 | // call we make |
932 | m_page_to_free = queues_buffer; |
933 | m_page_to_free_size = queues_buffer_size; |
934 | |
935 | DataExtractor (data.GetBytes(), data.GetByteSize(), |
936 | m_process->GetByteOrder(), |
937 | m_process->GetAddressByteSize()); |
938 | offset_t offset = 0; |
939 | uint64_t queues_read = 0; |
940 | |
941 | // The information about the queues is stored in this format (v1): typedef |
942 | // struct introspection_dispatch_queue_info_s { |
943 | // uint32_t offset_to_next; |
944 | // dispatch_queue_t queue; |
945 | // uint64_t serialnum; // queue's serialnum in the process, as |
946 | // provided by libdispatch |
947 | // uint32_t running_work_items_count; |
948 | // uint32_t pending_work_items_count; |
949 | // |
950 | // char data[]; // Starting here, we have variable-length data: |
951 | // // char queue_label[]; |
952 | // } introspection_dispatch_queue_info_s; |
953 | |
954 | while (queues_read < count && offset < queues_buffer_size) { |
955 | offset_t start_of_this_item = offset; |
956 | |
957 | uint32_t offset_to_next = extractor.GetU32(offset_ptr: &offset); |
958 | |
959 | offset += 4; // Skip over the 4 bytes of reserved space |
960 | addr_t queue = extractor.GetAddress(offset_ptr: &offset); |
961 | uint64_t serialnum = extractor.GetU64(offset_ptr: &offset); |
962 | uint32_t running_work_items_count = extractor.GetU32(offset_ptr: &offset); |
963 | uint32_t pending_work_items_count = extractor.GetU32(offset_ptr: &offset); |
964 | |
965 | // Read the first field of the variable length data |
966 | offset = start_of_this_item + |
967 | m_lib_backtrace_recording_info.queue_info_data_offset; |
968 | const char *queue_label = extractor.GetCStr(offset_ptr: &offset); |
969 | if (queue_label == nullptr) |
970 | queue_label = "" ; |
971 | |
972 | offset_t start_of_next_item = start_of_this_item + offset_to_next; |
973 | offset = start_of_next_item; |
974 | |
975 | LLDB_LOGF(log, |
976 | "SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added " |
977 | "queue with dispatch_queue_t 0x%" PRIx64 |
978 | ", serial number 0x%" PRIx64 |
979 | ", running items %d, pending items %d, name '%s'" , |
980 | queue, serialnum, running_work_items_count, |
981 | pending_work_items_count, queue_label); |
982 | |
983 | QueueSP queue_sp( |
984 | new Queue(m_process->shared_from_this(), serialnum, queue_label)); |
985 | queue_sp->SetNumRunningWorkItems(running_work_items_count); |
986 | queue_sp->SetNumPendingWorkItems(pending_work_items_count); |
987 | queue_sp->SetLibdispatchQueueAddress(queue); |
988 | queue_sp->SetKind(GetQueueKind(dispatch_queue_addr: queue)); |
989 | queue_list.AddQueue(queue: queue_sp); |
990 | queues_read++; |
991 | } |
992 | } |
993 | } |
994 | |
995 | SystemRuntimeMacOSX::ItemInfo SystemRuntimeMacOSX::( |
996 | lldb_private::DataExtractor &) { |
997 | ItemInfo item; |
998 | |
999 | offset_t offset = 0; |
1000 | |
1001 | item.item_that_enqueued_this = extractor.GetAddress(offset_ptr: &offset); |
1002 | item.function_or_block = extractor.GetAddress(offset_ptr: &offset); |
1003 | item.enqueuing_thread_id = extractor.GetU64(offset_ptr: &offset); |
1004 | item.enqueuing_queue_serialnum = extractor.GetU64(offset_ptr: &offset); |
1005 | item.target_queue_serialnum = extractor.GetU64(offset_ptr: &offset); |
1006 | item.enqueuing_callstack_frame_count = extractor.GetU32(offset_ptr: &offset); |
1007 | item.stop_id = extractor.GetU32(offset_ptr: &offset); |
1008 | |
1009 | offset = m_lib_backtrace_recording_info.item_info_data_offset; |
1010 | |
1011 | for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++) { |
1012 | item.enqueuing_callstack.push_back(x: extractor.GetAddress(offset_ptr: &offset)); |
1013 | } |
1014 | item.enqueuing_thread_label = extractor.GetCStr(offset_ptr: &offset); |
1015 | item.enqueuing_queue_label = extractor.GetCStr(offset_ptr: &offset); |
1016 | item.target_queue_label = extractor.GetCStr(offset_ptr: &offset); |
1017 | |
1018 | return item; |
1019 | } |
1020 | |
1021 | void SystemRuntimeMacOSX::Initialize() { |
1022 | PluginManager::RegisterPlugin( |
1023 | name: GetPluginNameStatic(), |
1024 | description: "System runtime plugin for Mac OS X native libraries." , create_callback: CreateInstance); |
1025 | } |
1026 | |
1027 | void SystemRuntimeMacOSX::Terminate() { |
1028 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
1029 | } |
1030 | |