summaryrefslogtreecommitdiffstats
path: root/lldb/tools/debugserver/source/MacOSX
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/debugserver/source/MacOSX')
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CMakeLists.txt1
-rw-r--r--lldb/tools/debugserver/source/MacOSX/Genealogy.cpp302
-rw-r--r--lldb/tools/debugserver/source/MacOSX/Genealogy.h116
-rw-r--r--lldb/tools/debugserver/source/MacOSX/GenealogySPI.h96
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h12
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.mm41
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachTask.mm54
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThread.cpp205
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThread.h13
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp48
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThreadList.h8
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp114
-rw-r--r--lldb/tools/debugserver/source/MacOSX/ThreadInfo.h26
13 files changed, 911 insertions, 125 deletions
diff --git a/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt b/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt
index 24342c84f87..a7e4993c2a0 100644
--- a/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt
+++ b/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt
@@ -31,6 +31,7 @@ add_lldb_executable(debugserver
CFBundle.cpp
CFData.cpp
CFString.cpp
+ Genealogy.cpp
MachException.cpp
MachProcess.mm
MachTask.mm
diff --git a/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp b/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp
new file mode 100644
index 00000000000..1544dc26b60
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp
@@ -0,0 +1,302 @@
+///===-- Activity.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <Availability.h>
+#include <string>
+#include <dlfcn.h>
+#include <uuid/uuid.h>
+
+#include "DNBDefs.h"
+#include "Genealogy.h"
+#include "GenealogySPI.h"
+#include "MachThreadList.h"
+
+//---------------------------
+/// Constructor
+//---------------------------
+
+Genealogy::Genealogy () :
+ m_os_activity_diagnostic_for_pid (nullptr),
+ m_os_activity_iterate_processes (nullptr),
+ m_os_activity_iterate_breadcrumbs (nullptr),
+ m_os_activity_iterate_messages (nullptr),
+ m_os_activity_iterate_activities (nullptr),
+ m_os_trace_get_type (nullptr),
+ m_os_trace_copy_formatted_message (nullptr),
+ m_os_activity_for_thread (nullptr),
+ m_os_activity_for_task_thread (nullptr),
+ m_thread_activities(),
+ m_process_executable_infos(),
+ m_diagnosticd_call_timed_out(false)
+{
+ m_os_activity_diagnostic_for_pid = (bool (*)(pid_t, os_activity_t, uint32_t, os_diagnostic_block_t))dlsym (RTLD_DEFAULT, "os_activity_diagnostic_for_pid");
+ m_os_activity_iterate_processes = (void (*)(os_activity_process_list_t, bool (^)(os_activity_process_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_processes");
+ m_os_activity_iterate_breadcrumbs = (void (*)(os_activity_process_t, bool (^)(os_activity_breadcrumb_t))) dlsym (RTLD_DEFAULT, "os_activity_iterate_breadcrumbs");
+ m_os_activity_iterate_messages = (void (*)(os_trace_message_list_t, os_activity_process_t, bool (^)(os_trace_message_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_messages");
+ m_os_activity_iterate_activities = (void (*)(os_activity_list_t, os_activity_process_t, bool (^)(os_activity_entry_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_activities");
+ m_os_trace_get_type = (uint8_t (*)(os_trace_message_t)) dlsym (RTLD_DEFAULT, "os_trace_get_type");
+ m_os_trace_copy_formatted_message = (char *(*)(os_trace_message_t)) dlsym (RTLD_DEFAULT, "os_trace_copy_formatted_message");
+ m_os_activity_for_thread = (os_activity_t (*)(os_activity_process_t, uint64_t)) dlsym (RTLD_DEFAULT, "os_activity_for_thread");
+ m_os_activity_for_task_thread = (os_activity_t (*)(task_t, uint64_t)) dlsym (RTLD_DEFAULT, "os_activity_for_task_thread");
+ m_os_activity_messages_for_thread = (os_trace_message_list_t (*) (os_activity_process_t process, os_activity_t activity, uint64_t thread_id)) dlsym (RTLD_DEFAULT, "os_activity_messages_for_thread");
+}
+
+Genealogy::ThreadActivitySP
+Genealogy::GetGenealogyInfoForThread (pid_t pid, nub_thread_t tid, const MachThreadList &thread_list, task_t task, bool &timed_out)
+{
+ ThreadActivitySP activity;
+ //
+ // if we've timed out trying to get the activities, don't try again at this process stop.
+ // (else we'll need to hit the timeout for every thread we're asked about.)
+ // We'll try again at the next public stop.
+
+ if (m_thread_activities.size() == 0 && m_diagnosticd_call_timed_out == false)
+ {
+ GetActivities(pid, thread_list, task);
+ }
+ std::map<nub_thread_t, ThreadActivitySP>::const_iterator search;
+ search = m_thread_activities.find(tid);
+ if (search != m_thread_activities.end())
+ {
+ activity = search->second;
+ }
+ timed_out = m_diagnosticd_call_timed_out;
+ return activity;
+}
+
+void
+Genealogy::Clear()
+{
+ m_thread_activities.clear();
+ m_diagnosticd_call_timed_out = false;
+}
+
+void
+Genealogy::GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task)
+{
+ if (m_os_activity_diagnostic_for_pid != nullptr
+ && m_os_activity_iterate_processes != nullptr
+ && m_os_activity_iterate_breadcrumbs != nullptr
+ && m_os_activity_iterate_messages != nullptr
+ && m_os_activity_iterate_activities != nullptr
+ && m_os_trace_get_type != nullptr
+ && m_os_trace_copy_formatted_message != nullptr
+ && (m_os_activity_for_thread != nullptr || m_os_activity_for_task_thread != nullptr)
+ )
+ {
+ __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
+ __block BreadcrumbList breadcrumbs;
+ __block ActivityList activities;
+ __block MessageList messages;
+ __block std::map<nub_thread_t, uint64_t> thread_activity_mapping;
+
+ os_activity_diagnostic_flag_t flags = OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES | OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY;
+ if (m_os_activity_diagnostic_for_pid (pid, 0, flags, ^(os_activity_process_list_t processes, int error)
+ {
+ if (error == 0)
+ {
+ m_os_activity_iterate_processes (processes, ^bool(os_activity_process_t process_info)
+ {
+ if (pid == process_info->pid)
+ {
+ // Collect all the Breadcrumbs
+ m_os_activity_iterate_breadcrumbs (process_info, ^bool(os_activity_breadcrumb_t breadcrumb)
+ {
+ Breadcrumb bc;
+ bc.breadcrumb_id = breadcrumb->breadcrumb_id;
+ bc.activity_id = breadcrumb->activity_id;
+ bc.timestamp = breadcrumb->timestamp;
+ if (breadcrumb->name)
+ bc.name = breadcrumb->name;
+ breadcrumbs.push_back (bc);
+ return true;
+ });
+
+ // Collect all the Activites
+ m_os_activity_iterate_activities (process_info->activities, process_info, ^bool(os_activity_entry_t activity)
+ {
+ Activity ac;
+ ac.activity_start = activity->activity_start;
+ ac.activity_id = activity->activity_id;
+ ac.parent_id = activity->parent_id;
+ if (activity->activity_name)
+ ac.activity_name = activity->activity_name;
+ if (activity->reason)
+ ac.reason = activity->reason;
+ activities.push_back (ac);
+ return true;
+ });
+
+
+ // Collect all the Messages -- messages not associated with any thread
+ m_os_activity_iterate_messages (process_info->messages, process_info, ^bool(os_trace_message_t trace_msg)
+ {
+ Message msg;
+ msg.timestamp = trace_msg->timestamp;
+ msg.trace_id = trace_msg->trace_id;
+ msg.thread = trace_msg->thread;
+ msg.type = m_os_trace_get_type (trace_msg);
+ msg.activity_id = 0;
+ if (trace_msg->image_uuid && trace_msg->image_path)
+ {
+ ProcessExecutableInfoSP process_info_sp (new ProcessExecutableInfo());
+ uuid_copy (process_info_sp->image_uuid, trace_msg->image_uuid);
+ process_info_sp->image_path = trace_msg->image_path;
+ msg.process_info_index = AddProcessExecutableInfo (process_info_sp);
+ }
+ const char *message_text = m_os_trace_copy_formatted_message (trace_msg);
+ if (message_text)
+ msg.message = message_text;
+ messages.push_back (msg);
+ return true;
+ });
+
+ // Discover which activities are said to be running on threads currently
+ const nub_size_t num_threads = thread_list.NumThreads();
+ for (nub_size_t i = 0; i < num_threads; ++i)
+ {
+ nub_thread_t thread_id = thread_list.ThreadIDAtIndex(i);
+ os_activity_t act = 0;
+ if (m_os_activity_for_task_thread != nullptr)
+ {
+ act = m_os_activity_for_task_thread (task, thread_id);
+ }
+ else if (m_os_activity_for_thread != nullptr)
+ {
+ act = m_os_activity_for_thread (process_info, thread_id);
+ }
+ if (act != 0)
+ thread_activity_mapping[thread_id] = act;
+ }
+
+ // Collect all Messages -- messages associated with a thread
+
+ // When there's no genealogy information, an early version of os_activity_messages_for_thread
+ // can crash in rare circumstances. Check to see if this process has any activities before
+ // making the call to get messages.
+ if (process_info->activities != nullptr && thread_activity_mapping.size() > 0)
+ {
+ std::map<nub_thread_t, uint64_t>::const_iterator iter;
+ for (iter = thread_activity_mapping.begin(); iter != thread_activity_mapping.end(); ++iter)
+ {
+ nub_thread_t thread_id = iter->first;
+ os_activity_t act = iter->second;
+ os_trace_message_list_t this_thread_messages = m_os_activity_messages_for_thread (process_info, act, thread_id);
+ m_os_activity_iterate_messages (this_thread_messages, process_info, ^bool(os_trace_message_t trace_msg)
+ {
+ Message msg;
+ msg.timestamp = trace_msg->timestamp;
+ msg.trace_id = trace_msg->trace_id;
+ msg.thread = trace_msg->thread;
+ msg.type = m_os_trace_get_type (trace_msg);
+ msg.activity_id = act;
+ if (trace_msg->image_uuid && trace_msg->image_path)
+ {
+ ProcessExecutableInfoSP process_info_sp (new ProcessExecutableInfo());
+ uuid_copy (process_info_sp->image_uuid, trace_msg->image_uuid);
+ process_info_sp->image_path = trace_msg->image_path;
+ msg.process_info_index = AddProcessExecutableInfo (process_info_sp);
+ }
+ const char *message_text = m_os_trace_copy_formatted_message (trace_msg);
+ if (message_text)
+ msg.message = message_text;
+ messages.push_back (msg);
+ return true;
+ });
+ }
+ }
+ }
+ return true;
+ });
+ }
+ dispatch_semaphore_signal(semaphore);
+ }) == true)
+ {
+ // Wait for the diagnosticd xpc calls to all finish up -- or half a second to elapse.
+ dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
+ bool success = dispatch_semaphore_wait(semaphore, timeout) == 0;
+ if (!success)
+ {
+ m_diagnosticd_call_timed_out = true;
+ return;
+ }
+ }
+
+ // breadcrumbs, activities, and messages have all now been filled in.
+
+ std::map<nub_thread_t, uint64_t>::const_iterator iter;
+ for (iter = thread_activity_mapping.begin(); iter != thread_activity_mapping.end(); ++iter)
+ {
+ nub_thread_t thread_id = iter->first;
+ uint64_t activity_id = iter->second;
+ ActivityList::const_iterator activity_search;
+ bool found_activity_for_this_thread = false;
+ for (activity_search = activities.begin(); activity_search != activities.end(); ++activity_search)
+ {
+ if (activity_search->activity_id == activity_id)
+ {
+ found_activity_for_this_thread = true;
+ ThreadActivitySP thread_activity_sp (new ThreadActivity());
+ thread_activity_sp->current_activity = *activity_search;
+
+ BreadcrumbList::const_iterator breadcrumb_search;
+ for (breadcrumb_search = breadcrumbs.begin(); breadcrumb_search != breadcrumbs.end(); ++breadcrumb_search)
+ {
+ if (breadcrumb_search->activity_id == activity_id)
+ {
+ thread_activity_sp->breadcrumbs.push_back (*breadcrumb_search);
+ }
+ }
+ MessageList::const_iterator message_search;
+ for (message_search = messages.begin(); message_search != messages.end(); ++message_search)
+ {
+ if (message_search->thread == thread_id)
+ {
+ thread_activity_sp->messages.push_back (*message_search);
+ }
+ }
+
+ m_thread_activities[thread_id] = thread_activity_sp;
+ break;
+ }
+ }
+ }
+ }
+}
+
+uint32_t
+Genealogy::AddProcessExecutableInfo (ProcessExecutableInfoSP process_exe_info)
+{
+ const uint32_t info_size = m_process_executable_infos.size();
+ for (uint32_t idx = 0; idx < info_size; ++idx)
+ {
+ if (uuid_compare (m_process_executable_infos[idx]->image_uuid, process_exe_info->image_uuid) == 0)
+ {
+ return idx + 1;
+ }
+ }
+ m_process_executable_infos.push_back (process_exe_info);
+ return info_size + 1;
+}
+
+Genealogy::ProcessExecutableInfoSP
+Genealogy::GetProcessExecutableInfosAtIndex(uint32_t idx)
+{
+ ProcessExecutableInfoSP info_sp;
+ if (idx > 0)
+ {
+ idx--;
+ if (idx <= m_process_executable_infos.size())
+ {
+ info_sp = m_process_executable_infos[idx];
+ }
+ }
+ return info_sp;
+}
+
diff --git a/lldb/tools/debugserver/source/MacOSX/Genealogy.h b/lldb/tools/debugserver/source/MacOSX/Genealogy.h
new file mode 100644
index 00000000000..18521ee2346
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/Genealogy.h
@@ -0,0 +1,116 @@
+//===-- Activity.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __Genealogy_h__
+#define __Genealogy_h__
+
+#include <string>
+#include <vector>
+#include <map>
+#include <pthread.h>
+#include <mach/task.h>
+
+#include "GenealogySPI.h"
+#include "MachThreadList.h"
+
+class Genealogy
+{
+public:
+
+ Genealogy ();
+
+ ~Genealogy ()
+ {
+ }
+
+ void
+ Clear();
+
+ struct Breadcrumb
+ {
+ uint32_t breadcrumb_id;
+ uint64_t activity_id;
+ uint64_t timestamp;
+ std::string name;
+ };
+
+ struct Activity
+ {
+ uint64_t activity_start;
+ uint64_t activity_id;
+ uint64_t parent_id;
+ std::string activity_name;
+ std::string reason;
+ };
+
+ struct Message
+ {
+ uint64_t timestamp;
+ uint64_t activity_id;
+ uint64_t trace_id;
+ uint64_t thread;
+ uint8_t type; // OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_DEBUG, OS_TRACE_TYPE_ERROR, OS_TRACE_TYPE_FAULT
+ uint32_t process_info_index; // index # of the image uuid/file path, 0 means unknown
+ std::string message;
+ };
+
+ typedef std::vector<Message> MessageList;
+ typedef std::vector<Breadcrumb> BreadcrumbList;
+ typedef std::vector<Activity> ActivityList;
+
+ struct ThreadActivity
+ {
+ Activity current_activity;
+ MessageList messages;
+ BreadcrumbList breadcrumbs; // should be 0 or 1 breadcrumbs; no more than 1 BC for any given activity
+ };
+
+ typedef std::shared_ptr<ThreadActivity> ThreadActivitySP;
+
+ ThreadActivitySP
+ GetGenealogyInfoForThread (pid_t pid, nub_thread_t tid, const MachThreadList &thread_list, task_t task, bool &timed_out);
+
+ struct ProcessExecutableInfo
+ {
+ std::string image_path;
+ uuid_t image_uuid;
+ };
+
+ typedef std::shared_ptr<ProcessExecutableInfo> ProcessExecutableInfoSP;
+
+ ProcessExecutableInfoSP
+ GetProcessExecutableInfosAtIndex(uint32_t idx);
+
+ uint32_t
+ AddProcessExecutableInfo(ProcessExecutableInfoSP process_exe_info);
+
+private:
+
+ void
+ GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task);
+
+ // the spi we need to call into libtrace - look them up via dlsym at runtime
+ bool (*m_os_activity_diagnostic_for_pid) (pid_t pid, os_activity_t activity, uint32_t flags, os_diagnostic_block_t block);
+ void (*m_os_activity_iterate_processes) (os_activity_process_list_t processes, bool (^iterator)(os_activity_process_t process_info));
+ void (*m_os_activity_iterate_breadcrumbs) (os_activity_process_t process_info, bool (^iterator)(os_activity_breadcrumb_t breadcrumb));
+ void (*m_os_activity_iterate_messages) (os_trace_message_list_t messages, os_activity_process_t process_info, bool (^iterator)(os_trace_message_t tracemsg));
+ void (*m_os_activity_iterate_activities) (os_activity_list_t activities, os_activity_process_t process_info, bool (^iterator)(os_activity_entry_t activity));
+ uint8_t (*m_os_trace_get_type) (os_trace_message_t trace_msg);
+ char * (*m_os_trace_copy_formatted_message) (os_trace_message_t trace_msg);
+ os_activity_t (*m_os_activity_for_thread) (os_activity_process_t process, uint64_t thread_id);
+ os_activity_t (*m_os_activity_for_task_thread) (task_t target, uint64_t thread_id);
+ os_trace_message_list_t (*m_os_activity_messages_for_thread) (os_activity_process_t process, os_activity_t activity, uint64_t thread_id);
+
+
+ std::map<nub_thread_t, ThreadActivitySP> m_thread_activities;
+ std::vector<ProcessExecutableInfoSP> m_process_executable_infos;
+ bool m_diagnosticd_call_timed_out;
+};
+
+#endif // __Genealogy_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h b/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h
new file mode 100644
index 00000000000..f84e930e872
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h
@@ -0,0 +1,96 @@
+//===-- ActivitySPI.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===//
+
+#ifndef __GenealogySPI_h__
+#define __GenealogySPI_h__
+
+#include <xpc/xpc.h>
+
+typedef void *os_activity_process_list_t;
+typedef void *os_activity_list_t;
+typedef void *os_trace_message_list_t;
+typedef struct os_activity_watch_s *os_activity_watch_t;
+typedef uint64_t os_activity_t;
+
+struct os_activity_breadcrumb_s {
+ uint32_t breadcrumb_id;
+ uint64_t activity_id;
+ uint64_t timestamp;
+ const char *name;
+};
+
+typedef struct os_activity_breadcrumb_s *os_activity_breadcrumb_t;
+
+typedef struct os_trace_message_s {
+ uint64_t trace_id;
+ uint64_t thread;
+ uint64_t timestamp;
+ uint32_t offset;
+ xpc_object_t __unsafe_unretained payload;
+ const uint8_t *image_uuid;
+ const char *image_path;
+ const char *format;
+ const void *buffer;
+ size_t bufferLen;
+} *os_trace_message_t;
+
+typedef struct os_activity_process_s {
+ os_activity_process_list_t child_procs;
+ os_trace_message_list_t messages;
+ os_activity_list_t activities;
+ void *breadcrumbs;
+ uint64_t proc_id;
+ const uint8_t *image_uuid;
+ const char *image_path;
+ pid_t pid;
+} *os_activity_process_t;
+
+typedef struct os_activity_entry_s {
+ uint64_t activity_start;
+ os_activity_t activity_id;
+ os_activity_t parent_id;
+ const char *activity_name;
+ const char *reason;
+ os_trace_message_list_t messages;
+} *os_activity_entry_t;
+
+enum
+{
+ OS_ACTIVITY_DIAGNOSTIC_DEFAULT = 0x00000000,
+ OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY = 0x00000001,
+ OS_ACTIVITY_DIAGNOSTIC_SKIP_DECODE = 0x00000002,
+ OS_ACTIVITY_DIAGNOSTIC_FLATTENED = 0x00000004,
+ OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES = 0x00000008,
+ OS_ACTIVITY_DIAGNOSTIC_MAX = 0x0000000f
+};
+typedef uint32_t os_activity_diagnostic_flag_t;
+
+enum
+{
+ OS_ACTIVITY_WATCH_DEFAULT = 0x00000000,
+ OS_ACTIVITY_WATCH_PROCESS_ONLY = 0x00000001,
+ OS_ACTIVITY_WATCH_SKIP_DECODE = 0x00000002,
+ OS_ACTIVITY_WATCH_PAYLOAD = 0x00000004,
+ OS_ACTIVITY_WATCH_ERRORS = 0x00000008,
+ OS_ACTIVITY_WATCH_FAULTS = 0x00000010,
+ OS_ACTIVITY_WATCH_MAX = 0x0000001f
+};
+typedef uint32_t os_activity_watch_flag_t;
+
+// Return values from os_trace_get_type()
+#define OS_TRACE_TYPE_RELEASE (1u << 0)
+#define OS_TRACE_TYPE_DEBUG (1u << 1)
+#define OS_TRACE_TYPE_ERROR ((1u << 6) | (1u << 0))
+#define OS_TRACE_TYPE_FAULT ((1u << 7) | (1u << 6) | (1u << 0))
+
+
+typedef void (^os_activity_watch_block_t)(os_activity_watch_t watch, os_activity_process_t process_info, bool canceled);
+typedef void (^os_diagnostic_block_t)(os_activity_process_list_t processes, int error);
+
+#endif
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
index 78be93c6976..9a643603f57 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -25,6 +25,8 @@
#include "PThreadCondition.h"
#include "PThreadEvent.h"
#include "PThreadMutex.h"
+#include "Genealogy.h"
+#include "ThreadInfo.h"
#include <mach/mach.h>
#include <sys/signal.h>
@@ -179,6 +181,11 @@ public:
nub_bool_t SyncThreadState (nub_thread_t tid);
const char * ThreadGetName (nub_thread_t tid);
nub_state_t ThreadGetState (nub_thread_t tid);
+ ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index);
+ nub_addr_t GetPThreadT (nub_thread_t tid);
+ nub_addr_t GetDispatchQueueT (nub_thread_t tid);
+ nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
+
nub_size_t GetNumThreads () const;
nub_thread_t GetThreadAtIndex (nub_size_t thread_idx) const;
nub_thread_t GetCurrentThread ();
@@ -265,6 +272,10 @@ public:
bool ProcessUsingSpringBoard() const { return (m_flags & eMachProcessFlagsUsingSBS) != 0; }
bool ProcessUsingBackBoard() const { return (m_flags & eMachProcessFlagsUsingBKS) != 0; }
+ Genealogy::ThreadActivitySP GetGenealogyInfoForThread (nub_thread_t tid, bool &timed_out);
+
+ Genealogy::ProcessExecutableInfoSP GetGenealogyImageInfo (size_t idx);
+
DNBProfileDataScanType GetProfileScanType () { return m_profile_scan_type; }
private:
@@ -311,6 +322,7 @@ private:
PThreadMutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages
MachThreadList m_thread_list; // A list of threads that is maintained/updated after each stop
+ Genealogy m_activities; // A list of activities that is updated after every stop lazily
nub_state_t m_state; // The state of our process
PThreadMutex m_state_mutex; // Multithreaded protection for m_state
PThreadEvent m_events; // Process related events in the child processes lifetime can be waited upon
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
index 0ac985b1cb6..85123977f0b 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -126,6 +126,7 @@ MachProcess::MachProcess() :
m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE),
m_profile_data (),
m_thread_list (),
+ m_activities (),
m_exception_messages (),
m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
m_state (eStateUnloaded),
@@ -219,6 +220,30 @@ MachProcess::SyncThreadState (nub_thread_t tid)
}
+ThreadInfo::QoS
+MachProcess::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index)
+{
+ return m_thread_list.GetRequestedQoS (tid, tsd, dti_qos_class_index);
+}
+
+nub_addr_t
+MachProcess::GetPThreadT (nub_thread_t tid)
+{
+ return m_thread_list.GetPThreadT (tid);
+}
+
+nub_addr_t
+MachProcess::GetDispatchQueueT (nub_thread_t tid)
+{
+ return m_thread_list.GetDispatchQueueT (tid);
+}
+
+nub_addr_t
+MachProcess::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
+{
+ return m_thread_list.GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
+}
+
nub_thread_t
MachProcess::GetCurrentThread ()
{
@@ -365,6 +390,7 @@ MachProcess::Clear(bool detaching)
PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
m_exception_messages.clear();
}
+ m_activities.Clear();
if (m_profile_thread)
{
pthread_join(m_profile_thread, NULL);
@@ -605,6 +631,7 @@ MachProcess::Detach()
{
m_thread_actions.Clear();
+ m_activities.Clear();
DNBThreadResumeAction thread_action;
thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx);
thread_action.state = eStateRunning;
@@ -1250,6 +1277,7 @@ MachProcess::ExceptionMessageBundleComplete()
DNBArchProtocol::SetArchitecture (process_cpu_type);
}
m_thread_list.Clear();
+ m_activities.Clear();
m_breakpoints.DisableAll();
}
@@ -1288,6 +1316,7 @@ MachProcess::ExceptionMessageBundleComplete()
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
m_thread_list.ProcessDidStop(this);
+ m_activities.Clear();
// Let each thread know of any exceptions
for (i=0; i<m_exception_messages.size(); ++i)
@@ -1666,6 +1695,18 @@ MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len)
return INVALID_NUB_PROCESS;
}
+Genealogy::ThreadActivitySP
+MachProcess::GetGenealogyInfoForThread (nub_thread_t tid, bool &timed_out)
+{
+ return m_activities.GetGenealogyInfoForThread (m_pid, tid, m_thread_list, m_task.TaskPort(), timed_out);
+}
+
+Genealogy::ProcessExecutableInfoSP
+MachProcess::GetGenealogyImageInfo (size_t idx)
+{
+ return m_activities.GetProcessExecutableInfosAtIndex (idx);
+}
+
// Do the process specific setup for attach. If this returns NULL, then there's no
// platform specific stuff to be done to wait for the attach. If you get non-null,
// pass that token to the CheckForProcess method, and then to CleanupAfterAttach.
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/lldb/tools/debugserver/source/MacOSX/MachTask.mm
index 42e07ee0f28..078ae3ef9ee 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachTask.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm
@@ -54,6 +54,15 @@ extern "C"
}
#endif
+#include <AvailabilityMacros.h>
+
+#ifdef LLDB_ENERGY
+#include <mach/mach_time.h>
+#include <pmenergy.h>
+#include <pmsample.h>
+#endif
+
+
//----------------------------------------------------------------------
// MachTask constructor
//----------------------------------------------------------------------
@@ -330,6 +339,8 @@ MachTask::GetProfileData (DNBProfileDataScanType scanType)
if (task == TASK_NULL)
return result;
+ pid_t pid = m_process->ProcessID();
+
struct task_basic_info task_info;
DNBError err;
err = BasicInfo(task, &task_info);
@@ -363,7 +374,7 @@ MachTask::GetProfileData (DNBProfileDataScanType scanType)
if (scanType & eProfileThreadsCPU)
{
- get_threads_profile_data(scanType, task, m_process->ProcessID(), threads_id, threads_name, threads_used_usec);
+ get_threads_profile_data(scanType, task, pid, threads_id, threads_name, threads_used_usec);
}
struct vm_statistics vm_stats;
@@ -375,7 +386,7 @@ MachTask::GetProfileData (DNBProfileDataScanType scanType)
mach_vm_size_t dirty_size = 0;
mach_vm_size_t purgeable = 0;
mach_vm_size_t anonymous = 0;
- if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, m_process->GetCPUType(), m_process->ProcessID(), vm_stats, physical_memory, rprvt, rsize, vprvt, vsize, dirty_size, purgeable, anonymous))
+ if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, m_process->GetCPUType(), pid, vm_stats, physical_memory, rprvt, rsize, vprvt, vsize, dirty_size, purgeable, anonymous))
{
std::ostringstream profile_data_stream;
@@ -436,17 +447,23 @@ MachTask::GetProfileData (DNBProfileDataScanType scanType)
pagesize = PageSize();
}
+ /* Unused values. Optimized out for transfer performance.
profile_data_stream << "wired:" << vm_stats.wire_count * pagesize << ';';
profile_data_stream << "active:" << vm_stats.active_count * pagesize << ';';
profile_data_stream << "inactive:" << vm_stats.inactive_count * pagesize << ';';
+ */
uint64_t total_used_count = vm_stats.wire_count + vm_stats.inactive_count + vm_stats.active_count;
profile_data_stream << "used:" << total_used_count * pagesize << ';';
+ /* Unused values. Optimized out for transfer performance.
profile_data_stream << "free:" << vm_stats.free_count * pagesize << ';';
+ */
profile_data_stream << "rprvt:" << rprvt << ';';
+ /* Unused values. Optimized out for transfer performance.
profile_data_stream << "rsize:" << rsize << ';';
profile_data_stream << "vprvt:" << vprvt << ';';
profile_data_stream << "vsize:" << vsize << ';';
+ */
if (scanType & eProfileMemoryDirtyPage)
profile_data_stream << "dirty:" << dirty_size << ';';
@@ -458,6 +475,39 @@ MachTask::GetProfileData (DNBProfileDataScanType scanType)
}
}
+ // proc_pid_rusage pm_sample_task_and_pid pm_energy_impact needs to be tested for weakness in Cab
+#ifdef LLDB_ENERGY
+ if ((scanType & eProfileEnergy) && (pm_sample_task_and_pid != NULL))
+ {
+ struct rusage_info_v2 info;
+ int rc = proc_pid_rusage(pid, RUSAGE_INFO_V2, (rusage_info_t *)&info);
+ if (rc == 0)
+ {
+ uint64_t now = mach_absolute_time();
+ pm_task_energy_data_t pm_energy;
+ memset(&pm_energy, 0, sizeof(pm_energy));
+ /*
+ * Disable most features of pm_sample_pid. It will gather
+ * network/GPU/WindowServer information; fill in the rest.
+ */
+ pm_sample_task_and_pid(task, pid, &pm_energy, now, PM_SAMPLE_ALL & ~PM_SAMPLE_NAME & ~PM_SAMPLE_INTERVAL & ~PM_SAMPLE_CPU & ~PM_SAMPLE_DISK);
+ pm_energy.sti.total_user = info.ri_user_time;
+ pm_energy.sti.total_system = info.ri_system_time;
+ pm_energy.sti.task_interrupt_wakeups = info.ri_interrupt_wkups;
+ pm_energy.sti.task_platform_idle_wakeups = info.ri_pkg_idle_wkups;
+ pm_energy.diskio_bytesread = info.ri_diskio_bytesread;
+ pm_energy.diskio_byteswritten = info.ri_diskio_byteswritten;
+ pm_energy.pageins = info.ri_pageins;
+
+ uint64_t total_energy = (uint64_t)(pm_energy_impact(&pm_energy) * NSEC_PER_SEC);
+ //uint64_t process_age = now - info.ri_proc_start_abstime;
+ //uint64_t avg_energy = 100.0 * (double)total_energy / (double)process_age;
+
+ profile_data_stream << "energy:" << total_energy << ';';
+ }
+ }
+#endif
+
profile_data_stream << "--end--;";
result = profile_data_stream.str();
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
index f3a9d51c808..f0650d34783 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
@@ -12,10 +12,13 @@
//===----------------------------------------------------------------------===//
#include <inttypes.h>
+#include <mach/thread_policy.h>
+#include <dlfcn.h>
#include "MachThread.h"
#include "MachProcess.h"
#include "DNBLog.h"
#include "DNB.h"
+#include "ThreadInfo.h"
static uint32_t
GetSequenceID()
@@ -24,7 +27,7 @@ GetSequenceID()
return ++g_nextID;
}
-MachThread::MachThread (MachProcess *process, uint64_t unique_thread_id, thread_t mach_port_num) :
+MachThread::MachThread (MachProcess *process, bool is_64_bit, uint64_t unique_thread_id, thread_t mach_port_num) :
m_process (process),
m_unique_id (unique_thread_id),
m_mach_port_number (mach_port_num),
@@ -38,12 +41,16 @@ MachThread::MachThread (MachProcess *process, uint64_t unique_thread_id, thread_
m_num_reg_sets (0),
m_ident_info(),
m_proc_threadinfo(),
- m_dispatch_queue_name()
+ m_dispatch_queue_name(),
+ m_is_64_bit(is_64_bit),
+ m_pthread_qos_class_decode (nullptr)
{
nub_size_t num_reg_sets = 0;
m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets);
m_num_reg_sets = num_reg_sets;
+ m_pthread_qos_class_decode = (unsigned int (*)(unsigned long, int*, unsigned long*)) dlsym (RTLD_DEFAULT, "_pthread_qos_class_decode");
+
// Get the thread state so we know if a thread is in a state where we can't
// muck with it and also so we get the suspend count correct in case it was
// already suspended
@@ -719,3 +726,197 @@ MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id)
}
return tident.thread_id;
}
+
+nub_addr_t
+MachThread::GetPThreadT ()
+{
+ nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS;
+ if (MachPortNumberIsValid (m_mach_port_number))
+ {
+ kern_return_t kr;
+ thread_identifier_info_data_t tident;
+ mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
+ kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO,
+ (thread_info_t) &tident, &tident_count);
+ if (kr == KERN_SUCCESS)
+ {
+ // Dereference thread_handle to get the pthread_t value for this thread.
+ if (m_is_64_bit)
+ {
+ uint64_t addr;
+ if (m_process->ReadMemory (tident.thread_handle, 8, &addr) == 8)
+ {
+ if (addr != 0)
+ {
+ pthread_t_value = addr;
+ }
+ }
+ }
+ else
+ {
+ uint32_t addr;
+ if (m_process->ReadMemory (tident.thread_handle, 4, &addr) == 4)
+ {
+ if (addr != 0)
+ {
+ pthread_t_value = addr;
+ }
+ }
+ }
+ }
+ }
+ return pthread_t_value;
+}
+
+// Return this thread's TSD (Thread Specific Data) address.
+// This is computed based on this thread's pthread_t value.
+//
+// We compute the TSD from the pthread_t by one of two methods.
+//
+// If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we add to
+// the pthread_t to get the TSD base address.
+//
+// Else we read a pointer from memory at pthread_t + plo_pthread_tsd_base_address_offset and
+// that gives us the TSD address.
+//
+// These plo_pthread_tsd_base values must be read out of libpthread by lldb & provided to debugserver.
+
+nub_addr_t
+MachThread::GetTSDAddressForThread (uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
+{
+ nub_addr_t tsd_addr = INVALID_NUB_ADDRESS;
+ nub_addr_t pthread_t_value = GetPThreadT();
+ if (plo_pthread_tsd_base_offset != 0 && plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS)
+ {
+ tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset;
+ }
+ else
+ {
+ if (plo_pthread_tsd_entry_size == 4)
+ {
+ uint32_t addr = 0;
+ if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 4, &addr) == 4)
+ {
+ if (addr != 0)
+ {
+ tsd_addr = addr;
+ }
+ }
+ }
+ if (plo_pthread_tsd_entry_size == 4)
+ {
+ uint64_t addr = 0;
+ if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 8, &addr) == 8)
+ {
+ if (addr != 0)
+ {
+ tsd_addr = addr;
+ }
+ }
+ }
+ }
+ return tsd_addr;
+}
+
+
+nub_addr_t
+MachThread::GetDispatchQueueT ()
+{
+ nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS;
+ if (MachPortNumberIsValid (m_mach_port_number))
+ {
+ kern_return_t kr;
+ thread_identifier_info_data_t tident;
+ mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
+ kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO,
+ (thread_info_t) &tident, &tident_count);
+ if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 && tident.dispatch_qaddr != INVALID_NUB_ADDRESS)
+ {
+ // Dereference dispatch_qaddr to get the dispatch_queue_t value for this thread's queue, if any.
+ if (m_is_64_bit)
+ {
+ uint64_t addr;
+ if (m_process->ReadMemory (tident.dispatch_qaddr, 8, &addr) == 8)
+ {
+ if (addr != 0)
+ dispatch_queue_t_value = addr;
+ }
+ }
+ else
+ {
+ uint32_t addr;
+ if (m_process->ReadMemory (tident.dispatch_qaddr, 4, &addr) == 4)
+ {
+ if (addr != 0)
+ dispatch_queue_t_value = addr;
+ }
+ }
+ }
+ }
+ return dispatch_queue_t_value;
+}
+
+
+ThreadInfo::QoS
+MachThread::GetRequestedQoS (nub_addr_t tsd, uint64_t dti_qos_class_index)
+{
+ ThreadInfo::QoS qos_value;
+ if (MachPortNumberIsValid (m_mach_port_number) && m_pthread_qos_class_decode != nullptr)
+ {
+ uint64_t pthread_priority_value = 0;
+ if (m_is_64_bit)
+ {
+ uint64_t pri;
+ if (m_process->ReadMemory (tsd + (dti_qos_class_index * 8), 8, &pri) == 8)
+ {
+ pthread_priority_value = pri;
+ }
+ }
+ else
+ {
+ uint32_t pri;
+ if (m_process->ReadMemory (tsd + (dti_qos_class_index * 4), 4, &pri) == 4)
+ {
+ pthread_priority_value = pri;
+ }
+ }
+
+ uint32_t requested_qos = m_pthread_qos_class_decode (pthread_priority_value, NULL, NULL);
+
+ switch (requested_qos)
+ {
+ // These constants from <pthread/qos.h>
+ case 0x21:
+ qos_value.enum_value = requested_qos;
+ qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE";
+ qos_value.printable_name = "User Interactive";
+ break;
+ case 0x19:
+ qos_value.enum_value = requested_qos;
+ qos_value.constant_name = "QOS_CLASS_USER_INITIATED";
+ qos_value.printable_name = "User Initiated";
+ break;
+ case 0x15:
+ qos_value.enum_value = requested_qos;
+ qos_value.constant_name = "QOS_CLASS_DEFAULT";
+ qos_value.printable_name = "Default";
+ break;
+ case 0x11:
+ qos_value.enum_value = requested_qos;
+ qos_value.constant_name = "QOS_CLASS_UTILITY";
+ qos_value.printable_name = "Utility";
+ break;
+ case 0x09:
+ qos_value.enum_value = requested_qos;
+ qos_value.constant_name = "QOS_CLASS_BACKGROUND";
+ qos_value.printable_name = "Background";
+ break;
+ case 0x00:
+ qos_value.enum_value = requested_qos;
+ qos_value.constant_name = "QOS_CLASS_UNSPECIFIED";
+ qos_value.printable_name = "Unspecified";
+ break;
+ }
+ }
+ return qos_value;
+}
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h
index c3121112980..a4667603c44 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachThread.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h
@@ -28,6 +28,8 @@
#include "DNBArch.h"
#include "DNBRegisterInfo.h"
+#include "ThreadInfo.h"
+
class DNBBreakpoint;
class MachProcess;
class MachThreadList;
@@ -36,7 +38,7 @@ class MachThread
{
public:
- MachThread (MachProcess *process, uint64_t unique_thread_id = 0, thread_t mach_port_number = 0);
+ MachThread (MachProcess *process, bool is_64_bit, uint64_t unique_thread_id = 0, thread_t mach_port_number = 0);
~MachThread ();
MachProcess * Process() { return m_process; }
@@ -111,6 +113,11 @@ public:
return m_arch_ap.get();
}
+ ThreadInfo::QoS GetRequestedQoS (nub_addr_t tsd, uint64_t dti_qos_class_index);
+ nub_addr_t GetPThreadT();
+ nub_addr_t GetDispatchQueueT();
+ nub_addr_t GetTSDAddressForThread (uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
+
static uint64_t GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id);
protected:
@@ -138,6 +145,10 @@ protected:
thread_identifier_info_data_t m_ident_info;
struct proc_threadinfo m_proc_threadinfo;
std::string m_dispatch_queue_name;
+ bool m_is_64_bit;
+
+ // qos_class_t _pthread_qos_class_decode(pthread_priority_t priority, int *, unsigned long *);
+ unsigned int (*m_pthread_qos_class_decode) (unsigned long priority, int*, unsigned long *);
private:
friend class MachThreadList;
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp
index 634d2576332..68b272a6bd7 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp
@@ -22,7 +22,8 @@
MachThreadList::MachThreadList() :
m_threads(),
- m_threads_mutex(PTHREAD_MUTEX_RECURSIVE)
+ m_threads_mutex(PTHREAD_MUTEX_RECURSIVE),
+ m_is_64_bit(false)
{
}
@@ -48,6 +49,42 @@ MachThreadList::GetName (nub_thread_t tid)
return NULL;
}
+ThreadInfo::QoS
+MachThreadList::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index)
+{
+ MachThreadSP thread_sp (GetThreadByID (tid));
+ if (thread_sp)
+ return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index);
+ return ThreadInfo::QoS();
+}
+
+nub_addr_t
+MachThreadList::GetPThreadT (nub_thread_t tid)
+{
+ MachThreadSP thread_sp (GetThreadByID (tid));
+ if (thread_sp)
+ return thread_sp->GetPThreadT();
+ return INVALID_NUB_ADDRESS;
+}
+
+nub_addr_t
+MachThreadList::GetDispatchQueueT (nub_thread_t tid)
+{
+ MachThreadSP thread_sp (GetThreadByID (tid));
+ if (thread_sp)
+ return thread_sp->GetDispatchQueueT();
+ return INVALID_NUB_ADDRESS;
+}
+
+nub_addr_t
+MachThreadList::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
+{
+ MachThreadSP thread_sp (GetThreadByID (tid));
+ if (thread_sp)
+ return thread_sp->GetTSDAddressForThread(plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
+ return INVALID_NUB_ADDRESS;
+}
+
nub_thread_t
MachThreadList::SetCurrentThread(nub_thread_t tid)
{
@@ -276,19 +313,18 @@ MachThreadList::UpdateThreadList(MachProcess *process, bool update, MachThreadLi
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process->ProcessID() };
struct kinfo_proc processInfo;
size_t bufsize = sizeof(processInfo);
- bool is_64_bit = false;
if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0)
{
if (processInfo.kp_proc.p_flag & P_LP64)
- is_64_bit = true;
+ m_is_64_bit = true;
}
#if defined (__i386__) || defined (__x86_64__)
- if (is_64_bit)
+ if (m_is_64_bit)
DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
else
DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
#elif defined (__arm__) || defined (__arm64__)
- if (is_64_bit)
+ if (m_is_64_bit)
DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
else
DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
@@ -326,7 +362,7 @@ MachThreadList::UpdateThreadList(MachProcess *process, bool update, MachThreadLi
else
{
// We don't have this thread, lets add it.
- thread_sp.reset(new MachThread(process, unique_thread_id, mach_port_num));
+ thread_sp.reset(new MachThread(process, m_is_64_bit, unique_thread_id, mach_port_num));
// Add the new thread regardless of its is user ready state...
// Make sure the thread is ready to be displayed and shown to users
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h
index 46bccfee8de..5fac2c4b457 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h
@@ -15,6 +15,7 @@
#define __MachThreadList_h__
#include "MachThread.h"
+#include "ThreadInfo.h"
class DNBThreadResumeActions;
@@ -40,6 +41,12 @@ public:
const char * GetName (nub_thread_t tid);
nub_state_t GetState (nub_thread_t tid);
nub_thread_t SetCurrentThread (nub_thread_t tid);
+
+ ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index);
+ nub_addr_t GetPThreadT (nub_thread_t tid);
+ nub_addr_t GetDispatchQueueT (nub_thread_t tid);
+ nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
+
bool GetThreadStoppedReason (nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const;
void DumpThreadStoppedReason (nub_thread_t tid) const;
bool GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info);
@@ -73,6 +80,7 @@ protected:
collection m_threads;
mutable PThreadMutex m_threads_mutex;
MachThreadSP m_current_thread;
+ bool m_is_64_bit;
};
#endif // #ifndef __MachThreadList_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
index 857955b566d..df30ad637a4 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
@@ -243,66 +243,9 @@ MachVMMemory::GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t
kern_return_t kr;
info_count = TASK_VM_INFO_COUNT;
-#ifdef TASK_VM_INFO_PURGEABLE
kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count);
-#else
- kr = task_info(task, TASK_VM_INFO, (task_info_t)&vm_info, &info_count);
-#endif
if (kr == KERN_SUCCESS)
dirty_size = vm_info.internal;
-
-#else
- mach_vm_address_t address = 0;
- mach_vm_size_t size;
- kern_return_t err = 0;
- unsigned nestingDepth = 0;
- mach_vm_size_t pages_resident = 0;
- mach_vm_size_t pages_dirtied = 0;
-
- while (1)
- {
- mach_msg_type_number_t count;
- struct vm_region_submap_info_64 info;
-
- count = VM_REGION_SUBMAP_INFO_COUNT_64;
- err = mach_vm_region_recurse(task, &address, &size, &nestingDepth, (vm_region_info_t)&info, &count);
- if (err == KERN_INVALID_ADDRESS)
- {
- // It seems like this is a good break too.
- break;
- }
- else if (err)
- {
- mach_error("vm_region",err);
- break; // reached last region
- }
-
- bool should_count = true;
- if (info.is_submap)
- { // is it a submap?
- nestingDepth++;
- should_count = false;
- }
- else
- {
- // Don't count malloc stack logging data in the TOTAL VM usage lines.
- if (info.user_tag == VM_MEMORY_ANALYSIS_TOOL)
- should_count = false;
-
- address = address+size;
- }
-
- if (should_count)
- {
- pages_resident += info.pages_resident;
- pages_dirtied += info.pages_dirtied;
- }
- }
-
- vm_size_t pagesize = PageSize (task);
- rsize = pages_resident * pagesize;
- dirty_size = pages_dirtied * pagesize;
-
#endif
}
@@ -443,78 +386,21 @@ MachVMMemory::GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid,
rprvt += aliased;
}
-#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
-#ifndef TASK_VM_INFO_PURGEABLE
-// cribbed from sysmond
-static uint64_t
-SumVMPurgeableInfo(const vm_purgeable_info_t info)
-{
- uint64_t sum = 0;
- int i;
-
- for (i = 0; i < 8; i++)
- {
- sum += info->fifo_data[i].size;
- }
- sum += info->obsolete_data.size;
- for (i = 0; i < 8; i++)
- {
- sum += info->lifo_data[i].size;
- }
-
- return sum;
-}
-#endif /* !TASK_VM_INFO_PURGEABLE */
-#endif
-
static void
GetPurgeableAndAnonymous(task_t task, uint64_t &purgeable, uint64_t &anonymous)
{
#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
kern_return_t kr;
-#ifndef TASK_VM_INFO_PURGEABLE
- task_purgable_info_t purgeable_info;
- uint64_t purgeable_sum = 0;
-#endif /* !TASK_VM_INFO_PURGEABLE */
mach_msg_type_number_t info_count;
task_vm_info_data_t vm_info;
-#ifndef TASK_VM_INFO_PURGEABLE
- typedef kern_return_t (*task_purgable_info_type) (task_t, task_purgable_info_t *);
- task_purgable_info_type task_purgable_info_ptr = NULL;
- task_purgable_info_ptr = (task_purgable_info_type)dlsym(RTLD_NEXT, "task_purgable_info");
- if (task_purgable_info_ptr != NULL)
- {
- kr = (*task_purgable_info_ptr)(task, &purgeable_info);
- if (kr == KERN_SUCCESS) {
- purgeable_sum = SumVMPurgeableInfo(&purgeable_info);
- purgeable = purgeable_sum;
- }
- }
-#endif /* !TASK_VM_INFO_PURGEABLE */
-
info_count = TASK_VM_INFO_COUNT;
-#ifdef TASK_VM_INFO_PURGEABLE
kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count);
-#else
- kr = task_info(task, TASK_VM_INFO, (task_info_t)&vm_info, &info_count);
-#endif
if (kr == KERN_SUCCESS)
{
-#ifdef TASK_VM_INFO_PURGEABLE
purgeable = vm_info.purgeable_volatile_resident;
anonymous = vm_info.internal - vm_info.purgeable_volatile_pmap;
-#else
- if (purgeable_sum < vm_info.internal)
- {
- anonymous = vm_info.internal - purgeable_sum;
- }
- else
- {
- anonymous = 0;
- }
-#endif
}
#endif
diff --git a/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h b/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h
new file mode 100644
index 00000000000..1fd9d5790cf
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h
@@ -0,0 +1,26 @@
+//===-- ThreadInfo.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ThreadInfo_h__
+#define __ThreadInfo_h__
+
+namespace ThreadInfo {
+
+class QoS {
+public:
+ QoS () : constant_name(), printable_name(), enum_value(UINT32_MAX) { }
+ bool IsValid () { return enum_value != UINT32_MAX; }
+ std::string constant_name;
+ std::string printable_name;
+ uint32_t enum_value;
+};
+
+};
+
+#endif // __ThreadInfo_h__
OpenPOWER on IntegriCloud