xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrick //===-- AppleGetPendingItemsHandler.cpp -------------------------------*- C++
2*061da546Spatrick //-*-===//
3*061da546Spatrick //
4*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
6*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*061da546Spatrick //
8*061da546Spatrick //===----------------------------------------------------------------------===//
9*061da546Spatrick 
10*061da546Spatrick #include "AppleGetPendingItemsHandler.h"
11*061da546Spatrick 
12*061da546Spatrick 
13*061da546Spatrick #include "lldb/Core/Module.h"
14*061da546Spatrick #include "lldb/Core/Value.h"
15*061da546Spatrick #include "lldb/Expression/DiagnosticManager.h"
16*061da546Spatrick #include "lldb/Expression/FunctionCaller.h"
17*061da546Spatrick #include "lldb/Expression/UtilityFunction.h"
18*061da546Spatrick #include "lldb/Symbol/ClangASTContext.h"
19*061da546Spatrick #include "lldb/Symbol/Symbol.h"
20*061da546Spatrick #include "lldb/Target/ExecutionContext.h"
21*061da546Spatrick #include "lldb/Target/Process.h"
22*061da546Spatrick #include "lldb/Target/Target.h"
23*061da546Spatrick #include "lldb/Target/Thread.h"
24*061da546Spatrick #include "lldb/Utility/ConstString.h"
25*061da546Spatrick #include "lldb/Utility/Log.h"
26*061da546Spatrick #include "lldb/Utility/StreamString.h"
27*061da546Spatrick 
28*061da546Spatrick using namespace lldb;
29*061da546Spatrick using namespace lldb_private;
30*061da546Spatrick 
31*061da546Spatrick const char *AppleGetPendingItemsHandler::g_get_pending_items_function_name =
32*061da546Spatrick     "__lldb_backtrace_recording_get_pending_items";
33*061da546Spatrick const char *AppleGetPendingItemsHandler::g_get_pending_items_function_code =
34*061da546Spatrick     "                                  \n\
35*061da546Spatrick extern \"C\"                                                                                                    \n\
36*061da546Spatrick {                                                                                                               \n\
37*061da546Spatrick     /*                                                                                                          \n\
38*061da546Spatrick      * mach defines                                                                                             \n\
39*061da546Spatrick      */                                                                                                         \n\
40*061da546Spatrick                                                                                                                 \n\
41*061da546Spatrick     typedef unsigned int uint32_t;                                                                              \n\
42*061da546Spatrick     typedef unsigned long long uint64_t;                                                                        \n\
43*061da546Spatrick     typedef uint32_t mach_port_t;                                                                               \n\
44*061da546Spatrick     typedef mach_port_t vm_map_t;                                                                               \n\
45*061da546Spatrick     typedef int kern_return_t;                                                                                  \n\
46*061da546Spatrick     typedef uint64_t mach_vm_address_t;                                                                         \n\
47*061da546Spatrick     typedef uint64_t mach_vm_size_t;                                                                            \n\
48*061da546Spatrick                                                                                                                 \n\
49*061da546Spatrick     mach_port_t mach_task_self ();                                                                              \n\
50*061da546Spatrick     kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);         \n\
51*061da546Spatrick                                                                                                                 \n\
52*061da546Spatrick     /*                                                                                                          \n\
53*061da546Spatrick      * libBacktraceRecording defines                                                                            \n\
54*061da546Spatrick      */                                                                                                         \n\
55*061da546Spatrick                                                                                                                 \n\
56*061da546Spatrick     typedef uint32_t queue_list_scope_t;                                                                        \n\
57*061da546Spatrick     typedef void *dispatch_queue_t;                                                                             \n\
58*061da546Spatrick     typedef void *introspection_dispatch_queue_info_t;                                                          \n\
59*061da546Spatrick     typedef void *introspection_dispatch_item_info_ref;                                                         \n\
60*061da546Spatrick                                                                                                                 \n\
61*061da546Spatrick     extern uint64_t __introspection_dispatch_queue_get_pending_items (dispatch_queue_t queue,                   \n\
62*061da546Spatrick                                                  introspection_dispatch_item_info_ref *returned_queues_buffer,  \n\
63*061da546Spatrick                                                  uint64_t *returned_queues_buffer_size);                        \n\
64*061da546Spatrick     extern int printf(const char *format, ...);                                                                 \n\
65*061da546Spatrick                                                                                                                 \n\
66*061da546Spatrick     /*                                                                                                          \n\
67*061da546Spatrick      * return type define                                                                                       \n\
68*061da546Spatrick      */                                                                                                         \n\
69*061da546Spatrick                                                                                                                 \n\
70*061da546Spatrick     struct get_pending_items_return_values                                                                      \n\
71*061da546Spatrick     {                                                                                                           \n\
72*061da546Spatrick         uint64_t pending_items_buffer_ptr;    /* the address of the items buffer from libBacktraceRecording */  \n\
73*061da546Spatrick         uint64_t pending_items_buffer_size;   /* the size of the items buffer from libBacktraceRecording */     \n\
74*061da546Spatrick         uint64_t count;                /* the number of items included in the queues buffer */                  \n\
75*061da546Spatrick     };                                                                                                          \n\
76*061da546Spatrick                                                                                                                 \n\
77*061da546Spatrick     void  __lldb_backtrace_recording_get_pending_items                                                          \n\
78*061da546Spatrick                                                (struct get_pending_items_return_values *return_buffer,          \n\
79*061da546Spatrick                                                 int debug,                                                      \n\
80*061da546Spatrick                                                 uint64_t /* dispatch_queue_t */ queue,                          \n\
81*061da546Spatrick                                                 void *page_to_free,                                             \n\
82*061da546Spatrick                                                 uint64_t page_to_free_size)                                     \n\
83*061da546Spatrick {                                                                                                               \n\
84*061da546Spatrick     if (debug)                                                                                                  \n\
85*061da546Spatrick       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*061da546Spatrick     if (page_to_free != 0)                                                                                      \n\
87*061da546Spatrick     {                                                                                                           \n\
88*061da546Spatrick         mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
89*061da546Spatrick     }                                                                                                           \n\
90*061da546Spatrick                                                                                                                 \n\
91*061da546Spatrick     return_buffer->count = __introspection_dispatch_queue_get_pending_items (                                   \n\
92*061da546Spatrick                                                       (void*) queue,                                            \n\
93*061da546Spatrick                                                       (void**)&return_buffer->pending_items_buffer_ptr,         \n\
94*061da546Spatrick                                                       &return_buffer->pending_items_buffer_size);               \n\
95*061da546Spatrick     if (debug)                                                                                                  \n\
96*061da546Spatrick         printf(\"result was count %lld\\n\", return_buffer->count);                                             \n\
97*061da546Spatrick }                                                                                                               \n\
98*061da546Spatrick }                                                                                                               \n\
99*061da546Spatrick ";
100*061da546Spatrick 
101*061da546Spatrick AppleGetPendingItemsHandler::AppleGetPendingItemsHandler(Process *process)
102*061da546Spatrick     : m_process(process), m_get_pending_items_impl_code(),
103*061da546Spatrick       m_get_pending_items_function_mutex(),
104*061da546Spatrick       m_get_pending_items_return_buffer_addr(LLDB_INVALID_ADDRESS),
105*061da546Spatrick       m_get_pending_items_retbuffer_mutex() {}
106*061da546Spatrick 
107*061da546Spatrick AppleGetPendingItemsHandler::~AppleGetPendingItemsHandler() {}
108*061da546Spatrick 
109*061da546Spatrick void AppleGetPendingItemsHandler::Detach() {
110*061da546Spatrick   if (m_process && m_process->IsAlive() &&
111*061da546Spatrick       m_get_pending_items_return_buffer_addr != LLDB_INVALID_ADDRESS) {
112*061da546Spatrick     std::unique_lock<std::mutex> lock(m_get_pending_items_retbuffer_mutex,
113*061da546Spatrick                                       std::defer_lock);
114*061da546Spatrick     lock.try_lock(); // Even if we don't get the lock, deallocate the buffer
115*061da546Spatrick     m_process->DeallocateMemory(m_get_pending_items_return_buffer_addr);
116*061da546Spatrick   }
117*061da546Spatrick }
118*061da546Spatrick 
119*061da546Spatrick // Compile our __lldb_backtrace_recording_get_pending_items() function (from
120*061da546Spatrick // the source above in g_get_pending_items_function_code) if we don't find that
121*061da546Spatrick // function in the inferior already with USE_BUILTIN_FUNCTION defined.  (e.g.
122*061da546Spatrick // this would be the case for testing.)
123*061da546Spatrick //
124*061da546Spatrick // Insert the __lldb_backtrace_recording_get_pending_items into the inferior
125*061da546Spatrick // process if needed.
126*061da546Spatrick //
127*061da546Spatrick // Write the get_pending_items_arglist into the inferior's memory space to
128*061da546Spatrick // prepare for the call.
129*061da546Spatrick //
130*061da546Spatrick // Returns the address of the arguments written down in the inferior process,
131*061da546Spatrick // which can be used to make the function call.
132*061da546Spatrick 
133*061da546Spatrick lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction(
134*061da546Spatrick     Thread &thread, ValueList &get_pending_items_arglist) {
135*061da546Spatrick   ThreadSP thread_sp(thread.shared_from_this());
136*061da546Spatrick   ExecutionContext exe_ctx(thread_sp);
137*061da546Spatrick   DiagnosticManager diagnostics;
138*061da546Spatrick   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME));
139*061da546Spatrick 
140*061da546Spatrick   lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
141*061da546Spatrick   FunctionCaller *get_pending_items_caller = nullptr;
142*061da546Spatrick 
143*061da546Spatrick   // Scope for mutex locker:
144*061da546Spatrick   {
145*061da546Spatrick     std::lock_guard<std::mutex> guard(m_get_pending_items_function_mutex);
146*061da546Spatrick 
147*061da546Spatrick     // First stage is to make the ClangUtility to hold our injected function:
148*061da546Spatrick 
149*061da546Spatrick     if (!m_get_pending_items_impl_code) {
150*061da546Spatrick       if (g_get_pending_items_function_code != nullptr) {
151*061da546Spatrick         Status error;
152*061da546Spatrick         m_get_pending_items_impl_code.reset(
153*061da546Spatrick             exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(
154*061da546Spatrick                 g_get_pending_items_function_code, eLanguageTypeObjC,
155*061da546Spatrick                 g_get_pending_items_function_name, error));
156*061da546Spatrick         if (error.Fail()) {
157*061da546Spatrick           LLDB_LOGF(log,
158*061da546Spatrick                     "Failed to get UtilityFunction for pending-items "
159*061da546Spatrick                     "introspection: %s.",
160*061da546Spatrick                     error.AsCString());
161*061da546Spatrick           return args_addr;
162*061da546Spatrick         }
163*061da546Spatrick 
164*061da546Spatrick         if (!m_get_pending_items_impl_code->Install(diagnostics, exe_ctx)) {
165*061da546Spatrick           if (log) {
166*061da546Spatrick             LLDB_LOGF(log, "Failed to install pending-items introspection.");
167*061da546Spatrick             diagnostics.Dump(log);
168*061da546Spatrick           }
169*061da546Spatrick           m_get_pending_items_impl_code.reset();
170*061da546Spatrick           return args_addr;
171*061da546Spatrick         }
172*061da546Spatrick       } else {
173*061da546Spatrick         LLDB_LOGF(log, "No pending-items introspection code found.");
174*061da546Spatrick         return LLDB_INVALID_ADDRESS;
175*061da546Spatrick       }
176*061da546Spatrick 
177*061da546Spatrick       // Next make the runner function for our implementation utility function.
178*061da546Spatrick       Status error;
179*061da546Spatrick       ClangASTContext *clang_ast_context =
180*061da546Spatrick           ClangASTContext::GetScratch(thread.GetProcess()->GetTarget());
181*061da546Spatrick       CompilerType get_pending_items_return_type =
182*061da546Spatrick           clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
183*061da546Spatrick       get_pending_items_caller =
184*061da546Spatrick           m_get_pending_items_impl_code->MakeFunctionCaller(
185*061da546Spatrick               get_pending_items_return_type, get_pending_items_arglist,
186*061da546Spatrick               thread_sp, error);
187*061da546Spatrick       if (error.Fail() || get_pending_items_caller == nullptr) {
188*061da546Spatrick         LLDB_LOGF(log,
189*061da546Spatrick                   "Failed to install pending-items introspection function "
190*061da546Spatrick                   "caller: %s.",
191*061da546Spatrick                   error.AsCString());
192*061da546Spatrick         m_get_pending_items_impl_code.reset();
193*061da546Spatrick         return args_addr;
194*061da546Spatrick       }
195*061da546Spatrick     }
196*061da546Spatrick   }
197*061da546Spatrick 
198*061da546Spatrick   diagnostics.Clear();
199*061da546Spatrick 
200*061da546Spatrick   if (get_pending_items_caller == nullptr) {
201*061da546Spatrick     LLDB_LOGF(log, "Failed to get get_pending_items_caller.");
202*061da546Spatrick     return LLDB_INVALID_ADDRESS;
203*061da546Spatrick   }
204*061da546Spatrick 
205*061da546Spatrick   // Now write down the argument values for this particular call.  This looks
206*061da546Spatrick   // like it might be a race condition if other threads were calling into here,
207*061da546Spatrick   // but actually it isn't because we allocate a new args structure for this
208*061da546Spatrick   // call by passing args_addr = LLDB_INVALID_ADDRESS...
209*061da546Spatrick 
210*061da546Spatrick   if (!get_pending_items_caller->WriteFunctionArguments(
211*061da546Spatrick           exe_ctx, args_addr, get_pending_items_arglist, diagnostics)) {
212*061da546Spatrick     if (log) {
213*061da546Spatrick       LLDB_LOGF(log, "Error writing pending-items function arguments.");
214*061da546Spatrick       diagnostics.Dump(log);
215*061da546Spatrick     }
216*061da546Spatrick 
217*061da546Spatrick     return args_addr;
218*061da546Spatrick   }
219*061da546Spatrick 
220*061da546Spatrick   return args_addr;
221*061da546Spatrick }
222*061da546Spatrick 
223*061da546Spatrick AppleGetPendingItemsHandler::GetPendingItemsReturnInfo
224*061da546Spatrick AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue,
225*061da546Spatrick                                              addr_t page_to_free,
226*061da546Spatrick                                              uint64_t page_to_free_size,
227*061da546Spatrick                                              Status &error) {
228*061da546Spatrick   lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
229*061da546Spatrick   ProcessSP process_sp(thread.CalculateProcess());
230*061da546Spatrick   TargetSP target_sp(thread.CalculateTarget());
231*061da546Spatrick   ClangASTContext *clang_ast_context = ClangASTContext::GetScratch(*target_sp);
232*061da546Spatrick   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME));
233*061da546Spatrick 
234*061da546Spatrick   GetPendingItemsReturnInfo return_value;
235*061da546Spatrick   return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
236*061da546Spatrick   return_value.items_buffer_size = 0;
237*061da546Spatrick   return_value.count = 0;
238*061da546Spatrick 
239*061da546Spatrick   error.Clear();
240*061da546Spatrick 
241*061da546Spatrick   if (!thread.SafeToCallFunctions()) {
242*061da546Spatrick     LLDB_LOGF(log, "Not safe to call functions on thread 0x%" PRIx64,
243*061da546Spatrick               thread.GetID());
244*061da546Spatrick     error.SetErrorString("Not safe to call functions on this thread.");
245*061da546Spatrick     return return_value;
246*061da546Spatrick   }
247*061da546Spatrick 
248*061da546Spatrick   // Set up the arguments for a call to
249*061da546Spatrick 
250*061da546Spatrick   // struct get_pending_items_return_values
251*061da546Spatrick   // {
252*061da546Spatrick   //     uint64_t pending_items_buffer_ptr;    /* the address of the items
253*061da546Spatrick   //     buffer from libBacktraceRecording */
254*061da546Spatrick   //     uint64_t pending_items_buffer_size;   /* the size of the items buffer
255*061da546Spatrick   //     from libBacktraceRecording */
256*061da546Spatrick   //     uint64_t count;                /* the number of items included in the
257*061da546Spatrick   //     queues buffer */
258*061da546Spatrick   // };
259*061da546Spatrick   //
260*061da546Spatrick   // void  __lldb_backtrace_recording_get_pending_items
261*061da546Spatrick   //                                            (struct
262*061da546Spatrick   //                                            get_pending_items_return_values
263*061da546Spatrick   //                                            *return_buffer,
264*061da546Spatrick   //                                             int debug,
265*061da546Spatrick   //                                             uint64_t /* dispatch_queue_t */
266*061da546Spatrick   //                                             queue
267*061da546Spatrick   //                                             void *page_to_free,
268*061da546Spatrick   //                                             uint64_t page_to_free_size)
269*061da546Spatrick 
270*061da546Spatrick   // Where the return_buffer argument points to a 24 byte region of memory
271*061da546Spatrick   // already allocated by lldb in the inferior process.
272*061da546Spatrick 
273*061da546Spatrick   CompilerType clang_void_ptr_type =
274*061da546Spatrick       clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
275*061da546Spatrick   Value return_buffer_ptr_value;
276*061da546Spatrick   return_buffer_ptr_value.SetValueType(Value::eValueTypeScalar);
277*061da546Spatrick   return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type);
278*061da546Spatrick 
279*061da546Spatrick   CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
280*061da546Spatrick   Value debug_value;
281*061da546Spatrick   debug_value.SetValueType(Value::eValueTypeScalar);
282*061da546Spatrick   debug_value.SetCompilerType(clang_int_type);
283*061da546Spatrick 
284*061da546Spatrick   CompilerType clang_uint64_type =
285*061da546Spatrick       clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
286*061da546Spatrick   Value queue_value;
287*061da546Spatrick   queue_value.SetValueType(Value::eValueTypeScalar);
288*061da546Spatrick   queue_value.SetCompilerType(clang_uint64_type);
289*061da546Spatrick 
290*061da546Spatrick   Value page_to_free_value;
291*061da546Spatrick   page_to_free_value.SetValueType(Value::eValueTypeScalar);
292*061da546Spatrick   page_to_free_value.SetCompilerType(clang_void_ptr_type);
293*061da546Spatrick 
294*061da546Spatrick   Value page_to_free_size_value;
295*061da546Spatrick   page_to_free_size_value.SetValueType(Value::eValueTypeScalar);
296*061da546Spatrick   page_to_free_size_value.SetCompilerType(clang_uint64_type);
297*061da546Spatrick 
298*061da546Spatrick   std::lock_guard<std::mutex> guard(m_get_pending_items_retbuffer_mutex);
299*061da546Spatrick   if (m_get_pending_items_return_buffer_addr == LLDB_INVALID_ADDRESS) {
300*061da546Spatrick     addr_t bufaddr = process_sp->AllocateMemory(
301*061da546Spatrick         32, ePermissionsReadable | ePermissionsWritable, error);
302*061da546Spatrick     if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS) {
303*061da546Spatrick       LLDB_LOGF(log, "Failed to allocate memory for return buffer for get "
304*061da546Spatrick                      "current queues func call");
305*061da546Spatrick       return return_value;
306*061da546Spatrick     }
307*061da546Spatrick     m_get_pending_items_return_buffer_addr = bufaddr;
308*061da546Spatrick   }
309*061da546Spatrick 
310*061da546Spatrick   ValueList argument_values;
311*061da546Spatrick 
312*061da546Spatrick   return_buffer_ptr_value.GetScalar() = m_get_pending_items_return_buffer_addr;
313*061da546Spatrick   argument_values.PushValue(return_buffer_ptr_value);
314*061da546Spatrick 
315*061da546Spatrick   debug_value.GetScalar() = 0;
316*061da546Spatrick   argument_values.PushValue(debug_value);
317*061da546Spatrick 
318*061da546Spatrick   queue_value.GetScalar() = queue;
319*061da546Spatrick   argument_values.PushValue(queue_value);
320*061da546Spatrick 
321*061da546Spatrick   if (page_to_free != LLDB_INVALID_ADDRESS)
322*061da546Spatrick     page_to_free_value.GetScalar() = page_to_free;
323*061da546Spatrick   else
324*061da546Spatrick     page_to_free_value.GetScalar() = 0;
325*061da546Spatrick   argument_values.PushValue(page_to_free_value);
326*061da546Spatrick 
327*061da546Spatrick   page_to_free_size_value.GetScalar() = page_to_free_size;
328*061da546Spatrick   argument_values.PushValue(page_to_free_size_value);
329*061da546Spatrick 
330*061da546Spatrick   addr_t args_addr = SetupGetPendingItemsFunction(thread, argument_values);
331*061da546Spatrick 
332*061da546Spatrick   DiagnosticManager diagnostics;
333*061da546Spatrick   ExecutionContext exe_ctx;
334*061da546Spatrick   FunctionCaller *get_pending_items_caller =
335*061da546Spatrick       m_get_pending_items_impl_code->GetFunctionCaller();
336*061da546Spatrick 
337*061da546Spatrick   EvaluateExpressionOptions options;
338*061da546Spatrick   options.SetUnwindOnError(true);
339*061da546Spatrick   options.SetIgnoreBreakpoints(true);
340*061da546Spatrick   options.SetStopOthers(true);
341*061da546Spatrick #if __has_feature(address_sanitizer)
342*061da546Spatrick   options.SetTimeout(process_sp->GetUtilityExpressionTimeout());
343*061da546Spatrick #else
344*061da546Spatrick   options.SetTimeout(std::chrono::milliseconds(500));
345*061da546Spatrick #endif
346*061da546Spatrick   options.SetTryAllThreads(false);
347*061da546Spatrick   options.SetIsForUtilityExpr(true);
348*061da546Spatrick   thread.CalculateExecutionContext(exe_ctx);
349*061da546Spatrick 
350*061da546Spatrick   if (get_pending_items_caller == nullptr) {
351*061da546Spatrick     error.SetErrorString("Unable to compile function to call "
352*061da546Spatrick                          "__introspection_dispatch_queue_get_pending_items");
353*061da546Spatrick     return return_value;
354*061da546Spatrick   }
355*061da546Spatrick 
356*061da546Spatrick   ExpressionResults func_call_ret;
357*061da546Spatrick   Value results;
358*061da546Spatrick   func_call_ret = get_pending_items_caller->ExecuteFunction(
359*061da546Spatrick       exe_ctx, &args_addr, options, diagnostics, results);
360*061da546Spatrick   if (func_call_ret != eExpressionCompleted || !error.Success()) {
361*061da546Spatrick     LLDB_LOGF(log,
362*061da546Spatrick               "Unable to call "
363*061da546Spatrick               "__introspection_dispatch_queue_get_pending_items(), got "
364*061da546Spatrick               "ExpressionResults %d, error contains %s",
365*061da546Spatrick               func_call_ret, error.AsCString(""));
366*061da546Spatrick     error.SetErrorString("Unable to call "
367*061da546Spatrick                          "__introspection_dispatch_queue_get_pending_items() "
368*061da546Spatrick                          "for list of queues");
369*061da546Spatrick     return return_value;
370*061da546Spatrick   }
371*061da546Spatrick 
372*061da546Spatrick   return_value.items_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory(
373*061da546Spatrick       m_get_pending_items_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
374*061da546Spatrick   if (!error.Success() ||
375*061da546Spatrick       return_value.items_buffer_ptr == LLDB_INVALID_ADDRESS) {
376*061da546Spatrick     return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
377*061da546Spatrick     return return_value;
378*061da546Spatrick   }
379*061da546Spatrick 
380*061da546Spatrick   return_value.items_buffer_size = m_process->ReadUnsignedIntegerFromMemory(
381*061da546Spatrick       m_get_pending_items_return_buffer_addr + 8, 8, 0, error);
382*061da546Spatrick 
383*061da546Spatrick   if (!error.Success()) {
384*061da546Spatrick     return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
385*061da546Spatrick     return return_value;
386*061da546Spatrick   }
387*061da546Spatrick 
388*061da546Spatrick   return_value.count = m_process->ReadUnsignedIntegerFromMemory(
389*061da546Spatrick       m_get_pending_items_return_buffer_addr + 16, 8, 0, error);
390*061da546Spatrick   if (!error.Success()) {
391*061da546Spatrick     return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
392*061da546Spatrick     return return_value;
393*061da546Spatrick   }
394*061da546Spatrick 
395*061da546Spatrick   LLDB_LOGF(log,
396*061da546Spatrick             "AppleGetPendingItemsHandler called "
397*061da546Spatrick             "__introspection_dispatch_queue_get_pending_items "
398*061da546Spatrick             "(page_to_free == 0x%" PRIx64 ", size = %" PRId64
399*061da546Spatrick             "), returned page is at 0x%" PRIx64 ", size %" PRId64
400*061da546Spatrick             ", count = %" PRId64,
401*061da546Spatrick             page_to_free, page_to_free_size, return_value.items_buffer_ptr,
402*061da546Spatrick             return_value.items_buffer_size, return_value.count);
403*061da546Spatrick 
404*061da546Spatrick   return return_value;
405*061da546Spatrick }
406