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