summaryrefslogtreecommitdiffstats
path: root/lldb/source
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2014-02-05 05:44:54 +0000
committerJason Molenda <jmolenda@apple.com>2014-02-05 05:44:54 +0000
commit2fd83355a837da553efe170439c054d3c70a68ee (patch)
tree40c46e628fc4560d92a166e9abfc14c0b289371e /lldb/source
parent7ca1d180559f3f5ceef45387cfeaa70a82280602 (diff)
downloadbcm5719-llvm-2fd83355a837da553efe170439c054d3c70a68ee.tar.gz
bcm5719-llvm-2fd83355a837da553efe170439c054d3c70a68ee.zip
Change the Mac OS X SystemRuntime plugin from using the placeholder
libldi library to collect extended backtrace information; switch to the libBacktraceRecording library and its APIs. Complete the work of adding QueueItems to Queues and allow for the QueueItems to be interrogated about their extended backtraces in turn. There's still cleanup and documentation to do on this code but the code is functional and I it's a good time to get the work-in-progress checked in. <rdar://problem/15314027> llvm-svn: 200822
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/SBQueue.cpp52
-rw-r--r--lldb/source/API/SBQueueItem.cpp1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp112
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h48
-rw-r--r--lldb/source/Plugins/Process/Utility/HistoryThread.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/HistoryThread.h10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp13
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp390
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h118
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp402
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h121
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp401
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h118
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp385
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h115
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt4
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp731
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h201
-rw-r--r--lldb/source/Target/Process.cpp35
-rw-r--r--lldb/source/Target/Queue.cpp61
-rw-r--r--lldb/source/Target/QueueItem.cpp25
-rw-r--r--lldb/source/Target/SystemRuntime.cpp5
-rw-r--r--lldb/source/lldb-log.cpp3
23 files changed, 2786 insertions, 567 deletions
diff --git a/lldb/source/API/SBQueue.cpp b/lldb/source/API/SBQueue.cpp
index 0b60a693f2b..8d67a48d6b8 100644
--- a/lldb/source/API/SBQueue.cpp
+++ b/lldb/source/API/SBQueue.cpp
@@ -32,8 +32,8 @@ namespace lldb_private
m_queue_wp(),
m_threads(),
m_thread_list_fetched(false),
- m_items(),
- m_queue_items_fetched(false)
+ m_pending_items(),
+ m_pending_items_fetched(false)
{
}
@@ -41,8 +41,8 @@ namespace lldb_private
m_queue_wp(),
m_threads(),
m_thread_list_fetched(false),
- m_items(),
- m_queue_items_fetched(false)
+ m_pending_items(),
+ m_pending_items_fetched(false)
{
m_queue_wp = queue_sp;
}
@@ -54,8 +54,8 @@ namespace lldb_private
m_queue_wp = rhs.m_queue_wp;
m_threads = rhs.m_threads;
m_thread_list_fetched = rhs.m_thread_list_fetched;
- m_items = rhs.m_items;
- m_queue_items_fetched = rhs.m_queue_items_fetched;
+ m_pending_items = rhs.m_pending_items;
+ m_pending_items_fetched = rhs.m_pending_items_fetched;
}
~QueueImpl ()
@@ -74,8 +74,8 @@ namespace lldb_private
m_queue_wp.reset();
m_thread_list_fetched = false;
m_threads.clear();
- m_queue_items_fetched = false;
- m_items.clear();
+ m_pending_items_fetched = false;
+ m_pending_items.clear();
}
void
@@ -162,7 +162,7 @@ namespace lldb_private
void
FetchItems ()
{
- if (m_queue_items_fetched == false)
+ if (m_pending_items_fetched == false)
{
QueueSP queue_sp = m_queue_wp.lock();
if (queue_sp)
@@ -170,15 +170,15 @@ namespace lldb_private
Process::StopLocker stop_locker;
if (stop_locker.TryLock (&queue_sp->GetProcess()->GetRunLock()))
{
- const std::vector<QueueItemSP> queue_items(queue_sp->GetItems());
- m_queue_items_fetched = true;
- const uint32_t num_items = queue_items.size();
- for (uint32_t idx = 0; idx < num_items; ++idx)
+ const std::vector<QueueItemSP> queue_items(queue_sp->GetPendingItems());
+ m_pending_items_fetched = true;
+ const uint32_t num_pending_items = queue_items.size();
+ for (uint32_t idx = 0; idx < num_pending_items; ++idx)
{
QueueItemSP item = queue_items[idx];
if (item && item->IsValid())
{
- m_items.push_back (item);
+ m_pending_items.push_back (item);
}
}
}
@@ -223,26 +223,26 @@ namespace lldb_private
uint32_t
- GetNumItems ()
+ GetNumPendingItems ()
{
uint32_t result = 0;
FetchItems();
- if (m_queue_items_fetched)
+ if (m_pending_items_fetched)
{
- result = m_items.size();
+ result = m_pending_items.size();
}
return result;
}
lldb::SBQueueItem
- GetItemAtIndex (uint32_t idx)
+ GetPendingItemAtIndex (uint32_t idx)
{
SBQueueItem result;
FetchItems();
- if (m_queue_items_fetched && idx < m_items.size())
+ if (m_pending_items_fetched && idx < m_pending_items.size())
{
- result.SetQueueItem (m_items[idx]);
+ result.SetQueueItem (m_pending_items[idx]);
}
return result;
}
@@ -263,8 +263,8 @@ namespace lldb_private
lldb::QueueWP m_queue_wp;
std::vector<lldb::ThreadWP> m_threads; // threads currently executing this queue's items
bool m_thread_list_fetched; // have we tried to fetch the threads list already?
- std::vector<lldb::QueueItemSP> m_items; // items currently enqueued
- bool m_queue_items_fetched; // have we tried to fetch the item list already?
+ std::vector<lldb::QueueItemSP> m_pending_items; // items currently enqueued
+ bool m_pending_items_fetched; // have we tried to fetch the item list already?
};
}
@@ -350,15 +350,15 @@ SBQueue::GetThreadAtIndex (uint32_t idx)
uint32_t
-SBQueue::GetNumItems ()
+SBQueue::GetNumPendingItems ()
{
- return m_opaque_sp->GetNumItems ();
+ return m_opaque_sp->GetNumPendingItems ();
}
SBQueueItem
-SBQueue::GetItemAtIndex (uint32_t idx)
+SBQueue::GetPendingItemAtIndex (uint32_t idx)
{
- return m_opaque_sp->GetItemAtIndex (idx);
+ return m_opaque_sp->GetPendingItemAtIndex (idx);
}
SBProcess
diff --git a/lldb/source/API/SBQueueItem.cpp b/lldb/source/API/SBQueueItem.cpp
index b68c40b3e02..481d51e5542 100644
--- a/lldb/source/API/SBQueueItem.cpp
+++ b/lldb/source/API/SBQueueItem.cpp
@@ -15,6 +15,7 @@
#include "lldb/API/SBThread.h"
#include "lldb/Core/Address.h"
#include "lldb/Target/QueueItem.h"
+#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index 09d11efea18..0f3833841f9 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -38,9 +38,7 @@ using namespace lldb_private;
//------------------------------------------------------------------
PlatformDarwin::PlatformDarwin (bool is_host) :
PlatformPOSIX(is_host), // This is the local host platform
- m_developer_directory (),
- m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
- m_libdispatch_offsets()
+ m_developer_directory ()
{
}
@@ -872,114 +870,6 @@ PlatformDarwin::ModuleIsExcludedForNonModuleSpecificSearches (lldb_private::Targ
return false;
}
-std::string
-PlatformDarwin::GetQueueNameForThreadQAddress (Process *process, addr_t thread_dispatch_qaddr)
-{
- std::string dispatch_queue_name;
- if (thread_dispatch_qaddr == LLDB_INVALID_ADDRESS || thread_dispatch_qaddr == 0 || process == NULL)
- return "";
-
- ReadLibdispatchOffsets (process);
- if (m_libdispatch_offsets.IsValid ())
- {
- Error error;
- addr_t queue_addr = process->ReadPointerFromMemory (thread_dispatch_qaddr, error);
- if (error.Success())
- {
- if (m_libdispatch_offsets.dqo_version >= 4)
- {
- // libdispatch versions 4+, pointer to dispatch name is in the
- // queue structure.
- addr_t pointer_to_label_address = queue_addr + m_libdispatch_offsets.dqo_label;
- addr_t label_addr = process->ReadPointerFromMemory (pointer_to_label_address, error);
- if (error.Success())
- {
- process->ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
- }
- }
- else
- {
- // libdispatch versions 1-3, dispatch name is a fixed width char array
- // in the queue structure.
- addr_t label_addr = queue_addr + m_libdispatch_offsets.dqo_label;
- dispatch_queue_name.resize (m_libdispatch_offsets.dqo_label_size, '\0');
- size_t bytes_read = process->ReadMemory (label_addr, &dispatch_queue_name[0], m_libdispatch_offsets.dqo_label_size, error);
- if (bytes_read < m_libdispatch_offsets.dqo_label_size)
- dispatch_queue_name.erase (bytes_read);
- }
- }
- }
- return dispatch_queue_name;
-}
-
-void
-PlatformDarwin::ReadLibdispatchOffsetsAddress (Process *process)
-{
- if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS)
- return;
-
- static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
- const Symbol *dispatch_queue_offsets_symbol = NULL;
-
- // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
- ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
- ModuleSP module_sp(process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
- if (module_sp)
- dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
-
- // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
- if (dispatch_queue_offsets_symbol == NULL)
- {
- ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
- module_sp = process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
- if (module_sp)
- dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
- }
- if (dispatch_queue_offsets_symbol)
- m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&process->GetTarget());
-}
-
-void
-PlatformDarwin::ReadLibdispatchOffsets (Process *process)
-{
- if (m_libdispatch_offsets.IsValid())
- return;
-
- ReadLibdispatchOffsetsAddress (process);
-
- uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)];
- DataExtractor data (memory_buffer,
- sizeof(memory_buffer),
- process->GetTarget().GetArchitecture().GetByteOrder(),
- process->GetTarget().GetArchitecture().GetAddressByteSize());
-
- Error error;
- if (process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
- {
- lldb::offset_t data_offset = 0;
-
- // The struct LibdispatchOffsets is a series of uint16_t's - extract them all
- // in one big go.
- data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t));
- }
-}
-
-lldb::queue_id_t
-PlatformDarwin::GetQueueIDForThreadQAddress (Process *process, lldb::addr_t dispatch_qaddr)
-{
- if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0 || process == NULL)
- return LLDB_INVALID_QUEUE_ID;
-
- Error error;
- uint32_t ptr_size = process->GetTarget().GetArchitecture().GetAddressByteSize();
- uint64_t this_thread_queue_id = process->ReadUnsignedIntegerFromMemory (dispatch_qaddr, ptr_size, LLDB_INVALID_QUEUE_ID, error);
- if (!error.Success())
- return LLDB_INVALID_QUEUE_ID;
-
- return this_thread_queue_id;
-}
-
-
bool
PlatformDarwin::x86GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
{
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
index a8bfdd19236..b2a6eae5e6f 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -118,12 +118,6 @@ public:
virtual size_t
GetEnvironment (lldb_private::StringList &environment);
- std::string
- GetQueueNameForThreadQAddress (lldb_private::Process *process, lldb::addr_t dispatch_qaddr);
-
- lldb::queue_id_t
- GetQueueIDForThreadQAddress (lldb_private::Process *process, lldb::addr_t dispatch_qaddr);
-
bool
ARMGetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
@@ -148,49 +142,7 @@ protected:
lldb::ModuleSP *old_module_sp_ptr,
bool *did_create_ptr);
- // Based on libdispatch src/queue_private.h, struct dispatch_queue_offsets_s
- // With dqo_version 1-3, the dqo_label field is a per-queue value and cannot be cached.
- // With dqo_version 4 (Mac OS X 10.9 / iOS 7), dqo_label is a constant value that can be cached.
- struct LibdispatchOffsets
- {
- uint16_t dqo_version;
- uint16_t dqo_label;
- uint16_t dqo_label_size;
- uint16_t dqo_flags;
- uint16_t dqo_flags_size;
- uint16_t dqo_serialnum;
- uint16_t dqo_serialnum_size;
- uint16_t dqo_width;
- uint16_t dqo_width_size;
- uint16_t dqo_running;
- uint16_t dqo_running_size;
-
- LibdispatchOffsets ()
- {
- dqo_version = UINT16_MAX;
- dqo_flags = UINT16_MAX;
- dqo_serialnum = UINT16_MAX;
- dqo_label = UINT16_MAX;
- dqo_width = UINT16_MAX;
- dqo_running = UINT16_MAX;
- };
-
- bool
- IsValid ()
- {
- return dqo_version != UINT16_MAX;
- }
-
- bool
- LabelIsValid ()
- {
- return dqo_label != UINT16_MAX;
- }
- };
-
std::string m_developer_directory;
- lldb::addr_t m_dispatch_queue_offsets_addr;
- struct LibdispatchOffsets m_libdispatch_offsets;
const char *
GetDeveloperDirectory();
diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
index 521136295fd..d045bc7e10d 100644
--- a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
+++ b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -25,7 +25,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process,
std::vector<lldb::addr_t> pcs,
uint32_t stop_id,
bool stop_id_is_valid) :
- Thread (process, LLDB_INVALID_THREAD_ID),
+ Thread (process, tid),
m_framelist_mutex(),
m_framelist(),
m_pcs (pcs),
diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.h b/lldb/source/Plugins/Process/Utility/HistoryThread.h
index 01fdd160870..f9a431d8340 100644
--- a/lldb/source/Plugins/Process/Utility/HistoryThread.h
+++ b/lldb/source/Plugins/Process/Utility/HistoryThread.h
@@ -22,6 +22,16 @@
namespace lldb_private {
+//----------------------------------------------------------------------
+/// @class HistoryThread HistoryThread.h "HistoryThread.h"
+/// @brief A thread object representing a backtrace from a previous point in the process execution
+///
+/// This subclass of Thread is used to provide a backtrace from earlier in
+/// process execution. It is given a backtrace list of pc addresses and
+/// optionally a stop_id of when those pc addresses were collected, and it will
+/// create stack frames for them.
+//----------------------------------------------------------------------
+
class HistoryThread : public lldb_private::Thread
{
public:
diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
index 4e475c80bda..fb524deda81 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -19,6 +19,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Unwind.h"
@@ -74,10 +75,10 @@ ThreadGDBRemote::GetQueueName ()
ProcessSP process_sp (GetProcess());
if (process_sp)
{
- PlatformSP platform_sp (process_sp->GetTarget().GetPlatform());
- if (platform_sp)
+ SystemRuntime *runtime = process_sp->GetSystemRuntime ();
+ if (runtime)
{
- m_dispatch_queue_name = platform_sp->GetQueueNameForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr);
+ m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr);
}
if (m_dispatch_queue_name.length() > 0)
{
@@ -96,10 +97,10 @@ ThreadGDBRemote::GetQueueID ()
ProcessSP process_sp (GetProcess());
if (process_sp)
{
- PlatformSP platform_sp (process_sp->GetTarget().GetPlatform());
- if (platform_sp)
+ SystemRuntime *runtime = process_sp->GetSystemRuntime ();
+ if (runtime)
{
- return platform_sp->GetQueueIDForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr);
+ return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr);
}
}
}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
new file mode 100644
index 00000000000..7280199383e
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
@@ -0,0 +1,390 @@
+//===-- AppleGetItemInfoHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetItemInfoHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetItemInfoHandler::g_get_item_info_function_name = "__lldb_backtrace_recording_get_item_info";
+const char *AppleGetItemInfoHandler::g_get_item_info_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *dispatch_queue_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ typedef void *introspection_dispatch_item_info_ref; \n\
+ \n\
+ extern uint64_t __introspection_dispatch_queue_item_get_info (introspection_dispatch_item_info_ref item_info_ref, \n\
+ introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ extern int printf(const char *format, ...); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_item_info_return_values \n\
+ { \n\
+ uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
+ uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_item_info \n\
+ (struct get_item_info_return_values *return_buffer, \n\
+ int debug, \n\
+ uint64_t /* introspection_dispatch_item_info_ref item_info_ref */ item, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ if (debug) \n\
+ printf (\"entering get_item_info with args return_buffer == %p, debug == %d, item == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, item, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ __introspection_dispatch_queue_item_get_info ((void*) item, \n\
+ (void**)&return_buffer->item_info_buffer_ptr, \n\
+ &return_buffer->item_info_buffer_size); \n\
+} \n\
+} \n\
+";
+
+AppleGetItemInfoHandler::AppleGetItemInfoHandler (Process *process) :
+ m_process (process),
+ m_get_item_info_function (),
+ m_get_item_info_impl_code (),
+ m_get_item_info_function_mutex(),
+ m_get_item_info_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_item_info_retbuffer_mutex()
+{
+}
+
+AppleGetItemInfoHandler::~AppleGetItemInfoHandler ()
+{
+}
+
+void
+AppleGetItemInfoHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_item_info_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_item_info_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_item_info_return_buffer_addr);
+ }
+}
+
+// Compile our __lldb_backtrace_recording_get_item_info() function (from the
+// source above in g_get_item_info_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_item_info into the inferior process if needed.
+//
+// Write the get_item_info_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetItemInfoHandler::SetupGetItemInfoFunction (Thread &thread, ValueList &get_item_info_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Address impl_code_address;
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_item_info_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target.
+ // This is useful for debugging additions to the get_impl function 'cause you don't have
+ // to bother with string-ifying the code into g_get_item_info_function_code.
+
+ if (USE_BUILTIN_FUNCTION)
+ {
+ ConstString our_utility_function_name("__lldb_backtrace_recording_get_item_info");
+ SymbolContextList sc_list;
+
+ exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list);
+ if (sc_list.GetSize() == 1)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(0, sc);
+ if (sc.symbol != NULL)
+ impl_code_address = sc.symbol->GetAddress();
+
+ //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr());
+ //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr);
+ }
+ else
+ {
+ //printf ("Could not find queues introspection function address.\n");
+ return args_addr;
+ }
+ }
+ else if (!m_get_item_info_impl_code.get())
+ {
+ if (g_get_item_info_function_code != NULL)
+ {
+ m_get_item_info_impl_code.reset (new ClangUtilityFunction (g_get_item_info_function_code,
+ g_get_item_info_function_name));
+ if (!m_get_item_info_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install get-item-info introspection: %s.", errors.GetData());
+ m_get_item_info_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No get-item-info introspection code found.");
+ errors.Printf ("No get-item-info introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_item_info_impl_code->StartAddress());
+ }
+ else
+ {
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_item_info_impl_code->StartAddress());
+ }
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_item_info_function.get())
+ {
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ ClangASTType get_item_info_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ m_get_item_info_function.reset(new ClangFunction (thread,
+ get_item_info_return_type,
+ impl_code_address,
+ get_item_info_arglist));
+
+ errors.Clear();
+ unsigned num_errors = m_get_item_info_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling get-item-info function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ errors.Clear();
+ if (!m_get_item_info_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting get-item-info function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!m_get_item_info_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_item_info_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing get-item-info function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetItemInfoHandler::GetItemInfoReturnInfo
+AppleGetItemInfoHandler::GetItemInfo (Thread &thread, uint64_t item, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetItemInfoReturnInfo return_value;
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.item_buffer_size = 0;
+
+ error.Clear();
+
+ // Set up the arguments for a call to
+
+ // struct get_item_info_return_values
+ // {
+ // uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */
+ // uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */
+ // };
+ //
+ // void __lldb_backtrace_recording_get_item_info
+ // (struct get_item_info_return_values *return_buffer,
+ // int debug,
+ // uint64_t item,
+ // void *page_to_free,
+ // uint64_t page_to_free_size)
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetClangType (clang_void_ptr_type);
+
+ ClangASTType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetClangType (clang_int_type);
+
+ ClangASTType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value item_value;
+ item_value.SetValueType (Value::eValueTypeScalar);
+ item_value.SetClangType (clang_uint64_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetClangType (clang_void_ptr_type);
+
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetClangType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_item_info_retbuffer_mutex);
+ if (m_get_item_info_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_item_info_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_item_info_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ item_value.GetScalar() = item;
+ argument_values.PushValue (item_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetItemInfoFunction (thread, argument_values);
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ if (m_get_item_info_function == NULL)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_queue_item_get_info");
+ return return_value;
+ }
+
+
+ ExecutionResults func_call_ret;
+ Value results;
+ func_call_ret = m_get_item_info_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExecutionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call __introspection_dispatch_queue_item_get_info(), got ExecutionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call __introspection_dispatch_queue_get_item_info() for list of queues");
+ return return_value;
+ }
+
+ return_value.item_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_item_info_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.item_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.item_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_item_info_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return return_value;
+}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h
new file mode 100644
index 00000000000..96bcc6e65b4
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h
@@ -0,0 +1,118 @@
+//===-- AppleGetItemInfoHandler.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_AppleGetItemInfoHandler_h_
+#define lldb_AppleGetItemInfoHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+// This class will insert a ClangUtilityFunction into the inferior process for
+// calling libBacktraceRecording's __introspection_dispatch_queue_item_get_info()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_item_info_return_values
+// {
+// introspection_dispatch_item_info_ref *item_buffer;
+// uint64_t item_buffer_size;
+// };
+//
+// The item_buffer pointer is an address in the inferior program's address
+// space (item_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb.
+//
+// The AppleGetItemInfoHandler object should persist so that the ClangUtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetItemInfoHandler {
+public:
+
+ AppleGetItemInfoHandler (lldb_private::Process *process);
+
+ ~AppleGetItemInfoHandler();
+
+ struct GetItemInfoReturnInfo
+ {
+ lldb::addr_t item_buffer_ptr; /* the address of the item buffer from libBacktraceRecording */
+ lldb::addr_t item_buffer_size; /* the size of the item buffer from libBacktraceRecording */
+
+ GetItemInfoReturnInfo() :
+ item_buffer_ptr(LLDB_INVALID_ADDRESS),
+ item_buffer_size(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the information about a work item by calling
+ /// __introspection_dispatch_queue_item_get_info. If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] item
+ /// The introspection_dispatch_item_info_ref value for the item of interest.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the item_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetItemInfoReturnInfo
+ GetItemInfo (Thread &thread, lldb::addr_t item, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetItemInfoFunction (Thread &thread, ValueList &get_item_info_arglist);
+
+ static const char *g_get_item_info_function_name;
+ static const char *g_get_item_info_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<ClangFunction> m_get_item_info_function;
+ std::unique_ptr<ClangUtilityFunction> m_get_item_info_impl_code;
+ Mutex m_get_item_info_function_mutex;
+
+ lldb::addr_t m_get_item_info_return_buffer_addr;
+ Mutex m_get_item_info_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetItemInfoHandler_h_
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
new file mode 100644
index 00000000000..45be3439d2a
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
@@ -0,0 +1,402 @@
+//===-- AppleGetPendingItemsHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetPendingItemsHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetPendingItemsHandler::g_get_pending_items_function_name = "__lldb_backtrace_recording_get_pending_items";
+const char *AppleGetPendingItemsHandler::g_get_pending_items_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *dispatch_queue_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ typedef void *introspection_dispatch_item_info_ref; \n\
+ \n\
+ extern uint64_t __introspection_dispatch_queue_get_pending_items (dispatch_queue_t queue, \n\
+ introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ extern int printf(const char *format, ...); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_pending_items_return_values \n\
+ { \n\
+ uint64_t pending_items_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
+ uint64_t pending_items_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
+ uint64_t count; /* the number of items included in the queues buffer */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_pending_items \n\
+ (struct get_pending_items_return_values *return_buffer, \n\
+ int debug, \n\
+ uint64_t /* dispatch_queue_t */ queue, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ if (debug) \n\
+ 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\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ return_buffer->count = __introspection_dispatch_queue_get_pending_items ( \n\
+ (void*) queue, \n\
+ (void**)&return_buffer->pending_items_buffer_ptr, \n\
+ &return_buffer->pending_items_buffer_size); \n\
+ if (debug) \n\
+ printf(\"result was count %lld\\n\", return_buffer->count); \n\
+} \n\
+} \n\
+";
+
+AppleGetPendingItemsHandler::AppleGetPendingItemsHandler (Process *process) :
+ m_process (process),
+ m_get_pending_items_function (),
+ m_get_pending_items_impl_code (),
+ m_get_pending_items_function_mutex(),
+ m_get_pending_items_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_pending_items_retbuffer_mutex()
+{
+}
+
+AppleGetPendingItemsHandler::~AppleGetPendingItemsHandler ()
+{
+}
+
+void
+AppleGetPendingItemsHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_pending_items_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_pending_items_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_pending_items_return_buffer_addr);
+ }
+}
+
+// Compile our __lldb_backtrace_recording_get_pending_items() function (from the
+// source above in g_get_pending_items_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_pending_items into the inferior process if needed.
+//
+// Write the get_pending_items_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetPendingItemsHandler::SetupGetPendingItemsFunction (Thread &thread, ValueList &get_pending_items_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Address impl_code_address;
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_pending_items_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target.
+ // This is useful for debugging additions to the get_impl function 'cause you don't have
+ // to bother with string-ifying the code into g_get_pending_items_function_code.
+
+ if (USE_BUILTIN_FUNCTION)
+ {
+ ConstString our_utility_function_name("__lldb_backtrace_recording_get_pending_items");
+ SymbolContextList sc_list;
+
+ exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list);
+ if (sc_list.GetSize() == 1)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(0, sc);
+ if (sc.symbol != NULL)
+ impl_code_address = sc.symbol->GetAddress();
+
+ //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr());
+ //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr);
+ }
+ else
+ {
+ //printf ("Could not find queues introspection function address.\n");
+ return args_addr;
+ }
+ }
+ else if (!m_get_pending_items_impl_code.get())
+ {
+ if (g_get_pending_items_function_code != NULL)
+ {
+ m_get_pending_items_impl_code.reset (new ClangUtilityFunction (g_get_pending_items_function_code,
+ g_get_pending_items_function_name));
+ if (!m_get_pending_items_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install pending-items introspection: %s.", errors.GetData());
+ m_get_pending_items_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No pending-items introspection code found.");
+ errors.Printf ("No pending-items introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_pending_items_impl_code->StartAddress());
+ }
+ else
+ {
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_pending_items_impl_code->StartAddress());
+ }
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_pending_items_function.get())
+ {
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ ClangASTType get_pending_items_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ m_get_pending_items_function.reset(new ClangFunction (thread,
+ get_pending_items_return_type,
+ impl_code_address,
+ get_pending_items_arglist));
+
+ errors.Clear();
+ unsigned num_errors = m_get_pending_items_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling pending-items function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ errors.Clear();
+ if (!m_get_pending_items_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting pending-items function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!m_get_pending_items_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_pending_items_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing pending-items function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetPendingItemsHandler::GetPendingItemsReturnInfo
+AppleGetPendingItemsHandler::GetPendingItems (Thread &thread, addr_t queue, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetPendingItemsReturnInfo return_value;
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.items_buffer_size = 0;
+ return_value.count = 0;
+
+ error.Clear();
+
+ // Set up the arguments for a call to
+
+ // struct get_pending_items_return_values
+ // {
+ // uint64_t pending_items_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */
+ // uint64_t pending_items_buffer_size; /* the size of the items buffer from libBacktraceRecording */
+ // uint64_t count; /* the number of items included in the queues buffer */
+ // };
+ //
+ // void __lldb_backtrace_recording_get_pending_items
+ // (struct get_pending_items_return_values *return_buffer,
+ // int debug,
+ // uint64_t /* dispatch_queue_t */ queue
+ // void *page_to_free,
+ // uint64_t page_to_free_size)
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetClangType (clang_void_ptr_type);
+
+ ClangASTType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetClangType (clang_int_type);
+
+ ClangASTType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value queue_value;
+ queue_value.SetValueType (Value::eValueTypeScalar);
+ queue_value.SetClangType (clang_uint64_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetClangType (clang_void_ptr_type);
+
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetClangType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_pending_items_retbuffer_mutex);
+ if (m_get_pending_items_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_pending_items_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_pending_items_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ queue_value.GetScalar() = queue;
+ argument_values.PushValue (queue_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetPendingItemsFunction (thread, argument_values);
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ if (m_get_pending_items_function == NULL)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_queue_get_pending_items");
+ }
+
+
+ ExecutionResults func_call_ret;
+ Value results;
+ func_call_ret = m_get_pending_items_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExecutionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call __introspection_dispatch_queue_get_pending_items(), got ExecutionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call __introspection_dispatch_queue_get_pending_items() for list of queues");
+ return return_value;
+ }
+
+ return_value.items_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_pending_items_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.items_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.items_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_pending_items_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.count = m_process->ReadUnsignedIntegerFromMemory (m_get_pending_items_return_buffer_addr + 16, 8, 0, error);
+ if (!error.Success())
+ {
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return return_value;
+}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h
new file mode 100644
index 00000000000..b8188282e67
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h
@@ -0,0 +1,121 @@
+//===-- AppleGetPendingItemsHandler.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_AppleGetPendingItemsHandler_h_
+#define lldb_AppleGetPendingItemsHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+// This class will insert a ClangUtilityFunction into the inferior process for
+// calling libBacktraceRecording's __introspection_dispatch_queue_get_pending_items()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_pending_items_return_values
+// {
+// introspection_dispatch_item_info_ref *items_buffer;
+// uint64_t items_buffer_size;
+// uint64_t count;
+// };
+//
+// The items_buffer pointer is an address in the inferior program's address
+// space (items_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb. count is the number of items that were stored in the buffer.
+//
+// The AppleGetPendingItemsHandler object should persist so that the ClangUtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetPendingItemsHandler {
+public:
+
+ AppleGetPendingItemsHandler (lldb_private::Process *process);
+
+ ~AppleGetPendingItemsHandler();
+
+ struct GetPendingItemsReturnInfo
+ {
+ lldb::addr_t items_buffer_ptr; /* the address of the pending items buffer from libBacktraceRecording */
+ lldb::addr_t items_buffer_size; /* the size of the pending items buffer from libBacktraceRecording */
+ uint64_t count; /* the number of pending items included in the buffer */
+
+ GetPendingItemsReturnInfo () :
+ items_buffer_ptr(LLDB_INVALID_ADDRESS),
+ items_buffer_size(0),
+ count(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the list of pending items for a given queue via a call to
+ /// __introspection_dispatch_queue_get_pending_items. If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] queue
+ /// The dispatch_queue_t value for the queue of interest.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the items_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetPendingItemsReturnInfo
+ GetPendingItems (Thread &thread, lldb::addr_t queue, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetPendingItemsFunction (Thread &thread, ValueList &get_pending_items_arglist);
+
+ static const char *g_get_pending_items_function_name;
+ static const char *g_get_pending_items_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<ClangFunction> m_get_pending_items_function;
+ std::unique_ptr<ClangUtilityFunction> m_get_pending_items_impl_code;
+ Mutex m_get_pending_items_function_mutex;
+
+ lldb::addr_t m_get_pending_items_return_buffer_addr;
+ Mutex m_get_pending_items_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetPendingItemsHandler_h_
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
new file mode 100644
index 00000000000..3cf110f0b6c
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
@@ -0,0 +1,401 @@
+//===-- AppleGetQueuesHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetQueuesHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "AppleThreadPlanStepThroughObjCTrampoline.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetQueuesHandler::g_get_current_queues_function_name = "__lldb_backtrace_recording_get_current_queues";
+const char *AppleGetQueuesHandler::g_get_current_queues_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ \n\
+ extern uint64_t __introspection_dispatch_get_queues (queue_list_scope_t scope, \n\
+ introspection_dispatch_queue_info_t *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ extern int printf(const char *format, ...); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_current_queues_return_values \n\
+ { \n\
+ uint64_t queues_buffer_ptr; /* the address of the queues buffer from libBacktraceRecording */ \n\
+ uint64_t queues_buffer_size; /* the size of the queues buffer from libBacktraceRecording */ \n\
+ uint64_t count; /* the number of queues included in the queues buffer */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_current_queues \n\
+ (struct get_current_queues_return_values *return_buffer, \n\
+ int debug, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ if (debug) \n\
+ printf (\"entering get_current_queues with args %p, %d, 0x%p, 0x%llx\\n\", return_buffer, debug, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ return_buffer->count = __introspection_dispatch_get_queues ( \n\
+ /* QUEUES_WITH_ANY_ITEMS */ 2, \n\
+ (void**)&return_buffer->queues_buffer_ptr, \n\
+ &return_buffer->queues_buffer_size); \n\
+ if (debug) \n\
+ printf(\"result was count %lld\\n\", return_buffer->count); \n\
+} \n\
+} \n\
+";
+
+AppleGetQueuesHandler::AppleGetQueuesHandler (Process *process) :
+ m_process (process),
+ m_get_queues_function (),
+ m_get_queues_impl_code (),
+ m_get_queues_function_mutex(),
+ m_get_queues_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_queues_retbuffer_mutex()
+{
+}
+
+AppleGetQueuesHandler::~AppleGetQueuesHandler ()
+{
+}
+
+void
+AppleGetQueuesHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_queues_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_queues_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_queues_return_buffer_addr);
+ }
+}
+
+// Construct a ClangASTType for the structure that g_get_current_queues_function_code will return by value
+// so we can extract the fields after performing the function call.
+// i.e. we are getting this struct returned to us:
+//
+// struct get_current_queues_return_values
+// {
+// introspection_dispatch_queue_info_t *queues_buffer;
+// uint64_t queues_buffer_size;
+// uint64_t count;
+// };
+
+
+// Compile our __lldb_backtrace_recording_get_current_queues() function (from the
+// source above in g_get_current_queues_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_current_queues into the inferior process if needed.
+//
+// Write the get_queues_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetQueuesHandler::SetupGetQueuesFunction (Thread &thread, ValueList &get_queues_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Address impl_code_address;
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_queues_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target.
+ // This is useful for debugging additions to the get_impl function 'cause you don't have
+ // to bother with string-ifying the code into g_get_current_queues_function_code.
+
+ if (USE_BUILTIN_FUNCTION)
+ {
+ ConstString our_utility_function_name("__lldb_backtrace_recording_get_current_queues");
+ SymbolContextList sc_list;
+
+ exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list);
+ if (sc_list.GetSize() == 1)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(0, sc);
+ if (sc.symbol != NULL)
+ impl_code_address = sc.symbol->GetAddress();
+
+ //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr());
+ //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr);
+ }
+ else
+ {
+ //printf ("Could not find queues introspection function address.\n");
+ return args_addr;
+ }
+ }
+ else if (!m_get_queues_impl_code.get())
+ {
+ if (g_get_current_queues_function_code != NULL)
+ {
+ m_get_queues_impl_code.reset (new ClangUtilityFunction (g_get_current_queues_function_code,
+ g_get_current_queues_function_name));
+ if (!m_get_queues_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install queues introspection: %s.", errors.GetData());
+ m_get_queues_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No queues introspection code found.");
+ errors.Printf ("No queues introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_queues_impl_code->StartAddress());
+ }
+ else
+ {
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_queues_impl_code->StartAddress());
+ }
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_queues_function.get())
+ {
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ ClangASTType get_queues_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ m_get_queues_function.reset(new ClangFunction (thread,
+ get_queues_return_type,
+ impl_code_address,
+ get_queues_arglist));
+
+ errors.Clear();
+ unsigned num_errors = m_get_queues_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling get-queues function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ errors.Clear();
+ if (!m_get_queues_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting get-queues function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!m_get_queues_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_queues_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing get-queues function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetQueuesHandler::GetQueuesReturnInfo
+AppleGetQueuesHandler::GetCurrentQueues (Thread &thread, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetQueuesReturnInfo return_value;
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.queues_buffer_size = 0;
+ return_value.count = 0;
+
+ error.Clear();
+
+ // Set up the arguments for a call to
+
+ // struct get_current_queues_return_values
+ // {
+ // uint64_t queues_buffer_ptr; /* the address of the queues buffer from libBacktraceRecording */
+ // uint64_t queues_buffer_size; /* the size of the queues buffer from libBacktraceRecording */
+ // uint64_t count; /* the number of queues included in the queues buffer */
+ // };
+ //
+ // void
+ // __lldb_backtrace_recording_get_current_queues
+ // (struct get_current_queues_return_values *return_buffer,
+ // void *page_to_free,
+ // uint64_t page_to_free_size);
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetClangType (clang_void_ptr_type);
+
+ ClangASTType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetClangType (clang_int_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetClangType (clang_void_ptr_type);
+
+ ClangASTType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetClangType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_queues_retbuffer_mutex);
+ if (m_get_queues_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_queues_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_queues_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetQueuesFunction (thread, argument_values);
+
+ if (m_get_queues_function == NULL)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_get_queues");
+ }
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ ExecutionResults func_call_ret;
+ Value results;
+ func_call_ret = m_get_queues_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExecutionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call introspection_get_dispatch_queues(), got ExecutionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call introspection_get_dispatch_queues() for list of queues");
+ return return_value;
+ }
+
+ return_value.queues_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_queues_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.queues_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.queues_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_queues_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.count = m_process->ReadUnsignedIntegerFromMemory (m_get_queues_return_buffer_addr + 16, 8, 0, error);
+ if (!error.Success())
+ {
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return return_value;
+}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h
new file mode 100644
index 00000000000..75b43dfb233
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h
@@ -0,0 +1,118 @@
+//===-- AppleGetQueuesHandler.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_AppleGetQueuesHandler_h_
+#define lldb_AppleGetQueuesHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+// This class will insert a ClangUtilityFunction into the inferior process for
+// calling libBacktraceRecording's introspection_get_dispatch_queues()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_current_queues_return_values
+// {
+// introspection_dispatch_queue_info_t *queues_buffer;
+// uint64_t queues_buffer_size;
+// uint64_t count;
+// };
+//
+// The queues_buffer pointer is an address in the inferior program's address
+// space (queues_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb. count is the number of queues that were stored in the buffer.
+//
+// The AppleGetQueuesHandler object should persist so that the ClangUtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetQueuesHandler {
+public:
+
+ AppleGetQueuesHandler (lldb_private::Process *process);
+
+ ~AppleGetQueuesHandler();
+
+ struct GetQueuesReturnInfo
+ {
+ lldb::addr_t queues_buffer_ptr; /* the address of the queues buffer from libBacktraceRecording */
+ lldb::addr_t queues_buffer_size; /* the size of the queues buffer from libBacktraceRecording */
+ uint64_t count; /* the number of queues included in the queues buffer */
+
+ GetQueuesReturnInfo() :
+ queues_buffer_ptr(LLDB_INVALID_ADDRESS),
+ queues_buffer_size(0),
+ count(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the list of queues that exist (with any active or pending items) via
+ /// a call to introspection_get_dispatch_queues(). If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the queues_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetQueuesReturnInfo
+ GetCurrentQueues (Thread &thread, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetQueuesFunction (Thread &thread, ValueList &get_queues_arglist);
+
+ static const char *g_get_current_queues_function_name;
+ static const char *g_get_current_queues_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<ClangFunction> m_get_queues_function;
+ std::unique_ptr<ClangUtilityFunction> m_get_queues_impl_code;
+ Mutex m_get_queues_function_mutex;
+
+ lldb::addr_t m_get_queues_return_buffer_addr;
+ Mutex m_get_queues_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetQueuesHandler_h_
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
new file mode 100644
index 00000000000..7151f12598c
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
@@ -0,0 +1,385 @@
+//===-- AppleGetThreadItemInfoHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetThreadItemInfoHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetThreadItemInfoHandler::g_get_thread_item_info_function_name = "__lldb_backtrace_recording_get_thread_item_info";
+const char *AppleGetThreadItemInfoHandler::g_get_thread_item_info_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ typedef void *pthread_t; \n\
+ extern int printf(const char *format, ...); \n\
+ extern pthread_t pthread_self(void); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *dispatch_queue_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ typedef void *introspection_dispatch_item_info_ref; \n\
+ \n\
+ extern void __introspection_dispatch_thread_get_item_info (pthread_t thread, \n\
+ introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_thread_item_info_return_values \n\
+ { \n\
+ uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
+ uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_thread_item_info \n\
+ (struct get_thread_item_info_return_values *return_buffer, \n\
+ int debug, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ void *pthread_id = pthread_self (); \n\
+ if (debug) \n\
+ printf (\"entering get_thread_item_info with args return_buffer == %p, debug == %d, pthread id == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, (uint64_t) pthread_id, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ __introspection_dispatch_thread_get_item_info (pthread_id, \n\
+ (void**)&return_buffer->item_info_buffer_ptr, \n\
+ &return_buffer->item_info_buffer_size); \n\
+} \n\
+} \n\
+";
+
+AppleGetThreadItemInfoHandler::AppleGetThreadItemInfoHandler (Process *process) :
+ m_process (process),
+ m_get_thread_item_info_function (),
+ m_get_thread_item_info_impl_code (),
+ m_get_thread_item_info_function_mutex(),
+ m_get_thread_item_info_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_thread_item_info_retbuffer_mutex()
+{
+}
+
+AppleGetThreadItemInfoHandler::~AppleGetThreadItemInfoHandler ()
+{
+}
+
+void
+AppleGetThreadItemInfoHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_thread_item_info_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_thread_item_info_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_thread_item_info_return_buffer_addr);
+ }
+}
+
+// Compile our __lldb_backtrace_recording_get_thread_item_info() function (from the
+// source above in g_get_thread_item_info_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_thread_item_info into the inferior process if needed.
+//
+// Write the get_thread_item_info_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction (Thread &thread, ValueList &get_thread_item_info_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Address impl_code_address;
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_thread_item_info_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target.
+ // This is useful for debugging additions to the get_impl function 'cause you don't have
+ // to bother with string-ifying the code into g_get_thread_item_info_function_code.
+
+ if (USE_BUILTIN_FUNCTION)
+ {
+ ConstString our_utility_function_name("__lldb_backtrace_recording_get_thread_item_info");
+ SymbolContextList sc_list;
+
+ exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list);
+ if (sc_list.GetSize() == 1)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(0, sc);
+ if (sc.symbol != NULL)
+ impl_code_address = sc.symbol->GetAddress();
+
+ //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr());
+ //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr);
+ }
+ else
+ {
+ //printf ("Could not find queues introspection function address.\n");
+ return args_addr;
+ }
+ }
+ else if (!m_get_thread_item_info_impl_code.get())
+ {
+ if (g_get_thread_item_info_function_code != NULL)
+ {
+ m_get_thread_item_info_impl_code.reset (new ClangUtilityFunction (g_get_thread_item_info_function_code,
+ g_get_thread_item_info_function_name));
+ if (!m_get_thread_item_info_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install get-thread-item-info introspection: %s.", errors.GetData());
+ m_get_thread_item_info_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No get-thread-item-info introspection code found.");
+ errors.Printf ("No get-thread-item-info introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_thread_item_info_impl_code->StartAddress());
+ }
+ else
+ {
+ impl_code_address.Clear();
+ impl_code_address.SetOffset(m_get_thread_item_info_impl_code->StartAddress());
+ }
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_thread_item_info_function.get())
+ {
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ ClangASTType get_thread_item_info_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ m_get_thread_item_info_function.reset(new ClangFunction (thread,
+ get_thread_item_info_return_type,
+ impl_code_address,
+ get_thread_item_info_arglist));
+
+ errors.Clear();
+ unsigned num_errors = m_get_thread_item_info_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling get-thread-item-info function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ errors.Clear();
+ if (!m_get_thread_item_info_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting get-thread-item-info function: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!m_get_thread_item_info_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_thread_item_info_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing get-thread-item-info function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo
+AppleGetThreadItemInfoHandler::GetThreadItemInfo (Thread &thread, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetThreadItemInfoReturnInfo return_value;
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.item_buffer_size = 0;
+
+ error.Clear();
+
+ // Set up the arguments for a call to
+
+ // struct get_thread_item_info_return_values
+ // {
+ // uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */
+ // uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */
+ // };
+ //
+ // void __lldb_backtrace_recording_get_thread_item_info
+ // (struct get_thread_item_info_return_values *return_buffer,
+ // int debug,
+ // void *page_to_free,
+ // uint64_t page_to_free_size)
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetClangType (clang_void_ptr_type);
+
+ ClangASTType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetClangType (clang_int_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetClangType (clang_void_ptr_type);
+
+ ClangASTType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetClangType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_thread_item_info_retbuffer_mutex);
+ if (m_get_thread_item_info_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_thread_item_info_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_thread_item_info_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetThreadItemInfoFunction (thread, argument_values);
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ if (m_get_thread_item_info_function == NULL)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_thread_get_item_info");
+ return return_value;
+ }
+
+
+ ExecutionResults func_call_ret;
+ Value results;
+ func_call_ret = m_get_thread_item_info_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExecutionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call __introspection_dispatch_thread_get_item_info(), got ExecutionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call __introspection_dispatch_thread_get_item_info() for list of queues");
+ return return_value;
+ }
+
+ return_value.item_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_thread_item_info_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.item_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.item_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_thread_item_info_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return return_value;
+}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h
new file mode 100644
index 00000000000..a7fb9c73949
--- /dev/null
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h
@@ -0,0 +1,115 @@
+//===-- AppleGetThreadItemInfoHandler.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_AppleGetThreadItemInfoHandler_h_
+#define lldb_AppleGetThreadItemInfoHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+// This class will insert a ClangUtilityFunction into the inferior process for
+// calling libBacktraceRecording's __introspection_dispatch_thread_get_item_info()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_thread_item_info_return_values
+// {
+// introspection_dispatch_item_info_ref *item_buffer;
+// uint64_t item_buffer_size;
+// };
+//
+// The item_buffer pointer is an address in the inferior program's address
+// space (item_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb.
+//
+// The AppleGetThreadItemInfoHandler object should persist so that the ClangUtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetThreadItemInfoHandler {
+public:
+
+ AppleGetThreadItemInfoHandler (lldb_private::Process *process);
+
+ ~AppleGetThreadItemInfoHandler();
+
+ struct GetThreadItemInfoReturnInfo
+ {
+ lldb::addr_t item_buffer_ptr; /* the address of the item buffer from libBacktraceRecording */
+ lldb::addr_t item_buffer_size; /* the size of the item buffer from libBacktraceRecording */
+
+ GetThreadItemInfoReturnInfo() :
+ item_buffer_ptr(LLDB_INVALID_ADDRESS),
+ item_buffer_size(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the information about a work item by calling
+ /// __introspection_dispatch_thread_get_item_info. If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the item_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetThreadItemInfoReturnInfo
+ GetThreadItemInfo (Thread &thread, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetThreadItemInfoFunction (Thread &thread, ValueList &get_thread_item_info_arglist);
+
+ static const char *g_get_thread_item_info_function_name;
+ static const char *g_get_thread_item_info_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<ClangFunction> m_get_thread_item_info_function;
+ std::unique_ptr<ClangUtilityFunction> m_get_thread_item_info_impl_code;
+ Mutex m_get_thread_item_info_function_mutex;
+
+ lldb::addr_t m_get_thread_item_info_return_buffer_addr;
+ Mutex m_get_thread_item_info_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetThreadItemInfoHandler_h_
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt
index 4fc1356f70f..e450ff42ace 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt
@@ -1,5 +1,9 @@
set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginSystemRuntimeMacOSX
+ AppleGetItemInfoHandler.cpp
+ AppleGetPendingItemsHandler.cpp
+ AppleGetQueuesHandler.cpp
+ AppleGetThreadItemInfoHandler.cpp
SystemRuntimeMacOSX.cpp
)
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
index 5756e7071d7..fd705077566 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
@@ -26,6 +26,8 @@
#include "lldb/Target/QueueList.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+
#include "SystemRuntimeMacOSX.h"
@@ -82,9 +84,17 @@ SystemRuntimeMacOSX::CreateInstance (Process* process)
SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) :
SystemRuntime(process),
m_break_id(LLDB_INVALID_BREAK_ID),
- m_mutex(Mutex::eMutexTypeRecursive)
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_get_queues_handler(process),
+ m_get_pending_items_handler(process),
+ m_get_item_info_handler(process),
+ m_get_thread_item_info_handler(process),
+ m_page_to_free(LLDB_INVALID_ADDRESS),
+ m_page_to_free_size(0),
+ m_lib_backtrace_recording_info(),
+ m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_libdispatch_offsets()
{
- m_ldi_header.initialized = 0;
}
//----------------------------------------------------------------------
@@ -95,6 +105,15 @@ SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
Clear (true);
}
+void
+SystemRuntimeMacOSX::Detach ()
+{
+ m_get_queues_handler.Detach();
+ m_get_pending_items_handler.Detach();
+ m_get_item_info_handler.Detach();
+ m_get_thread_item_info_handler.Detach();
+}
+
//----------------------------------------------------------------------
// Clear out the state of this class.
//----------------------------------------------------------------------
@@ -109,213 +128,336 @@ SystemRuntimeMacOSX::Clear (bool clear_process)
if (clear_process)
m_process = NULL;
m_break_id = LLDB_INVALID_BREAK_ID;
- m_ldi_header.initialized = 0;
}
-void
-SystemRuntimeMacOSX::DidAttach ()
+std::string
+SystemRuntimeMacOSX::GetQueueNameFromThreadQAddress (addr_t dispatch_qaddr)
{
-}
+ std::string dispatch_queue_name;
+ if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
+ return "";
-void
-SystemRuntimeMacOSX::DidLaunch ()
-{
+ ReadLibdispatchOffsets ();
+ if (m_libdispatch_offsets.IsValid ())
+ {
+ // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
+ // deref it to get the address of the dispatch_queue_t structure for this thread's
+ // queue.
+ Error error;
+ addr_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
+ if (error.Success())
+ {
+ if (m_libdispatch_offsets.dqo_version >= 4)
+ {
+ // libdispatch versions 4+, pointer to dispatch name is in the
+ // queue structure.
+ addr_t pointer_to_label_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
+ addr_t label_addr = m_process->ReadPointerFromMemory (pointer_to_label_address, error);
+ if (error.Success())
+ {
+ m_process->ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
+ }
+ }
+ else
+ {
+ // libdispatch versions 1-3, dispatch name is a fixed width char array
+ // in the queue structure.
+ addr_t label_addr = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
+ dispatch_queue_name.resize (m_libdispatch_offsets.dqo_label_size, '\0');
+ size_t bytes_read = m_process->ReadMemory (label_addr, &dispatch_queue_name[0], m_libdispatch_offsets.dqo_label_size, error);
+ if (bytes_read < m_libdispatch_offsets.dqo_label_size)
+ dispatch_queue_name.erase (bytes_read);
+ }
+ }
+ }
+ return dispatch_queue_name;
}
-void
-SystemRuntimeMacOSX::ModulesDidLoad (ModuleList &module_list)
+lldb::queue_id_t
+SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr)
{
-}
+ queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
-bool
-SystemRuntimeMacOSX::LdiHeadersInitialized ()
-{
- ParseLdiHeaders();
- return m_ldi_header.initialized;
-}
+ if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
+ return queue_id;
-void
-SystemRuntimeMacOSX::ParseLdiHeaders ()
-{
- if (m_ldi_header.initialized)
- return;
- static ConstString ldi_header_symbol ("ldi_infos");
- SymbolContextList sc_list;
- if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (ldi_header_symbol, eSymbolTypeData, sc_list) > 0)
+ ReadLibdispatchOffsets ();
+ if (m_libdispatch_offsets.IsValid ())
{
- SymbolContext sc;
- sc_list.GetContextAtIndex (0, sc);
- AddressRange addr_range;
- sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
-
+ // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
+ // deref it to get the address of the dispatch_queue_t structure for this thread's
+ // queue.
Error error;
- Address ldi_header_addr = addr_range.GetBaseAddress();
- uint8_t version_buf[6]; // version, ldi_header_size, initialized fields
- DataExtractor data (version_buf, sizeof(version_buf), m_process->GetByteOrder(), m_process->GetAddressByteSize());
- const size_t count = sizeof (version_buf);
- const bool prefer_file_cache = false;
- if (m_process->GetTarget().ReadMemory (ldi_header_addr, prefer_file_cache, version_buf, count, error) == sizeof (version_buf))
+ uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
+ if (error.Success())
{
- int version, initialized, ldi_header_size;
- offset_t offset = 0;
- version = data.GetU16(&offset);
- ldi_header_size = data.GetU16(&offset);
- initialized = data.GetU16(&offset);
- if (initialized)
+ addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum;
+ queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory (serialnum_address, m_libdispatch_offsets.dqo_serialnum_size, LLDB_INVALID_QUEUE_ID, error);
+ if (error.Success())
{
- DataBufferHeap ldi_header (ldi_header_size, 0);
- DataExtractor ldi_extractor (ldi_header.GetBytes(), ldi_header.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
- if (m_process->GetTarget().ReadMemory (ldi_header_addr, prefer_file_cache, ldi_header.GetBytes(), ldi_header.GetByteSize(), error) == ldi_header.GetByteSize())
- {
- offset = 0;
- m_ldi_header.version = ldi_extractor.GetU16(&offset);
- m_ldi_header.ldi_header_size = ldi_extractor.GetU16(&offset);
- m_ldi_header.initialized = ldi_extractor.GetU16(&offset);
- m_ldi_header.queue_size = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_size = ldi_extractor.GetU16(&offset);
-
- // 6 bytes of padding here
- offset += 6;
-
- m_ldi_header.queues_head_ptr_address = ldi_extractor.GetU64(&offset);
- m_ldi_header.items_head_ptr_address = ldi_extractor.GetU64(&offset);
-
- m_ldi_header.queue_offsets.next = ldi_extractor.GetU16(&offset);
- m_ldi_header.queue_offsets.prev = ldi_extractor.GetU16(&offset);
- m_ldi_header.queue_offsets.queue_id = ldi_extractor.GetU16(&offset);
- m_ldi_header.queue_offsets.current_item_ptr = ldi_extractor.GetU16(&offset);
-
- m_ldi_header.item_offsets.next = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.prev = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.type = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.identifier = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.stop_id = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.backtrace_length = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.backtrace_ptr = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.thread_name_ptr = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.queue_name_ptr = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.unique_thread_id = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.pthread_id = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.enqueueing_thread_dispatch_queue_t = ldi_extractor.GetU16(&offset);
- m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr = ldi_extractor.GetU16(&offset);
-
- if (ldi_header.GetByteSize () > offset)
- {
- m_ldi_header.item_offsets.queue_id_from_thread_info = ldi_extractor.GetU16(&offset);
- }
- else
- {
- m_ldi_header.item_offsets.queue_id_from_thread_info = 0xffff;
- }
- }
+ queue_id = serialnum;
}
}
}
+
+ return queue_id;
}
-lldb::addr_t
-SystemRuntimeMacOSX::GetQueuesHead ()
+
+void
+SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress ()
{
- if (!LdiHeadersInitialized())
- return LLDB_INVALID_ADDRESS;
+ if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS)
+ return;
- Error error;
- addr_t queues_head = m_process->ReadPointerFromMemory (m_ldi_header.queues_head_ptr_address, error);
- if (error.Success() == false || queues_head == LLDB_INVALID_ADDRESS || queues_head == 0)
- return LLDB_INVALID_ADDRESS;
+ static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
+ const Symbol *dispatch_queue_offsets_symbol = NULL;
- return queues_head;
+ // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
+ ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
+ ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+
+ // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
+ if (dispatch_queue_offsets_symbol == NULL)
+ {
+ ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
+ module_sp = m_process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+ }
+ if (dispatch_queue_offsets_symbol)
+ m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget());
}
-lldb::addr_t
-SystemRuntimeMacOSX::GetItemsHead ()
+void
+SystemRuntimeMacOSX::ReadLibdispatchOffsets ()
{
- if (!LdiHeadersInitialized())
- return LLDB_INVALID_ADDRESS;
+ if (m_libdispatch_offsets.IsValid())
+ return;
+
+ ReadLibdispatchOffsetsAddress ();
+
+ uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)];
+ DataExtractor data (memory_buffer,
+ sizeof(memory_buffer),
+ m_process->GetByteOrder(),
+ m_process->GetAddressByteSize());
Error error;
- addr_t items_head = m_process->ReadPointerFromMemory (m_ldi_header.items_head_ptr_address, error);
- if (error.Success() == false || items_head == LLDB_INVALID_ADDRESS || items_head == 0)
- return LLDB_INVALID_ADDRESS;
+ if (m_process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
+ {
+ lldb::offset_t data_offset = 0;
- return items_head;
+ // The struct LibdispatchOffsets is a series of uint16_t's - extract them all
+ // in one big go.
+ data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t));
+ }
}
-addr_t
-SystemRuntimeMacOSX::GetThreadCreatorItem (ThreadSP thread_sp)
+
+ThreadSP
+SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type)
{
- addr_t enqueued_item_ptr = thread_sp->GetExtendedBacktraceToken();
- if (enqueued_item_ptr == LLDB_INVALID_ADDRESS)
+ ThreadSP originating_thread_sp;
+ if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch"))
{
- if (thread_sp->GetQueueID() == LLDB_INVALID_QUEUE_ID || thread_sp->GetQueueID() == 0)
- return LLDB_INVALID_ADDRESS;
-
Error error;
- uint64_t this_thread_queue_id = thread_sp->GetQueueID();
-
- addr_t queues_head = GetQueuesHead();
- if (queues_head == LLDB_INVALID_ADDRESS)
- return LLDB_INVALID_ADDRESS;
-
- // Step through the queues_head linked list looking for a queue matching this thread, if any
- uint64_t queue_obj_ptr = queues_head;
- enqueued_item_ptr = LLDB_INVALID_ADDRESS;
-
- while (queue_obj_ptr != 0)
+
+ // real_thread is either an actual, live thread (in which case we need to call into
+ // libBacktraceRecording to find its originator) or it is an extended backtrace itself,
+ // in which case we get the token from it and call into libBacktraceRecording to find
+ // the originator of that token.
+
+ if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS)
+ {
+ originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken());
+ }
+ else
{
- uint64_t queue_id = m_process->ReadUnsignedIntegerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.queue_id, 8, LLDB_INVALID_ADDRESS, error);
- if (error.Success() && queue_id != LLDB_INVALID_ADDRESS)
+ AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = m_get_thread_item_info_handler.GetThreadItemInfo (*real_thread.get(), m_page_to_free, m_page_to_free_size, error);
+ if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
{
- if (queue_id == this_thread_queue_id)
+ DataBufferHeap data (ret.item_buffer_size, 0);
+ if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
{
- enqueued_item_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.current_item_ptr, error);
- break;
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ ItemInfo item = ExtractItemInfoFromBuffer (extractor);
+ bool stop_id_is_valid = true;
+ if (item.stop_id == 0)
+ stop_id_is_valid = false;
+ originating_thread_sp.reset (new HistoryThread (*m_process,
+ item.enqueuing_thread_id,
+ item.enqueuing_callstack,
+ item.stop_id,
+ stop_id_is_valid));
+ originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
+ originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
+ originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
+// originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
}
}
- queue_obj_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.next, error);
- if (error.Success() == false || queue_obj_ptr == LLDB_INVALID_ADDRESS)
- {
- break;
- }
}
}
-
- return enqueued_item_ptr;
+ return originating_thread_sp;
}
-SystemRuntimeMacOSX::ArchivedBacktrace
-SystemRuntimeMacOSX::GetLibdispatchExtendedBacktrace (ThreadSP thread_sp)
+ThreadSP
+SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref)
{
- ArchivedBacktrace bt;
- bt.stop_id = 0;
- bt.stop_id_is_valid = false;
- bt.libdispatch_queue_id = LLDB_INVALID_QUEUE_ID;
-
- addr_t enqueued_item_ptr = GetThreadCreatorItem (thread_sp);
-
- if (enqueued_item_ptr == LLDB_INVALID_ADDRESS)
- return bt;
+ ThreadSP return_thread_sp;
+ AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
Error error;
- uint32_t ptr_size = m_process->GetTarget().GetArchitecture().GetAddressByteSize();
+ ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
+ if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
+ {
+ DataBufferHeap data (ret.item_buffer_size, 0);
+ if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ ItemInfo item = ExtractItemInfoFromBuffer (extractor);
+ bool stop_id_is_valid = true;
+ if (item.stop_id == 0)
+ stop_id_is_valid = false;
+ return_thread_sp.reset (new HistoryThread (*m_process,
+ item.enqueuing_thread_id,
+ item.enqueuing_callstack,
+ item.stop_id,
+ stop_id_is_valid));
+ return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
+ return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
+ return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
+// return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
+
+ }
+ }
+ return return_thread_sp;
+}
+
+ThreadSP
+SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem (QueueItemSP queue_item_sp, ConstString type)
+{
+ ThreadSP extended_thread_sp;
+ if (type != ConstString("libdispatch"))
+ return extended_thread_sp;
+
+ bool stop_id_is_valid = true;
+ if (queue_item_sp->GetStopID() == 0)
+ stop_id_is_valid = false;
+
+ extended_thread_sp.reset (new HistoryThread (*m_process,
+ queue_item_sp->GetEnqueueingThreadID(),
+ queue_item_sp->GetEnqueueingBacktrace(),
+ queue_item_sp->GetStopID(),
+ stop_id_is_valid));
+ extended_thread_sp->SetExtendedBacktraceToken (queue_item_sp->GetItemThatEnqueuedThis());
+ extended_thread_sp->SetQueueName (queue_item_sp->GetQueueLabel().c_str());
+ extended_thread_sp->SetQueueID (queue_item_sp->GetEnqueueingQueueID());
+// extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str());
+
+ return extended_thread_sp;
+}
+
+/* Returns true if we were able to get the version / offset information
+ * out of libBacktraceRecording. false means we were unable to retrieve
+ * this; the queue_info_version field will be 0.
+ */
+
+bool
+SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized ()
+{
+ if (m_lib_backtrace_recording_info.queue_info_version != 0)
+ return true;
+
+ addr_t queue_info_version_address = LLDB_INVALID_ADDRESS;
+ addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS;
+ addr_t item_info_version_address = LLDB_INVALID_ADDRESS;
+ addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS;
+ Target &target = m_process->GetTarget();
+
+
+ static ConstString introspection_dispatch_queue_info_version ("__introspection_dispatch_queue_info_version");
+ SymbolContextList sc_list;
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ queue_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+ sc_list.Clear();
+
+ static ConstString introspection_dispatch_queue_info_data_offset ("__introspection_dispatch_queue_info_data_offset");
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ queue_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+ sc_list.Clear();
- uint32_t backtrace_length = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_length, 4, 0, error);
- addr_t pc_array_address = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_ptr, error);
+ static ConstString introspection_dispatch_item_info_version ("__introspection_dispatch_item_info_version");
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_version, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ item_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+ sc_list.Clear();
- if (backtrace_length == 0 || pc_array_address == LLDB_INVALID_ADDRESS)
- return bt;
+ static ConstString introspection_dispatch_item_info_data_offset ("__introspection_dispatch_item_info_data_offset");
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ item_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
- for (uint32_t idx = 0; idx < backtrace_length; idx++)
+ if (queue_info_version_address != LLDB_INVALID_ADDRESS
+ && queue_info_data_offset_address != LLDB_INVALID_ADDRESS
+ && item_info_version_address != LLDB_INVALID_ADDRESS
+ && item_info_data_offset_address != LLDB_INVALID_ADDRESS)
{
- addr_t pc_val = m_process->ReadPointerFromMemory (pc_array_address + (ptr_size * idx), error);
- if (error.Success() && pc_val != LLDB_INVALID_ADDRESS)
+ Error error;
+ m_lib_backtrace_recording_info.queue_info_version = m_process->ReadUnsignedIntegerFromMemory (queue_info_version_address, 2, 0, error);
+ if (error.Success())
{
- bt.pcs.push_back (pc_val);
+ m_lib_backtrace_recording_info.queue_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (queue_info_data_offset_address, 2, 0, error);
+ if (error.Success())
+ {
+ m_lib_backtrace_recording_info.item_info_version = m_process->ReadUnsignedIntegerFromMemory (item_info_version_address, 2, 0, error);
+ if (error.Success())
+ {
+ m_lib_backtrace_recording_info.item_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (item_info_data_offset_address, 2, 0, error);
+ if (!error.Success())
+ {
+ m_lib_backtrace_recording_info.queue_info_version = 0;
+ }
+ }
+ else
+ {
+ m_lib_backtrace_recording_info.queue_info_version = 0;
+ }
+ }
+ else
+ {
+ m_lib_backtrace_recording_info.queue_info_version = 0;
+ }
}
}
- return bt;
+ return m_lib_backtrace_recording_info.queue_info_version != 0;
}
const std::vector<ConstString> &
@@ -324,146 +466,233 @@ SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
if (m_types.size () == 0)
{
m_types.push_back(ConstString("libdispatch"));
- m_types.push_back(ConstString("pthread"));
+ // We could have pthread as another type in the future if we have a way of
+ // gathering that information & it's useful to distinguish between them.
}
return m_types;
}
void
-SystemRuntimeMacOSX::SetNewThreadQueueName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
+SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
{
- addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
-
- if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
+ if (!BacktraceRecordingHeadersInitialized())
{
- Error error;
- addr_t queue_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_name_ptr, error);
- if (queue_name_ptr != LLDB_INVALID_ADDRESS && error.Success())
+ // We don't have libBacktraceRecording -- build the list of queues by looking at
+ // all extant threads, and the queues that they currently belong to.
+
+ for (ThreadSP thread_sp : m_process->Threads())
{
- char namebuf[512];
- if (m_process->ReadCStringFromMemory (queue_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success())
+ if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
{
- new_extended_thread_sp->SetQueueName (namebuf);
+ if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
+ {
+ QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
+ queue_list.AddQueue (queue_sp);
+ }
}
}
}
-}
-
-void
-SystemRuntimeMacOSX::SetNewThreadThreadName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
-{
- addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
-
- if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
+ else
{
- Error error;
- addr_t thread_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.thread_name_ptr, error);
- if (thread_name_ptr != LLDB_INVALID_ADDRESS && error.Success())
- {
- char namebuf[512];
- if (m_process->ReadCStringFromMemory (thread_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success())
+ AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ if (cur_thread_sp)
+ {
+ Error error;
+ queue_info_pointer = m_get_queues_handler.GetCurrentQueues (*cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error);
+ if (error.Success())
{
- new_extended_thread_sp->SetName (namebuf);
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+
+ if (queue_info_pointer.count > 0
+ && queue_info_pointer.queues_buffer_size > 0
+ && queue_info_pointer.queues_buffer_ptr != 0
+ && queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS)
+ {
+ PopulateQueuesUsingLibBTR (queue_info_pointer.queues_buffer_ptr, queue_info_pointer.queues_buffer_size, queue_info_pointer.count, queue_list);
+ }
}
}
}
}
-
void
-SystemRuntimeMacOSX::SetNewThreadExtendedBacktraceToken (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
+SystemRuntimeMacOSX::PopulatePendingItemsForQueue (Queue *queue)
{
- addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
- if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
+ if (BacktraceRecordingHeadersInitialized())
{
- Error error;
- uint64_t further_extended_backtrace = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr, error);
- if (error.Success() && further_extended_backtrace != 0 && further_extended_backtrace != LLDB_INVALID_ADDRESS)
+ std::vector<addr_t> pending_item_refs = GetPendingItemRefsForQueue (queue->GetLibdispatchQueueAddress());
+ for (addr_t pending_item : pending_item_refs)
{
- new_extended_thread_sp->SetExtendedBacktraceToken (further_extended_backtrace);
+ AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ Error error;
+ ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), pending_item, m_page_to_free, m_page_to_free_size, error);
+ if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
+ {
+ DataBufferHeap data (ret.item_buffer_size, 0);
+ if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ ItemInfo item = ExtractItemInfoFromBuffer (extractor);
+ QueueItemSP queue_item_sp (new QueueItem (queue->shared_from_this()));
+ queue_item_sp->SetItemThatEnqueuedThis (item.item_that_enqueued_this);
+
+ Address addr;
+ if (!m_process->GetTarget().ResolveLoadAddress (item.function_or_block, addr, item.stop_id))
+ {
+ m_process->GetTarget().ResolveLoadAddress (item.function_or_block, addr);
+ }
+ queue_item_sp->SetAddress (addr);
+ queue_item_sp->SetEnqueueingThreadID (item.enqueuing_thread_id);
+ queue_item_sp->SetTargetQueueID (item.enqueuing_thread_id);
+ queue_item_sp->SetStopID (item.stop_id);
+ queue_item_sp->SetEnqueueingBacktrace (item.enqueuing_callstack);
+ queue_item_sp->SetThreadLabel (item.enqueuing_thread_label);
+ queue_item_sp->SetQueueLabel (item.enqueuing_queue_label);
+ queue_item_sp->SetTargetQueueLabel (item.target_queue_label);
+
+ queue->PushPendingQueueItem (queue_item_sp);
+ }
+ }
}
}
}
-void
-SystemRuntimeMacOSX::SetNewThreadQueueID (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
+// Returns an array of introspection_dispatch_item_info_ref's for the pending items on
+// a queue. The information about each of these pending items then needs to be fetched
+// individually by passing the ref to libBacktraceRecording.
+
+std::vector<lldb::addr_t>
+SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue)
{
- queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
- addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
- if (enqueued_item_ptr != LLDB_INVALID_ADDRESS && m_ldi_header.item_offsets.queue_id_from_thread_info != 0xffff)
- {
+ std::vector<addr_t> pending_item_refs;
+ AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ if (cur_thread_sp)
+ {
Error error;
- queue_id = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_id_from_thread_info, 8, LLDB_INVALID_QUEUE_ID, error);
- if (!error.Success())
- queue_id = LLDB_INVALID_QUEUE_ID;
- }
-
- if (queue_id != LLDB_INVALID_QUEUE_ID)
- {
- new_extended_thread_sp->SetQueueID (queue_id);
+ pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error);
+ if (error.Success())
+ {
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+ if (pending_items_pointer.count > 0
+ && pending_items_pointer.items_buffer_size > 0
+ && pending_items_pointer.items_buffer_ptr != 0
+ && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS)
+ {
+ DataBufferHeap data (pending_items_pointer.items_buffer_size, 0);
+ if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error))
+ {
+ offset_t offset = 0;
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ int i = 0;
+ while (offset < pending_items_pointer.items_buffer_size && i < pending_items_pointer.count)
+ {
+ pending_item_refs.push_back (extractor.GetPointer (&offset));
+ i++;
+ }
+ }
+ m_page_to_free = pending_items_pointer.items_buffer_ptr;
+ m_page_to_free_size = pending_items_pointer.items_buffer_size;
+ }
+ }
}
+ return pending_item_refs;
}
-lldb::tid_t
-SystemRuntimeMacOSX::GetNewThreadUniqueThreadID (ThreadSP original_thread_sp)
+void
+SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size,
+ uint64_t count, lldb_private::QueueList &queue_list)
{
- tid_t ret = LLDB_INVALID_THREAD_ID;
- addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
- if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
+ Error error;
+ DataBufferHeap data (queues_buffer_size, 0);
+ if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success())
{
- Error error;
- ret = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.unique_thread_id, 8, LLDB_INVALID_THREAD_ID, error);
- if (!error.Success())
- ret = LLDB_INVALID_THREAD_ID;
+ // We've read the information out of inferior memory; free it on the next call we make
+ m_page_to_free = queues_buffer;
+ m_page_to_free_size = queues_buffer_size;
+
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ offset_t offset = 0;
+ uint64_t queues_read = 0;
+
+ // The information about the queues is stored in this format (v1):
+ // typedef struct introspection_dispatch_queue_info_s {
+ // uint32_t offset_to_next;
+ // dispatch_queue_t queue;
+ // uint64_t serialnum; // queue's serialnum in the process, as provided by libdispatch
+ // uint32_t running_work_items_count;
+ // uint32_t pending_work_items_count;
+ //
+ // char data[]; // Starting here, we have variable-length data:
+ // // char queue_label[];
+ // } introspection_dispatch_queue_info_s;
+
+ while (queues_read < count && offset < queues_buffer_size)
+ {
+ offset_t start_of_this_item = offset;
+
+ uint32_t offset_to_next = extractor.GetU32 (&offset);
+ /* on 64-bit architectures, the pointer will be 8-byte aligned so there's 4 bytes of
+ * padding between these fields.
+ */
+ if (m_process->GetAddressByteSize() == 8)
+ offset += 4;
+ addr_t queue = extractor.GetPointer (&offset);
+ uint64_t serialnum = extractor.GetU64 (&offset);
+ uint32_t running_work_items_count = extractor.GetU32 (&offset);
+ uint32_t pending_work_items_count = extractor.GetU32 (&offset);
+
+ // Read the first field of the variable length data
+ offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset;
+ const char *queue_label = extractor.GetCStr (&offset);
+ if (queue_label == NULL)
+ queue_label = "";
+
+ offset_t start_of_next_item = start_of_this_item + offset_to_next;
+ offset = start_of_next_item;
+
+ QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label));
+ queue_sp->SetNumRunningWorkItems (running_work_items_count);
+ queue_sp->SetNumPendingWorkItems (pending_work_items_count);
+ queue_sp->SetLibdispatchQueueAddress (queue);
+ queue_list.AddQueue (queue_sp);
+ queues_read++;
+ }
}
- return ret;
}
-ThreadSP
-SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP original_thread_sp, ConstString type)
+SystemRuntimeMacOSX::ItemInfo
+SystemRuntimeMacOSX::ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor)
{
- ThreadSP new_extended_thread_sp;
-
- if (type != ConstString("libdispatch"))
- return new_extended_thread_sp;
-
- ArchivedBacktrace bt = GetLibdispatchExtendedBacktrace (original_thread_sp);
-
- if (bt.pcs.size() == 0)
- return new_extended_thread_sp;
-
- tid_t unique_thread_id = GetNewThreadUniqueThreadID (original_thread_sp);
-
- new_extended_thread_sp.reset (new HistoryThread (*m_process, unique_thread_id, bt.pcs, bt.stop_id, bt.stop_id_is_valid));
+ ItemInfo item;
- SetNewThreadThreadName (original_thread_sp, new_extended_thread_sp);
- SetNewThreadQueueName (original_thread_sp, new_extended_thread_sp);
- SetNewThreadQueueID (original_thread_sp, new_extended_thread_sp);
- SetNewThreadExtendedBacktraceToken (original_thread_sp, new_extended_thread_sp);
- return new_extended_thread_sp;
-}
+ offset_t offset = 0;
+
+ item.item_that_enqueued_this = extractor.GetPointer (&offset);
+ item.function_or_block = extractor.GetPointer (&offset);
+ item.enqueuing_thread_id = extractor.GetU64 (&offset);
+ item.enqueuing_queue_serialnum = extractor.GetU64 (&offset);
+ item.target_queue_serialnum = extractor.GetU64 (&offset);
+ item.enqueuing_callstack_frame_count = extractor.GetU32 (&offset);
+ item.stop_id = extractor.GetU32 (&offset);
-void
-SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
-{
- // For now, iterate over the threads and see what queue each thread is associated with.
- // If we haven't already added this queue, add it to the QueueList.
- // (a single libdispatch queue may be using multiple threads simultaneously.)
+ offset = m_lib_backtrace_recording_info.item_info_data_offset;
- for (ThreadSP thread_sp : m_process->Threads())
+ for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++)
{
- if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
- {
- if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
- {
- QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
- queue_list.AddQueue (queue_sp);
- }
- }
+ item.enqueuing_callstack.push_back (extractor.GetPointer (&offset));
}
-}
+ item.enqueuing_thread_label = extractor.GetCStr (&offset);
+ item.enqueuing_queue_label = extractor.GetCStr (&offset);
+ item.target_queue_label = extractor.GetCStr (&offset);
+ return item;
+}
void
SystemRuntimeMacOSX::Initialize()
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
index 4c684fee7b2..a308844d0e6 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
@@ -26,6 +26,12 @@
#include "lldb/Core/UUID.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/QueueItem.h"
+
+#include "AppleGetItemInfoHandler.h"
+#include "AppleGetQueuesHandler.h"
+#include "AppleGetPendingItemsHandler.h"
+#include "AppleGetThreadItemInfoHandler.h"
class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
{
@@ -48,6 +54,11 @@ public:
static lldb_private::SystemRuntime *
CreateInstance (lldb_private::Process *process);
+
+ //------------------------------------------------------------------
+ // instance methods
+ //------------------------------------------------------------------
+
SystemRuntimeMacOSX (lldb_private::Process *process);
virtual
@@ -57,13 +68,7 @@ public:
Clear (bool clear_process);
void
- DidAttach ();
-
- void
- DidLaunch();
-
- void
- ModulesDidLoad (lldb_private::ModuleList &module_list);
+ Detach ();
const std::vector<lldb_private::ConstString> &
GetExtendedBacktraceTypes ();
@@ -71,18 +76,29 @@ public:
lldb::ThreadSP
GetExtendedBacktraceThread (lldb::ThreadSP thread, lldb_private::ConstString type);
- // REMOVE THE FOLLOWING 4
- bool
- SetItemEnqueuedBreakpoint ();
+ lldb::ThreadSP
+ GetExtendedBacktraceForQueueItem (lldb::QueueItemSP queue_item_sp, lldb_private::ConstString type);
- bool
- DidSetItemEnqueuedBreakpoint () const;
+ lldb::ThreadSP
+ GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref);
- static bool
- ItemEnqueuedCallback (void *baton, lldb_private::StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+ void
+ PopulateQueueList (lldb_private::QueueList &queue_list);
- bool
- ItemEnqueuedBreakpointHit (lldb_private::StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+ void
+ PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size, uint64_t count, lldb_private::QueueList &queue_list);
+
+ void
+ PopulatePendingQueuesUsingLibBTR (lldb::addr_t items_buffer, uint64_t items_buffer_size, uint64_t count, lldb_private::Queue *queue);
+
+ std::string
+ GetQueueNameFromThreadQAddress (lldb::addr_t dispatch_qaddr);
+
+ lldb::queue_id_t
+ GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr);
+
+ void
+ PopulatePendingItemsForQueue (lldb_private::Queue *queue);
//------------------------------------------------------------------
// PluginInterface protocol
@@ -93,19 +109,6 @@ public:
virtual uint32_t
GetPluginVersion();
-private:
- struct ArchivedBacktrace {
- uint32_t stop_id;
- bool stop_id_is_valid;
- lldb::queue_id_t libdispatch_queue_id; // LLDB_INVALID_QUEUE_ID if unavailable
- std::vector<lldb::addr_t> pcs;
- };
-
- SystemRuntimeMacOSX::ArchivedBacktrace
- GetLibdispatchExtendedBacktrace (lldb::ThreadSP thread);
-
- void
- PopulateQueueList (lldb_private::QueueList &queue_list);
protected:
lldb::user_id_t m_break_id;
@@ -113,73 +116,103 @@ protected:
private:
- void
- ParseLdiHeaders ();
-
- bool
- LdiHeadersInitialized ();
-
- lldb::addr_t
- GetQueuesHead ();
-
- lldb::addr_t
- GetItemsHead ();
+ struct libBacktraceRecording_info {
+ uint16_t queue_info_version;
+ uint16_t queue_info_data_offset;
+ uint16_t item_info_version;
+ uint16_t item_info_data_offset;
+
+ libBacktraceRecording_info () :
+ queue_info_version(0),
+ queue_info_data_offset(0),
+ item_info_version(0),
+ item_info_data_offset(0) {}
+ };
- lldb::addr_t
- GetThreadCreatorItem (lldb::ThreadSP thread);
- lldb::tid_t
- GetNewThreadUniqueThreadID (lldb::ThreadSP original_thread_sp);
+ // A structure which reflects the data recorded in the
+ // libBacktraceRecording introspection_dispatch_item_info_s.
+ struct ItemInfo {
+ lldb::addr_t item_that_enqueued_this;
+ lldb::addr_t function_or_block;
+ uint64_t enqueuing_thread_id;
+ uint64_t enqueuing_queue_serialnum;
+ uint64_t target_queue_serialnum;
+ uint32_t enqueuing_callstack_frame_count;
+ uint32_t stop_id;
+ std::vector<lldb::addr_t> enqueuing_callstack;
+ std::string enqueuing_thread_label;
+ std::string enqueuing_queue_label;
+ std::string target_queue_label;
+ };
- void
- SetNewThreadThreadName (lldb::ThreadSP original_thread_sp, lldb::ThreadSP new_extended_thread_sp);
+ // The offsets of different fields of the dispatch_queue_t structure in
+ // a thread/queue process.
+ // Based on libdispatch src/queue_private.h, struct dispatch_queue_offsets_s
+ // With dqo_version 1-3, the dqo_label field is a per-queue value and cannot be cached.
+ // With dqo_version 4 (Mac OS X 10.9 / iOS 7), dqo_label is a constant value that can be cached.
+ struct LibdispatchOffsets
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ uint16_t dqo_flags;
+ uint16_t dqo_flags_size;
+ uint16_t dqo_serialnum;
+ uint16_t dqo_serialnum_size;
+ uint16_t dqo_width;
+ uint16_t dqo_width_size;
+ uint16_t dqo_running;
+ uint16_t dqo_running_size;
+
+ LibdispatchOffsets ()
+ {
+ dqo_version = UINT16_MAX;
+ dqo_flags = UINT16_MAX;
+ dqo_serialnum = UINT16_MAX;
+ dqo_label = UINT16_MAX;
+ dqo_width = UINT16_MAX;
+ dqo_running = UINT16_MAX;
+ };
+
+ bool
+ IsValid ()
+ {
+ return dqo_version != UINT16_MAX;
+ }
+
+ bool
+ LabelIsValid ()
+ {
+ return dqo_label != UINT16_MAX;
+ }
+ };
- void
- SetNewThreadQueueName (lldb::ThreadSP original_thread_sp, lldb::ThreadSP new_extended_thread_sp);
+ bool
+ BacktraceRecordingHeadersInitialized ();
void
- SetNewThreadExtendedBacktraceToken (lldb::ThreadSP original_thread_sp, lldb::ThreadSP new_extended_thread_sp);
+ ReadLibdispatchOffsetsAddress();
void
- SetNewThreadQueueID (lldb::ThreadSP original_thread_sp, lldb::ThreadSP new_extended_thread_sp);
+ ReadLibdispatchOffsets ();
- struct ldi_queue_offsets {
- uint16_t next;
- uint16_t prev;
- uint16_t queue_id;
- uint16_t current_item_ptr;
- };
+ std::vector<lldb::addr_t>
+ GetPendingItemRefsForQueue (lldb::addr_t queue);
- struct ldi_item_offsets {
- uint16_t next;
- uint16_t prev;
- uint16_t type;
- uint16_t identifier;
- uint16_t stop_id;
- uint16_t backtrace_length;
- uint16_t backtrace_ptr;
- uint16_t thread_name_ptr;
- uint16_t queue_name_ptr;
- uint16_t unique_thread_id;
- uint16_t pthread_id;
- uint16_t enqueueing_thread_dispatch_queue_t;
- uint16_t enqueueing_thread_dispatch_block_ptr;
- uint16_t queue_id_from_thread_info;
- };
+ ItemInfo
+ ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor);
- struct ldi_header {
- uint16_t version;
- uint16_t ldi_header_size;
- uint16_t initialized; // 0 means uninitialized
- uint16_t queue_size;
- uint16_t item_size;
- uint64_t queues_head_ptr_address; // Address of queues head structure
- uint64_t items_head_ptr_address; // Address of items_head
- struct ldi_queue_offsets queue_offsets;
- struct ldi_item_offsets item_offsets;
- };
+ lldb_private::AppleGetQueuesHandler m_get_queues_handler;
+ lldb_private::AppleGetPendingItemsHandler m_get_pending_items_handler;
+ lldb_private::AppleGetItemInfoHandler m_get_item_info_handler;
+ lldb_private::AppleGetThreadItemInfoHandler m_get_thread_item_info_handler;
- struct ldi_header m_ldi_header;
+ lldb::addr_t m_page_to_free;
+ uint64_t m_page_to_free_size;
+ libBacktraceRecording_info m_lib_backtrace_recording_info;
+ lldb::addr_t m_dispatch_queue_offsets_addr;
+ struct LibdispatchOffsets m_libdispatch_offsets;
DISALLOW_COPY_AND_ASSIGN (SystemRuntimeMacOSX);
};
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index a18eab0f265..68d95a9eeba 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1020,9 +1020,7 @@ Process::Process(Target &target, Listener &listener) :
m_mod_id (),
m_process_unique_id(0),
m_thread_index_id (0),
- m_queue_index_id (0),
m_thread_id_to_index_id_map (),
- m_queue_id_to_index_id_map (),
m_exit_status (-1),
m_exit_string (),
m_thread_mutex (Mutex::eMutexTypeRecursive),
@@ -1699,39 +1697,6 @@ Process::AssignIndexIDToThread(uint64_t thread_id)
return result;
}
-bool
-Process::HasAssignedIndexIDToQueue(queue_id_t queue_id)
-{
- std::map<uint64_t, uint32_t>::iterator iterator = m_queue_id_to_index_id_map.find(queue_id);
- if (iterator == m_queue_id_to_index_id_map.end())
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-uint32_t
-Process::AssignIndexIDToQueue(queue_id_t queue_id)
-{
- uint32_t result = 0;
- std::map<uint64_t, uint32_t>::iterator iterator = m_queue_id_to_index_id_map.find(queue_id);
- if (iterator == m_queue_id_to_index_id_map.end())
- {
- result = ++m_queue_index_id;
- m_queue_id_to_index_id_map[queue_id] = result;
- }
- else
- {
- result = iterator->second;
- }
-
- return result;
-}
-
-
StateType
Process::GetState()
{
diff --git a/lldb/source/Target/Queue.cpp b/lldb/source/Target/Queue.cpp
index 21e1127e82d..2b9d2a0ed9a 100644
--- a/lldb/source/Target/Queue.cpp
+++ b/lldb/source/Target/Queue.cpp
@@ -11,6 +11,7 @@
#include "lldb/Target/Queue.h"
#include "lldb/Target/QueueList.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/SystemRuntime.h"
using namespace lldb;
using namespace lldb_private;
@@ -19,13 +20,15 @@ Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue
m_process_wp (),
m_queue_id (queue_id),
m_queue_name (),
- m_enqueued_items()
+ m_running_work_items_count(0),
+ m_pending_work_items_count(0),
+ m_pending_items(),
+ m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS)
{
if (queue_name)
m_queue_name = queue_name;
m_process_wp = process_sp;
- m_index_id = process_sp->AssignIndexIDToQueue (queue_id);
}
Queue::~Queue ()
@@ -50,7 +53,7 @@ Queue::GetName ()
uint32_t
Queue::GetIndexID ()
{
- return m_index_id;
+ return m_queue_id;
}
std::vector<lldb::ThreadSP>
@@ -70,3 +73,55 @@ Queue::GetThreads ()
}
return result;
}
+
+void
+Queue::SetNumRunningWorkItems (uint32_t count)
+{
+ m_running_work_items_count = count;
+}
+
+uint32_t
+Queue::GetNumRunningWorkItems () const
+{
+ return m_running_work_items_count;
+}
+
+
+void
+Queue::SetNumPendingWorkItems (uint32_t count)
+{
+ m_pending_work_items_count = count;
+}
+
+uint32_t
+Queue::GetNumPendingWorkItems () const
+{
+ return m_pending_work_items_count;
+}
+
+void
+Queue::SetLibdispatchQueueAddress (addr_t dispatch_queue_t_addr)
+{
+ m_dispatch_queue_t_addr = dispatch_queue_t_addr;
+}
+
+addr_t
+Queue::GetLibdispatchQueueAddress () const
+{
+ return m_dispatch_queue_t_addr;
+}
+
+
+const std::vector<lldb::QueueItemSP> &
+Queue::GetPendingItems ()
+{
+ if (m_pending_items.size() == 0)
+ {
+ ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp && process_sp->GetSystemRuntime())
+ {
+ process_sp->GetSystemRuntime()->PopulatePendingItemsForQueue (this);
+ }
+ }
+ return m_pending_items;
+}
diff --git a/lldb/source/Target/QueueItem.cpp b/lldb/source/Target/QueueItem.cpp
index b2cd9fa1d63..bb6762829ca 100644
--- a/lldb/source/Target/QueueItem.cpp
+++ b/lldb/source/Target/QueueItem.cpp
@@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/Queue.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/QueueItem.h"
+#include "lldb/Target/SystemRuntime.h"
using namespace lldb;
using namespace lldb_private;
@@ -16,7 +18,16 @@ using namespace lldb_private;
QueueItem::QueueItem (QueueSP queue_sp) :
m_queue_wp (),
m_kind (eQueueItemKindUnknown),
- m_address ()
+ m_address (),
+ m_item_that_enqueued_this_ref (LLDB_INVALID_ADDRESS),
+ m_enqueueing_thread_id (LLDB_INVALID_THREAD_ID),
+ m_enqueueing_queue_id (LLDB_INVALID_QUEUE_ID),
+ m_target_queue_id (LLDB_INVALID_QUEUE_ID),
+ m_stop_id (0),
+ m_backtrace(),
+ m_thread_label(),
+ m_queue_label(),
+ m_target_queue_label()
{
m_queue_wp = queue_sp;
}
@@ -52,5 +63,15 @@ QueueItem::SetAddress (Address addr)
ThreadSP
QueueItem::GetExtendedBacktraceThread (ConstString type)
{
- return ThreadSP();
+ ThreadSP return_thread;
+ QueueSP queue_sp = m_queue_wp.lock();
+ if (queue_sp)
+ {
+ ProcessSP process_sp = queue_sp->GetProcess();
+ if (process_sp && process_sp->GetSystemRuntime())
+ {
+ return_thread = process_sp->GetSystemRuntime()->GetExtendedBacktraceForQueueItem (this->shared_from_this(), type);
+ }
+ }
+ return return_thread;
}
diff --git a/lldb/source/Target/SystemRuntime.cpp b/lldb/source/Target/SystemRuntime.cpp
index 5c07ed388ae..c3fb9c8091f 100644
--- a/lldb/source/Target/SystemRuntime.cpp
+++ b/lldb/source/Target/SystemRuntime.cpp
@@ -56,6 +56,11 @@ SystemRuntime::DidLaunch()
}
void
+SystemRuntime::Detach()
+{
+}
+
+void
SystemRuntime::ModulesDidLoad (ModuleList &module_list)
{
}
diff --git a/lldb/source/lldb-log.cpp b/lldb/source/lldb-log.cpp
index 5e1dc3a54e8..c00d2e649e2 100644
--- a/lldb/source/lldb-log.cpp
+++ b/lldb/source/lldb-log.cpp
@@ -141,6 +141,7 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm)
else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits &= ~LIBLLDB_LOG_UNWIND;
else if (0 == ::strncasecmp(arg, "types", 5)) flag_bits &= ~LIBLLDB_LOG_TYPES;
else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits &= ~LIBLLDB_LOG_SYMBOLS;
+ else if (0 == ::strcasecmp(arg, "system-runtime")) flag_bits &= ~LIBLLDB_LOG_SYSTEM_RUNTIME;
else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits &= ~LIBLLDB_LOG_MODULES;
else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits &= ~LIBLLDB_LOG_MMAP;
else if (0 == ::strcasecmp(arg, "os")) flag_bits &= ~LIBLLDB_LOG_OS;
@@ -208,6 +209,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const ch
else if (0 == ::strcasecmp(arg, "state")) flag_bits |= LIBLLDB_LOG_STATE;
else if (0 == ::strcasecmp(arg, "step")) flag_bits |= LIBLLDB_LOG_STEP;
else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits |= LIBLLDB_LOG_SYMBOLS;
+ else if (0 == ::strcasecmp(arg, "system-runtime")) flag_bits |= LIBLLDB_LOG_SYSTEM_RUNTIME;
else if (0 == ::strcasecmp(arg, "target")) flag_bits |= LIBLLDB_LOG_TARGET;
else if (0 == ::strncasecmp(arg, "temp", 4)) flag_bits |= LIBLLDB_LOG_TEMPORARY;
else if (0 == ::strcasecmp(arg, "thread")) flag_bits |= LIBLLDB_LOG_THREAD;
@@ -256,6 +258,7 @@ lldb_private::ListLogCategories (Stream *strm)
" state - log private and public process state changes\n"
" step - log step related activities\n"
" symbol - log symbol related issues and warnings\n"
+ " system-runtime - log system runtime events\n"
" target - log target events and activities\n"
" thread - log thread events and activities\n"
" types - log type system related activities\n"
OpenPOWER on IntegriCloud