diff options
Diffstat (limited to 'lldb/tools/debugserver/source/MacOSX')
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/Genealogy.cpp | 302 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/Genealogy.h | 116 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/GenealogySPI.h | 96 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachProcess.h | 12 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachProcess.mm | 41 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachTask.mm | 54 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachThread.cpp | 205 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachThread.h | 13 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp | 48 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachThreadList.h | 8 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp | 114 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/ThreadInfo.h | 26 |
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__ |