blob: be1b100cad3a0e81d4ffb0daf5d5b3fff60d73f1 [file] [log] [blame]
Kate Stoneb9c1b512016-09-06 20:57:50 +00001//===-- AppleGetPendingItemsHandler.cpp -------------------------------*- C++
2//-*-===//
Jason Molenda2fd83352014-02-05 05:44:54 +00003//
Chandler Carruth2946cd72019-01-19 08:50:56 +00004// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Jason Molenda2fd83352014-02-05 05:44:54 +00007//
8//===----------------------------------------------------------------------===//
9
10#include "AppleGetPendingItemsHandler.h"
11
Jason Molenda2fd83352014-02-05 05:44:54 +000012
Jason Molenda2fd83352014-02-05 05:44:54 +000013#include "lldb/Core/Module.h"
Jason Molenda2fd83352014-02-05 05:44:54 +000014#include "lldb/Core/Value.h"
Sean Callanan579e70c2016-03-19 00:03:59 +000015#include "lldb/Expression/DiagnosticManager.h"
Jim Ingham151c0322015-09-15 21:13:50 +000016#include "lldb/Expression/FunctionCaller.h"
17#include "lldb/Expression/UtilityFunction.h"
Jason Molenda2fd83352014-02-05 05:44:54 +000018#include "lldb/Symbol/ClangASTContext.h"
19#include "lldb/Symbol/Symbol.h"
20#include "lldb/Target/ExecutionContext.h"
21#include "lldb/Target/Process.h"
22#include "lldb/Target/Target.h"
23#include "lldb/Target/Thread.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000024#include "lldb/Utility/ConstString.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000025#include "lldb/Utility/Log.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000026#include "lldb/Utility/StreamString.h"
Jason Molenda2fd83352014-02-05 05:44:54 +000027
28using namespace lldb;
29using namespace lldb_private;
30
Kate Stoneb9c1b512016-09-06 20:57:50 +000031const char *AppleGetPendingItemsHandler::g_get_pending_items_function_name =
32 "__lldb_backtrace_recording_get_pending_items";
33const char *AppleGetPendingItemsHandler::g_get_pending_items_function_code =
34 " \n\
Jason Molenda2fd83352014-02-05 05:44:54 +000035extern \"C\" \n\
36{ \n\
37 /* \n\
38 * mach defines \n\
39 */ \n\
40 \n\
41 typedef unsigned int uint32_t; \n\
42 typedef unsigned long long uint64_t; \n\
43 typedef uint32_t mach_port_t; \n\
44 typedef mach_port_t vm_map_t; \n\
45 typedef int kern_return_t; \n\
46 typedef uint64_t mach_vm_address_t; \n\
47 typedef uint64_t mach_vm_size_t; \n\
48 \n\
49 mach_port_t mach_task_self (); \n\
50 kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
51 \n\
52 /* \n\
53 * libBacktraceRecording defines \n\
54 */ \n\
55 \n\
56 typedef uint32_t queue_list_scope_t; \n\
57 typedef void *dispatch_queue_t; \n\
58 typedef void *introspection_dispatch_queue_info_t; \n\
59 typedef void *introspection_dispatch_item_info_ref; \n\
60 \n\
61 extern uint64_t __introspection_dispatch_queue_get_pending_items (dispatch_queue_t queue, \n\
62 introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
63 uint64_t *returned_queues_buffer_size); \n\
64 extern int printf(const char *format, ...); \n\
65 \n\
66 /* \n\
67 * return type define \n\
68 */ \n\
69 \n\
70 struct get_pending_items_return_values \n\
71 { \n\
72 uint64_t pending_items_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
73 uint64_t pending_items_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
74 uint64_t count; /* the number of items included in the queues buffer */ \n\
75 }; \n\
76 \n\
77 void __lldb_backtrace_recording_get_pending_items \n\
78 (struct get_pending_items_return_values *return_buffer, \n\
79 int debug, \n\
80 uint64_t /* dispatch_queue_t */ queue, \n\
81 void *page_to_free, \n\
82 uint64_t page_to_free_size) \n\
83{ \n\
84 if (debug) \n\
85 printf (\"entering get_pending_items with args return_buffer == %p, debug == %d, queue == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, queue, page_to_free, page_to_free_size); \n\
86 if (page_to_free != 0) \n\
87 { \n\
88 mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
89 } \n\
90 \n\
91 return_buffer->count = __introspection_dispatch_queue_get_pending_items ( \n\
92 (void*) queue, \n\
93 (void**)&return_buffer->pending_items_buffer_ptr, \n\
94 &return_buffer->pending_items_buffer_size); \n\
95 if (debug) \n\
96 printf(\"result was count %lld\\n\", return_buffer->count); \n\
97} \n\
98} \n\
99";
100
Saleem Abdulrasool16ff8602016-05-18 01:59:10 +0000101AppleGetPendingItemsHandler::AppleGetPendingItemsHandler(Process *process)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 : m_process(process), m_get_pending_items_impl_code(),
Saleem Abdulrasool16ff8602016-05-18 01:59:10 +0000103 m_get_pending_items_function_mutex(),
104 m_get_pending_items_return_buffer_addr(LLDB_INVALID_ADDRESS),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 m_get_pending_items_retbuffer_mutex() {}
Jason Molenda2fd83352014-02-05 05:44:54 +0000106
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107AppleGetPendingItemsHandler::~AppleGetPendingItemsHandler() {}
Jason Molenda2fd83352014-02-05 05:44:54 +0000108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109void AppleGetPendingItemsHandler::Detach() {
110 if (m_process && m_process->IsAlive() &&
111 m_get_pending_items_return_buffer_addr != LLDB_INVALID_ADDRESS) {
112 std::unique_lock<std::mutex> lock(m_get_pending_items_retbuffer_mutex,
113 std::defer_lock);
114 lock.try_lock(); // Even if we don't get the lock, deallocate the buffer
115 m_process->DeallocateMemory(m_get_pending_items_return_buffer_addr);
116 }
Jason Molenda2fd83352014-02-05 05:44:54 +0000117}
118
Adrian Prantl05097242018-04-30 16:49:04 +0000119// Compile our __lldb_backtrace_recording_get_pending_items() function (from
120// the source above in g_get_pending_items_function_code) if we don't find that
121// function in the inferior already with USE_BUILTIN_FUNCTION defined. (e.g.
122// this would be the case for testing.)
Jason Molenda2fd83352014-02-05 05:44:54 +0000123//
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124// Insert the __lldb_backtrace_recording_get_pending_items into the inferior
125// process if needed.
Jason Molenda2fd83352014-02-05 05:44:54 +0000126//
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127// Write the get_pending_items_arglist into the inferior's memory space to
128// prepare for the call.
129//
130// Returns the address of the arguments written down in the inferior process,
Adrian Prantl05097242018-04-30 16:49:04 +0000131// which can be used to make the function call.
Jason Molenda2fd83352014-02-05 05:44:54 +0000132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction(
134 Thread &thread, ValueList &get_pending_items_arglist) {
135 ThreadSP thread_sp(thread.shared_from_this());
136 ExecutionContext exe_ctx(thread_sp);
137 DiagnosticManager diagnostics;
138 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME));
Jim Ingham6896b352016-03-21 19:21:13 +0000139
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140 lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
141 FunctionCaller *get_pending_items_caller = nullptr;
Sean Callanan579e70c2016-03-19 00:03:59 +0000142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143 // Scope for mutex locker:
144 {
145 std::lock_guard<std::mutex> guard(m_get_pending_items_function_mutex);
Saleem Abdulrasool16ff8602016-05-18 01:59:10 +0000146
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 // First stage is to make the ClangUtility to hold our injected function:
Jason Molenda2fd83352014-02-05 05:44:54 +0000148
Jonas Devlieghere70355ac2019-02-12 03:47:39 +0000149 if (!m_get_pending_items_impl_code) {
Konrad Kleine248a1302019-05-23 11:14:47 +0000150 if (g_get_pending_items_function_code != nullptr) {
Zachary Turner97206d52017-05-12 04:51:55 +0000151 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 m_get_pending_items_impl_code.reset(
153 exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(
154 g_get_pending_items_function_code, eLanguageTypeObjC,
155 g_get_pending_items_function_name, error));
156 if (error.Fail()) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000157 LLDB_LOGF(log,
158 "Failed to get UtilityFunction for pending-items "
159 "introspection: %s.",
160 error.AsCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000161 return args_addr;
Jason Molenda2fd83352014-02-05 05:44:54 +0000162 }
Sean Callanan579e70c2016-03-19 00:03:59 +0000163
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 if (!m_get_pending_items_impl_code->Install(diagnostics, exe_ctx)) {
165 if (log) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000166 LLDB_LOGF(log, "Failed to install pending-items introspection.");
Sean Callanan579e70c2016-03-19 00:03:59 +0000167 diagnostics.Dump(log);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 }
169 m_get_pending_items_impl_code.reset();
170 return args_addr;
Sean Callanan579e70c2016-03-19 00:03:59 +0000171 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 } else {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000173 LLDB_LOGF(log, "No pending-items introspection code found.");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 return LLDB_INVALID_ADDRESS;
175 }
Sean Callanan579e70c2016-03-19 00:03:59 +0000176
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177 // Next make the runner function for our implementation utility function.
Zachary Turner97206d52017-05-12 04:51:55 +0000178 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 ClangASTContext *clang_ast_context =
Alex Langford30318182019-11-14 13:41:52 -0800180 ClangASTContext::GetScratch(thread.GetProcess()->GetTarget());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 CompilerType get_pending_items_return_type =
182 clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
183 get_pending_items_caller =
184 m_get_pending_items_impl_code->MakeFunctionCaller(
185 get_pending_items_return_type, get_pending_items_arglist,
186 thread_sp, error);
Jason Molendaed2977f2016-10-27 23:52:46 +0000187 if (error.Fail() || get_pending_items_caller == nullptr) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000188 LLDB_LOGF(log,
189 "Failed to install pending-items introspection function "
190 "caller: %s.",
191 error.AsCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 m_get_pending_items_impl_code.reset();
Jason Molenda2fd83352014-02-05 05:44:54 +0000193 return args_addr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 }
195 }
196 }
197
198 diagnostics.Clear();
199
200 if (get_pending_items_caller == nullptr) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000201 LLDB_LOGF(log, "Failed to get get_pending_items_caller.");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202 return LLDB_INVALID_ADDRESS;
203 }
204
205 // Now write down the argument values for this particular call. This looks
Adrian Prantl05097242018-04-30 16:49:04 +0000206 // like it might be a race condition if other threads were calling into here,
207 // but actually it isn't because we allocate a new args structure for this
208 // call by passing args_addr = LLDB_INVALID_ADDRESS...
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209
210 if (!get_pending_items_caller->WriteFunctionArguments(
211 exe_ctx, args_addr, get_pending_items_arglist, diagnostics)) {
212 if (log) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000213 LLDB_LOGF(log, "Error writing pending-items function arguments.");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000214 diagnostics.Dump(log);
Jason Molenda2fd83352014-02-05 05:44:54 +0000215 }
Sean Callanan579e70c2016-03-19 00:03:59 +0000216
Jason Molenda2fd83352014-02-05 05:44:54 +0000217 return args_addr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 }
219
220 return args_addr;
Jason Molenda2fd83352014-02-05 05:44:54 +0000221}
222
223AppleGetPendingItemsHandler::GetPendingItemsReturnInfo
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue,
225 addr_t page_to_free,
226 uint64_t page_to_free_size,
Zachary Turner97206d52017-05-12 04:51:55 +0000227 Status &error) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
229 ProcessSP process_sp(thread.CalculateProcess());
230 TargetSP target_sp(thread.CalculateTarget());
Alex Langford30318182019-11-14 13:41:52 -0800231 ClangASTContext *clang_ast_context = ClangASTContext::GetScratch(*target_sp);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME));
Jason Molenda2fd83352014-02-05 05:44:54 +0000233
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234 GetPendingItemsReturnInfo return_value;
235 return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
236 return_value.items_buffer_size = 0;
237 return_value.count = 0;
Jason Molenda2fd83352014-02-05 05:44:54 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 error.Clear();
Jason Molenda2fd83352014-02-05 05:44:54 +0000240
Jonas Devliegherea6682a42018-12-15 00:15:33 +0000241 if (!thread.SafeToCallFunctions()) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000242 LLDB_LOGF(log, "Not safe to call functions on thread 0x%" PRIx64,
243 thread.GetID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000244 error.SetErrorString("Not safe to call functions on this thread.");
Jason Molenda2fd83352014-02-05 05:44:54 +0000245 return return_value;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 }
247
248 // Set up the arguments for a call to
249
250 // struct get_pending_items_return_values
251 // {
252 // uint64_t pending_items_buffer_ptr; /* the address of the items
253 // buffer from libBacktraceRecording */
254 // uint64_t pending_items_buffer_size; /* the size of the items buffer
255 // from libBacktraceRecording */
256 // uint64_t count; /* the number of items included in the
257 // queues buffer */
258 // };
259 //
260 // void __lldb_backtrace_recording_get_pending_items
261 // (struct
262 // get_pending_items_return_values
263 // *return_buffer,
264 // int debug,
265 // uint64_t /* dispatch_queue_t */
266 // queue
267 // void *page_to_free,
268 // uint64_t page_to_free_size)
269
270 // Where the return_buffer argument points to a 24 byte region of memory
Adrian Prantl05097242018-04-30 16:49:04 +0000271 // already allocated by lldb in the inferior process.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272
273 CompilerType clang_void_ptr_type =
274 clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
275 Value return_buffer_ptr_value;
276 return_buffer_ptr_value.SetValueType(Value::eValueTypeScalar);
277 return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type);
278
279 CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
280 Value debug_value;
281 debug_value.SetValueType(Value::eValueTypeScalar);
282 debug_value.SetCompilerType(clang_int_type);
283
284 CompilerType clang_uint64_type =
285 clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
286 Value queue_value;
287 queue_value.SetValueType(Value::eValueTypeScalar);
288 queue_value.SetCompilerType(clang_uint64_type);
289
290 Value page_to_free_value;
291 page_to_free_value.SetValueType(Value::eValueTypeScalar);
292 page_to_free_value.SetCompilerType(clang_void_ptr_type);
293
294 Value page_to_free_size_value;
295 page_to_free_size_value.SetValueType(Value::eValueTypeScalar);
296 page_to_free_size_value.SetCompilerType(clang_uint64_type);
297
298 std::lock_guard<std::mutex> guard(m_get_pending_items_retbuffer_mutex);
299 if (m_get_pending_items_return_buffer_addr == LLDB_INVALID_ADDRESS) {
300 addr_t bufaddr = process_sp->AllocateMemory(
301 32, ePermissionsReadable | ePermissionsWritable, error);
302 if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000303 LLDB_LOGF(log, "Failed to allocate memory for return buffer for get "
304 "current queues func call");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 return return_value;
306 }
307 m_get_pending_items_return_buffer_addr = bufaddr;
308 }
309
310 ValueList argument_values;
311
312 return_buffer_ptr_value.GetScalar() = m_get_pending_items_return_buffer_addr;
313 argument_values.PushValue(return_buffer_ptr_value);
314
315 debug_value.GetScalar() = 0;
316 argument_values.PushValue(debug_value);
317
318 queue_value.GetScalar() = queue;
319 argument_values.PushValue(queue_value);
320
321 if (page_to_free != LLDB_INVALID_ADDRESS)
322 page_to_free_value.GetScalar() = page_to_free;
323 else
324 page_to_free_value.GetScalar() = 0;
325 argument_values.PushValue(page_to_free_value);
326
327 page_to_free_size_value.GetScalar() = page_to_free_size;
328 argument_values.PushValue(page_to_free_size_value);
329
330 addr_t args_addr = SetupGetPendingItemsFunction(thread, argument_values);
331
332 DiagnosticManager diagnostics;
333 ExecutionContext exe_ctx;
334 FunctionCaller *get_pending_items_caller =
335 m_get_pending_items_impl_code->GetFunctionCaller();
336
337 EvaluateExpressionOptions options;
338 options.SetUnwindOnError(true);
339 options.SetIgnoreBreakpoints(true);
340 options.SetStopOthers(true);
Jason Molenda5b0a6872019-09-07 01:38:37 +0000341#if __has_feature(address_sanitizer)
Adrian Prantl4c03ea12019-04-05 22:43:42 +0000342 options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
Jason Molenda5b0a6872019-09-07 01:38:37 +0000343#else
344 options.SetTimeout(std::chrono::milliseconds(500));
345#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000346 options.SetTryAllThreads(false);
Raphael Isemannc01783a2018-08-29 22:50:54 +0000347 options.SetIsForUtilityExpr(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 thread.CalculateExecutionContext(exe_ctx);
349
Konrad Kleine248a1302019-05-23 11:14:47 +0000350 if (get_pending_items_caller == nullptr) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000351 error.SetErrorString("Unable to compile function to call "
352 "__introspection_dispatch_queue_get_pending_items");
353 return return_value;
354 }
355
356 ExpressionResults func_call_ret;
357 Value results;
358 func_call_ret = get_pending_items_caller->ExecuteFunction(
359 exe_ctx, &args_addr, options, diagnostics, results);
360 if (func_call_ret != eExpressionCompleted || !error.Success()) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000361 LLDB_LOGF(log,
362 "Unable to call "
363 "__introspection_dispatch_queue_get_pending_items(), got "
364 "ExpressionResults %d, error contains %s",
365 func_call_ret, error.AsCString(""));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366 error.SetErrorString("Unable to call "
367 "__introspection_dispatch_queue_get_pending_items() "
368 "for list of queues");
369 return return_value;
370 }
371
372 return_value.items_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory(
373 m_get_pending_items_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
374 if (!error.Success() ||
375 return_value.items_buffer_ptr == LLDB_INVALID_ADDRESS) {
376 return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
377 return return_value;
378 }
379
380 return_value.items_buffer_size = m_process->ReadUnsignedIntegerFromMemory(
381 m_get_pending_items_return_buffer_addr + 8, 8, 0, error);
382
383 if (!error.Success()) {
384 return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
385 return return_value;
386 }
387
388 return_value.count = m_process->ReadUnsignedIntegerFromMemory(
389 m_get_pending_items_return_buffer_addr + 16, 8, 0, error);
390 if (!error.Success()) {
391 return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
392 return return_value;
393 }
394
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +0000395 LLDB_LOGF(log,
396 "AppleGetPendingItemsHandler called "
397 "__introspection_dispatch_queue_get_pending_items "
398 "(page_to_free == 0x%" PRIx64 ", size = %" PRId64
399 "), returned page is at 0x%" PRIx64 ", size %" PRId64
400 ", count = %" PRId64,
401 page_to_free, page_to_free_size, return_value.items_buffer_ptr,
402 return_value.items_buffer_size, return_value.count);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000403
404 return return_value;
Jason Molenda2fd83352014-02-05 05:44:54 +0000405}